如何生成一次性密码(OTP/HOTP)?

isN*_*247 13 c# security

我们决定开始为多因素身份验证开展工作,为我们的客户发布iPhone,Android和Blackberry应用程序.

想想Google Authenticator的一次性密码系统.

我可以通过使用基于帐户密钥加上设备序列号(或其他唯一标识符)的SALT进行散列来生成唯一字符串.

但有没有人知道如何以谷歌的方式生成一个独特的短数字?和/或有没有人有任何关于实现这种事情的文章的良好链接?

非常感谢

isN*_*247 10

最后,我发现这在RFC 4226中有很好的记录,关于整数转换,这可以使用第7页所示的按位操作来完成,基本上它与下面的答案中显示的相同.

关于计算器另一篇文章在C#背景下,这可能是值得一读,如果你是在一个类似的立场对此.

在C#中我基本上散列了一个时间标识符(即以秒为单位的当前时间除以30 - 得到一个对当前30秒间隔有效的长度).然后使用我的密钥作为SALT对此进行哈希处理.

然后...

// Use a bitwise operation to get a representative binary code from the hash
// Refer section 5.4 at http://tools.ietf.org/html/rfc4226#page-7            
int offset = hashBytes[19] & 0xf;
int binaryCode = (hashBytes[offset] & 0x7f) << 24
    | (hashBytes[offset + 1] & 0xff) << 16
    | (hashBytes[offset + 2] & 0xff) << 8
    | (hashBytes[offset + 3] & 0xff);

// Generate the OTP using the binary code. As per RFC 4426 [link above] "Implementations MUST extract a 6-digit code at a minimum 
// and possibly 7 and 8-digit code"
int otp = binaryCode % (int)Math.Pow(10, 6); // where 6 is the password length

return otp.ToString().PadLeft(6, '0');
Run Code Online (Sandbox Code Playgroud)

对于那些不知道的人,Google Authenticator是一个开源项目 - 您可以在这里浏览源代码.

  • 你能否添加用于散列时间标识符的代码? (3认同)

irc*_*ell 6

那么,它不具有是唯一的.它只需要有相当多的熵.这意味着获得相同字符串的可能性相当低.

这样做的一种方法是获取哈希并切断一定数量的整数:

var hash = sha1(salt + device + secretKey);
var numbers = base_convert(hash, 16, 10); // Convert hex string to a integer
var key = numbers % 100000; // Limit to 5 digits (you can change this on need)
Run Code Online (Sandbox Code Playgroud)

只记得留下数字,0如果它太短,它就以文字开头.

  • @Marcin:简单.因为谁想给某人一个40个字符的十六进制字符串从他们的手机输入?这是让用户讨厌你的快捷方式.当然,在一些非常安全的环境中,它可能是可以接受的,但总是需要平衡安全性和可用性.你想要一个相当容易使用的系统...... (3认同)