簡體   English   中英

在 Python 中生成 YubiOTP 驗證 HMAC-SHA-1 簽名

[英]Generate YubiOTP verification HMAC-SHA-1 signatures in Python

我對我需要在這里為 Python 做的事情感到有些困惑,但是來自 Yubikey API 文檔,用於驗證具有 YubiOTP 的 Yubikeys 需要以特定方式生成 HMAC 簽名 - 從他們的文檔中:

生成簽名

該協議使用 HMAC-SHA-1 簽名。 要使用的 HMAC 密鑰是客戶端 API 密鑰。

在消息中的參數上生成簽名。 每條消息都包含一組鍵/值對,並且簽名始終覆蓋整個集合(不包括簽名本身),並按鍵的字母順序排序。 更准確地說,要生成消息簽名,請執行以下操作:

  • 按鍵順序按字母順序對鍵/值對集進行排序。

  • 構造一行,每個有序鍵/值對使用 & 連接,每個鍵和值使用=連接。 不要添加任何換行符。 不要添加空格。 例如: a=2&b=1&c=3

  • 使用 API 密鑰作為密鑰在行上應用 HMAC-SHA-1 算法作為八位字節字符串(請記住對從 Yubico 獲得的 API 密鑰進行 base64decode)。

  • Base 64 根據 RFC 4648 對結果值進行編碼,例如t2ZMtKeValdA+H0jVpj3LIichn4=

  • Append 消息的鍵 h 下的值。

現在我從他們的文檔中對他們的 API 的理解說明了以下有效的請求參數:

  • id - Yubico API 的客戶端 ID
  • otp - 來自 yubikey 的 YubiOTP 組件的 YubiOTP 值。
  • h - 請求的 HMAC-SHA1 簽名
  • timestamp - 空什么都不做, 1包括來自服務器的回復中的時間戳
  • nonce - 包含隨機唯一數據的 16 到 40 個字符長的字符串。
  • sl - 一個 0 到 100 的值,表示客戶端所需的同步百分比,或字符串“快速”或“安全”以使用服務器值; 如果不存在的服務器決定
  • timeout - 等待同步響應的秒數; 讓服務器決定是否缺席。

我總共嘗試使用兩個函數來嘗試處理所有這些事情並生成 URL。 即,我們 HMAC 支持 function 和生成 URL 的verify_url_generate (並且API_KEY是靜態編碼的 - 我的 ZDB974238714CA8DE634A7CE1D083A14 的密鑰):

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 中的連接參數傳遞給每個參數格式,用&分隔?

您可以嘗試在最終的 URL 中使用 standard_b64encode 然后使用 urllib.parse.quote(url) 嗎?

我之所以問,是因為此頁面上說“因此,所有參數必須正確 URL 編碼。特別是值字段中的某些 base64 字符(例如“+”)需要轉義。” 這意味着它在 args 中期待 +(或 %2B) 並執行取消引用然后正常解碼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM