HMAC を実装する in Python


HMAC (RFC 2104) を Python で実装しました。 ハッシュ関数には ライブラリ にある SHA-256 を使いました。

HMAC の概要

HMAC は、メッセージの送信者の認証とメッセージの改ざんの検出に用いられるメッセージ認証符号(MAC: Message Authentication Code)を生成するための暗号化技術です。 HMACは、ハッシュ関数と秘密鍵を組み合わせて、MACを求めます。

HMACは、以下のような特徴を持ちます。

  • 秘密鍵とメッセージの両方に依存してMACを生成するので、秘密鍵を知らない者は同じMACを計算できません。これにより、送信者の認証が可能になります。
  • ハッシュ関数を2回適用することで、メッセージの一部を変更してもMACが一致する確率を非常に低くします。これにより、メッセージの改ざんを検知する能力を高めます。
  • HMACは、任意のハッシュ関数を用いることができます。例えば、SHA-256やMD5などのハッシュ関数をHMACに適用することができます。
  • HMACは、不可逆な暗号化技術です。

手続の説明

RFC 2104 に丁寧に手続きが記載されています。

HMAC に必要なのは、 ハッシュ関数 H と 秘密鍵 K です。

ハッシュ関数 H のブロック長を B バイト, 出力長を L バイト と表すことにします。 ハッシュ関数 H = SHA-256 のときは、 B = 64, L = 32 です。

K は秘密鍵とありますが、 公開鍵暗号における秘密鍵である必要はなく、 他の人に知られることがない秘密の文字列であればOKです。 RFC 2104 では private key ではなく secret key と書かれています。 K の長さは、 RFC では、最低でもハッシュ関数の出力長と記載されています。 K はハッシュ値とのビット演算を行うものであるため、 ハッシュ値より短いと規定の値で埋める必要があり、推測しやすくなるからですね。

HMAC の計算の流れは次のとおりです。

  1. 秘密鍵 K が ハッシュ関数のブロック長 B よりも長い場合は、 ハッシュ関数によって K を L バイト のハッシュ値に変換します。 生成されたハッシュ値を HMAC で使用する秘密鍵 K とします。
  2. 秘密鍵 K が ハッシュ関数のブロック長 B よりも短い場合は、 全体で B バイト になるように、 K の末尾に ゼロ (0x00) を追加します。
  3. 上の計算結果と 0x36 を B 回 繰り返した値 (ipad = b'\x36' * B) の、 XOR を計算します。 ビット単位の演算です。
  4. 上の計算結果の後ろに 暗号化したいメッセージ (ビット配列) を加えます。
  5. 上の計算結果を ハッシュ関数 H によってハッシュ値に変換します。
  6. 秘密鍵と、 0x5c を B 回 繰り返した値 (opad = b'\x5c' * B) の XOR を計算します。 ビット単位の演算です。
  7. 計算されたハッシュ値を上の計算で得られたXORの後ろに追加します。
  8. 上の計算結果を ハッシュ関数 H を使ってハッシュ値に変換します。

プログラム

そしてこちらがPythonで記述した HMAC (SHA-256) です。

環境

  • Python 3.10.13

コード

HMAC に代わる他のMAC生成方法

HMAC は ハッシュ関数秘密鍵 を組み合わせて MAC を求める方法でした。 MAC を生成する他の方法に、 Keccakハッシュ関数を使用する KMAC, 任意のブロック暗号を使用する CMAC があります。