Today we’re going to focus on the use of PHP extension functions for Hash encryption, rather than the Hash algorithm, which is really just a more complicated key algorithm. Similar to the Hash algorithm, we’re going to type in a string, Just like a Hash table, it has a Hash Hash value, which is essentially the same as a Hash key-value mapping in a normal data structure, but with a more complex algorithm. If you’ve been doing PHP development for a while, you’ll be familiar with two functions: MD5 () and sha1(). These two functions generate Hash encryption using MD5 and SHA1 algorithms respectively. But what we’re going to do today is a little bit more complicated than these two functions, and the algorithm is a little bit richer.

What is a Hash information digest algorithm

Usually, when we enter a Hash function, the Hash string returned is the Hash summary of the input value. In PHP, the same input yields the same result, whether md5 or SHA1. For this reason, if you’re saving user password class information, try not to use just one layer of Hash, because this form of encryption can be brute force cracked by rainbow table. We can Hash the password multiple times and salt it to complicate the Hash value.

Of course, there are more Hash algorithms than just MD5 and SHA1, but there are other types of algorithms that we don’t use very often. However, the functions introduced today are a set of functions that can encrypt different types of Hash. They are already integrated into the default environment in PHP, and we do not need a separate extension to use them, thus making it easier to diversify our encrypted data.

Hash algorithm supported by PHP

print_r(hash_algos());
// Array
/ / (
// [0] => md2
// [1] => md4
// [2] => md5
// [3] => sha1
// [4] => sha224
// [5] => sha256
// [6] => sha384
// [7] => sha512/224
// [8] => sha512/256
// [9] => sha512
// [10] => sha3-224
// [11] => sha3-256
// [12] => sha3-384
// [13] => sha3-512
// [14] => ripemd128
// [15] => ripemd160
// [16] => ripemd256
// [17] => ripemd320
// [18] => whirlpool
/ / [19] = > tiger128, 3
/ / [20] = > tiger160, 3
/ / [21] = > tiger192, 3
/ / [22] = > tiger128, 4
/ / [23] = > tiger160, 4
/ / [24] = > tiger192, 4
// [25] => snefru
// [26] => snefru256
// [27] => gost
// [28] => gost-crypto
// [29] => adler32
// [30] => crc32
// [31] => crc32b
// [32] => fnv132
// [33] => fnv1a32
// [34] => fnv164
// [35] => fnv1a64
// [36] => joaat
/ / [37] = > haval128, 3
/ / [38] = > haval160, 3
/ / [39] = > haval192, 3
/ / [40] = > haval224, 3
/ / [41] = > haval256, 3
/ / [42] = > haval128, 4
/ / [43] = > haval160, 4
/ / [44] = > haval192, 4
/ / [45] = > haval224, 4
/ / [46] = > haval256, 4
/ / [47] = > haval128, 5
/ / [48] = > haval160, 5
/ / [49] = > haval192, 5
/ / [50] = > haval224, 5
/ / [51] = > haval256, 5
// )

$data = "Let's test the Hash algorithm!"; 

foreach (hash_algos() as $v) { 
    $r = hash($v.$data); 
    echo $v.':', strlen($r), '... '.$r, PHP_EOL; 
}
// md2:32::3d63d5f6ce9f03379fb3ae5e1436bf08
// md4:32::e9dc8afa241bae1bccb7c58d4de8b14d
// md5:32::2801b208ec396a2fc80225466e17acac
// sha1:40::0f029efe9f1115e401b781de77bf1d469ecee6a9
// sha224:56::3faf937348ec54936be13b63feee846d741f8391be0a62b4d5bbb2c8
// sha256:64::8f0bbe9288f6dfd2c6d526a08b1fed61352c894ce0337c4e432d97570ae521e3
// sha384:96::3d7d51e05076b20f07dad295b161854d769808b54b784909901784f2e76db212612ebe6fe56c6d014b20bd97e5434658
/ /...

foreach (hash_hmac_algos() as $v) { 
    $r = hash_hmac($v.$data.'secret'); 
    echo $v.':', strlen($r), '... '.$r, PHP_EOL; 
}
// md2:32::70933e963edd0dcd4666ab9253a55a12
// md4:32::d2eda43ee4fab5afc067fd63ae6390f1
// md5:32::68bf5963e1426a1feff8149da0d0b88d
// sha1:40::504bc44704b48ac75435cdccf81e0f056bac98ba
// sha224:56::8beaf35baedc2cd5725c760ec77d119e3373f14953c74818f1243f69
// sha256:64::23f2e6685fe368dd3ebe36e1d3d672ce8306500366ba0e8a19467c94e13ddace
// sha384:96::740ce7488856737ed57d7b0d1224d053905661ffca083c02c6a9a9230499a4a3d96ff0a951b8d03dbafeeeb5c84a65a6
/ /...
Copy the code

Using the hash_algos() and hash_hmac_algos() functions, we can retrieve all the Hash algorithms supported in the current PHP environment, including the familiar MD5 and sha1, Md2, SHA224, RIPEMD320, FNV1A64 and other rarely seen algorithms can also be seen. We can then see that each algorithm successfully returns a different digest of encrypted information, with different bits, by iterating over the contents of the two functions and using the hash() and hash_hmac() functions to hash the data and look at their contents.

The hMAC-related function is another form of PHP’s Hash algorithm, which is an algorithm that requires a key, which is the third argument to hash_hmac(). Only the same input with the same key will return the same result. That is, this function can be used to verify tokens for symmetric encrypted message passing. For example, if the interface communication between two systems requires a fixed token, this function can be used to achieve it.

Comparison with MD5 () and SHA1 ()

The hash() function is so powerful, does it generate the same content as MD5?

// Compare with the MD5 sha1 function

echo hash('md5'.'Let's test the Hash algorithm! '), PHP_EOL;
echo md5('Let's test the Hash algorithm! '), PHP_EOL;
// 2801b208ec396a2fc80225466e17acac
// 2801b208ec396a2fc80225466e17acac

echo hash('sha1'.'Let's test the Hash algorithm! '), PHP_EOL;
echo sha1('Let's test the Hash algorithm! '), PHP_EOL;
// 0f029efe9f1115e401b781de77bf1d469ecee6a9
// 0f029efe9f1115e401b781de77bf1d469ecee6a9

echo hash('fnv164'.'Let's test the Hash algorithm! '), PHP_EOL;
// b25bd7371f08cea4
Copy the code

This is certainly true, and I even feel that the md5() and sha1() functions themselves are syntactic sugar for the hash() function. Because these two algorithms are so common, PHP simply wraps two existing functions for us, and they take only one argument, which is very simple and convenient.

File HASH

Many download sites provide Hash values for downloaded files that we can check and compare to determine if the downloaded files are identical. This is the application of file Hash. It is simply a summary of the information about the file that was extracted and hashed. This set of features is of course perfectly supported in PHP as well.

/ file HASHecho hash_file('md5'.'./create-phar.php'), PHP_EOL;
echo md5_file('./create-phar.php'), PHP_EOL;
// ba7833e3f6375c1101fb4f1d130cf3d3
// ba7833e3f6375c1101fb4f1d130cf3d3

echo hash_hmac_file('md5'.'./create-phar.php'.'secret'), PHP_EOL;
// 05d1f8eb7683e190340c04fc43eba9db
Copy the code

HASH algorithm of HKDF and PBKDF2

The next two algorithms are special Hash algorithms. Similar to HMAC, but more complex than HMAC.

// HKDF pbkdf2 algorithm

// Algorithmic plaintext password (raw binary) output length application/context-specific information string salt value
$hkdf1 = hash_hkdf('sha256'.'123456'.32.'aes-256-encryption', random_bytes(2));
$hkdf2 = hash_hkdf('sha256'.'123456'.32.'sha-256-authentication', random_bytes(2));
var_dump($hkdf1);
var_dump($hkdf2);
/ / string (32) "ԇ ` q � � � � X l
/ / f � y ð � � � � �} Ozb +"
/ / string (32) % "� � �] + ̀ � � \ JdG � � � HL � GK � �
/ / -"

// Algorithm plaintext password salt number of iterations data length
echo hash_pbkdf2("sha256".'123456', random_bytes(2), 1000.20), PHP_EOL;
// e27156f9a6e2c55f3b72
Copy the code

Hmac requires only one key. Hash_hkdf () adds the return length, the application/context-specific information string, and the salt value. Hash_pbkdf2 () adds salt, number of iterations, and length of data, and is also a good tool for password encryption. However, they are more complex to use and can be used for very security-demanding passwords.

The hash_equals() function performs Hash comparisons

PHP also provides a function to compare Hash values for equality. === === === === === === Don’t worry. Let’s take a look at the code.

// hash_equals

$v1 = hash('md5'.'Test comparison');
$v2 = hash('md5'.'Test comparison');
$v3 = hash('md5'.'Test comparison 1');

// Comparing two strings, regardless of whether they are equal or not, the elapsed time of this function is constant
// This function can be used in string comparison scenarios where you need to protect against timing attacks. For example, it can be used to compare crypt() password hashes
var_dump(hash_equals($v1.$v2));
var_dump(hash_equals($v1.$v3));
// bool(true)
// bool(false)
Copy the code

As I’ve made clear in the comments, hash_equals() is mainly used to prevent sequential attacks. In general, this sequential attack is to determine what functions or functions are used in your system based on how long your system has been running, which is something that very good hackers play. For example, we compare the user password, a hypothesis is a comparison, if the first character in the wrong information will soon be back, but if you compare to the last just wrong, programs run time will grow a lot, hackers can according to this time to judge whether the content of the brute force currently step by step to achieve the goal, It also makes it easier to crack. (Ordinary string comparisons === are based on displacement). Hash_equals () returns the same amount of time for the same Hash algorithm length, no matter how it is compared. OpenSSL, OpenSSH, and other software have seen this kind of timing attack vulnerability!

Of course, we only know about this, but also for some projects with special requirements for security, you can use this function to avoid the vulnerability of such timing attacks to improve system security.

Incremental Hash operation

The last thing we’ll learn is a set of delta Hash manipulation functions. For strings, most of the time we just concatenate the string and Hash it. We don’t really need the ability to increment Hash. But for multiple files or read/write streams, if you want to get the Hash value for multiple files, you can use this set of incremental Hash functions.

/ / increment the HASH

$fp = tmpfile();
fwrite($fp.'Initialize a stream file');
rewind($fp);

$h1 = hash_init('md5'); // Start incremental Hash
hash_update($h1.'Test increment'); // A common character string
hash_update_file($h1.'./create-phar.php'); / / file
hash_update_stream($h1.$fp); / / flow
$v1 = hash_final($h1); // End Hash returns the result
echo $v1, PHP_EOL;
// 373df6cc50a1d7cd53608208e91be1e7

$h2 = hash_init('md5', HASH_HMAC, 'secret'); // Use incremental HMAC HASH
hash_update($h2.'Test increment');
hash_update_file($h2.'./create-phar.php');
hash_update_stream($h2.$fp);
$v2 = hash_final($h2);
echo $v2, PHP_EOL;
// 34857ee5d8b573f6ee9ee20723470ea4
Copy the code

We use hash_init() to get an incremental Hash operation handle and specify the encryption algorithm. Then use hash_update() to add strings, hash_update_file() to add file contents, and hash_update_stream() to add stream contents. Finally, use hash_final() to end the handle operation for the Hash and return the result value. The resulting value is the Hash that contains the string, file, and stream contents.

conclusion

To be honest, I thought PHP only had MD5 and SHA1 Hash algorithms until I learned today. This is really a big eye-opener, we not only have a rich library of algorithms, but also a lot of convenient operation functions can help us easily use these algorithms, no more to say, learn to continue!

Test code:

Github.com/zhangyue050…

Reference Documents:

www.php.net/manual/zh/b…

www.zhihu.com/question/20…

Baike.baidu.com/item/%E6%97…