我找到了一个使用AES加密来加密文本的示例。代码是这样的:
public static string Encrypt(string PlainText, string Password,
string Salt = "Kosher", string HashAlgorithm = "SHA1",
int PasswordIterations = 2, string InitialVector = "OFRna73m*aze01xY",
int KeySize = 256)
{
if (string.IsNullOrEmpty(PlainText))
return "";
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);
}
我的问题是:AES算法的密钥是如何生成的?这2行:
PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(Password, SaltValueBytes, HashAlgorithm, PasswordIterations);
byte[] KeyBytes = DerivedPassword.GetBytes(KeySize / 8);
首先,它创建一个256字节的派生密钥,然后,创建一个获取此派生密钥的伪随机字节的密钥。它必须除以8,因为AES算法需要128、182或256位,而不是字节。在这种情况下,密钥的导出方式是256个字节,而AES的密钥将是256位。
但是为什么要这么做呢?是否会更好地创建具有所需长度而不是256字节而是256位(256字节/ 8)的派生密钥?因此,不需要使用派生密钥的1/8字节来创建新密钥。
此外,在该方法的描述中,getBytes()方法还说它返回了伪随机密钥字节。难道AES密钥在每种情况下都不同吗?如果它是伪随机密钥字节,如何从解密中再次生成AES密钥?
谢谢。
答案 0 :(得分:1)
首先,它创建一个256个字节的派生密钥
在哪里?我看不到创建任何256字节密钥。
,然后创建一个密钥,获取该派生密钥的伪随机字节。必须将其除以8,因为AES算法需要128、182或256位,而不是字节
是的,KeySize
(按常规C#命名约定应为keySize
)的函数输入是以位为单位的,但是GetBytes
是以字节为单位的输入。 x / 8
是该转换的三个正确答案之一((x + 7) / 8
是另一个,而x & 7 == 0 ? x / 8 : throw new ArgumentException(nameof(x))
是第三个答案)
但是为什么要这么做呢?是否会更好地创建具有所需长度而不是256字节而是256位(256字节/ 8)的派生密钥?因此,不需要使用派生密钥的1/8字节来创建新密钥。
这样做会很好。但是,既然已经这样做了,那就没有“更好”了。
此外,在该方法的描述中,getBytes()方法还说它返回了伪随机密钥字节。难道AES密钥在每种情况下都不同吗?如果它是伪随机密钥字节,如何从解密中再次生成AES密钥?
我必须指出一点:没有getBytes
方法。 C#是区分大小写的语言,方法名称为GetBytes
。
pseudorandom:注意到或涉及由确定的计算过程生成的满足统计检验的随机数。
PasswordDeriveBytes
是PBKDF1
的实现(除了它超出了PBKDF1的限制),这是一种确定性算法。给定相同的输入(密码,种子,迭代计数,伪随机函数(哈希算法)),则会产生相同的输出。稍微更改任何输入,输出就会明显不同。
Rfc2898DeriveBytes
(PBKDF2
的实现)也是确定性的但混乱的算法。
因此,您通过提供所有相同的输入,在其中一个(但不是跨它们)中再次产生相同的答案。
使用基于密码的加密(PKCS#5)时,流程是
解密时
尽管此代码正确执行了该部分,但IV和Salt不应为ASCII(或UTF8)字符串,而应为“仅为字节”(byte[]
)。如果需要将它们作为字符串进行传输,则它们应该是base64或其他“任意” binary-to-text encoding。