У меня есть приложение C #, которому необходимо зашифровать строку и сохранить ключ в виде хеша. Ключ сохраняется в виде хеша для проверки правильности введенного ключа перед попыткой дешифрования сообщения.
Во-первых, у меня есть этот метод для генерации строки хэша — надеюсь, «готовый к работе» и готовый к работе.
public static byte[] GetHash(string inputString)
{
using (HashAlgorithm algorithm = SHA256.Create())
return algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString));
}
public static string GetHashString(string inputString)
{
StringBuilder sb = new StringBuilder();
foreach (byte b in GetHash(inputString))
sb.Append(b.ToString("X2"));
return sb.ToString();
}
Затем мой метод расширения шифрования:
private const int Keysize = 256;
private const int DerivationIterations = 1000;
public static string Encrypt(this string plainText, string passPhrase)
{
// Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
// so that the same Salt and IV values can be used when decrypting.
var saltStringBytes = Generate256BitsOfRandomEntropy();
var ivStringBytes = Generate256BitsOfRandomEntropy();
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
var engine = new RijndaelEngine(256);
var blockCipher = new CbcBlockCipher(engine);
var cipher = new PaddedBufferedBlockCipher(blockCipher, new Pkcs7Padding());
var keyParam = new KeyParameter(keyBytes);
var keyParamWithIV = new ParametersWithIV(keyParam, ivStringBytes, 0, 32);
cipher.Init(true, keyParamWithIV);
var comparisonBytes = new byte[cipher.GetOutputSize(plainTextBytes.Length)];
var length = cipher.ProcessBytes(plainTextBytes, comparisonBytes, 0);
cipher.DoFinal(comparisonBytes, length);
// return Convert.ToBase64String(comparisonBytes);
return Convert.ToBase64String(saltStringBytes.Concat(ivStringBytes).Concat(comparisonBytes).ToArray());
}
}
private static byte[] Generate256BitsOfRandomEntropy()
{
var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits.
using (var rngCsp = new RNGCryptoServiceProvider())
{
// Fill the array with cryptographically secure random bytes.
rngCsp.GetBytes(randomBytes);
}
return randomBytes;
}
Которая затем вызывается во входной строке:
var encryptedString = inputString.Encrypt(_appSettings.EncryptionSecret + passPhrase);
Парольная фраза — это случайный набор символов, к которому добавляется строка приложения.
Меня беспокоит то, что кодовая фраза представляет собой 4 набора слов «diceware» (например, здесь: https://diceware.dmuth.org/) и, следовательно, может быть грубой силой. Добавил бы больше к passphrase, например, хэш DateTime.UtcNow.ToString("yyyyMMdd") или же GetHashString(random-string) например, добавить дополнительную защиту или это просто театр, а кодовая фраза «diceware» практически не поддается взлому?
