web-dev-qa-db-ja.com

AES / CTR / NoPaddingに適切なIV(初期化ベクトル)を選択する方法は?

Webappによって書き込まれたCookieを暗号化し、Cookieのサイズを最小限に抑えたいので、AES/CTR/NoPaddingを選択した理由です。

十分にランダムで、アプリをステートレスに保つIVとして使用することをお勧めします。ランダムなIVを生成してメッセージに追加できることは知っていますが、それによりCookieのサイズが大きくなります。

また、128ビットAESのIVの推奨サイズは何ですか?

誰もこれをやっていますか? 「試行錯誤した」方法はありますか?私は車輪を再発明したくありません。

31
Drew

CTRセキュリティでは、同じキーで2つのメッセージ暗号化にIVを再利用する必要がありますnever。実際にはさらに厳しくなります。CTRモードは、カウンターの連続する値を暗号化することで機能し(IVはそのカウンターの初期値に過ぎません)、同じカウンター値が2回使用されない場合にのみ適切なセキュリティが実現されます。つまり、IVで値を暗号化すると、実際には別の暗号化で再利用してはならない連続したIV値のシーケンスが「消費」されます。

そのための簡単な方法は、cryptographically secure random number generatorを使用し、すべてのメッセージに対して新しい16バイトのランダムIVを作成することです。それは重要だからです。基本的な乱数ジェネレータでは不十分です。 Javaでは、_Java.util.SecureRandom_を使用します。 Win32では、CryptGenRandom()を呼び出します。ランダムな選択では、可能な128ビットIVのスペースは十分に大きいため、衝突は非常に起こりにくいです。実際、これがAESが128ビットブロックを使用する理由です(したがって、128ビットIVを意味します)。

メッセージを復号化するエンティティはIVを知っている必要があるため、暗号化されたメッセージとともにIVを保存する必要があります。それは余分な16バイトです。このオーバーヘッドは、あなたが避けたいものであることを理解していますが、クッキーにとっては16バイトはそれほど多くありません。 Cookieの有効な最大長はWebブラウザーによって異なりますが、4000文字は「どこでも」機能するようです。 16バイトIVは、文字でエンコードされた場合(たとえば、Base64を使用)、約22文字を使用します。つまり、Cookieの最大サイズの1%をはるかに下回ります。

これでファンキーになり、トリックを使用してIVの長さを短くすることができます。

  • ハッシュ関数でIVを生成します:サーバー側で、カウンターを使用します。カウンターは0から始まり、新しいIVが必要になるたびにインクリメントされます。 IVを取得するには、適切なハッシュ関数でカウンターをハッシュします。 SHA-256、およびハッシュ値の最初の16バイトを保持します。ハッシュ関数の「ランダム化プロパティ」は、CTR要件に関してIVを十分にランダムにするのに十分です。これには暗号的に安全なハッシュ関数が必要であるため、SHA-256(MD5は避けてください)。カウンター値をCookieに保存するだけで、カウンターは16バイトより短くなります(たとえば、顧客が40億人以下の場合、カウンターは4バイトに収まります)。ただし、隠れたコストがあります。サーバー(サーバーがシステムで暗号化を実行していると仮定します)は、カウンター値を再利用しないことを確認する必要があるため、「現在のカウンター」を、サーバーが再起動し、複数のフロントエンドにスケールアップしても失敗しません。それは簡単ではないようです。

  • 外部の一意の値を使用します:Cookieは、各暗号化に一意の値を生成するのに十分なデータを提供するコンテキストの一部である可能性があります。たとえば、リクエストに(クリアテキストで)「ユーザーID」も含まれている場合、そのユーザーIDをIVソースとして使用できます。セットアップは上記のものと似ています。すべてのデータを取得して、SHA-256に詰め込み、SHA-256出力の最初の16バイトが必要なIVです。これは、特定の暗号化されたメッセージに対してそのデータが変更されない場合、およびそれが本当に一意である場合にのみ機能します。これはまれにしか発生しません。たとえば、「ユーザーID」は、同じユーザーの新しいメッセージを再暗号化する必要がなく、ユーザーIDが再利用される可能性がまったくない場合(たとえば、古いユーザーは終了し、新しいユーザーが来て、現在無料のユーザーIDを選択します)。

暗号的に安全なPRNGで生成されたランダムな16バイトIVを使用することは、依然として「安全な」方法であり、推奨される方法です。Cookieのスペースが不足している場合は、 4 kBの制限に近づいており、その時点で圧縮を使用することができます(データ上でbefore暗号化;暗号化後、圧縮が機能する可能性は非常に低いです)。 zlib を使用します=(Javaでは、_Java.util.Zip_を介してzlibにアクセスできます)。

警告:上記のすべてで、私はanything Cookie暗号化がセキュリティ特性を提供するのに役立つかどうかについては言っていません達成しようとしています。通常、暗号化が必要な場合、実際には暗号化と整合性の両方が必要であるため、暗号化と整合性の組み合わせモードを使用する必要があります。ルックアップ [〜#〜] gcm [〜#〜] および [〜#〜] ccm [〜#〜] 。さらに、Cookie暗号化は、主に1つの目的に適しています。これは、サーバー側にユーザ​​ー固有のデータを格納するコストを回避することです。他の何かのためにクッキーを暗号化したい場合、例えばto authenticate有効なユーザー、あなたは間違っています:暗号化はそのための正しいツールではありません。

49
Thomas Pornin

あなたの質問に対する直接的な答えはありませんが、いくつか追加することがあります。

まず、Cookieを暗号化しても意味がありません。データの機密性が必要な場合は、とにかくCookieに保存しないでください。整合性が必要な場合(つまり、Cookieのコンテンツを改ざんできないようにする場合)、キー付きハッシュ(HMACなど)を使用する必要があります。

別の注意点は、never利便性のためにすべて0のIVを使用することです。

IVはブロックのサイズと同じです。 AES-128の場合、ブロックサイズは128、キーサイズは128であるため、IVは128ビットです。

これを行う最良の方法は、ランダムなAESキーを作成し、それをIVとして使用することです。このランダムIVは、同じキーを使用した後続の暗号化で再利用されない限り、パブリックである可能性があります

編集

使用するモードの詳細については、このWikiページをご覧ください。ただし、使用する必要があることが確実でない限り、ECBを使用しないでください。そして、それでも、専門家に確認してください。私が知る限り、CBCは(PCBCとともに)最も安全です。

http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation

4
Henri

IVをランダムにしない場合(つまり、数字の繰り返しグループを使用する場合)、Cookieが常に同じクリアテキストで始まる場合、キーを見つけやすくなります。

AES-128のIVサイズは128ビットです。 IIRC、IVは暗号ブロックと同じサイズです。 128ビットは16バイトです。 ASCII 16進文字列として保存した場合、32バイト。これは本当に多すぎますか?この日と年齢で32バイトはあまり多くありません...

2

CBCを使用し、メッセージの前にHMACを保存することにより、ランダムIVを回避することができます。ランダムに選択された定数IVを使用しても問題ありません。ただし、メッセージがすべて異なることを確認する必要があります。

これは、暗号化されたメッセージが常に異なる場合です。シリアル番号付きのライセンスキーは、この基準に一致します。ユーザーIDまたはセッションIDを持つCookieも一致します。

メッセージの前にhmacを保存する場合、ランダム定数IVでCBCを使用できます。ハッシュは、最初のブロックのメッセージに広がるすべてのバリエーションを累積します。また、数バイトをランダムに追加することも、シリアル番号を追加することもできます。シリアル番号が一意であるか、非常に長い間再利用されないことを確認できます。

定数IVでCTRを使用することさえ考えないでください。

0
chmike

Cookieに大きな乱数を含めます。おそらく64ビットまたは128ビットの数値で十分です。複製を取得するのが非常に困難になるように、十分に大きくする必要があります。この数に十分なエントロピーを入れてください。 gettime()を使用しないでください。 CRNGにアクセスできる場合は、ここで使用してください。

アプリケーションに256ビットのマスターキーを保存します。 SHA256を使用して、キー情報を導き出します。この場合も、CRNGを使用します。

$keyblob = sha256( concat("aeskeyid", $masterkey , $randomnumberwithcookie ) )
$aeskey = $keyblob[0..15]
$aesiv = $keyblob[16..31]

HMACのキーを導出することもできます。

$mackeyblob = sha256( concat("hmackeyid", $masterkey , $randomnumberwithcookie ) )

または、SHA512を使用して、上記の2つのハッシュ操作を1つに結合することもできます。

$keyblob = sha512( concat("randomkeyid", $masterkey , $randomnumberwithcookie ) )
$aeskey = $keyblob[0..15]
$aesiv = $keyblob[16..31]
$hmackey = $keyblob[32..63]