Вы не говорите, что онлайн-инструментам удалось или не удалось воспроизвести ваши результаты, так что это общий ответ вместо указания c.
//AES blocksize (AES 192 etc.) (min 128)
crypt.BlockSize = BlockSize;
BlockSize для AES равен 128. Всегда (в отличие от исходного алгоритма Rijndael, который позволяет изменять BlockSize).
AES-128 / AES-192 / AES-256 относятся к KeySize, а не к BlockSize.
crypt.Key = hash.ComputeHash(Encoding.Unicode.GetBytes(passwd));
Вы используете MD5(UTF16(password))
в качестве своей функции получения ключа (KDF). Может быть, вы можете найти онлайн-образец, который использует это, но они с большей вероятностью будут использовать MD5(UTF8(password))
(что будет от Encoding.UTF8
, против Encoding.Unicode
). Лучшим ответом было бы использование правильной функции получения ключа на основе пароля, такой как PBKDF2 (которая вызывается Rfc2898DeriveBytes
in. NET по ... причинам).
[Когда я шифрую I like to keep my secrets
Я получаю ответ, который вдвое длиннее онлайновых инструментов.]
Вы шифруете представление этой строки в формате UTF-16. Строка состоит из 25 значений кодовой точки Unicode, все из диапазона US-ASCII. Таким образом, представление UTF-16 - это просто длина кодовой точки * 2 (50 байтов).
50 байтов разбивается на 3 16-байтовых (128-битных) блока, плюс 2 оставшихся байта. Добавьте заполнение, которое станет 4 блоками вывода AES-CB C -PKCS # 7 (64 байта). 64 байта преобразуются в Base64 как 21 полное значение (из 3 байтов -> 4 символов) с оставшимся 1 байтом, поэтому значение Base64 заканчивается 2 =
дополнительными символами общей длиной 88 символов. Это соответствует вашему описанию, hooray:).
Если, с другой стороны, вы использовали кодировку UTF-8, у вас будет 25 байтов для шифрования, что станет 2 выходными блоками (32 байта), которые превращается в 10 полных преобразований в base64 с оставшимися 2 байтами, поэтому один =
в сумме составляет 44 символа ... что очень похоже на то, что используют онлайн-инструменты.
Вы также должны создать новый IV за каждый раз, когда вы шифруете одним и тем же ключом. IV не является ключом, но изменение IV приводит к тому, что один и тот же секретный ввод шифруется по-разному, поэтому тот, кто может видеть ваши зашифрованные данные, не может сказать, что вы отправили то же сообщение, которое вы только что отправили. (По крайней мере, это является целью в режиме блока CB C, в других режимах блока это имеет иногда более важные цели). IV может быть передано с сообщением ... на самом деле так и должно быть, если только у вас нет другого способа согласиться с обеими сторонами (без жесткого кодирования).
И, конечно, вы должны распоряжаться всеми из ваших одноразовых предметов. Если изменить кодировку на UTF-8, но не менять KDF, лучше будет
private static string Encrypt(string content, string password)
{
byte[] bytes = Encoding.UTF8.GetBytes(content);
using (SymmetricAlgorithm crypt = Aes.Create())
using (HashAlgorithm hash = MD5.Create())
using (MemoryStream memoryStream = new MemoryStream())
{
alg.Key = hash.ComputeHash(Encoding.UTF8.GetBytes(password));
// This is really only needed before you call CreateEncryptor the second time,
// since it starts out random. But it's here just to show it exists.
alg.GenerateIV();
using (CryptoStream cryptoStream = new CryptoStream(
memoryStream, crypt.CreateEncryptor(), CryptoStreamMode.Write))
{
cryptoStream.Write(bytes, 0, bytes.Length);
}
string base64IV = Convert.ToBase64String(crypt.IV);
string base64Ciphertext = Convert.ToBase64String(memoryStream.ToArray());
return base64IV + "!" + base64Ciphertext;
}
}