Я работаю над реализацией SCrypt Csharp SCrypt в VS2015. Мне нужно зашифровать/дешифровать текстовые файлы, предназначенные для отправки в виде вложений электронной почты. Первоначально я использовал AES, но учитывая, что HMAC-SHA1 устарел, я решил использовать SCrypt для хэширования паролей. Однако SCrypt не раскрывает общедоступные методы для самого шифрования данных, так что имеет смысл передавать AES-пароль SCrypt, а затем использовать последнее для шифрования данных? Или, может быть, есть лучший подход?CryptSharp SCrypt реализация в C#
В этом случае, я бы себе представить, что-то вроде этого, но я должен был бы найти способ надежно рандомизации 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
}
}
}
}
Несмотря на то, что это работает, я не уверен, что это имеет смысл, поэтому большое спасибо за понимание.
EDIT:
В соответствии с рекомендациями 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;
}
Отредактировано для отражения рекомендаций vcsjones. – Frank