加密和比较哈希值

Checked a lot of tutorials and guides about Encrypting and Hashing on StackOver and I do now understand the difference between both of them. Encryption when we need decryption. Hash when you don't (e.g: passwords).

But my question today is, for generating random unique tokens. A lot of people recommend using base64_encode(rand_bytes(32)); because it generates a secure cryptographical id with random bytes/letters so it takes a long time to be cracked by a brute force ( to be predicted ).

But when you, for example, hash_hmac or crypt that id will it make it weaker? If so it won't matter if you use mt_rand or random_bytes as it will generate other letters/id. So what do you guys recommend?

Also, Is crypt better than hash_hmac for hashing?

The last question, Since blowfish has a really strong hashing algorithm, do I need to store my, for example, PHPSESSID or CSRF token with it or just a normal random_bytes?

Please guys, provide me with detailed information about these questions or documentation. Sorry for my lack of information and inexperience, I am new to PHP coding and thanks!

Edit: I have seen some guides on SO, not covering all my questions, so I need a 2017 detailed information not a 10 years ago post where md5 was the best etc..!

When you just want tokens that are unpredictable, use random_bytes(32). As long as you keep the tokens secret, there is no reason to alter the result of this function.

But you ask a lot of specific questions, so I will try to answer them as best I can:

When you hash or crypt() that id will it make it weaker?

This depends on the HMAC or crypt routine. When you generate 32 bytes of random data, and then use a function to reduce the size to 16 bytes, the security will be halved. However, if you use a cryptographically secure function that has at least 32 bytes of output, the security is not reduced. Now I say this, because crypt() is not cryptographically secure function. When hashing passwords, use password_hash() instead.

Is there a difference between using mt_rand and using random_bytes?

Yes, it will matter. mt_rand() uses a Mersenne Twister random number generator. These are not secure. This means that an attacker could use token values to guess other tokens. In the case of mt_rand(), this is often very easy. If you need the tokens to be secure (authentication tokens, session cookies, CSRF tokens, id's that may not be enumerated, etc.), use random_bytes. Also, if you are not sure, use random_bytes.

Also, Is crypt better than hash_hmac for hashing?

No. Crypt is deprecated and you should not use it. Use HMAC when you need message authentication codes (for example for password reset URLs). For password hashing, use password_hash.

Do I need to store my, for example, PHPSESSID or CSRF token with Blowfish or just a normal random_bytes?

Just use random_bytes. The random data is already random, it does not need to be randomized again. At least, as long as you keep these tokens secret and revoke them immediately when they have been leaked.

Hashing can't make your tokens any stronger or more random, there is no way to increase the entropy of a really random token or to improve it otherwise.

The only moment hashing a token makes sense, is when it is stored in the session/database (the client always should get the original token). Storing a hash in the database, will protect the tokens in case of a stolen database (SQL-injection).

In contrast to "weak" user passwords, "strong" random tokens cannot be successfully brute-forced, therefore salting and key-stretching is not necessary. One can use a simple fast hash function like SHA-256, which keeps the hashes searchable. When the client makes a request, the original token can be hashed again and the stored hash can be searched for.

@martinstoeckli Bro, you are amazing, I understood everything that you described clearly as you deeply explained everything. To double sure that I have it clear, check my code!

1-) Random tokens which have no hashes and is not stored in a database like CSFR tokens

$random_code = base64_encode(random_bytes(32)); //without hashing

2-) Remember Me - Client will have the random_code, and in the database, I have the hashed token stored.

example for remember_me

$random_code = base64_encode(random_bytes(32));

            $token = hash_hmac('sha256', ($random_code . $username) , $random_code);
            $token = hash_hmac('sha256', $random_code , $token);


      setcookie("remember", $username . "|" . $random_code, time()+(60 * 60 * 24 * 7), "/", "", 1, 1); //1 week