Python: HMACを試す。

Webベースのサービスにおいて、送受信するデータの真贋を検証するためによく使われているHMAC(Hash-based Message Authentication Code)をPythonで試してみました。

1. HMACとは

HMAC (Hash-based Message Authentication Code) とは、メッセージ認証符号 (MAC; Message Authentication Code) の一つであり、秘密鍵とメッセージ(データ)とハッシュ関数をもとに計算される。

1997年2月、IBMのKrawczykらにより提唱され、RFC 2104として公開されている。 また、FIPS PUB 198にも採用されている。

Wikipediaより

2. HMACを使ったデータ検証

クライアントが送信したい「データ」と、そのデータを「秘密鍵」を使ってゴニョゴニョと符号化した「署名」をワンセットにして、Webサービスのエンドポイント(APIを受け付けるURL)に送信します。

サービス側は、クライアントと共有の秘密鍵で受信データをゴニョゴニョ符号化し、それを受信した署名と一致するかどうか検証します。
サービス側が送信したデータを、受信したクライアント側で検証するのも同様です。

さて、データをゴニョゴニョと符号化した署名の正体は何かというと、MD5とかSHA-256などのハッシュ関数を使って得たハッシュ値のことです。

ハッシュ関数とは、任意長のビット列から規則性のない固定長のビット列を生成する関数、手順のことをいう。一般に、ハッシュ関数への入力データは「メッセージ」、ハッシュ関数からの出力データは「ハッシュ値」「メッセージダイジェスト」「フィンガープリント」などと呼ばれる。ハッシュ関数は一方向関数であるため、出力データから入力データを推定することは極めて難しい。

@ITより

 

3. Pythonによる実装

今どきのプログラミング言語Python(3.7.3を使用)はハッシュもHMACも標準装備しています。

送信側を想定して、送信データ(sendData)と秘密鍵(secret)から署名(sig)を作成してみましょう。
なお、ハッシュ関数にSHA-256を使いました。

sigは256ビット長の非ASCIIを含むバイナリなので、WebサービスのAPI仕様にもよりますが、Base64などを使ってASCIIに変換してから送受信します。

 

16進数64桁のASCII文字列形式でハッシュ値を得ることも可能です。

 

あとは、APIの仕様にしたがって、Requestsなどを使いデータと署名を送信すればOK。
(割愛)

 

受信側を想定した、受信データを検証するプログラムです。

compare_digest()は符合同士が一致するかどうか検証する関数で、一致すればTrueを返します。

送信側と受信側で、同じデータ、秘密鍵、ハッシュ関数を使っているので、compareがTrueになるのは当然ですね。もし、compareがFalseになったら、受信データは偽物ということです。

わざわざcompare_digest()を使わずともcompare = signature == hexdigestで良さそうですが非推奨とのこと。

警告

hexdigest() の出力結果と外部から供給されたダイジェストを検証ルーチン内で比較しようとするのであれば、タイミング攻撃への脆弱性を減らすために、 == 演算子ではなく compare_digest()を使うことをお奨めします。

Python 3.7.3ドキュメントより

以上です。

Leave a Comment

メールアドレスが公開されることはありません。

CAPTCHA


このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください