A way to prevent timing attacks for hash string comparison is to perform additional HMAC signing in order to randomize the verification process (see https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/february/double-hmac-verification/).
In addition to the second HMAC hashing for each hash, a random salt of random length is added to both in order to make the hashing timing / process even less predictable.
My implementation of this look like this:
function hmac_verify ($hash_original, $message, $key) {
$hmac_salt = '...'; // was added at the original HMAC signing
$random_salt = openssl_random_pseudo_bytes (rand(16,96));
$raw_hash = hash_hmac('sha512', $message . $hmac_salt, $key, true);
$hash_compare = base64_encode ($raw_hash); // $hash_original is in base64
$hash_compare_safe = hash_hmac('sha512', $hash_compare, $random_salt, true);
$hash_original_safe = hash_hmac('sha512', $hash_original, $random_salt, true);
if ($hash_compare_safe === $hash_original_safe) return true;
else return false;
}
The function is called in this way after decrypting the encrypted text in order to verify the decryption result:
if (!hmac_verify ($hmac_hash, $plaintext . $cipher_text, $key . $iv)) return "HASH ERROR";
Will this successfully prevent a timing attack? Am I doing anything unnecessary? Could something be improved?
A second question is whether it is more advisable to perform the HMAC verification on the plaintext, the ciphertext, or both (as in my example), and why.