I am trying to write verification code in PhP following these steps...
The verification code is calculated by:
So far I have this code, but it's not working like I was hoping for:
function calculateVcode($hashString) {
$md = hash_init('sha256');
$hash = base64_decode($hashString);
hash_update($md, $hash);
$hash = hash_final($md, true);
$last = substr($hash, -2);
$code = bindec($last);
return substr(strval($code), -4);
}
$hashString = "Demo string for Authentication";
$md5Hash = md5($hashString);
$result = calculateVcode($md5Hash);`
Any ideas how to get this working or am I totally on the wrong path ?
Result could be like: Text used to generate a hash string “Auðkenni APP Authentication”
Hash string generated n/kRNhXaZ2jFKv8KlQX7ydgedXUmVy8b2O4xNq2ZxHteG7wOvCa0Kg3rY1JLOrOBXYQm+z2FRVwIv47w8gUb5g==
Verification code calculated from the hash 4141
What you need for proper SHA-256 hashing is the raw binary data that MD5 represents, not the encoded or string version of it. If you start with an MD5 hash string, you should convert this string back to its binary format if it's hex-encoded, or ensure that you're dealing with the binary data directly.
Also the way you're converting the last 2 bytes to an integer isn't quite right. The bindec()
function is not for converting binary data directly to integer, as it interprets a binary string, not raw bytes.
Once these are corrected you should expected results:
function calculateVcode($hashString) {
// Assume $hashString is already a proper byte sequence
$hash = hash('sha256', $hashString, true); // true for raw binary output
$lastTwoBytes = substr($hash, -2); // Get the last 2 bytes
$value = unpack("n", $lastTwoBytes); // Unpack as a big-endian ushort (16-bit int)
$code = $value[1] % 10000; // get last 4 digits
return $code;
}
$originalText = "Auðkenni APP Authentication";
$hashString = base64_decode("n/kRNhXaZ2jFKv8KlQX7ydgedXUmVy8b2O4xNq2ZxHteG7wOvCa0Kg3rY1JLOrOBXYQm+z2FRVwIv47w8gUb5g==");
$result = calculateVcode($hashString);
echo "Verification code: " . $result . "\n";
BTW: Your method to take the last 4 digits might result in errors if the converted integer is less than 4 digits long.
what is the best way to create the raw hash string ?
I'd generate a raw (in its binary form) SHA-512 hash of your data. Then encode it into Base64, which is necessary to transmit or store the hash in a text-friendly format. When you need to use this hash for further processing (like calculating your verification code), you'll decode it from Base64 back to its original raw binary form:
function createBase64EncodedSHA512(string $input): string {
$rawHash = hash('sha512', $input, true);
return base64_encode($rawHash);
}
function calculateVcodeFromBase64SHA512(string $base64EncodedHash): int {
$hashBytes = base64_decode($base64EncodedHash);
$hash = hash('sha256', $hashBytes, true);
$lastTwoBytes = substr($hash, -2);
$value = unpack("n", $lastTwoBytes);
$code = $value[1] % 10000;
return $code;
}
Usage example
$inputData = "Your data here";
$base64SHA512 = createBase64EncodedSHA512($inputData);
$verificationCode = calculateVcodeFromBase64SHA512($base64SHA512);
echo "Verification Code: " . $verificationCode . "\n";