在C#中加密数据

我有一个应用程序,需要加密数据,然后存储在文件中。 此数据应加密为行业标准,如AES。 数据可以是文本数据或二进制数据。

用户不应将密钥存储在某处,而应提供字母数字密码(用作密钥)来解密数据。

在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); 

  using System.IO; using System.Security; using System.Security.Cryptography; using System.Runtime.InteropServices; //  // Encrypts a string //  // Text to be Encrypted // Password to Encrypt with // Salt to Encrypt with // Can be either SHA1 or MD5 // Number of iterations to do // Needs to be 16 ASCII characters long // Can be 128, 192, or 256 // A decrypted string 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); } //  // Decrypts a string //  // Text to be decrypted // Password to decrypt with // Salt to decrypt with // Can be either SHA1 or MD5 // Number of iterations to do // Needs to be 16 ASCII characters long // Can be 128, 192, or 256 // A decrypted string 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类中。 虽然我相信有更好的解决方案……

您需要“基于密码的密钥派生函数”或PBKDF2。

对于AES 128,MD5为您提供正确的大小输出,因此这可用作密钥生成function(但请继续阅读):

 key = md5("MyPassw0rd!"); 

但它很弱。 PBKDF添加了许多盐迭代,如下所示:

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

哪个更好,但仍然很弱。 MD5不是最强的哈希算法,并且没有足够的迭代。

StackOverflow上有很多PBKDF函数 ,选择最适合你的函数 。

你应该用

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

有关详细信息,请参阅以下文章http://explicitcoder.in/encryption-and-decryption-methods-text-file-and-binary-files-c-net/