让TOTP支持国密SM3算法

我们经常会扫码绑定动态令牌,其实这些二维码的内容是otpauth url,其格式如下:

otpauth-uri = “otpauth://” uri-type “/” uri-label “?” uri-parameters
uri-type = “totp” / “hotp”
uri-label = *VCHAR 标签
uri-parameters = “secret=” *base-32 [ 必须包含sercret参数为编码为base32的字符串 ]
uri-opt-parameters = (“&algorithm=” 算法默认SHA1,可选SHA256、SHA512)
uri-opt-parameters =/ (“&digits=” 默认位数6)
uri-opt-parameters =/ (“&counter=” *DIGIT HOTP需要设置) / (“&period=” *DIGIT 默认30秒)
uri-opt-parameters =/ (“&issuer=” *VCHAR) / (“&” *VCHAR “=” *VCHAR) 颁发者

以下主要讨论的是TOTP,即基于时间的OTP
做一个算法为SM3的otpauth url很简单,设置下&algorithm=SM3即可,不过常用的这些扫码的app由于不支持SM3算法,所以不能正确显示动态密码。需要在OTP的服务器上支持生成SM3的密钥,支持SM3动态密码的生成,支持SM3动态口令的验证。需要在手机app端能扫码SM3的otpauth url,并能正确显示其动态密码。

国密SM3算法是公开的,可以自行开发实现。当然我们可以采用官方的轮子了,比如GmSSL-JS中的sm3.js就够用了,其实该文件还存在一些小问题,你用的时候自行修改即可。在最后一行要添加一句
module.exports = { sm3_kdf, sm3_hmac } 用来在其他js中调用
在手机端的话,除了sm3的函数需要调用,你其实还需要设计实现base32的解码或者引入一个轮子来解码。至于扫二维码识别,可以考虑app中调用系统相机的二维码识别或者微信小程序中直接调用微信扫码识别。前端就没有什么更多好说的了。
后端关于生成SM3密钥可以考虑随机生成一个长字符串比如长度为64?然后调用sm3_kdf这个密钥派生函数生成密钥,注意转换成base32码生成otpauth url的二维码,让用户手机扫码绑定。只是生成当前时间的动态密码还达不到OTP的功能要求,一般OTP还能允许预设定的前后几个时间窗口的密码验证通过,实现起来也不麻烦,不过可以直接利用其他现成的轮子改改,比如speakeasy的OTP,虽然默认不支持SM3,但是跟其他算法的主要区别就在摘要函数实现中,改改就可以支持SM3算法了。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
TOTP(Time-Based One-Time Password)是一种基于时间的一次性密码算法,用于生成动态密码。它是基于HOTP(HMAC-Based One-Time Password)算法的扩展,通过结合时间戳和密钥生成密码,以提供更高的安全性。 以下是使用uniapp实现TOTP算法的示例代码: ```javascript // 导入js库 import jsSHA from 'jssha'; // 生成TOTP密码 function generateTOTP(secretKey) { // 获取当前时间戳 const timestamp = Math.floor(Date.now() / 1000); // 将时间戳转换为8字节的大端字节数组 const timeBytes = new Array(8); for (let i = 7; i >= 0; i--) { timeBytes[i] = timestamp & 0xff; timestamp >>>= 8; } // 使用HMAC-SHA1算法计算哈希值 const shaObj = new jsSHA('SHA-1', 'ARRAYBUFFER'); shaObj.setHMACKey(secretKey, 'ARRAYBUFFER'); shaObj.update(new Uint8Array(timeBytes)); const hmac = shaObj.getHMAC('ARRAYBUFFER'); // 获取哈希值的最后一个字节 const offset = hmac[hmac.length - 1] & 0xf; // 从哈希值中截取4个字节作为动态密码 const otp = ( ((hmac[offset] & 0x7f) << 24) | ((hmac[offset + 1] & 0xff) << 16) | ((hmac[offset + 2] & 0xff) << 8) | (hmac[offset + 3] & 0xff) ) % 1000000; // 将动态密码转换为6位字符串 const otpString = otp.toString().padStart(6, '0'); return otpString; } // 使用示例 const secretKey = 'JBSWY3DPEHPK3PXP'; // 密钥 const totp = generateTOTP(secretKey); console.log('TOTP密码:', totp); ``` 请注意,上述代码中使用了`jssha`库来计算HMAC-SHA1哈希值。在使用之前,需要先安装该库。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值