2012-02-19 90 views
0

我有一個應用程序需要加密數據然後存儲在文件中。這些數據應該按照AES等行業標準進行加密。 數據可能是文本或二進制數據。在C中加密數據#

與其將密鑰存儲在某處,用戶應該提供一個字母數字密碼(用作密鑰)來解密數據。

什麼是最好的方式去在C#.NET 3.5中做到這一點?理想的情況是我在找一個黑盒類,我可以使用像這樣:

byte[] writeThisToFile = EncryptionClass.Encrypt(string data, string password); 

byte[] writeThisToFile = EncryptionClass.Encrypt(byte[] data, string password); 

byte[] plainBinaryData = EncryptionClass.DecryptBinary(byte[] encryptedFileContents, string password); 

string plainText = EncryptionClass.DecryptText(byte[] encryptedFileContents, string password); 
+0

已經內置到.net 3.5中。而這個問題幾乎是重複的:http://stackoverflow.com/questions/3683277/aes-encryption-and-c-sharp – 2012-02-19 02:59:47

+0

http://msdn.microsoft.com/en-us/library/system.security .cryptography.aescryptoserviceprovider.aspx – GSerg 2012-02-19 03:00:24

+0

檢查了這一點:http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndael.aspx – 2012-02-19 03:01:05

回答

2
using System.IO; 
    using System.Security; 
    using System.Security.Cryptography; 
    using System.Runtime.InteropServices; 

    // <summary> 
    // Encrypts a string   
    // </summary>   
    // <param name="CipherText">Text to be Encrypted</param>   
    // <param name="Password">Password to Encrypt with</param>   
    // <param name="Salt">Salt to Encrypt with</param>   
    // <param name="HashAlgorithm">Can be either SHA1 or MD5</param>   
    // <param name="PasswordIterations">Number of iterations to do</param>   
    // <param name="InitialVector">Needs to be 16 ASCII characters long</param>   
    // <param name="KeySize">Can be 128, 192, or 256</param>   
    // <returns>A decrypted string</returns>  
    public static string AESEncrypt(string PlainText, string Password, string Salt, string HashAlgorithm, int PasswordIterations, string InitialVector, int KeySize) 
    { 
     if (string.IsNullOrEmpty(PlainText)) 
     { 
      return "The Text to be Decryped by AES must not be null..."; 
     } 
     else if (string.IsNullOrEmpty(Password)) 
     { 
      return "The Password for AES Decryption must not be null..."; 
     } 
     byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector); 
     byte[] SaltValueBytes = Encoding.ASCII.GetBytes(Salt); 
     byte[] PlainTextBytes = Encoding.UTF8.GetBytes(PlainText); 
     PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(Password, SaltValueBytes, HashAlgorithm, PasswordIterations); 
     byte[] KeyBytes = DerivedPassword.GetBytes(KeySize/8); 

     RijndaelManaged SymmetricKey = new RijndaelManaged(); 

     SymmetricKey.Mode = CipherMode.CBC; 

     byte[] CipherTextBytes = null; 

     using (ICryptoTransform Encryptor = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes)) 
     { 

      using (MemoryStream MemStream = new MemoryStream()) 
      { 
       using (CryptoStream CryptoStream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write)) 
       { 
        CryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length); 
        CryptoStream.FlushFinalBlock(); 
        CipherTextBytes = MemStream.ToArray(); 
        MemStream.Close(); 
        CryptoStream.Close(); 
       } 
      } 
     } 
     SymmetricKey.Clear(); 
     return Convert.ToBase64String(CipherTextBytes); 

    } 


    // <summary> 
    // Decrypts a string   
    // </summary>   
    // <param name="CipherText">Text to be decrypted</param>   
    // <param name="Password">Password to decrypt with</param>   
    // <param name="Salt">Salt to decrypt with</param>   
    // <param name="HashAlgorithm">Can be either SHA1 or MD5</param>   
    // <param name="PasswordIterations">Number of iterations to do</param>   
    // <param name="InitialVector">Needs to be 16 ASCII characters long</param>   
    // <param name="KeySize">Can be 128, 192, or 256</param>   
    // <returns>A decrypted string</returns>   
    public static string AESDecrypt(string CipherText, string Password, string Salt, string HashAlgorithm, int PasswordIterations, string InitialVector, int KeySize) 
    { 
     if (string.IsNullOrEmpty(CipherText)) 
     { 
      return "The Text to be Decryped by AES must not be null..."; 
     } 
     else if (string.IsNullOrEmpty(Password)) 
     { 
      return "The Password for AES Decryption must not be null..."; 
     } 
     byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector); 
     byte[] SaltValueBytes = Encoding.ASCII.GetBytes(Salt); 
     byte[] CipherTextBytes = Convert.FromBase64String(CipherText); 
     PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(Password, SaltValueBytes, HashAlgorithm, PasswordIterations); 
     byte[] KeyBytes = DerivedPassword.GetBytes(KeySize/8); 
     RijndaelManaged SymmetricKey = new RijndaelManaged(); 
     SymmetricKey.Mode = CipherMode.CBC; 
     byte[] PlainTextBytes = new byte[CipherTextBytes.Length]; 
     int ByteCount = 0; 
     try 
     { 

      using (ICryptoTransform Decryptor = SymmetricKey.CreateDecryptor(KeyBytes, InitialVectorBytes)) 
      { 
       using (MemoryStream MemStream = new MemoryStream(CipherTextBytes)) 
       { 
        using (CryptoStream CryptoStream = new CryptoStream(MemStream, Decryptor, CryptoStreamMode.Read)) 
        { 
         ByteCount = CryptoStream.Read(PlainTextBytes, 0, PlainTextBytes.Length); 
         MemStream.Close(); 
         CryptoStream.Close(); 
        } 
       } 
      } 
     } 
     catch (Exception e) 
     { 
      return "Please Enter the Correct Password and Salt..." + "The Following Error Occured: " + "/n" + e; 
     } 
     SymmetricKey.Clear(); 
     return Encoding.UTF8.GetString(PlainTextBytes, 0, ByteCount); 

    } 
那裏我獲得了從這個代碼,但我改變了它返回的加密結果作爲

不能準確記住一個字符串。這些方法可以很容易地包裝到FileEncryptor類中。雖然我確信有更好的解決方案...

2

你需要一個「基於密碼的密鑰派生功能」,或PBKDF2。

對於AES 128,MD5給你正確的大小輸出,所以這可以作爲一個密鑰生成功能(但請繼續閱讀):

key = md5("MyPassw0rd!"); 

但它是非常微弱的。 PBKDF添加了許多迭代鹽,如下所示:

salt = "SomeValueDifferentForEachKeyGenerated"; 
key = md5(salt+md5(salt+md5(salt+md5(salt+"MyPassw0rd!")))); 

哪個更好,但仍然很弱。 MD5並不是最強大的散列算法,並且沒有足夠的迭代。

有很多PBKDF functions on StackOverflow,挑一個最適合你的。

+0

感謝這有助於用戶提供的密碼部分。 – ose 2012-02-19 03:08:16