DomBlack / php-scrypt

A PHP wrapper fo the scrypt hashing algorithm
Other
209 stars 57 forks source link

Default hash length is twice what it needs to be #36

Open multiwebinc opened 9 years ago

multiwebinc commented 9 years ago

The key length can safely be set to 16 instead of 32 because the string length of the hash returned by scrypt() for some reason is always doubled. So if you put 16 in, you get a 32 character hash, if you put 32 in you get 64 characters being produced. Since only the first 32 characters of the hash are ever used, making it longer than this is unnecessary.

var_dump(scrypt('password', 'salty', pow(2,14), 8, 2, 16));
var_dump(scrypt('password', 'salty', pow(2,14), 8, 2, 20));
var_dump(scrypt('password', 'salty', pow(2,14), 8, 2, 24));
var_dump(scrypt('password', 'salty', pow(2,14), 8, 2, 28));
var_dump(scrypt('password', 'salty', pow(2,14), 8, 2, 32));
var_dump(scrypt('password', 'salty', pow(2,14), 8, 2, 50));

Produces the output:

string(32) "e5135483ad9e2955f65dd1287a3b83d0"
string(40) "e5135483ad9e2955f65dd1287a3b83d0632f5082"
string(48) "e5135483ad9e2955f65dd1287a3b83d0632f50823b3ad12f"
string(56) "e5135483ad9e2955f65dd1287a3b83d0632f50823b3ad12fc3b7e874"
string(64) "e5135483ad9e2955f65dd1287a3b83d0632f50823b3ad12fc3b7e87432085014"
string(100) "e5135483ad9e2955f65dd1287a3b83d0632f50823b3ad12fc3b7e87432085014bf127be1b54afcb040ac456c4ff
Parent5446 commented 9 years ago

That would be because it is in hex. The key length determines how long the actual hash will be (in binary), but since hex characters only represent 4 bits, it will double when converted into hex.

multiwebinc commented 9 years ago

@Parent5446 Thanks for the explanation of why it's twice as long. However since the first 32 hex characters are always the same no matter what the key length, anything after that is unnecessary.

DomBlack commented 9 years ago

The hex output is only for connivance, given that the binary output would be preffered for most encoding schemes (see https://gitorious.org/scrypt/scrypt-unix-crypt) which uses the crypt(3) base64 encoding.

That said, we can't change the output of the hex encoding, simply because it will break any existing hashes which have been made. The best I can suggest is I update the documentation to state the the key length is in bytes, thus the hex encoding will be twice the length.

multiwebinc commented 9 years ago

That said, we can't change the output of the hex encoding

If you're talking about changing the type of encoding then I would agree that that can't be done, even if the crypt(3) base64 encoding would be preferred. However setting the key length to 16 wouldn't break current hashes if you truncated anything after 32 characters in the check method:

$hash = substr($hash, 0, 32);

(any time after the list() function is called)

My1 commented 8 years ago

but is it even safe when larger keys directly start with the smaller key? I dont know how muhc the work differentiates between long and short keys but if shorter keys are easier to compute an attacker could use shorter keys for trying and when found a collision try with larger key lengths.

multiwebinc commented 8 years ago

@My1 The chances of a collision happening with scrypt is essentially zero, so you can basically assume that no two different strings will ever be hashed to produce the same ciphertext. Since the first 32 characters of the ciphertext is always the same when increasing the key length, whether the key length increases the hash time or not is irrelevant because you only ever have to compare the first 32 characters to validate the input text. To quote @DomBlack:

The key length is almost irrelevant as changing the key length of the hash from X bits to X + 10 bits does not change the first X bits of output. Thus increasing you key length has no affect on security.

If hash difficulty is what you're after, the other parameters will affect this significantly more than the key length and do directly affect your hash's security.

The point of this bug is that increasing key length to anything beyond 16 will unnecessarily use up extra storage space, and changing it to 16 will not break any current hashes as long as they are truncated to 32 characters in the verify function. And since the first 32 characters is the only part that affects security, truncating anything after that would not matter.

My1 commented 8 years ago

well my point is that if creating an scrypt hash with just 10 characters would be easier to make with the same parameters (which should be made properly, obviously enough) then an attacker could instead bruteforce for those 10 first and check if he's gotten the pw, I am not even talking about collisions here, but especially with the simple passwords you can see in the world any vulnerability to a algorhythm used for password storage is bad.

multiwebinc commented 8 years ago

You can't create a hash with 10 characters. The minimum hash length is 32 characters, which is what is produced when using a key length of 16.

My1 commented 8 years ago

so you cannot make scrypt shorter than usual, that's good because I tried to invert the logic of this issue and wanted to know whether that works which seems not to be the case, which is good.

multiwebinc commented 8 years ago

Just out of curiosity I just did a quick test and hashing a password using a key length of 16 took 0.3019 seconds and a key length of 2^16 took 0.3052 seconds. So key length appears to have a negligible effect hash calculation time anyway.

My1 commented 8 years ago

wow a key length of 2^16 in such a short time that is not bad but good to know that the length doesnt matter in the first place, but if longer hashes would take longer it would be pretty epic to get the end result that will be used for whateber from somewhere in the back of the key...

gomin1d commented 4 years ago

use

$hash = pack("H*", $hash);