\( \def\vector#1{\boldsymbol{#1}} \)

メッセージ認証コード

Takami Torao Java 11 #MAC #HMAC
  • このエントリーをはてなブックマークに追加

概要

メッセージ認証コード (MAC; message authentication code) はメッセージが発行者によって発行されてから破損や改ざんを受けていないことを検証するために使用する小さなデータ。送信者はメッセージと共通鍵を使用して作成した MAC 値をメッセージと共に送信する。受信者は、同じく自身が持つ共通鍵を使ってメッセージから MAC 値を算出し、受信した MAC 値と一致していればメッセージの完全性が保証される。

メッセージの送信者と受信者が共通鍵を共有することによって行われる点がメッセージダイジェストとは異なる。

この方法は共通鍵を持たない中間者によるメッセージ改ざんを防ぐ事ができる。また、メッセージ内にシーケンス番号や日時のような nonce を含めることで中間者が同一のメッセージを繰り返し送信するリプレイ攻撃を防ぐことができる。

MAC 値の生成は MAC 値とメッセージから共有鍵の推測が困難なアルゴリズムであれば使用できる。不可逆ハッシュ関数を用いる方法は HMAC (hash-based message authentication code) と呼ばれる。ブロック暗号を用いる方法は

HMAC

HMAC (hash-based message authentication code) は MAC 値の生成に SHA などの不可逆ハッシュ関数を使用する方法である。

ユーザのパスワードをサーバサイドで保管/照合するケースでは一般的に SALT と不可逆ハッシュ関数を使ってハッシュ化した値を使用する手法がとられている。以下の例は共通鍵に SALT を使いパスワードをメッセージとして HMAC でハッシュ化する例である。

import java.nio.charset.StandardCharsets

import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec

val UTF8 = StandardCharsets.UTF_8

val algorithm = "HmacSHA224"
val password = "8ErY(cw92TLB".getBytes(UTF8)  // 入力されたパスワード
val salt = "K*t%A-qL6!vg".getBytes(UTF8)      // ランダムなバイト配列
val key = new SecretKeySpec(salt, algorithm)
val mac = Mac.getInstance(algorithm)
mac.init(key)
val encoded = mac.doFinal(password)
println(encoded.map(x => f"$x%02X").mkString) // => 467A4B8E5BD5F3B97D1296401547B5B329A162FC36A679EB53DB9E11

// encoded (28バイト) と、salt または key.getEncoded (12バイト) を保存する

上記の例では共通鍵のエンコード (salt.getEncoded; 12バイト) とパスワードの MAC 値 (encoded; 28バイト = 224ビット) を保存すれば良い。検証時は入力されたパスワードを同じアルゴリズムと共通鍵で MAC 値を算出して同じ値が得られれば同一のパスワードと見なすことができる。

この MAC 値は単に \(H({\rm password} + {\rm salt})\) で得たハッシュ値より強い暗号性能を持つ。例えばハッシュ関数 \(H\) に強衝突性が発見されたとしても HMAC で使っているのであれば直ちに脆弱であるということにはならない。また伸長攻撃への耐性もある。このため、パスワードに基づいて AES などの他の暗号アルゴリズムを使用するケースでは、\(H({\rm password} + {\rm salt})\) によるハッシュ値を cipher として使用するよりも安全である。

CBC-MAC

CBC MAC (cipher block chaining message authentication code) はブロック暗号を使用して MAC を算出するためのアルゴリズムである。メッセージ \(M\) はブロック暗号に適した長さの \(\{m_0, m_1, \cdots, m_n\}\) に分割される。初期状態のベクトル \(\vector{0}\) から開始し、直前の結果と \(m_i\) との XOR からブロック暗号を算出することを繰り返し、最終的な結果を MAC 値として使用する。

CBC MAC アルゴリズムは任意長メッセージに対して脆弱であることから、そのようなメッセージに対しては CMAC を使う必要がある。

CBC-MAC
CBC-MAC の算出手順