本帖最后由 candao2 于 2023-4-13 11:13 编辑
#申请原创#
概述: 前面3篇已经完成了所有的准备工作,本篇是最后的攻坚。TOTP验证码算法实际是使用HOTP算法,只是传给HOTP算法的参数counter是基于时间算出来的,本项目采用HOTP算法算出5位密码,再从device_id中取一位,一共6位作为验证码。TOTP算法依赖以下参数: device_id:设备id,实际项目中跟设备绑定,由服务器下发。 t_utc:当前网络时间,是UTC时间,不是北京时间。 t_interval: 时间步长,即多长时间内产生的密码相同,一般为60秒。 pow_lenth:HOTP算法算出的密码长度,为5位。
一 进行计算前的参数准备 下图中的cal_totp_pwd函数就是计算验证码,在sntp协议解析成功并更新本地RTC时间后调用计算一次验证码,图中有我定义的device_id值。同时,在任意时刻,只要按下按键KEY2(PA5),就会再进行一次计算。 上图的cal_totp_pwd函数实现,先准备好需要进行HOTP计算的key和counter参数,key是由设备id,再加上device_id[3]作为最后一位。counter是当前时间减去init_time时间得到的差,再除以时间步长得到的商,由此可见,步长时间(这里是60秒)之内计算的counter值相同,所以最后计算出来的密码也相同。 下图是从本地RTC时间转换成UTC时间,convert_time_to_second函数是把字符串格式的时间转换成以秒为单位的整数值。
二 HOTP的计算 如下图,调用HOTP函数时,传入到digits参数的值是5,即只取5位的密码,HOTP定义如下,HOTP计算分为3个步骤: 1 通过 HMAC的SHA-1 算法,生成一个 20 字节的数组digest[20] 2 dynamicTruncateSHA1函数从digest[20]中截取4位,组合成一个uint32_t类整数dt,至于是哪4位,依赖于此函数中的offset的计算,这里取digest[20]数组最后一个元素值作为offset。 3整数dt除以10的5次方即100000,得到的余数即是HOTP函数计算的值。
三 TOTP的计算 参看上面显示函数cal_totp_pwd定义的第二张图片,在函数cal_totp_pwd的最后3行,取HOTP函数返回的值code的高3位作为验证的高3位,code的低2位作为验证的低2位,验证码的还有一位直接取device_id的第4个字节device_id[3]。 如下图,在sntp完成之后,会自动计算一次验证,还可以按下一次KEY2(PA5)就会计算一次。在10点37时,是一个密码,10点38时,又是一个密码,同时看到device_id的第4个数就是验证码中的第4个数。
四 在windows平台计算验证码 如下图,把同样的TOTP算法代码移植到到windows平台,编译后,同一时间计算的验证码跟MCU 端一样。实际项目中,只需要把windows平台的验证码通过短信平台下发到手机上即可。 |