Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Intermittent error on Decrypting fields related to Padding ("Padding is invalid and cannot be removed") #48

Closed
AngeloPacione opened this issue Feb 22, 2023 · 3 comments
Labels
question Further information is requested

Comments

@AngeloPacione
Copy link

Hello,

I am using version 4.0 of your package and have an intermittent error that appears when attempting to decrypt data via EF calls. The error goes like this:
---ERROR---
System.Security.Cryptography.CryptographicException: Padding is invalid and cannot be removed.
   at System.Security.Cryptography.SymmetricPadding.GetPaddingLength(ReadOnlySpan1 block, PaddingMode paddingMode, Int32 blockSize)    at System.Security.Cryptography.UniversalCryptoDecryptor.UncheckedTransformFinalBlock(ReadOnlySpan1 inputBuffer, Span1 outputBuffer)    at System.Security.Cryptography.UniversalCryptoDecryptor.UncheckedTransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)    at System.Security.Cryptography.UniversalCryptoTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)    at System.Security.Cryptography.CryptoStream.ReadAsyncCore(Memory1 buffer, CancellationToken cancellationToken, Boolean useAsync)
   at System.Security.Cryptography.CryptoStream.Read(Byte[] buffer, Int32 offset, Int32 count)
   at System.Security.Cryptography.CryptoStream.CopyTo(Stream destination, Int32 bufferSize)
   at Microsoft.EntityFrameworkCore.DataEncryption.Providers.AesProvider.StreamToBytes(Stream stream)
   at Microsoft.EntityFrameworkCore.DataEncryption.Providers.AesProvider.Decrypt(Byte[] input)
   at Microsoft.EntityFrameworkCore.DataEncryption.Internal.EncryptionConverter2.Decrypt[TInput,TOupout](TProvider input, IEncryptionProvider encryptionProvider, StorageFormat storageFormat)    at lambda_method909(Closure, QueryContext, DbDataReader, ResultContext, SingleQueryResultCoordinator)    at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable1.AsyncEnumerator.MoveNextAsync()
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable1 asyncEnumerable, CancellationToken cancellationToken)    at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable1 asyncEnumerable, CancellationToken cancellationToken)
---ERROR---

I am using Attribute-based code to declare the fields as Encrypted. It is definitely intermittent so far. I am using a 256-key. I have also explicitly set the PaddingMode just to be sure and it does not seem to help the issue. The code below is how I declare the encryption setup in the EF DataContext Constructor and OnModelCreating method:

---DATACONTEXT CONSTUCTOR CODE---
using Aes aesCrypto = Aes.Create();
aesCrypto.Key = Convert.FromBase64String("MyKeyHere"); // Expecting 256-bit Base64 encoded string
aesCrypto.GenerateIV(); // Generating a new Initialization Vector each time
_encryptionProvider = new AesProvider(aesCrypto.Key, aesCrypto.IV, padding: PaddingMode.PKCS7);
---DATACONTEXT CONSTUCTOR CODE---

---ONMODELCREATING CODE---
modelBuilder.UseEncryption(_encryptionProvider);
---ONMODELCREATING CODE---

There is a lot of discussion out there on this error and most of it appears older with differing solutions. I am wondering if you have seen this before in your testing, or possibly have a best practice on the way the constructor code is written that may prevent this intermittent issue. To throw a wrench in this a bit more, I test this locally and it seems fine. But when deployed as a service in a development environment, this is when the intermittent error happens. This post I found in particular seems to talk about what may be happening here - https://stackoverflow.com/questions/66482089/aes-padding-is-invalid-and-cannot-be-removed

Any help on the matter is appreciated in advance.
Thank you.

@Eastrall
Copy link
Owner

Hi, by reading your code:

using Aes aesCrypto = Aes.Create();
aesCrypto.Key = Convert.FromBase64String("MyKeyHere"); // Expecting 256-bit Base64 encoded string
aesCrypto.GenerateIV(); // Generating a new Initialization Vector each time
_encryptionProvider = new AesProvider(aesCrypto.Key, aesCrypto.IV, padding: PaddingMode.PKCS7);

It looks like that your are generating an IV at every run of your program. If you do this you will not be able to decrypt the data your have encrypted with the (key, IV) pair. So you need to store the IV somewhere.

As this answer suggests: https://security.stackexchange.com/a/35211
You can genearte an IV at each encryption and add it to the begining of your encrypted data. EntityFrameworkCore.DataEncryption had once (in V3.X and prior) a support for dynamic IV on each encryption.
If you want to use it, I'd suggest you to checkout this comment: #46 (comment)

Note : when using a dynamic IV, all built-in LINQ-to-SQL statements will not work as intended. This is related to the ValueConverter (and thus the EncryptionProvider) being called each time you interact with the database.

@Eastrall Eastrall added the question Further information is requested label Feb 24, 2023
@AngeloPacione
Copy link
Author

AngeloPacione commented Feb 28, 2023 via email

@Eastrall
Copy link
Owner

Eastrall commented Mar 6, 2023

Great news! I'm closing this issue since it has been solved.

@Eastrall Eastrall closed this as completed Mar 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants