2026-08-21 08:45:25 +08:00
|
|
|
|
package simcu::otp
|
2026-08-21 08:43:24 +08:00
|
|
|
|
|
|
|
|
|
|
import stdx.crypto.digest.SHA1
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* HMAC-SHA1 实现(RFC 2104 / RFC 4226 第 5 节)。
|
|
|
|
|
|
* 仓颉标准库 std.crypto.digest 的 HMAC 目前仅支持 SHA512(HashType.SHA512),
|
|
|
|
|
|
* 而 HOTP/TOTP 标准基于 HMAC-SHA1,故在此基于 stdx 的 SHA1 自实现(blockSize=64)。
|
|
|
|
|
|
*/
|
|
|
|
|
|
public class HmacSha1 {
|
|
|
|
|
|
private let ipad: Array<Byte>
|
|
|
|
|
|
private let opad: Array<Byte>
|
|
|
|
|
|
|
|
|
|
|
|
public init(key: Array<Byte>) {
|
|
|
|
|
|
let blockSize: Int64 = 64
|
|
|
|
|
|
var tempKey = key
|
|
|
|
|
|
if (key.size > blockSize) {
|
|
|
|
|
|
let sha = SHA1()
|
|
|
|
|
|
sha.write(key)
|
|
|
|
|
|
tempKey = sha.finish()
|
|
|
|
|
|
}
|
|
|
|
|
|
ipad = Array<Byte>(blockSize, repeat: 0)
|
|
|
|
|
|
opad = Array<Byte>(blockSize, repeat: 0)
|
|
|
|
|
|
tempKey.copyTo(ipad, 0, 0, tempKey.size)
|
|
|
|
|
|
tempKey.copyTo(opad, 0, 0, tempKey.size)
|
|
|
|
|
|
for (i in 0..blockSize) {
|
|
|
|
|
|
ipad[i] ^= 0x36
|
|
|
|
|
|
opad[i] ^= 0x5c
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 计算 HMAC-SHA1(key, data)
|
|
|
|
|
|
public func compute(data: Array<Byte>): Array<Byte> {
|
|
|
|
|
|
let inner = SHA1()
|
|
|
|
|
|
inner.write(ipad)
|
|
|
|
|
|
inner.write(data)
|
|
|
|
|
|
let innerHash = inner.finish()
|
|
|
|
|
|
let outer = SHA1()
|
|
|
|
|
|
outer.write(opad)
|
|
|
|
|
|
outer.write(innerHash)
|
|
|
|
|
|
outer.finish()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|