Costanti PBKDF2

0

Recentemente ho trovato questo codice PBKDF2:

<?php
/*
 * Password Hashing With PBKDF2 (http://crackstation.net/hashing-security.htm).
 * Copyright (c) 2013, Taylor Hornby
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, 
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation 
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 * POSSIBILITY OF SUCH DAMAGE.
 */

// These constants may be changed without breaking existing hashes.
define("PBKDF2_HASH_ALGORITHM", "sha256");
define("PBKDF2_ITERATIONS", 1000);
define("PBKDF2_SALT_BYTE_SIZE", 24);
define("PBKDF2_HASH_BYTE_SIZE", 24);

define("HASH_SECTIONS", 4);
define("HASH_ALGORITHM_INDEX", 0);
define("HASH_ITERATION_INDEX", 1);
define("HASH_SALT_INDEX", 2);
define("HASH_PBKDF2_INDEX", 3);

function create_hash($password)
{
    // format: algorithm:iterations:salt:hash
    $salt = base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTE_SIZE, MCRYPT_DEV_URANDOM));
    return PBKDF2_HASH_ALGORITHM . ":" . PBKDF2_ITERATIONS . ":" .  $salt . ":" .
        base64_encode(pbkdf2(
            PBKDF2_HASH_ALGORITHM,
            $password,
            $salt,
            PBKDF2_ITERATIONS,
            PBKDF2_HASH_BYTE_SIZE,
            true
        ));
}

function validate_password($password, $correct_hash)
{
    $params = explode(":", $correct_hash);
    if(count($params) < HASH_SECTIONS)
       return false;
    $pbkdf2 = base64_decode($params[HASH_PBKDF2_INDEX]);
    return slow_equals(
        $pbkdf2,
        pbkdf2(
            $params[HASH_ALGORITHM_INDEX],
            $password,
            $params[HASH_SALT_INDEX],
            (int)$params[HASH_ITERATION_INDEX],
            strlen($pbkdf2),
            true
        )
    );
}

// Compares two strings $a and $b in length-constant time.
function slow_equals($a, $b)
{
    $diff = strlen($a) ^ strlen($b);
    for($i = 0; $i < strlen($a) && $i < strlen($b); $i++)
    {
        $diff |= ord($a[$i]) ^ ord($b[$i]);
    }
    return $diff === 0;
}

/*
 * PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
 * $algorithm - The hash algorithm to use. Recommended: SHA256
 * $password - The password.
 * $salt - A salt that is unique to the password.
 * $count - Iteration count. Higher is better, but slower. Recommended: At least 1000.
 * $key_length - The length of the derived key in bytes.
 * $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise.
 * Returns: A $key_length-byte key derived from the password and salt.
 *
 * Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
 *
 * This implementation of PBKDF2 was originally created by https://defuse.ca
 * With improvements by http://www.variations-of-shadow.com
 */
function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
    $algorithm = strtolower($algorithm);
    if(!in_array($algorithm, hash_algos(), true))
        trigger_error('PBKDF2 ERROR: Invalid hash algorithm.', E_USER_ERROR);
    if($count <= 0 || $key_length <= 0)
        trigger_error('PBKDF2 ERROR: Invalid parameters.', E_USER_ERROR);

    if (function_exists("hash_pbkdf2")) {
        // The output length is in NIBBLES (4-bits) if $raw_output is false!
        if (!$raw_output) {
            $key_length = $key_length * 2;
        }
        return hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output);
    }

    $hash_length = strlen(hash($algorithm, "", true));
    $block_count = ceil($key_length / $hash_length);

    $output = "";
    for($i = 1; $i <= $block_count; $i++) {
        // $i encoded as 4 bytes, big endian.
        $last = $salt . pack("N", $i);
        // first iteration
        $last = $xorsum = hash_hmac($algorithm, $last, $password, true);
        // perform the other $count - 1 iterations
        for ($j = 1; $j < $count; $j++) {
            $xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
        }
        $output .= $xorsum;
    }

    if($raw_output)
        return substr($output, 0, $key_length);
    else
        return bin2hex(substr($output, 0, $key_length));
}
?>

Tuttavia, non ho trovato da nessuna parte cosa fanno queste costanti e quali sono i loro valori raccomandati:

define("PBKDF2_SALT_BYTE_SIZE", 24);
define("PBKDF2_HASH_BYTE_SIZE", 24);
define("HASH_SECTIONS", 4);
define("HASH_ALGORITHM_INDEX", 0);
define("HASH_ITERATION_INDEX", 1);
define("HASH_SALT_INDEX", 2);
define("HASH_PBKDF2_INDEX", 3);

Puoi spiegarmelo per favore?

    
posta Vilican 21.11.2015 - 14:01
fonte

1 risposta

2

Prendendo prima il secondo blocco

define("HASH_SECTIONS", 4);
define("HASH_ALGORITHM_INDEX", 0);
define("HASH_ITERATION_INDEX", 1);
define("HASH_SALT_INDEX", 2);
define("HASH_PBKDF2_INDEX", 3);

è solo un modo prolisso per specificare il formato di archiviazione "stringato". La funzione create_hash concatena l'algoritmo hash, il conteggio dell'iterazione, il valore salt e il risultato pbkdf2 (hash della password) in questo ordine separati da due punti in un'unica stringa per l'archiviazione. validate_password divide quella stringa memorizzata nei due punti per ottenere 4 pezzi in un array, quindi l'algoritmo hash è nell'indice 0 nell'array ed è accessibile utilizzando [HASH_ALGORITHM_INDEX] dove HASH_ALGORITHM_INDEX è 0 e il conteggio dell'iterazione è all'indice 1 e si accede usando [HASH_ITERATION_INDEX] dove HASH_ITERATION_INDEX è 1, ecc.

Il primo blocco sono i parametri di sicurezza attuali:

PBKDF2_ITERATIONS = 1000 è stato consigliato quando rfc2898 è stato scritto nel 2000, ma quando l'hardware del computer è avanzato ora è meno sicuro. Se puoi, dovresti testare valori significativamente più grandi; prova per almeno 100k e un milione o più sarebbe meglio se non compromettesse le prestazioni del tuo sistema per il login (e la modifica della password, ma dovrebbe essere più raro).

PBKDF2_SALT_BYTE_SIZE = 24 è la dimensione in byte di sale, che dovrebbe essere abbastanza grande da essere unica con probabilità schiacciante per ogni password che hai; a causa del paradosso del compleanno questo dovrebbe estendersi almeno al quadrato del numero di password più un margine di sicurezza. 24 byte = 192 bit è generoso; Permette di pensare che ogni atomo del sistema solare abbia una password univoca sul tuo sistema, e non penso nemmeno che google lo pianifichi. potresti ridurlo a 16 o addirittura 12 se lo desideri, e ottenere in media un piccolo aumento delle prestazioni, ma probabilmente non ne vale la pena. Sicuramente non andare sotto l'8 o sei a rischio reale di duplicati.

PBKDF2_HASH_BYTE_SIZE = 24 è la dimensione in byte dell'hash generato. Dovrebbe essere abbastanza grande per essere ben al di fuori della gamma brute-force e come salt unica per ogni password, ma non dovrebbe essere superiore alla dimensione di output dell'hash (e quindi dell'HMAC) usato, perché che aumenta in modo differenziale il costo di difesa per l'attacco offline (dove non è possibile applicare la costante uguale a quella di un tempo costante). Per sha256 la dimensione dell'output è 32 byte quindi 24 va bene; in realtà qualsiasi cosa da circa 16 a 32 va bene. Se volevi usare sha1 dovresti ridurre la dimensione dell'hash a 20 byte, ma non ci sono buoni motivi per usare sha1 e farlo probabilmente attirerà critiche e forse verifiche che sarebbe una perdita di tempo da trattare con.

    
risposta data 22.11.2015 - 22:10
fonte

Leggi altre domande sui tag