0

If you have been using the RijndaelManaged .NET crypto class for your AES encryptions, you'll soon start seeing deprecation warnings like this:

RijndaelManaged is obsolete: The Rijndael and RijndaelManaged types are obsolete. Use Aes instead.

enter image description here

Here are some working (and tested) Encrypt() and Decrypt() samples to replace what you have.

Assuming you want constant encryption keys (that don't randomly change out from under you each time your methods execute), first generate a KEY and an IV like so:

  1. Go here: https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.aes
  2. Create a simple console app out of that. Run it in debug mode.
  3. Put a breakpoint where you can examine myAes.Key and myAes.IV
  4. Place those in the Watch window and wrap them each in System.Text.Encoding.Default.GetString() so you convert the byte array to a string that can be used as your key. Place those strings in a private const within your class. Each time you run the console app you'll get different keys, so that's an easy way to get new keys, and you'll never get the same keys as someone else running this sample, because it's randomized each time.

Here's what I got:

private const string _aesKey = "MjMgEO5A2Q...5OxRw="; 
private const string _aesIV = "Z/ENPB...zl5A==";

And here are the methods for you:

public static string Encrypt(string rawText) {
  if (!string.IsNullOrEmpty(rawText)) {
    using(Aes aes = Aes.Create()) {
      aes.Key = Convert.FromBase64String(_aesKey);
      aes.IV = Convert.FromBase64String(_aesIV);
      byte[] encryptedBytes = EncryptStringToBytes_Aes(rawText, aes.Key, aes.IV);
      return Convert.ToBase64String(encryptedBytes);
    }
  } else {
    return string.Empty;
  }
}

public static string Decrypt(string encryption) {
  if (!string.IsNullOrEmpty(encryption)) {
    using(Aes aes = Aes.Create()) {
      aes.Key = Convert.FromBase64String(_aesKey);
      aes.IV = Convert.FromBase64String(_aesIV);
      byte[] data = Convert.FromBase64String(encryption);
      return DecryptStringFromBytes_Aes(data, aes.Key, aes.IV);
    }
  } else {
    return string.Empty;
  }
}

public static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV) {
  if (plainText == null || plainText.Length <= 0) throw new ArgumentNullException("plainText");
  if (Key == null || Key.Length <= 0) throw new ArgumentNullException("Key");
  if (IV == null || IV.Length <= 0) throw new ArgumentNullException("IV");

  byte[] encrypted;

  using(Aes aesAlg = Aes.Create()) {
    aesAlg.Key = Key;
    aesAlg.IV = IV;

    ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

    using(MemoryStream msEncrypt = new MemoryStream()) {
      using(CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) {
        using(StreamWriter swEncrypt = new StreamWriter(csEncrypt)) {
          swEncrypt.Write(plainText);
        }

        encrypted = msEncrypt.ToArray();
      }
    }
  }

  return encrypted;
}

public static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV) {
  if (cipherText == null || cipherText.Length <= 0) throw new ArgumentNullException("cipherText");
  if (Key == null || Key.Length <= 0) throw new ArgumentNullException("Key");
  if (IV == null || IV.Length <= 0) throw new ArgumentNullException("IV");

  string plaintext = null;

  using(Aes aesAlg = Aes.Create()) {
    aesAlg.Key = Key;
    aesAlg.IV = IV;

    ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

    using(MemoryStream msDecrypt = new MemoryStream(cipherText)) {
      using(CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) {
        using(StreamReader srDecrypt = new StreamReader(csDecrypt)) {
          plaintext = srDecrypt.ReadToEnd();
        }
      }
    }
  }

  return plaintext;
}

If you're performing large numbers of encryptions per-run, consider moving the Aes.Create() constructions up into a constructor or single-use method for better efficiency.

HerrimanCoder
  • 6,835
  • 24
  • 78
  • 158
  • 1
    `RijndaelManaged` remains an important part of .NET Framework. The obsolete notice is applicable on .NET Core, and you can simply replace `RijndaelManaged` with `AES.Create` to get most of the existing sample code working. – Lex Li Sep 30 '22 at 23:42
  • Lex, there must be more to it than that. I get lots of errors when I try that simple swap. Provide working example? – HerrimanCoder Sep 30 '22 at 23:50
  • #SNMP Library has been using .NET AES for more than a decade, https://github.com/lextudio/sharpsnmplib/blob/master/SharpSnmpLib/Security/AESPrivacyProviderBase.cs So all tips I said have been used that long. – Lex Li Oct 01 '22 at 00:54
  • [Alternative](https://stackoverflow.com/a/66486747/14171304) Section. Many more around. [Here's](https://stackoverflow.com/a/73048133/14171304) another. – dr.null Oct 01 '22 at 06:27
  • Maybe you can create a more specific question about replacing `RijndaelManaged` with `Aes.Create`? That would be much more interesting. From what I saw, the comment of Lex Li hit the spot; that's exactly what you're supposed to be doing, and I've actually verified that with people that work on .NET. – Maarten Bodewes Oct 01 '22 at 09:51
  • AES is a subset of Rijndael. `RijndaelManaged` therefore supports block sizes that `Aes` does not support (e.g. 32 bytes). However, this depends on the environment (Framework or Core). This could also be a reason that the simple replacement fails. – Topaco Oct 01 '22 at 10:32
  • I converted the question to "share your knowledge, Q&A-style". – HerrimanCoder Oct 01 '22 at 19:52

0 Answers0