ハッシュ(HMAC)を使って弱い鍵を強い鍵に変える方法

(Last Updated On: 2019年2月5日)

既存の鍵から別の鍵を導出する方式としてはHKDF(RFC 5869)があります。AES用に弱い鍵から強い鍵を作るにはHKDFでなくてもHMACで十分です。実際、HKDFはHMACを組み合わせて鍵を導出しているだけなので、ここで紹介するHMACのみの鍵導出と同等です。

※ PHP 7.2からHKDFを実装したhash_hkdf()を使えます。hash_hkdf()が利用できる場合はシンプルにhash_hkdf()を使うと良いです。

前提条件

Web環境の場合、暗号化が必要となるのはサーバーサイドだけの場合も多いです。この場合、ユーザーが入力したパスワードを使ってデータを暗号化する際に暗号学的に強い鍵を使うことが容易な場合が多いです。弱い鍵から強い鍵をHMACで導出するだけです。

AESを使った暗号化にはPHPのOpenSSL関数を利用して暗号化する例の暗号化/復号化関数を使うこととします。

弱い鍵から強い鍵を作る方法

弱い鍵から強い鍵を作るにはHMACで十分な場合が多いです。PHPの場合、hash_hmac()を使って以下のように強い鍵を導出して使います。

<?php
// ユーザーが送信した暗号化用パスワード。
// 実際には安全な場所に保存しておく。
$password = $_POST['password'];

// 強い鍵を導出するための強い秘密のsalt(2つ目の鍵)。
// 256bit AESなので32バイト(256bit)のsaltを使う。
// 実際には安全な場所に保存しておく。
$secret_salt = random_bytes(32);

$strong_key = hash_hmac('sha256', $password, $secret_salt);

$encrypted = encrypt($important_data, $strong_key);
$decrypted = decrypt($encrypted, $strong_key);
?>

ポイントは

$strong_key = hash_hmac('sha256', $password, $secret_salt);

でHMACを使って強い鍵を導出している部分です。これは

$strong_key = hash('sha256', $password . $secret_salt);

のような文字列連結より強い鍵を導出します。

まとめ

強い秘密のsalt(鍵)を保存できる場合、暗号化データの安全性を飛躍的に高めることができます。Webアプリケーションの場合、強い秘密のsaltを保存できる場合が多いです。単純にユーザーが送信した暗号化パスワードを使うのではなく、可能な場合は強い鍵を導出して利用すると良いです。

データベースに暗号化データを保存する場合、強い秘密のsaltは別の場所(別のデータベースやサーバー)に保存した方がより安全です。別の場所に保存すれば、万が一アプリケーションにSQLインジェクション脆弱性があっても暗号化済みデータを簡単に解読することはできません。

どうしてもHKDFと同程度にしたい場合は、HKDFと同様にもう一度HMACを使うと良いでしょう。

$strong_key = hash_hmac('sha256', hash_hmac('sha256', $password, $secret_salt), 1);

こうするとHKDFと変わりません。

ログイン用のユーザー入力のパスワードを保存する場合などにはpassword_hash関数を利用すべきです。誤解が無いようにパスワードのハッシュ化で解説しました。

投稿者: yohgaki