Implementando partes do RFC4226 (HOTP) em MySQL
-
24-09-2019 - |
Pergunta
Como o título diz, estou tentando implementar as partes programáticas do RFC4226 "HOTP: um algoritmo de senha único baseado em HMAC" no SQL. Eu acho que tenho uma versão que funciona (para uma pequena amostra de teste, ela produz o mesmo resultado que a versão Java no código), mas contém um par de chamadas hexadecimais aninhadas (UNSEX ()), que eu A sensação pode ser feita melhor. Estou limitado por a) precisando fazer esse algoritmo e b) precisando fazê -lo no MySQL, caso contrário, fico feliz em procurar outras maneiras de fazer isso.
O que eu tenho até agora:
-- 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;
Existe uma maneira melhor (mais eficiente) de fazer isso?
Solução
Não li as especificações, mas acho que você não precisa se converter entre hexadecimal e binário, então isso pode ser um pouco mais eficiente:
SELECT (conv(substr(sha1(concat(secret, uses)), 1, 8), 16, 10) & 0x7fffffff) % 1000000
INTO otp
FROM otpsecrets;
Isso parece dar o mesmo resultado que sua consulta para alguns exemplos que testei.
Outras dicas
Isso é absolutamente horrível, mas funciona com meus tokens OTP de 6 dígitos. Ligue como:
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 ;