AES 解密的意外行为

问题描述 投票:0回答:1

问题:我已经实现了一些在特定事件时进行解密的功能,但是有时它会抛出意外和无法解释的异常。

流程: 获取主密钥/iv,然后获取数据(从 PostgreSQL 数据库获取)并从 Base64 解码,然后解密,然后再次解压缩并解码。所以总结是这样的:

  1. 获取钥匙/IV
  2. 从 Base64 解码
  3. 使用 AES-256 CBC 解密
  4. 从Gzip解压(此时有时会失败)
  5. 再次解码为UTF-8

这是代码

public async Task<byte[]> PrivateDecrypt(long userId, byte[] data)
{
   var key = await this.GetOrAddPrivateEncryptionKey(userId);
   var keyBytes = key.ToUTF8Bytes();
   var (cipher, ivBytes) = data.ExtractIVPadding();

   var decrypted = await cipher
      .AESDecryptAndDecompressAsync(keyBytes, ivBytes)
      .ConfigureAwait(false);

   return decrypted;
}
public static byte[] FromBase64(this string base64) => Convert.FromBase64String(base64);
public static async Task<byte[]> AESDecryptAndDecompressAsync(this byte[] cipher, byte[] key, byte[] iv)
{
   if (cipher == null || cipher.Length <= 0)
      throw new ArgumentNullException(nameof(cipher), "incorrect data");

   if (key == null || key.Length != 32)
      throw new ArgumentNullException(nameof(key), "incorrect key");

   if (iv == null || iv.Length != 16)
      throw new ArgumentNullException(nameof(iv), "incorrect iv");

   using var aesAlg = Aes.Create();

   aesAlg.Mode = CipherMode.CBC;
   aesAlg.KeySize = 256;

   aesAlg.Key = key;
   aesAlg.IV = iv;
   aesAlg.Padding = PaddingMode.PKCS7;

   using var decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

   using (var decompressedStream = new MemoryStream())
   {
      using (var encryptedStream = new MemoryStream(cipher))
      {
         using (var cryptoStream = new CryptoStream(encryptedStream, decryptor, CryptoStreamMode.Read))
         {
            using (var gzipStream = new GZipStream(cryptoStream, CompressionMode.Decompress))
               await gzipStream.CopyToAsync(decompressedStream).ConfigureAwait(false);

            return decompressedStream.ToArray();
         }           
      }           
   }
}

这是我收到的异常堆栈跟踪的一部分

    System.IO.InvalidDataException: The archive entry was compressed using an unsupported compression method.
   at System.IO.Compression.Inflater.Inflate(FlushCode flushCode)
   at System.IO.Compression.Inflater.ReadInflateOutput(Byte* bufPtr, Int32 length, FlushCode flushCode, Int32& bytesRead)
   at System.IO.Compression.Inflater.InflateVerified(Byte* bufPtr, Int32 length)
   at System.IO.Compression.DeflateStream.CopyToStream.WriteAsyncCore(ReadOnlyMemory`1 buffer, CancellationToken cancellationToken)
   at System.Security.Cryptography.CryptoStream.CopyToAsyncInternal(Stream destination, Int32 bufferSize, CancellationToken cancellationToken)
   at System.IO.Compression.DeflateStream.CopyToStream.CopyFromSourceToDestinationAsync()
   at Trading.Tools.Bytes.EncryptionExtensions.AESDecryptAndDecompressAsync(Byte[] cipher, Byte[] key, Byte[] iv) in /src/Trading.Tools/Bytes/EncryptionExtensions.cs:line 207
   at Trading.Web.Commons.Encryption.LocalEncryptionService.PrivateDecrypt(Int64 userId, Byte[] data) in /src/Trading.Web.Commons/Encryption/LocalEncryptionService.cs:line 107

正如您从堆栈跟踪中看到的,问题出在解密后的解压层。

假设:

  1. 我可以肯定地说这段代码是有效的
  2. 我遇到的这种异常很少发生
  3. 数据库中的数据是正确的,否则将无法工作

我的想法:

  1. 我相信,由于问题的概率性质,这可能是一个竞争条件。我看到有两种可能性:
  • 数据库没有返回完整的字符串,并且错误地转义了某些字符,那么解密是如何工作的?
  • 有时解密会返回奇怪的结果,这让我认为即使存在单独的实例,某处仍然存在共享状态?

附加信息:

  1. 我正在使用 EFCore 8.0.2 从数据库获取
  2. 我正在使用.NET Core 8.0.3
  3. 我正在使用 PostgreSQL 16.1-bullseye

更新1:我已将代码更新为@Charlieface建议,但不幸的是我仍然面临同样的问题

更新2:我用BouncyCastle Nuget替换了所有加密逻辑并解决了这个问题。我在 8.0.3 之前没有这个问题,所以我只能假设这是因为最新的补丁

.net postgresql exception encryption utf-8
1个回答
0
投票

我用 BouncyCastle Nuget 替换了所有加密逻辑并解决了这个问题。我在 8.0.3 之前没有这个问题,所以我只能假设这是因为最新的补丁

© www.soinside.com 2019 - 2024. All rights reserved.