2012-02-19 55 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