2012-12-16 14 views
20

Próbuję zrozumieć, w jaki sposób obsługiwać i zarządzać wektorem inicjalizacyjnym i solą (jeśli dotyczy) podczas szyfrowania i odszyfrowywania danych za pomocą symetrycznego algorytmu szyfrowania, w tym przypadku AES.Szyfrowanie symetryczne (AES): Czy zapisywanie IV i soli wraz z zaszyfrowanymi danymi jest bezpieczne i właściwe?

Wydedukowałem z różnych wątków SO i różnych innych stron internetowych, że ani IV, ani sól nie muszą być tajne, tylko unikalne w celu obrony przed atakami kryptoanalitycznymi, takimi jak brutalny atak. Mając to na uwadze, pomyślałem, że byłoby opłacalne przechowywanie mojego pseudo losowego IV z zaszyfrowanymi danymi. Pytam, czy metoda, której używam, jest właściwa, a ponadto czy powinienem traktować moją obecnie trudną zakodowaną sól w ten sam sposób? Że bycie pisania do strumienia pamięci wzdłuż boku IV

mój kodu:

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

Jestem również otwarty na wszelkie inne informacje na temat szyfrowania symetrycznego z odniesieniu do właściwej praktyki.

+0

Jeśli nie przechowujesz ich zaszyfrowanych danych, musisz je gdzieś przechowywać - tak YMMV. – larsw

+4

W trybie CBC każdy zaszyfrowany blok działa jak IV następnego bloku, więc IV będący wartością publiczną nie może być istotny z punktu widzenia bezpieczeństwa - w przeciwnym razie tryb działania CBC nie byłby bezpieczny. :) – vhallac

+0

@vhallac cóż, bardziej V (wektor) jako IV (wektor inicjalizacyjny) może oczywiście być tylko pierwszy. –

Odpowiedz

23

Przechowywanie IV i soli długo z tekstem szyfrowania jest właściwe i najlepszą praktyką. Twarde kodowanie soli jest nieprzydatne, ważne jest losowe, trudne kodowanie iteracji jest całkowicie w porządku, ale zwykle jest znacznie wyższe niż 300 (w rzeczywistości co najmniej 1000 i zwykle idzie o wiele wyżej, jeśli twoja maszyna/użycie może obsłużyć to jak w 10s tysięcy).

Ponieważ widziałem tak wiele złych (lub starych) przykładów szyfrowania C# z przecięcia stosu i wklejenia w kodzie open source, napisałem krótko kod wycinania i wklejania kodowania Modern Examples of Symmetric Authenticated Encryption of a string., który staram się zachować Data i recenzja. Przechowuje kod iv i sól za pomocą zaszyfrowanego tekstu, a także uwierzytelnia szyfrogram i wartości zawarte w tekście szyfrowania.

Najlepiej byłoby, gdyby korzystano z biblioteki szyfrowania wysokiego poziomu, która obsługiwałaby najlepsze praktyki, takie jak iv, jednak zwykle nie istniały dla csharp. Pracuję nad rodzimą biblioteką z google'a keyczar. Choć jest funkcjonalnie gotowy do użycia, chciałbym, aby jego kod był bardziej widoczny przed pierwszym oficjalnym wydaniem stabilnym.

13

Tak, zarówno IV jak i sól są wartościami publicznymi. Ważniejsze jest zapewnienie, że są to wartości losowe dla każdej operacji szyfrowania.

Aby dać przykład tego w naturze, spójrz na rncryptor data format. Tutaj sól i IV są pakowane do formatu danych wraz z tekstem zaszyfrowanym i wartością MAC. (Uwaga: jest to przykład celu-c).

Powiązane problemy