在 Python 中生成 YubiOTP 验证 HMAC-SHA-1 签名

问题描述

我对这里需要为 Python 做的事情有点困惑,但是从 Yubikey API 文档中验证具有 YubiOTP 的 Yubikeys 需要以特定方式生成 HMAC 签名 - 从他们的 documentation :

生成签名

该协议使用 HMAC-SHA-1 签名。要使用的 HMAC 密钥是 客户端 API 密钥。

对消息中的参数生成签名。每个 消息包含一组键/值对,并且签名总是 在整个集合(不包括签名本身),并排序 键的字母顺序。更准确地说,生成消息 签名做:

  • 按键顺序按字母顺序对键/值对集进行排序。

  • 用每个有序的键/值对构造一行 使用 & 连接,每个键和值都用 = 连接。做 不要添加任何换行符。不要添加空格。例如: a=2&b=1&c=3

  • 在行上应用 HMAC-SHA-1 算法作为八位字节字符串使用 API 密钥作为密钥(记得对从 尤比科)。

  • Base 64 根据 RFC 4648 对结果值进行编码,例如 例如,t2ZMtKeValdA+H0jVpj3LIichn4=

  • 将键 h 下的值附加到消息中。

现在我从他们的文档中了解他们的 API 声明了以下有效的请求参数:

  • id - Yubico API 的客户端 ID
  • otp - 来自 yubikey 的 YubiOTP 组件的 YubiOTP 值。
  • h - 请求的 HMAC-SHA1 签名
  • timestamp - empty 什么都不做,1 包括服务器回复中的时间戳
  • nonce - 包含随机唯一数据的 16 到 40 个字符长的字符串。
  • sl - 0 到 100 之间的值,表示客户端所需的同步百分比,或字符串“fast”或“Secure”以使用服务器值;如果不存在的服务器决定
  • timeout - 等待同步响应的秒数;让服务器决定是否缺席。

我一共尝试使用两个函数来尝试处理所有这些事情并生成 URL。即,我们的 HMAC 支持函数和生成 URL 的 verify_url_generate(并且 API_KEY 是静态编码的 - 我的来自 Yubico 的 API 密钥):

def generate_signature(message,key=base64.b64decode(API_KEY)):
    message = bytes(message,'UTF-8')

    digester = hmac.new(key,message,hashlib.sha1)
    digest = digester.digest()

    signature = base64.urlsafe_b64encode(digest)

    return str(signature,'UTF-8')


def verify_url_generate(otp):
    nonce = "".join(secrets.choice(ascii_lowercase) for _ in range(40))

    data = OrderedDict(
        {
            "id": None,"nonce": None,"otp": None,"sl": 50,"timeout": 10,"timestamp": 1
        }
    )

    data['otp'] = otp
    data['id'] = CLIENT_ID
    data['nonce'] = nonce

    args = ""

    for key,value in data.items():
        args += f"{key}={value}&"

    sig = generate_signature(args[:-1])

    url = YUBICO_API_URL + args + "&h=" + sig

    print(url)
    return

由此生成的任何 URL 都会触发来自远程站点的有关“BAD_SIGNATURE”的通知 - 生成的任何 URL 减去 HMAC sig (h=) 参数都有效。所以我们知道问题不在于 URL,而在于 HMAC 签名。

有谁知道我的 HMAC 生成方法做错了什么,通过向 HMAC sig 生成器传递 key=value 中由 & 分隔的有序 dict 中的连接 args,用于每个参数格式?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)