我正在开发VS2015中的CryptSharp SCrypt实现。我需要加密/解密意图作为电子邮件附件发送的文本文件。最初我使用的是AES,但考虑到HMAC-SHA1已经过时,我选择使用SCrypt进行密码散列。但是,SCrypt没有公开数据加密本身的公共方法,因此将SCrypt哈希密码传递给AES,然后使用后者进行数据加密是否有意义?或许还有更好的方法?
在这种情况下,我会想象这样的事情,但我需要找到一种方法来可靠地随机化IV ......
private static Aes SetAes(string userName, string password)
{
var passBytes = Encoding.UTF8.GetBytes(password);
var saltBytes = Encoding.UTF8.GetBytes(userName);
var cost = 131072; // around 5 secs with block at 16(on Xeon 1241 v3)
var blockSize = 16; // 8 is default but might not suffice against modern GPUs(?)
var parallel = 1;
var maxThreads = (int?)null;
byte[] derivedKey = new byte[32]; // 256 bits
SCrypt.ComputeKey(passBytes, saltBytes, cost, blockSize, parallel, maxThreads, derivedKey);
Aes aes = new AesManaged();
aes.Padding = PaddingMode.PKCS7;
aes.Key = derivedKey;
byte[] IV = new byte[16];
Array.Copy(derivedKey, IV, 16); // how to reliably randomize the IV?
aes.IV = IV;
return aes;
}
然后进行文件加密:
internal static void EncryptText(string text, string userName, string password, string file)
{
// omitting argument checks for readability
using (Aes aes = SetAes(userName, password))
{
using (FileStream fileStream = new FileStream(file, FileMode.Create, FileAccess.ReadWrite, FileShare.None))
{
using (CryptoStream cryptoStream = new CryptoStream(fileStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(cryptoStream, text); // I'm using a class to wrap the text for serialization, not shown here for readability
}
}
}
}
即使它似乎有效,但我不确定它是否有意义,所以非常感谢您的任何见解。
编辑:
根据vcsjones建议,如果我理解正确,SetAes函数将更像这样:
private static Aes SetAes(string userName, string password, byte[] IV = null)
{
var passBytes = Encoding.UTF8.GetBytes(password);
var saltBytes = Encoding.UTF8.GetBytes(userName);
var cost = 131072;
var blockSize = 16;
var parallel = 1;
var maxThreads = (int?)null;
byte[] derivedKey = new byte[32];
SCrypt.ComputeKey(passBytes, saltBytes, cost, blockSize, parallel, maxThreads, derivedKey);
Aes aes = new AesManaged();
aes.Padding = PaddingMode.PKCS7;
aes.Key = derivedKey;
if (IV == null) // when encrypting, generate IV
{
RandomNumberGenerator rn = RandomNumberGenerator.Create();
rn.GetBytes(aes.IV);
}
else aes.IV = IV; // when decrypting, read IV from file and pass it to aes through IV parameter for decryption
return aes;
}
答案 0 :(得分:2)
但是,SCrypt不公开数据加密本身的公共方法,因此将SCrypt哈希密码传递给AES是否有意义
SCrypt是一个关键的衍生函数,所以是的,这是可以接受的事情。
如何可靠地随机化IV?
不要在IV中使用KDF的输出。对于AES-CBC,IV应该是随机的,因此使用RandomNumberGenerator.Create()
为IV创建CSPRNG。使用KDF输出作为IV的一部分实际上泄漏了密钥,因为IV以明文形式存储。
AES-CBC中的IV应该随机,不应该重复使用。不要从密码中获取它。你需要将IV存储在某个地方。由于您似乎正在尝试加密文件,因此您可能只想将IV放在文件的开头。 IV不是秘密 - 如果有人可以阅读它,那就没关系。然后,当需要解密文件时,从文件中读取IV,然后通过IV解密所有内容。
我还建议你将文件作为MAC,因为你的应用程序现在不是authenticate the encryption。