microsoft / dotnet

This repo is the official home of .NET on GitHub. It's a great starting point to find many .NET OSS projects from Microsoft and the community, including many that are part of the .NET Foundation.
https://devblogs.microsoft.com/dotnet/
MIT License
14.34k stars 2.21k forks source link

Value encrypted by RijndaelManaged via .NET Standard 2.1 cannot be decrypted by ASP.NET MVC .NET 4.7.2 #1324

Closed filmar25 closed 2 years ago

filmar25 commented 2 years ago

Hi,

I have a weird of behavior to decrypt value that was previously encrypted by an asp.net core application.

I use this code in asp.net core to decrypt successfully the value :

private static byte[] DecryptBytes(this byte[] encryptedBytes, byte[] iv, byte[] key, byte[] encryptionKey)
{
  byte[] cipherBytes = encryptedBytes;
  byte[] keyBytes = new Rfc2898DeriveBytes(Encoding.UTF8.GetString(encryptionKey), key).GetBytes(256 / 8);
  var symmetricKey = new RijndaelManaged()
  {
    Mode = CipherMode.CBC,
    Padding = PaddingMode.None
  };

  var decryptor = symmetricKey.CreateDecryptor(keyBytes, iv);
  using (var memoryStream = new MemoryStream(cipherBytes))
  {
    using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
    {
      byte[] plainBytes = new byte[cipherBytes.Length];
      int decryptedByteCount = cryptoStream.Read(plainBytes, 0, plainBytes.Length);

      memoryStream.Close();
      cryptoStream.Close();

      return plainBytes;
    }
  }
}

The exact same code is use by an ASP.NET MVC .NET 4.7.2 application but the plainBytes return is not readable.

I had checked values of parameters in both framework and they are identicals. So my conclusion is that frameworks are not working the same. I have notice a difference of properties between symmetricKey.

Am I wrong in my conclusion ?

Thank you !

trylek commented 2 years ago

The last time I helped someone investigate a cryptography issue I was told that @bartonjs is the go-to expert in this area.

filmar25 commented 2 years ago

I made a test this morning.

I created a asp.net core .net 5 project with a controller that received all parameters that .NET 4.7.2 is using to decrypt. I copied the function showed in previous post in the new project to be used by the controller.

So in my .net 4.7.2, I made a called to the controller of the new project by passing all parameters. The controller has used the decrypt function successfully.

That's confirmed that RijndaelManaged has not the same behavior between framework.

bartonjs commented 2 years ago

The main thing I see out of the ordinary is you're assuming that CryptoStream.Read will fill your buffer completely. (This is generally true on .NET Framework and .NET 5 and below, but is no longer true on .NET 6)

int decryptedByteCount = cryptoStream.Read(plainBytes, 0, plainBytes.Length);

should instead be

int read = 0;
int decryptedByteCount = 0;

while ((read = cryptoStream.Read(plainBytes, decryptedByteCount, plainBytes.Length) != 0)
{
    decryptedByteCount += read;
}

Other than that, we'd need some actual inputs to test to see what's going on. The most suspicious thing is that you're turning a byte[] called encryptionKey into a string via Encoding.UTF8.GetString(byte[]); so you may be hitting differences in UTF-8 handling across versions of .NET. (When debugging, check that keyBytes actually got the same value in both framework versions)

filmar25 commented 2 years ago

Hi,

@bartonjs you are completely right !!

I have replace

byte[] keyBytes = new Rfc2898DeriveBytes(Encoding.UTF8.GetString(encryptionKey), key).GetBytes(256 / 8);

by

byte[] keyBytes = new Rfc2898DeriveBytes(encryptionKey, key, 10000).GetBytes(256 / 8);

Now all is working like a charm !

Thank you help me to have good direction !!