Implementazione di parti di RFC4226 (hotp) in mysql
-
24-09-2019 - |
Domanda
Come dice il titolo, sto cercando di implementare le parti programmatiche di RFC4226 "HOTP: un algoritmo di password One Time basato su HMAC in SQL. Penso di avere una versione che funziona (in quella per un piccolo campione di test, produce lo stesso risultato della versione Java nel codice), ma contiene una coppia nidificata di chiamate esadecimale (unlex ()), che i La sensazione può essere fatta meglio. Sono vincolato da a) che ho bisogno di fare questo algoritmo e b) che ho bisogno di farlo in Mysql, altrimenti sono felice di guardare altri modi di farlo.
Quello che ho finora:
-- From the inside out...
-- Concatinate the users secret, and the number of time its been used
-- find the SHA1 hash of that string
-- Turn a 40 byte hex encoding into a 20 byte binary string
-- keep the first 4 bytes
-- turn those back into a hex represnetation
-- convert that into an integer
-- Throw away the most-significant bit (solves signed/unsigned problems)
-- Truncate to 6 digits
-- store into otp
-- from the otpsecrets table
select (conv(hex(substr(unhex(sha1(concat(secret, uses))), 1, 4)), 16, 10) & 0x7fffffff) % 1000000
into otp
from otpsecrets;
Esiste un modo migliore (più efficiente) di farlo?
Soluzione
Non ho letto le specifiche, ma penso che tu non abbia bisogno di convertire avanti e indietro tra esadecimale e binario, quindi questo potrebbe essere un po 'più efficiente:
SELECT (conv(substr(sha1(concat(secret, uses)), 1, 8), 16, 10) & 0x7fffffff) % 1000000
INTO otp
FROM otpsecrets;
Questo sembra dare lo stesso risultato della tua domanda per alcuni esempi che ho testato.
Altri suggerimenti
Questo è assolutamente orribile, ma funziona con i miei token OTP a 6 cifre. Chiama come:
select HOTP( floor( unix_timestamp()/60), secret ) 'OTP' from SecretKeyTable;
drop function HOTP;
delimiter //
CREATE FUNCTION HOTP(C integer, K BINARY(64)) RETURNS char(6)
BEGIN
declare i INTEGER;
declare ipad BINARY(64);
declare opad BINARY(64);
declare hmac BINARY(20);
declare cbin BINARY(8);
set i = 1;
set ipad = repeat( 0x36, 64 );
set opad = repeat( 0x5c, 64 );
repeat
set ipad = insert( ipad, i, 1, char( ascii( substr( K, i, 1 ) ) ^ 0x36 ) );
set opad = insert( opad, i, 1, char( ascii( substr( K, i, 1 ) ) ^ 0x5C ) );
set i = i + 1;
until (i > 64) end repeat;
set cbin = unhex( lpad( hex( C ), 16, '0' ) );
set hmac = unhex( sha1( concat( opad, unhex( sha1( concat( ipad, cbin ) ) ) ) ) );
return lpad( (conv(hex(substr( hmac, (ascii( right( hmac, 1 ) ) & 0x0f) + 1, 4 )),16,10) & 0x7fffffff) % 1000000, 6, '0' );
END
//
delimiter ;