Reputation: 575
i'm trying to reproduce in php the test cases mentioned in the official of totp computation reference (https://www.rfc-editor.org/rfc/rfc6238 Appendix A) which are written in java. The reference provides example for sha1, sha256 and sha512 algorithm.
I've found this nice example by Rob Swan (see the 8 digit example) that reproduces fine one test case (with sha1). But if I change the algorithm to sha256 or sha512 (and change the seeds too, according to the reference input data) I got different results from the reference's ones.
May the hmac hash function of php be different from java's one?
Thank you!
Upvotes: 1
Views: 1878
Reputation: 575
* SOLUTION
Here is a copy of the php implementation by Rob Swan I mentioned:
<?php
// Define your secret seed
// NB: this is a hexadecimal representation of the example
// ASCII string which is: 12345678901234567890
$secret_seed = "3132333435363738393031323334353637383930";
// Determine the time window as 30 seconds
$time_window = 30;
// Set the timestamp manually
$exact_time = 1111111109;
// Round the time down to the time window
$rounded_time = floor($exact_time/$time_window);
// Pack the counter into binary
$packed_time = pack("N", $rounded_time);
// Make sure the packed time is 8 characters long
$padded_packed_time = str_pad($packed_time,8, chr(0), STR_PAD_LEFT);
// Pack the secret seed into a binary string
$packed_secret_seed = pack("H*", $secret_seed);
// Generate the hash using the SHA1 algorithm
$hash = hash_hmac ('sha1', $padded_packed_time, $packed_secret_seed, true);
// NB: Note we have change the exponent in the pow function
// from 6 to 8 to generate an 8 digit OTP not a 6 digit one
// Extract the 8 digit number fromt the hash as per RFC 6238
$offset = ord($hash[19]) & 0xf;
$otp = (
((ord($hash[$offset+0]) & 0x7f) << 24 ) |
((ord($hash[$offset+1]) & 0xff) << 16 ) |
((ord($hash[$offset+2]) & 0xff) << 8 ) |
(ord($hash[$offset+3]) & 0xff)
) % pow(10, 8);
// NB: Note that we are padding to 8 characters not 6 for this example
// Add any missing zeros to the left of the numerical output
$otp = str_pad($otp, 8, "0", STR_PAD_LEFT);
// Display the output, which should be
echo "This should display 07081804: " . $otp;
?>
The key point is this line:
$offset = ord($hash[19]) & 0xf;
This works fine under the hypotesis of using sha1 algorithm, which returns a 20 chars string.
To abstract the line and make it compatible with any other algorithm change this line to:
$offset = ord($hash[strlen($hash)-1]) & 0xf;
Now you have a general and working php version of RFC 6238 totp calculation!
Upvotes: 1