Creo que el culpable aquí es diferentes metodos de hash_hmac. Tu contador parece estar correcto, lo único que pudiera ser en ese aspecto es que los relojes no estén sincronizados.
Ahora, yo creo que el formato es el verdadero problema. En el RFC de TOTP ellos usan bytes para el secreto y el mensaje. Por ejemplo, si el secreto en ASCII es '12345678901234567890', el hexadecimal de este es:
Y por ejemplo, si el contador fuera 1, lo que ellos hacen es hacer 0 padding hasta tener 8 bytes.
En el ejemplo que ponen en su RFC, ellos usan Java y convierten el string hexadecimal a bytes. Para este preciso ejemplo, con Sha-1 y el secreto que mencione, ellos obtienen:
Y simplemente, no doy con ese TOTP sin importar que valores use en el hmac. Intente con strings en hexadecimal y ASCII (con pack). Simplemente, no obtengo esos números. Lo voy a probar con node, porque la libreria crypto en node si me deja usar buffers.
El RFC de TOTP por si te sirve:
https://tools.ietf.org/html/rfc6238
Edit: Ok, vale... pude hacerlo funcionar ya. Tanto el secreto como el contador parece que hash_hmac los toma como ASCII. No puedes enviar un entero como mensaje. Me imagino que PHP simplemente lo convierte a ASCII (1 vendría siendo 31 en hex). El contador también tiene que tener padding hasta que tengas 8 bytes. Un string en hexadecimal necesitaría tener 16 caracteres. Tomas el contador, lo conviertes a un string en hexadecimal y le agregas 0 hasta tener 16 caracteres.
Ejemplo:
3167928 es 3056B8 en hexadecimal. Le necesitas agregar otros 5 bytes (10 caracteres).
Y usas pack a ese string:
Los 0s son importantes...
En cuanto a tu secreto, es necesario que conviertas de Base32 a ASCII.
Ahora, yo creo que el formato es el verdadero problema. En el RFC de TOTP ellos usan bytes para el secreto y el mensaje. Por ejemplo, si el secreto en ASCII es '12345678901234567890', el hexadecimal de este es:
Código [Seleccionar]
31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30
Y por ejemplo, si el contador fuera 1, lo que ellos hacen es hacer 0 padding hasta tener 8 bytes.
Código [Seleccionar]
00 00 00 00 00 00 00 01
En el ejemplo que ponen en su RFC, ellos usan Java y convierten el string hexadecimal a bytes. Para este preciso ejemplo, con Sha-1 y el secreto que mencione, ellos obtienen:
Código [Seleccionar]
+-------------+--------------+------------------+----------+--------+
| Time (sec) | UTC Time | Value of T (hex) | TOTP | Mode |
+-------------+--------------+------------------+----------+--------+
| 59 | 1970-01-01 | 0000000000000001 | 94287082 | SHA1 |
| | 00:00:59 | | | |
+-------------+--------------+------------------+----------+--------+
Y simplemente, no doy con ese TOTP sin importar que valores use en el hmac. Intente con strings en hexadecimal y ASCII (con pack). Simplemente, no obtengo esos números. Lo voy a probar con node, porque la libreria crypto en node si me deja usar buffers.
El RFC de TOTP por si te sirve:
https://tools.ietf.org/html/rfc6238
Edit: Ok, vale... pude hacerlo funcionar ya. Tanto el secreto como el contador parece que hash_hmac los toma como ASCII. No puedes enviar un entero como mensaje. Me imagino que PHP simplemente lo convierte a ASCII (1 vendría siendo 31 en hex). El contador también tiene que tener padding hasta que tengas 8 bytes. Un string en hexadecimal necesitaría tener 16 caracteres. Tomas el contador, lo conviertes a un string en hexadecimal y le agregas 0 hasta tener 16 caracteres.
Ejemplo:
3167928 es 3056B8 en hexadecimal. Le necesitas agregar otros 5 bytes (10 caracteres).
Código [Seleccionar]
00000000003056B8
Y usas pack a ese string:
Código (php) [Seleccionar]
pack('H*', '00000000003056B8');
Los 0s son importantes...
En cuanto a tu secreto, es necesario que conviertas de Base32 a ASCII.