hash using sha512 - length of hash - php

I'm creating a 'unique' string by using:
hash('sha512', uniqid());
Will this always be the same length of characters - 128?
Am I correct in thinking that if I wish to change this length I could use sha256. Is that the difference between sha256/512 - the length of the hash?

A SHA-512 is 512 bits long as the name indicates.
The difference between SHA-256 and 512 is primarily in the number of rounds they perform internally (and other small details).
Note that if your main concern is the length of the string you can use a base 64 representation, i.e. you can use this chars [A-Za-z0-9]

Related

How many bits does CRYPT_BLOWFISH uses?

I use password_hash function in PHP to hash the user passwords before I store them in the database.
I use the default algorithm (ie. CRYPT_BLOWFISH) to hash the passwords. For the cost value I use 12 instead of 10. But one thing that I am not sure is the bit length of the encrypted password. is it 64, 128, 256 bit?
Also, does increasing the cost value increases the bit length?
Thanks
The PHP BCrypt implementation will generate base64 encoded strings with a length of 60 characters. This string contains all the parameters like salt and cost factor.
If your question is about the maximum number of characters that are used to generate the password, there is a limit with 72 characters. That means you can hash passwords of every length, but only the first 72 characters are used for the calculation (see How to hash long passwords...).

What is the format of password_hash output?

I know the PHP function, password_hash outputs the algorithm, cost, salt, and hash all in one string so password_verify can check a password.
Sample output from PHP page:
$2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a
so the $2y$ represents the algorithm, the 10 represents cost.
But how does password_verify separate the salt from the hash? I don't see any identifier separating the two afterwards.
For the bCrypt version of Password Hash.
Bcrypt has a fixed-length salt value. The crypt function which is what PHP calls internally when you're utilizing password_hash()/password_verify() with the default algorithm has a a 16 byte salt. This is given as a 22 characters of the custom base64 alphabet A-Za-z/. then it decodes the string into bytes as 22 B64 characters encode 16.5Bytes there is an extra nibble of data that is not taken into account.
For all other hashes the salt value is a defined set of bytes which are of course encoded into ASCII safe b64 and put after the $ sign and then the verifying function would only have to split the string into parts via the delimiter $ and then go for the third set of characters get the substr(0,B64_ENCODED_HASH_ALGORITHM_SALT_LEN). After that it would then pass the parameters it also got from the split string and pass those back into the password_hash function along with the password to check.
The string it gives you is defined by the hashing algorithm's standard in most cases but is almost always something to the pattern of
$<ALGORITHM_ID>$<COST_IN_FORMAT>$<BASE64_ENCODED_SALT><BASE64_ENCODED_HASH>$

Why shouldn't I use the 23rd character in a crypt() function's salt?

I'm learning about PHP's crypt() function and have been running some tests with it. According to this post, I should use a salt that's 22 characters long. I can, however, use a string that's 23 characters long with some limitations. When I use a 22 character long string I always get an outcome of '$2y$xxStringStringStringStri.HashHashHashHashHashHashHashHas'. I know the period is just part of the salt.
It seems that if I use 23 characters instead of just 22, I can successfully generate different hashes, but there is only 4 different outcomes for all 64 characters. The 23rd character "rounds down" to the nearest 1/4th of the 64 character alphabet (e.g. the 23rd character is "W" and rounds down to "O" or any number rounds down to "u")
v---------------v---------------v---------------v---------------
./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890
All four of these crypt functions generate the same salt:
crypt('Test123','$2y$09$AAAAAAAAAAAAAAAAAAAAAq');
crypt('Test123','$2y$09$AAAAAAAAAAAAAAAAAAAAAr');
crypt('Test123','$2y$09$AAAAAAAAAAAAAAAAAAAAAs');
crypt('Test123','$2y$09$AAAAAAAAAAAAAAAAAAAAAt');
But this one is different:
crypt('Test123','$2y$09$AAAAAAAAAAAAAAAAAAAAAu');
So why shouldn't I use the 23rd character when it can successfully generate different outcomes? Is there some kind of glitchy behavior in PHP that should be avoided by not using it?
For clarification on how I'm counting the 23rd character in the salt:
crypt('Test123','$2y$08$ABCDEFGHIJKLMNOPQRSTUV');
// The salt is '$ABCDEFGHIJKLMNOPQRSTUV'
// Which will be treated as '$ABCDEFGHIJKLMNOPQRSTUO'
It has to do with hash collisions. Once you exceed 22 characters your generated hashes are no longer unique depending on the NAMESPACE of the algorithm. To be said another way, more than 22 characters doesn't result in any increased security and can actually decrease your level of security.
$ is not part of the actual salt. It is a separator.
For Blowfish crypt, the format is $2[axy]$log2Rounds$[salt][hash]. You describe it adding a . -- that's because you are missing the last character. Blowfish's salt is 128 bits. You could use only 126, yes, but you are just unnecessarily weakening the salt.

Blowfish salt length for the Crypt() function?

According to the crypt() documentation, the salt needs to be 22 base 64 digits from the alphabet "./0-9A-Za-z".
This is the code example they give:
crypt('rasmuslerdorf', '$2a$07$usesomesillystringforsalt$');
The first confusing part is that salt has 25 characters, not 22.
Question #1: Does that mean the salt is supposed to be longer than 22 characters?
Then I tested the function myself and noticed something. If I use a 20 character salt, I get this
// using 20 char salt: 00000000001111111111
crypt('rasmuslerdorf', '$2a$07$00000000001111111111$');
// $2a$07$00000000001111111111$.6Th1f3O1SYpWaEUfdz7ieidkQOkGKh2
So, when I used a 20 character salt, the entire salt is in the output. Which is convenient, because I do not have to store the salt in a separate place then. (I want to use random salts). I would be able to read the salt back out of the generated hash.
However, if I use a 22 character salt as the documentation says, or a longer one, the salt is cut off at the end.
// using 22 char salt: 0000000000111111111122
crypt('rasmuslerdorf', '$2a$07$0000000000111111111122$');
// $2a$07$000000000011111111112uRTfyYkWmPPMWDRM/cUAlulrBkhVGlui
// 22nd character of the salt is gone
// using 25 char salt: 0000000000111111111122222
crypt('rasmuslerdorf', '$2a$07$0000000000111111111122222$');
// $2a$07$000000000011111111112uRTfyYkWmPPMWDRM/cUAlulrBkhVGlui
// Same hash was generated as before, 21 chars of the salt are in the hash
Question #2: So, what exactly is the proper length of a salt? 20? 22? Longer?
Question #3: Also, is it a good idea to read the salt out of the hash when it is time to check passwords? Instead of storing the salt in a separate field and reading it from there. (Which seems redundant since the salt seems to be included in the hash).
Blowfish salts should be 22 chars long (including the trailing $, so 21) - you can double check with var_dump(CRYPT_SALT_LENGTH), I can't verify this now but my guess is that less chars will return an error and more chars will be truncated.
Regarding your third question: yes, you should read and check the hash using the embedded salt (and cost) parameters from the hash itself.

Transforming a url into a unique 32 character token

I am writing an affiliate system, and I want to generate a unique 32 character wide token, from the url.
The problem is that a URL can be up to 128 chars long (IIRC). Is there a way that I can create a unique 32 char wide key/token from a given URL, without any 'collisions'?
I am not sure if this is an encoding, encryption or hashing problem (probably, a mixture of all three).
I will be implementing this 'mapping function' using PHP, since that is the language I am using to build this particular system. Any suggestions on how to go about doing this?
Is it even possible to map a 128 char string into a 32 char string uniquely (i.e. no collisions?) ...
[Edit]
I just did some reading up, and found that the max length of urls is actually, something in the order of 2K. However, I am not concerned about 'silly' edge cases like that. I am pretty sure that 99.9% of the time, my imposed limit of 128 chars should be sufficient.
Is it even possible to map a 128 char
string into a 32 char string uniquely
(i.e. no collisions?) ...
In part. You can use a hash function like md5 or sha1. That's what they were built to do.
MD5 generates a 32 char string, and SHA1 generates a 40 char string.
Of course you can't guarantee that there won't be collisions. That's impossible since the message space is too large for your hashes (there are 21024 messages vs 2128 possible hashes if you are using MD5), but these functions are meant to be collision resistant and hard to reverse.
Wikipedia references:
http://en.wikipedia.org/wiki/Hash_function
http://en.wikipedia.org/wiki/MD5
http://en.wikipedia.org/wiki/SHA-1
Is it even possible to map a 128 char string into a 32 char string uniquely (i.e. no collisions?) ...
That depends on the alphabet being used for both input and output. If your resulting 32 char hash is limited to an alphabet of a-z, you can encode a maximum of 26^32 = 1.901722×10^45 values in it. A URL can consist of at least a-z and quite a number of other characters, so can contain at least 26^128 = 1.307942×10^181 values. So, an alphabet of 26 characters is not enough.
Using a-zA-Z0-9 you can encode 62^32 = 2.272658×10^57 unique values, which is still not enough. Even an alphabet of 100 characters gives you only 100^32 = 1.0×10^64 possible values.
Depending on what exactly you want to do, you should either increase the length of the hash or rethink the overall approach.

Categories