Skip to main content

TOTP

时间同步, 客户端和服务端一致

是的,TOTP(Time-based One-Time Password)是一种基于时间的动态密码,它的生成依赖于共享的密钥和当前时间。由于时间同步的原因,客户端和服务端在同一时间点生成的 TOTP 应该是一致的。以下是对 TOTP 的进一步解释和在多因素认证中使用的示例。

TOTP 工作原理

  1. 共享密钥:客户端和服务端共享一个密钥(通常在注册或配置阶段进行)。
  2. 时间同步:客户端和服务端的系统时钟需要同步。
  3. TOTP 生成:客户端和服务端使用共享密钥和当前时间生成一个一次性密码。

示例代码

以下是一个 Python 示例,展示如何生成和验证 TOTP:

import time
import hmac
import base64
import struct
import hashlib

def generate_totp(secret, interval=30):
# 获取当前时间戳(以秒为单位)
current_time = int(time.time())
# 计算时间步数
time_step = current_time // interval
# 将时间步数转换为字节
time_bytes = struct.pack(">Q", time_step)
# 使用HMAC-SHA1算法生成哈希值
hmac_hash = hmac.new(secret, time_bytes, hashlib.sha1).digest()
# 取哈希值的最后一个字节的低4位作为偏移量
offset = hmac_hash[-1] & 0x0F
# 从哈希值中取出4个字节,并转换为整数
otp = (struct.unpack(">I", hmac_hash[offset:offset + 4])[0] & 0x7FFFFFFF) % 1000000
return otp

# 示例共享密钥(Base32编码)
shared_secret = base64.b32decode("JBSWY3DPEHPK3PXP")

# 生成TOTP
totp = generate_totp(shared_secret)
print(f"Generated TOTP: {totp}")

# 服务端验证TOTP
def verify_totp(secret, totp, interval=30, window=1):
# 验证当前时间步和前后时间步的TOTP
current_time = int(time.time())
for i in range(-window, window + 1):
time_step = (current_time // interval) + i
time_bytes = struct.pack(">Q", time_step)
hmac_hash = hmac.new(secret, time_bytes, hashlib.sha1).digest()
offset = hmac_hash[-1] & 0x0F
otp = (struct.unpack(">I", hmac_hash[offset:offset + 4])[0] & 0x7FFFFFFF) % 1000000
if otp == totp:
return True
return False

# 验证生成的TOTP是否有效
is_valid = verify_totp(shared_secret, totp)
print(f"Is TOTP valid: {is_valid}")

解释

  1. 生成 TOTP

    • generate_totp 函数使用共享密钥和当前时间生成一个 6 位的一次性密码。
    • 当前时间被分成 30 秒的时间步(interval)。
    • 使用 HMAC-SHA1 算法生成哈希值,并从中提取动态密码。
  2. 验证 TOTP

    • verify_totp 函数验证客户端提交的 TOTP 是否有效。
    • 为了处理时间同步误差,验证当前时间步和前后时间步的 TOTP。

Mermaid 交互图更新

解释

  1. 客户端派生多因素密钥(MFK):客户端使用多因素认证信息(如密码、TOTP 等)派生出一个密钥。
  2. 发送多因素信息(包括 TOTP):客户端将多因素信息(包括 TOTP)发送到服务端。
  3. 服务端验证多因素信息(包括 TOTP):服务端验证客户端提交的多因素信息(包括 TOTP)。
  4. 多因素验证通过/失败:服务端返回验证结果。如果验证失败,终止通信。
  5. 验证通过
    • 客户端和服务端生成并交换 DH 公钥。
    • 双方计算共享密钥。
    • 客户端结合共享密钥和 MFK,生成最终用于加密通信的密钥。
    • 客户端发送加密消息,服务端解密消息。
  6. 验证失败:服务端终止通信。

通过这种方式,确保只有通过多因素验证的客户端才能参与后续的密钥交换和加密通信,从而提高了通信的安全性。服务端在验证多因素信息后,可以使用共享密钥进行安全通信。