前言
最近看到朋友家装了新的只能门锁, 可以使用指纹或密码解锁. 密码解锁没什么, 但其在手机端可以生成一个临时密码倒是引起了我的兴趣. 这个场景是这样的:
- 密码锁不能联网
- 生成密码时, APP与密码锁没有通讯(不在一起, 且密码锁不能联网)
- APP 和密码锁仅在首次配对的时候进行过通讯
- 临时密码有效期为30分钟, 从密码的生成时间开始计算
- 手机端可以多次生成临时密码, 每个都不一样且有效
那么问题来了, 密码锁是如何验证密码是否有效的呢?
实现方案思考
方案一: 预生成
思路:
- APP与密码锁在首次配对的时候, 预先生成1万个临时密码
- 每次获取临时密码时, 从预生成列表中获取下一个即可
问题:
- 密码无法与时间绑定, 无法实现"临时"的需求
- 密码用尽后需要重新配对
方案二: TOTP
思路:
- 基于动态密码 TOTP 方案实现
- 在配对的时候同步共享密码与计数器
- 计数器每30分钟+1
问题:
- TOTP为固定时间窗口, 无法实现动态窗口
- 计数器每30分钟+1, 无法多次生成临时密码
方案三: 增强型 TOTP
到这里其实已经有方案了, TOTP是固定窗口, 那多个固定窗口连在一起, 不就是个滑动窗口么.
思路:
- 仍然基于 TOTP 的方案, 在配对时同步共享密钥和计数器
- 计数器每5秒+1
- 密码验证时, 验证当前时间向前推30分钟的所有 TOTP密码, 若与其中一个匹配即为可用
若计数器每5秒+1, 则30分钟可产生的密码数量为: (30min / 5s)=360
个
这个方案是我想到能够满足此场景的. 优势:
- 双方无需存储密码队列, 无存储开销
- 能够把握30分钟的滑动窗口, 误差为5秒
- 每5秒可生成一个新的动态密码, 支持重复生成
潜在问题:
- 时间同步: 密码锁长时间无对外通讯, 时间同步可能产生误差. 可在每次通讯时调整, 或适当放宽验证的时间范围以平衡时钟误差
- 计算资源: 每次密码验证需要进行360次 TOTP 计算. 可考虑在密码锁中维护一个密码队列, 每5秒生成密码添加到队列中, 并将旧密码出队列. 这样验证密码的时候就不需要频繁计算了
以上, 就是基于这个场景进行的设想, 其具体是如何实现的俺就不晓得了.