2012-12-16 12 views
20

対称暗号化アルゴリズム(この場合はAES)を使用してデータを暗号化および復号化する際に、初期化ベクトルと塩(該当する場合)を処理して管理する方法を理解しようとしています。対称暗号化(AES):IVと塩を暗号化されたデータと共に安全かつ適切に保存していますか?

私はさまざまなSOスレッドや他のさまざまなウェブサイトから、IVまたは塩のいずれも秘密にする必要がないことを推測しました。ブルートフォース攻撃などの暗号解読攻撃から防御するためには一意です。このことを念頭に置いて、暗号化されたデータを使って擬似ランダムIVを保存することが可能であると考えました。私が使用している方法が適切であるかどうか、また現在のハードコードされた塩を同じ方法で扱うべきかどうかを尋ねています。私はまた、適切な慣行に関して対称暗号化に関するその他の情報に開いてい

private const ushort ITERATIONS = 300; 
private static readonly byte[] SALT = new byte[] { 0x26, 0xdc, 0xff, 0x00, 0xad, 0xed, 0x7a, 0xee, 0xc5, 0xfe, 0x07, 0xaf, 0x4d, 0x08, 0x22, 0x3c }; 

private static byte[] CreateKey(string password, int keySize) 
{ 
    DeriveBytes derivedKey = new Rfc2898DeriveBytes(password, SALT, ITERATIONS); 
    return derivedKey.GetBytes(keySize >> 3); 
} 

public static byte[] Encrypt(byte[] data, string password) 
{ 
    byte[] encryptedData = null; 
    using (AesCryptoServiceProvider provider = new AesCryptoServiceProvider()) 
    { 
     provider.GenerateIV(); 
     provider.Key = CreateKey(password, provider.KeySize); 
     provider.Mode = CipherMode.CBC; 
     provider.Padding = PaddingMode.PKCS7; 

     using (MemoryStream memStream = new MemoryStream(data.Length)) 
     { 
      memStream.Write(provider.IV, 0, 16); 
      using (ICryptoTransform encryptor = provider.CreateEncryptor(provider.Key, provider.IV)) 
      { 
       using (CryptoStream cryptoStream = new CryptoStream(memStream, encryptor, CryptoStreamMode.Write)) 
       { 
        cryptoStream.Write(data, 0, data.Length); 
        cryptoStream.FlushFinalBlock(); 
       } 
      } 
      encryptedData = memStream.ToArray(); 
     } 
    } 
    return encryptedData; 
} 

public static byte[] Decrypt(byte[] data, string password) 
{ 
    byte[] decryptedData = new byte[data.Length]; 
    using (AesCryptoServiceProvider provider = new AesCryptoServiceProvider()) 
    { 
     provider.Key = CreateKey(password, provider.KeySize); 
     provider.Mode = CipherMode.CBC; 
     provider.Padding = PaddingMode.PKCS7; 
     using (MemoryStream memStream = new MemoryStream(data)) 
     { 
      byte[] iv = new byte[16]; 
      memStream.Read(iv, 0, 16); 
      using (ICryptoTransform decryptor = provider.CreateDecryptor(provider.Key, iv)) 
      { 
       using (CryptoStream cryptoStream = new CryptoStream(memStream, decryptor, CryptoStreamMode.Read)) 
       { 
        cryptoStream.Read(decryptedData, 0, decryptedData.Length); 
       } 
      } 
     } 
    } 
    return decryptedData; 
} 

:それは

側に沿ってメモリストリームにIVを、それを書いて私のコードされています。

+0

暗号化されたデータを格納していない場合は、それらをどこかに格納する必要があります(YMMVなど)。 – larsw

+4

CBCモードでは、暗号化された各ブロックが次のブロックのIVとして動作するため、IVが公開値であるとセキュリティ関連にはなりません。そうしないと、CBCモードの動作は安全になりません。 :) – vhallac

+0

@vhallacまあ、IV(初期化ベクトル)としてのV(ベクトル)は明らかに最初のものにすぎません。 –

答えて

23

暗号文でIVとSaltを長く保管することは適切であり、ベストプラクティスです。ハードコーディングは便利ではありません。ランダムであることが重要です。反復のコーディングは完全に大丈夫ですが、通常は300よりもはるかに高くなります(実際には少なくとも1000であり、マシン/何千もの)。

スタックオーバーフローによるオープンソースコードへのC#暗号化の悪い(または古い)例を見てきましたので、短くカット&ペーストの暗号コードModern Examples of Symmetric Authenticated Encryption of a string.を書いてみました。日付とレビュー。 ivとsaltを暗号文とともに格納し、暗号文とその暗号文に含まれる値も認証します。

理想的には、ivのようなベストプラクティスを扱う高水準の暗号化ライブラリを使用することをお勧めしますが、通常はcsharpには存在しません。私はGoogleのkeyczarライブラリのネイティブcsharp versionに取り組んでいます。機能的には使用準備が整っていますが、最初の正式な安定版がリリースされる前に、コードをもっと見たいと思っていました。

13

はい、IVと塩は共に公開値です。さらに重要なことは、これらが各暗号化操作のランダムな値であることを保証することです。

これを野生の例として挙げると、rncryptor data formatをご覧ください。ここで、塩とIVは、暗号文とMAC値とともにデータフォーマットにパッケージ化されています。 (注:これは目的であり、例です)。

関連する問題