[英]Encrypting data in 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);
您需要一個“基於密碼的密鑰派生功能”或PBKDF2。
對於AES 128,MD5為您提供正確的大小輸出,因此它可以用作密鑰生成功能(但請繼續閱讀):
key = md5("MyPassw0rd!");
但這是非常薄弱的。 PBKDF添加了許多次salt迭代,如下所示:
salt = "SomeValueDifferentForEachKeyGenerated";
key = md5(salt+md5(salt+md5(salt+md5(salt+"MyPassw0rd!"))));
哪個更好,但仍然很弱。 MD5不是周圍最強大的哈希算法,並且迭代次數不足。
StackOverflow上有很多PBKDF函數 ,請選擇最適合您的一個。
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類中。 盡管我確信那里有更好的解決方案...
你應該用
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/
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.