2

In MSDN for AES I can see the following part in the sample.

...
using (Aes aesAlg = Aes.Create())
{
  aesAlg.Key = Key;
  aesAlg.IV = IV;
  ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
  ...
} ...

I've tried to skipping the assignment of key and IV to the AES object (although setting them in the creation of the encryptor like this.

...
using (Aes aesAlg = Aes.Create())
{
  //aesAlg.Key = Key;
  //aesAlg.IV = IV;
  ICryptoTransform encryptor = aesAlg.CreateEncryptor(Key, IV);
  ...
} ...

It seems to make no difference in the outcome. However, since it is a part of the sample, I worry that there is a case when it matters. It might be that I only tried examples where it doesn't show.

When do I need to assign the key and IV to the AES object?

Konrad Viltersten
  • 36,151
  • 76
  • 250
  • 438
  • AES inherits from SymmetricAlgorithm, and according to [the remarks](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.symmetricalgorithm?view=net-5.0#remarks) for this class: *To decrypt data that was encrypted using one of the SymmetricAlgorithm classes, you must set the Key property and the IV property to the same values that were used for encryption* - thus it sounds like in order to be able to decrypt, you must know the Key and IV used for encryption. So setting the Key and IV of your AES class should allow for this. – Timothy G. May 15 '21 at 22:23
  • Not sure how the key and IV is set in this case, however, you did not define the encryption mode, too. Microsoft's [AesManaged](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.aesmanaged?view=net-5.0) Default encryption mode is CBC mode of encryption. CBC mode requires an unpredictable random IV to be secure. Therefore you need to generate it [randomly](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.aesmanaged.generateiv?view=net-5.0). Better to be use AES-GCM/ – kelalaka May 15 '21 at 22:57
  • [if (KeyValue == null) GenerateKey();](https://referencesource.microsoft.com/#mscorlib/system/security/cryptography/symmetricalgorithm.cs,135). – dr.null May 16 '21 at 00:01
  • @TimothyG. Agreed on that. However, that wasn't the question. I'm setting both the key and vector during creation of the encryptor, as shown in the sample. However, what I noticed is that the examples on the net, assign **also** directly to the object properties **and then again** pass them in the creation method. I wonder why and if it's needed. Apparently, it works well without it in my cases. However, I sense that there might be occasions where it must be set directly on the AES instance. – Konrad Viltersten May 16 '21 at 18:05
  • @dr.null Are you saying that if I won't specify, it's `null` and then gets called through `GenerateKey()`? Agreed on that. However, I wonder in which case that I have to specify it explicitly instead of relying on the method you linked to. – Konrad Viltersten May 16 '21 at 18:09

1 Answers1

2

In the first code snippet, you've assigned values to the Key and IV properties of the symmetric algorithm object so you don't need to pass them again when you create the crypto transform. In this case, use the parameterless overload which uses the already assigned Key and IV to create the encryptor/decryptor.

using (Aes aesAlg = Aes.Create())
{
  aesAlg.Key = Key;
  aesAlg.IV = IV;
  ICryptoTransform encryptor = aesAlg.CreateEncryptor();
  // ...
}

The second code snippet will create the same transform using the passed Key and IV params regardless of the aesAlg.Key and aesAlg.IV values. Consider the following:

using (Aes aesAlg = Aes.Create())
{
  aesAlg.Key = Key;
  aesAlg.IV = IV;
  ICryptoTransform encryptor = aesAlg.CreateEncryptor(someOtherKey, somOtherIV);
  // ...
}

Here, someOtherKey and someOtherIV are used to create the transform and the aesAlg properties are ignored. Another example to consider:

using (Aes aesAlg = Aes.Create())
{
  ICryptoTransform encryptor = aesAlg.CreateEncryptor();
  // ...
}

Now, both aesAlg.Key & aesAlg.IV properties are null and the .CreateEncryptor() will use them to create the transform. However, the method won't throw any exceptions because the getters of these properties - by design - don't return null and they create and assign random values instead.

You might want to try the following:

private void SomeCaller()
{
    using (var crypto = Aes.Create())
    {
        // A random Key is generated...
        PrintHexValue(crypto.Key);
        // And assigned...
        PrintHexValue(crypto.Key);

        var pass = "Konrad Viltersten";
        var bytes = Encoding.UTF8.GetBytes(pass);
        var rfc = new Rfc2898DeriveBytes(pass, 
            new SHA256Managed().ComputeHash(bytes), 1000);
        var key = rfc.GetBytes(crypto.LegalKeySizes[0].MaxSize / 8);
        var iv = rfc.GetBytes(crypto.LegalBlockSizes[0].MinSize / 8);

        // Doesn't change the crypto.Key and crypto.IV properties...
        var encr = crypto.CreateEncryptor(key, iv);

        // The generated password-based key...
        PrintHexValue(key);
        // The random key remains...
        PrintHexValue(crypto.Key);

        crypto.Key = key;
        crypto.IV = iv;

        // The password-based key is assigned to the crypto.Key...
        PrintHexValue(crypto.Key);
    }
}

private void PrintHexValue(byte[] bytes) =>
    Console.WriteLine(BitConverter.ToString(bytes).Replace("-", string.Empty));

Conclusion

Your second code snippet is a shortcut to create a crypto transform. You'll need the first one In wider scopes like this one for example.

dr.null
  • 4,032
  • 3
  • 9
  • 12
  • 1
    Very well formulated. Thanks. This was along the lines of my expectations but I was uncertain, since there were multiple ways, which sometimes indicates different outcomes, although similar. There should be one, single way to do things, so that the develop needs not to make unnecessary design decisions, in my opinion. – Konrad Viltersten May 17 '21 at 03:59