1

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 ?

user584018
  • 10,186
  • 15
  • 74
  • 160
  • 1
    [AesCryptoServiceProvider.KeySize](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.aescryptoserviceprovider.keysize?view=net-6.0) - For AES, the legal key sizes are 128, 192, and 256 bits. – Alexander Petrov Aug 24 '22 at 16:03

3 Answers3

3

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.

LilCoding
  • 71
  • 5
0

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
Sedat Kapanoglu
  • 46,641
  • 25
  • 114
  • 148
  • A type 4 Guid has 122 bits of random data. I'm about 99% sure that Windows uses a cryptographically secure random algorithm to generate those bits. That said... use one of the secure `RandomNumberGenerator` tools to generate your key – Flydog57 Aug 24 '22 at 19:17
  • @Flydog57 Possibly, but the API makes no such promise. That means, even if you get CSRNG by chance on Windows, you may not get it on, say, MacOS, or Linux. .NET isn't about Windows anymore. That said, 122-bits is still *six orders of magnitude* weaker than 128-bits. It makes *zero* sense to use a GUID instead of a CSRNG. – Sedat Kapanoglu Aug 25 '22 at 01:18
  • Oh, no argument from me on that. But 6 bits is not "6 orders of magnitude" difference in the normal sense, it's a factor of 64, about one and a half orders of magnitude – Flydog57 Aug 25 '22 at 02:02
  • 1
    @Flydog57 - although most commonly encountered with 10 as the base, orders of magnitude can be used with other bases and here, when working with binary values, base 2 does feel natural. – Damien_The_Unbeliever Aug 25 '22 at 06:04
0
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.

Jeremy Lakeman
  • 9,515
  • 25
  • 29
  • Creating the key with a cryptographically strong random number generator is better than a hashed password. A hashed password has the same entropy as the password. What a hashed password does is provide some way to exchange the keys (i.e., key exchange based on someone remembering a password) – Flydog57 Aug 25 '22 at 15:52
  • Sure a hashed password, with a well known salt, is vulnerable to a dictionary attack. But a key with known bits may be vulnerable to some math shortcut that attacks AES itself, which is much worse. – Jeremy Lakeman Aug 26 '22 at 00:50