[VOTE] Hash_pbkdf2

php.internals

Anthony Ferrara

14 years ago
Hello all, I've opened voting for the hash_pbkdf2 RFC adding hash_pbkdf2() to master: https://wiki.php.net/rfc/hash_pbkdf2#vote Thanks, Anthony

Paul Dragoonis

14 years ago
I see no coding examples, just a function declaration. On Mon, Jul 2, 2012 at 5:34 PM, Anthony Ferrara <ircmaxell@gmail.com> wrote:

Anthony Ferrara

14 years ago
Paul On Mon, Jul 2, 2012 at 12:38 PM, Paul Dragoonis <dragoonis@gmail.com> wrote:
> I see no coding examples, just a function declaration.
I've updated the RFC adding 2 examples. Anthony

Sara Golemon

14 years ago
I'd like to see hash_init() support this mode as well (for completeness). Perhaps something like the following: $ctx = hash_init("sha512", HASH_PBKDF2, $salt, array('length' => 32, 'iterations' => 5000)); The new fourth parameter being an overloadable options generic so that we don't have an endless list of parameters for all the possible hashing types. -Sara On Mon, Jul 2, 2012 at 9:34 AM, Anthony Ferrara <ircmaxell@gmail.com> wrote:

Anthony Ferrara

14 years ago
Sara, On Mon, Jul 2, 2012 at 8:24 PM, Sara Golemon <pollita@php.net> wrote:
> I'd like to see hash_init() support this mode as well (for completeness). >  Perhaps something like the following: > > $ctx = hash_init("sha512", HASH_PBKDF2, $salt, array('length' => 32, > 'iterations' => 5000)); > > The new fourth parameter being an overloadable options generic so that we > don't have an endless list of parameters for all the possible hashing types.
The only problem that I have with this sort of implementation is that the only way it would work is to buffer the entire input (each hash_update call), and run it all at the end. That's because the data (password) is used in every iteration, so there's no pre-computation that can be done. And at that point, what's the benefit to it? public function pbkdf2($algo, $password, $salt, $iterations, $length) { $size = getHashBlockSize($hash); $len = ceil($length / $size); $result = ''; for ($i = 1; $i <= $len; $i++) { $tmp = hash_hmac($hash, $salt . pack('N', $i), $password, true); $res = $tmp; for ($j = 1; $j < $iterations; $j++) { $tmp = hash_hmac($hash, $tmp, $password, true); $res ^= $tmp; } $result .= $res; } return substr($result, 0, $length); } Contrast that to a normal hash function (used by the current hash_init) which iterates over blocks of input, and once it's done with a block, it doesn't need it anymore (which is where using something like hash_init/hash_update can make sense on large input). Additionally, hmac only uses the message in a single hash, so it can be streamed in as well (pre-compute the earlier hashes/data, stream the intermediate hash, then hash the final one). So while it could be added (just make hash_update buffer into a context, then have hash_final actually run the derivation), I'm not sure it makes sense to add it there. Thoughts? Anthony

Sara Golemon

14 years ago
On Mon, Jul 2, 2012 at 5:49 PM, Anthony Ferrara <ircmaxell@gmail.com> wrote:
> Sara, > > On Mon, Jul 2, 2012 at 8:24 PM, Sara Golemon <pollita@php.net> wrote: > > I'd like to see hash_init() support this mode as well (for completeness). > > Perhaps something like the following: > > > > $ctx = hash_init("sha512", HASH_PBKDF2, $salt, array('length' => 32, > > 'iterations' => 5000)); > > > > The new fourth parameter being an overloadable options generic so that we > > don't have an endless list of parameters for all the possible hashing > types. > > The only problem that I have with this sort of implementation is that > the only way it would work is to buffer the entire input (each > hash_update call), and run it all at the end. That's because the data > (password) is used in every iteration, so there's no pre-computation > that can be done. And at that point, what's the benefit to it? > > public function pbkdf2($algo, $password, $salt, $iterations, $length) { > $size = getHashBlockSize($hash); > $len = ceil($length / $size); > $result = ''; > for ($i = 1; $i <= $len; $i++) { > $tmp = hash_hmac($hash, $salt . pack('N', $i), $password, > true); > $res = $tmp; > for ($j = 1; $j < $iterations; $j++) { > $tmp = hash_hmac($hash, $tmp, $password, true); > $res ^= $tmp; > } > $result .= $res; > } > return substr($result, 0, $length); > } > > Contrast that to a normal hash function (used by the current > hash_init) which iterates over blocks of input, and once it's done > with a block, it doesn't need it anymore (which is where using > something like hash_init/hash_update can make sense on large input). > > Additionally, hmac only uses the message in a single hash, so it can > be streamed in as well (pre-compute the earlier hashes/data, stream > the intermediate hash, then hash the final one). > > So while it could be added (just make hash_update buffer into a > context, then have hash_final actually run the derivation), I'm not > sure it makes sense to add it there. > > Thoughts? > > Anthony >
Ah, wasn't clear on how pbkdf2 worked. Your argument makes total sense. Thanks for explaining it. :)

Anthony Ferrara

14 years ago
Hey all, The voting phase has ended for hash_pbkdf2, and it has passed with a vote of 8:0. I've moved the RFC into Accepted state, and will merge the PR today into master, then move the RFC into Implemented. Thanks! Anthony On Mon, Jul 2, 2012 at 10:37 PM, Sara Golemon <pollita@php.net> wrote: