PHP 7.1を使用しており、次のように文字列の一部を正常に暗号化できます。
$key = random_bytes(32);
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-gcm'));
$cipherText = openssl_encrypt(
'The quick brown fox jumps over the lazy dog.',
'aes-256-gcm',
$key,
OPENSSL_RAW_DATA,
$iv,
$tag,
''
)
その後、私はそれを正常に復号化できます:
openssl_decrypt(
$cipherText,
'aes-256-gcm',
$key,
OPENSSL_RAW_DATA,
$iv,
$tag,
''
);
ただし、テスト中に、次の方法で解読するとわかりました。
openssl_decrypt(
$cipherText,
'aes-256-gcm',
$key,
OPENSSL_RAW_DATA,
$iv,
mb_substr($tag, 0, mb_strlen($tag) - 15),
''
);
私はまだ私のストリングを完全にうまくします。当然のことながら、base64url形式のときに認証タグからデータを削除した場合にも、これが発生します。
なぜこれが起こるのですか?
wikipedia によると:
Tで示されるタグのビット長は、セキュリティパラメータです。一般に、tは次の5つの値のいずれかになります。128、120、112、104、または96。特定のアプリケーションでは、tは64または32ですが、これら2つのタグの長さを使用すると、入力の長さが制限されます。データとキーの寿命。
テスト後、openssl_decrypt
では予想されるタグサイズを指定できないため、タグが有効である限り、任意のタグサイズを受け入れます。残念ながら、128-96ビットに制限されていません。1バイトでもエラーなしに復号化されます。つまり、PHPを使用したGCMは、タグが簡単に壊れるため、ほとんど機能しません。 brute-forcable。これを修正するには、openssl_decrypt
に渡す前にタグの長さを確認します。
これが実際にopenssl_decrypt
のバグなのか、関数の外部でタグの長さが確認されることが意図されたのかはわかりませんが、どちらの方法でもドキュメントには欠けています。
Rubyはまったく同じ issue を持っているようです。