I want to generate a 40 bytes random password with
k = ???
password = sha1(openssl_random_pseudo_bytes(k))
What would be the recommended value of k so password is strong enough?
SHA1 outputs 20 bytes, so giving it 20 bytes of random input should be enough. Think of it like this: An attacker could either try to guess passwords or try to guess SHA1 inputs. As long as the SHA1 input is at least as long as the output, it's easier for him to just brueforce the outputs, so the input is long enough.
However, I'm wondering about why you're using SHA1 on those random bytes at all. openssl_random_pseudo_bytes should already give you random bytes that you can simply convert to hex using bin2hex or so.
Related
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...).
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.
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.
I was wondering if I use PHP's hash() function to generate sha512 hashes how would my MySQL table field look like in-order to be capable of holding the hashed password.
Here is my current MySQL password field layout
char(40)
A sha512 hash is represented as a 128 characters-long string.
For example, the following portion of code :
$sha512 = hash('sha512', "Hello, World!");
echo strlen($sha512);
Will give this output :
128
Which means your char(40) is far too small, and that you should use a char(128).
Another solution would be to store it in a binary form, and not a string -- which would mean 64 bytes.
But note it might be harder to deal with that representation, in some cases, I suppose.
I don't think I was specific enough last time. Here we go:
I have a hex string:
742713478fb3c36e014d004100440041004
e0041004e00000060f347d15798c9010060
6b899c5a98c9014d007900470072006f007
500700000002f0000001f7691944b9a3306
295fb5f1f57ca52090d35b50060606060606
The last 20 bytes should (theoretically) contain a SHA1 Hash of the first part (complete string - 20 bytes). But it doesn't match for me.
Trying to do this with PHP, but no luck. Can you get a match?
Ticket:
742713478fb3c36e014d004100
440041004e0041004e00000060
f347d15798c90100606b899c5a
98c9014d007900470072006f00
7500700000002f0000001f7691944b9a
sha1 hash of ticket appended to original:
3306295fb5f1f57ca52090d35b50060606060606
My sha1 hash of ticket:
b6ecd613698ac3533b5f853bf22f6eb4afb94239
Here's what is in the ticket and how it's being stored. FWIW, I can pull out username, etc, and spot the various delimiters.
http://www.codeproject.com/KB/aspnet/Forms_Auth_Internals/AuthTicket2.JPG
Edited: I have discovered that the string is padded on the end by the decryption function it goes through before this point. I removed the last 6 bytes and adjusted by ticket and hash accordingly. Still doesn't work, but I'm closer.
Your ticket is being calculated on the hex string itself. Maybe the appended hash is calculated on another representation of the same data?
I think you are getting confused about bytes vs characters.
Internally, php stores every character in a string as a byte. The sha1 hash that PHP generates is a 40 character (40 byte) hexademical representation of the 20-byte binary data, since each binary value needs to be represented by 2 hex characters.
I'm not sure if this is the actual source of your discrepancy, but seeing this misunderstanding makes me wonder if it's related.
Try trimming the string first, its suprisingly easy to have a newline or space on the end that changes the hash completely.
According to this Online SHA1 tool the hash of the given text (after removing new lines and spaces) is
b6ecd613698ac3533b5f853bf22f6eb4afb94239
Idea: Make sure your inputing characters not a hex number to the PHP version.
The problem was that the original was a keyed hash. I had to use hash_hmac() with a validation key rather than sha1() without.