I have below method for symmetric encryption a string content,
public static class EncodeExtension
{
public static string AesEncryptString(this string plainText, string key)
{
byte[] iv = new byte[16];
byte[] array;
using (Aes aes = Aes.Create())
{
aes.Key = Encoding.UTF8.GetBytes(key);
aes.IV = iv;
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter streamWriter = new StreamWriter((Stream)cryptoStream))
{
streamWriter.Write(plainText);
}
array = memoryStream.ToArray();
}
}
}
return Convert.ToBase64String(array);
}
}
Now I want to pass a random Guid
as a key for each string content string,
var key1 = Guid.NewGuid().ToString();
var encryptedData = "test1".AesEncryptString(key1);
var key2 = Guid.NewGuid().ToString();
var encryptedData = "test2".AesEncryptString(key2);
Here I am getting Specified key is not a valid size for this algorithm
? What key size it's expecting here? I do generate a random key size ?
CodePudding user response:
Even if you can, never use a GUID for encryption key because they're not guaranteed to produce a cryptographically secure random number. It might be significantly easier to crack a GUID-based key than a securely generated key. Never use GUID for cryptographically sensitive operations.
I don't recommend running a KDF over the GUID either since that doesn't change the low entropy underneath.
As of .NET 6, it's way easier to generate a cryptographically secure random key:
byte[] key = RandomNumberGenerator.GetBytes(32); // generate 256-bits
CodePudding user response:
byte[] iv = new byte[16];
byte[] array;
using var aes = Aes.Create();
aes.Key = Encoding.UTF8.GetBytes(key);
aes.IV = iv;
Everything about this is terribly broken.
16 bytes that represent a valid UTF8 string, is not very random. If I saw your code, I would be able to guess a significant fraction of the bits of your key.
.IV
must always be unique. If you ever encrypt two different inputs with the same .Key
& .IV
, your encryption can be easily broken. It's common to generate a random IV and write it as plain text into the output. eg memoryStream.Write(aes.IV)
Using a salted hash to turn a password string into a key is better, but only if you can ensure that your salt is kept secret.
CodePudding user response:
This error comes from the fact that the size in bytes of the GUID UTF8 string isn't a valid key size for AES (128, 192 or 256 bits).
You could use a key derivation function such as PBKDF2 to derive the key from your GUID. PBKDF2 is implemented in .net by the class Rfc2898DeriveBytes
public static string AesEncryptString(this string plainText, string key) {
byte[] array;
byte[] keyBytes;
using (Aes aes = Aes.Create())
{
using (Rfc2898DeriveBytes pbkdf = new Rfc2898DeriveBytes(key, Encoding.UTF8.GetBytes(key)))
{
// here 16 bytes for AES128
keyBytes = pbkdf.GetBytes(16);
}
aes.Key = keyBytes;
//for convenience here we use the key as iv too
aes.IV = keyBytes;
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter streamWriter = new StreamWriter((Stream)cryptoStream))
{
streamWriter.Write(plainText);
}
array = memoryStream.ToArray();
}
}
}
return Convert.ToBase64String(array);
}
Be careful as you will have to use the same behavior to generate the key on decryption too.