在mysql中实现rfc4226(HOTP)的部分

时间:2010-01-30 18:58:33

标签: mysql one-time-password

就像标题所说,我正在尝试在SQL中实现RFC4226“HOTP:基于HMAC的一次性密码算法”的编程部分。我想我有一个可行的版本(对于一个小的测试样本,它产生与代码中的Java版本相同的结果),但它包含一对嵌套的十六进制(unhex())调用,我感觉可以做得更好。我受到以下因素的限制:a)需要做这个算法,b)需要在mysql中做,否则我很乐意看看其他方法。

到目前为止我得到了什么:

  -- 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;

有更好(更有效)的方法吗?

2 个答案:

答案 0 :(得分:2)

我没有阅读规范,但我认为你不需要在十六进制和二进制之间来回转换,所以这可能会更有效:

SELECT (conv(substr(sha1(concat(secret, uses)), 1, 8), 16, 10) & 0x7fffffff) % 1000000
INTO otp
FROM otpsecrets;

这似乎与我测试的一些示例的查询结果相同。

答案 1 :(得分:1)

这绝对是可怕的,但它适用于我的6位OTP令牌。请致电:

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 ;