メッセージ認証コード
- データの完全性を保護する暗号プリミティブとしてMessage Authentication Code(MAC)が得られる(定義できる?)。
- ハッシュ関数と秘密鍵を組み合わせることで定義される
- 秘密鍵の導入はどんなセキュリティでも基本的なもん。
- 鍵がないと機密性を保証できず、認証も出来ないため。
- ハッシュ関数は任意のデータについて真正性・完全性を保証する。
- 裏では改ざんが出来ない、信頼性の高い「経路」の存在が大きい。
- MACを使用して信頼性の高い経路を設けることや、MACで実現できる機能をさらう。
3.2 コードで見る実際の例
- MACを使う人が複数になった場合を想定してコードを書いてみる。
- 誰かと連絡を取りたいが、とりあえずメッセージを読まれても良い。
- ただし、メッセージの改ざんは防ぎたい。
- メッセージを送り合う2者が同じ秘密鍵を使って、メッセージの完全性を保護する。
- Hash-based MACは、コア部分でハッシュ関数を利用するMAC
- SHA-2で実装されることが多い RustでHMACを考える。
送信側
use sha2::Sha256;
use hmac::{Hmac, Mac, NewMac};
// u8: Rustのデータ型で符号なし整数(数字はポインタのサイズ)
fn send_message(key: &[u8], message: &[u8]) -> Vec<u8> {
// 秘密鍵とSHA-256ハッシュ関数でHMACを初期化する。
let mut mac = Hmac::<Sha256>::new(key.into());
// HMACへの追加入力をバッファに入れる
.update(message);
mac
// 認証タグを返す
.finalize().into_bytes().to_vec();
mac}
受信側
メッセージと認証タグをもらったら、受信側は同じ秘密鍵を使ってタグ生成を行い、
認証タグと比較すれば結果が返ってくる。
use sha2::Sha256;
use hmac::{Hmac, Mac, NewMac};
fn receive_message(key: &[u8], message: &[u8],
: &[u8]) -> bool {
authentiacion_tag// 同じ秘密鍵とメッセージから認証タグを再生成する
let mut mac = Hmac::<Sha256>::new(key);
// 再生性された認証タグが、受診したタグと一致するかを確認する
.verify(&authentiacion_tag).is_ok();
mac}
注意: リプレイが可能であるから完全ではない。
メッセージと認証タグをリプレイすること自体も真正性が維持されるし、
再送信されたメッセージかどうかを確認する方法がない。
3.3 MACのセキュリティ特性
MACにも難点・落とし穴が存在するが、そのためにはMACのセキュリティ特性と正しい利用場面を確認する必要がある MACの特徴は以下。
- 認証タグの捏造に強い
- 安全性を確保するには、認証タグの長さは最小限でなければならない
- 認証方法が単純だとメッセージのリプレイが可能になる
- 認証タグの検証がバグりやすい
3.3.1 認証タグの捏造
仮に攻撃者が、任意のメッセージに対する認証タグを大量に生成するようリクエストできたとしても、
MACは(それ以前に)見たことのないメッセージに対する認証タグを捏造できないという点が保証される。
(よくわからん。)
MACに使用する秘密鍵が秘匿されている限りは、こうした捏造から保護される。
そのためには秘密鍵が十分にランダムで、十分に大きくなっている(16バイト)必要がある。
- MACは「曖昧さを狙った攻撃」に弱い
- 構造を持ったメッセージを認証する場合、認証の前にシリアライズする必要がある。
説明
- 任意のメッセージ\(m\)に対して、認証タグ\(t = MAC(k, m)\)を生成した事を考える。
- このとき、\(k\)を知ることなしに認証タグを計算することが出来ない。
- 上記の理論的な安全性を保っているので最高だが、MACはそれ以上に強い性質。
- 制約のあるメッセージに対する認証タグの取得を攻撃者に許す場面が多い。
- Cookieで利用可能なニックネームを登録したら、任意の認証タグが得られる
- 制約のあるメッセージに対する認証タグの取得を攻撃者に許す場面が多い。
注
攻撃者が任意のメッセージに対する認証タグをリクエストできたとしたら、そもそも何を保護できるというのだろうか。 だが、暗号学におけるセキュリティの証明とはこういうものなのだ。実際には、攻撃者がここまで強力であることは少ないので、有能な攻撃者でさえ不正を行えないとすれば、それより非力な攻撃者には、まず手が打てないことになるからだ。
3.3.2 認証タグの長さ
MACを使っている場合、衝突攻撃が考えられる。
MACの衝突を考える場合、入力\(x\)、\(y\)に対して、
\(MAC(k, x) = MAC(k, y)\)が満たされる場合を衝突と定義する。
【復習】ハッシュ関数の衝突
\(HASH(x) = HASH(y)\)となるような入力\(x\)、\(y\)を見つける
誕生日限界を思い出すと、アルゴリズムの出力が大きくない場合、
衝突が見つかる期待は高まってしまう。
例: 64ビットの認証タグを生成するサービスに対する衝突は\(2^{32}\)回のリクエストでOK。
衝突攻撃に対して頑健であるために、128ビットを要請する。
\(2^{64}\)の認証タグリクエストは、秘密鍵を固定して、1Gbsのリンクでも25万年。
実際は秘密鍵も変更するので、まあ数十万年から数百万年かかる。
MACは秘密鍵を持つ関数であるので、オフラインでの最適化が難しい。
(ハッシュ関数はアルゴリズムが公開されているので、インターネットがなくても計算ができる)
攻撃側は認証タグをサーバにリクエストするしかないので、MACを攻撃するには
相当に時間がかかる。