2010-01-30 26 views
2

就像標題所說,我試圖在SQL中實現RFC4226「HOTP:基於HMAC的一次性密碼算法」的編程部分。我想我已經有了一個可行的版本(對於一個小測試示例,它產生的結果與代碼中的Java版本相同),但它包含一對嵌套的十六進制(unhex())調用,其中I感覺可以做得更好。我被a)需要做這個算法,b)需要在mysql中完成,否則我很高興看到其他方式做這個。在mysql中實現rfc4226(HOTP)的部分

到目前爲止,我已經得到了什麼:

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

我沒有讀過規範,但我認爲你不需要來回轉換十六進制和二進制之間,所以這可能是一個小更高效:

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

這似乎給對於我測試的幾個示例,查詢結果與您的查詢結果相同。

+0

感謝,背景應該並不重要,只要結果是相同的 – 2010-01-30 19:34:54

+0

是啊,那正是我想要的,再次感謝 – 2010-01-30 21:49:04

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 ;