2012-12-16 4 views
20

Ich versuche zu verstehen, wie man einen Initialisierungsvektor und das Salz (wenn anwendbar) behandelt und verwaltet, wenn Daten mit einem symmetrischen Verschlüsselungsalgorithmus, in diesem Fall AES, verschlüsselt und entschlüsselt werden.Symmetrische Verschlüsselung (AES): Ist das Speichern von IV und Salz neben den verschlüsselten Daten sicher und ordnungsgemäß?

Ich habe von verschiedenen SO-Threads und verschiedenen anderen Websites abgeleitet, dass weder die IV noch das Salz geheim sein müssen, nur einmalig, um sich gegen kryptoanalytische Angriffe wie einen Brute-Force-Angriff zu verteidigen. In Anbetracht dessen dachte ich, dass es sinnvoll wäre, meine Pseudozufalls-IV mit den verschlüsselten Daten zu speichern. Ich frage, ob die Methode, die ich benutze, richtig ist, und sollte ich mein hart codiertes Salz auf die gleiche Weise behandeln? Unter diesen Umständen ist es dem Speicherstrom an der Seite des IV

Mein Code zu schreiben:

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; 
} 

Ich bin auch offen für alle anderen Informationen über die symmetrische Verschlüsselung in Bezug auf die richtige Praxis.

+0

Wenn Sie sie nicht mit Ihren verschlüsselten Daten speichern, müssen Sie sie irgendwo speichern - also YMMV. – larsw

+4

Im CBC-Modus fungiert jeder verschlüsselte Block als IV des nächsten Blocks, sodass IV als öffentlicher Wert nicht sicherheitsrelevant sein kann - andernfalls wäre der CBC-Betriebsmodus nicht sicher. :) – vhallac

+0

@vhallac gut, mehr das V (Vektor) als die IV (Initialisierungsvektor) ist, kann natürlich nur die erste sein. –

Antwort

23

Speichern der IV und Salz eine lange mit dem Chiffre Text ist richtig und eine Best Practice. Hartes Codieren des Salzes ist nicht nützlich, zufällig zu sein ist wichtig, hartes Codieren der Iterationen ist vollkommen in Ordnung, aber ist typischerweise viel höher als 300 (tatsächlich mindestens 1000 und du gehst typischerweise viel höher, wenn deine Maschine/Verwendung damit umgehen kann wie in 10s) von Tausenden).

Da ich so viele schlechte (oder alte) Beispiele für C# Verschlüsselung von Stack-Überlauf geschnitten und in Open-Source-Code einfügen sah, schrieb ich ein kurzes Stück Code ausschneiden und einfügen Modern Examples of Symmetric Authenticated Encryption of a string., dass ich versuche, zu halten Datum und überprüft. Es speichert das iv und salt mit dem Chiffretext, es authentifiziert auch den Chiffretext und die Werte, die im Chiffretext enthalten sind.

Idealerweise wäre eine bessere Vorgehensweise, eine High-Level-Verschlüsselungsbibliothek zu verwenden, die Best Practices wie das iv für Sie behandeln würde, die jedoch für csharp normalerweise nicht existieren. Ich habe an einer nativen csharp version von googles keyczar Bibliothek gearbeitet. Obwohl es funktional einsatzbereit ist, wollte ich vor der ersten offiziellen stabilen Version mehr über den Code erfahren.

13

Ja, sowohl die IV und Salz sind öffentliche Werte. Was noch wichtiger ist, ist sicherzustellen, dass es sich um zufällige Werte für jede Verschlüsselungsoperation handelt.

Um ein Beispiel in freier Wildbahn zu geben, werfen Sie einen Blick auf die rncryptor data format. Hier werden das Salz und das IV zusammen mit dem Geheimtext und einem MAC-Wert in ein Datenformat verpackt. (Anmerkung: Dies ist ein Ziel-c-Beispiel).

Verwandte Themen