我有这个AES加密代码,有人可以验证这段代码是好还是没错?它工作正常,但我更关心算法的实现。
// Plaintext value to be encrypted.
//Passphrase from which a pseudo-random password will be derived.
//The derived password will be used to generate the encryption key.
//Password can be any string. In this example we assume that this passphrase is an ASCII string.
//Salt value used along with passphrase to generate password.
//Salt can be any string. In this example we assume that salt is an ASCII string.
//HashAlgorithm used to generate password. Allowed values are: "MD5" and "SHA1".
//SHA1 hashes are a bit slower, but more secure than MD5 hashes.
//PasswordIterations used to generate password. One or two iterations should be enough.
//InitialVector (or IV). This value is required to encrypt the first block of plaintext data.
//For RijndaelManaged class IV must be exactly 16 ASCII characters long.
//KeySize. Allowed values are: 128, 192, and 256.
//Longer keys are more secure than shorter keys.
//Encrypted value formatted as a base64-encoded string.
public static string Encrypt(string PlainText, string Password, string Salt, string HashAlgorithm, int PasswordIterations, string InitialVector, int KeySize)
{
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;
ICryptoTransform Encryptor = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes);
MemoryStream MemStream = new MemoryStream();
CryptoStream CryptoStream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write);
CryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length);
CryptoStream.FlushFinalBlock();
byte[] CipherTextBytes = MemStream.ToArray();
MemStream.Close();
CryptoStream.Close();
return Convert.ToBase64String(CipherTextBytes);
}
public static string Decrypt(string CipherText, string Password, string Salt, string HashAlgorithm, int PasswordIterations, string InitialVector, int KeySize)
{
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;
ICryptoTransform Decryptor = SymmetricKey.CreateDecryptor(KeyBytes, InitialVectorBytes);
MemoryStream MemStream = new MemoryStream(CipherTextBytes);
CryptoStream cryptoStream = new CryptoStream(MemStream, Decryptor, CryptoStreamMode.Read);
byte[] PlainTextBytes = new byte[CipherTextBytes.Length];
int ByteCount = cryptoStream.Read(PlainTextBytes, 0, PlainTextBytes.Length);
MemStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(PlainTextBytes, 0, ByteCount);
}
我不是专业安全人员或专业程序员,我开始学习,我喜欢理解它
我的计划是构建一个AES加密函数,这些函数需要最少的输入,但需要遵循以下标准,因此很容易在PHP和JavaScript等其他语言中创建等效函数!
谢谢
答案 0 :(得分:3)
一些一般性评论。第一个是围绕IV。通常,您希望IV是随机的。通过将其限制为(可显示的)ASCII,您在某种程度上限制了可能的值。一般来说,你最好通过a)使用GenerateIV()方法,和b)将IV值预先加到密文,这样c)你不需要将它作为参数传递给任何一个函数。 / p>
第二个评论是,一般来说,您需要计划将来对加密需求的更改。最好在密文旁边嵌入一些版本控制或参数信息,并避免在代码中嵌入特定的加密设置。例如,如果您决定将密码的迭代次数加倍,您可能仍希望解密使用旧设置加密的值(或警告用户该值不再可访问)。
您还可以将大量决策推送到配置文件中。例如,您今天可以create a name for your crypto提供商(例如MyAppSymmetricCrypto)映射到RijndaelManaged,但是以后可以更改为适当的任何内容。
答案 1 :(得分:2)
另外还有@Damien_The_Unbeliever回答
MS建议使用Rfc2898DeriveBytes
代替PasswordDeriveBytes
。 (然后你可以从方法参数中删除'HashAlgorithm'。)
您可以从密码中计算出IV:
var bytes = new Rfc2898DeriveBytes(password, salt, iterations);
var key = bytes.GetBytes(keySize);
var iv = bytes.GetBytes(ivSize);
您应检查无效值/范围的输入值。
包裹MemoryStream
& CryptoStream
语句中的using
个类。