You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Framework 4.6x迁移至.NET Core 6后AES解密填充无效问题

问题:.NET Core 6解密.NET Framework加密数据时出现填充无效错误

将加密类库从.NET Framework 4.6x迁移至.NET Core 6后,解密原.NET Framework加密的字符串时抛出错误:Padding is invalid and cannot be removed.。代码逻辑、加密配置(填充方式、密钥、初始化向量等)均未修改,原逻辑在.NET Framework中可正常运行,但在.NET Core中解密失败。目前该代码为遗留代码,暂无替换计划,需解决此问题。

疑问:加密字符串在数据库与类库之间的处理是否因.NET Core CLR与.NET Framework 4.6的CLR差异而受影响?


旧代码(.NET Framework 4.6x)

using Previdence.Common.Security.Cryptography.Interfaces;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace DatabaseTableExport.Common.Security.Cryptography
{
    public class AESEncryption : IEncryptionProvider
    {
        private readonly byte[] _key;
        private readonly byte[] _iv;

        public AESEncryption(string key)
        {
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(key, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
            _key = pdb.GetBytes(32);
            _iv = pdb.GetBytes(16);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
        public string Encrypt(string value)
        {
            
            if (string.IsNullOrWhiteSpace(value))
            {
                return value;
            }

            byte[] clearBytes = Encoding.Unicode.GetBytes(value);

            using (Aes encryptor = Aes.Create())
            {
                if (encryptor != null)
                {
                    encryptor.Padding = PaddingMode.PKCS7;
                    using (MemoryStream ms = new MemoryStream())
                    using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(_key, _iv), CryptoStreamMode.Write))
                    {
                        cs.Write(clearBytes, 0, clearBytes.Length);
                        cs.FlushFinalBlock();
                        value = Convert.ToBase64String(ms.ToArray());
                    }
                }
            }

            return value;
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
        public string Decrypt(string value)
        {
            
            if (string.IsNullOrWhiteSpace(value))
            {
                return value;
            }
            byte[] cipherBytes = Convert.FromBase64String(value);

            using (Aes encryptor = Aes.Create())
            {
                if (encryptor != null)
                {
                    encryptor.Padding = PaddingMode.PKCS7;
                    using (MemoryStream ms = new MemoryStream())
                    using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(_key, _iv), CryptoStreamMode.Write))
                    {
                        cs.Write(cipherBytes, 0, cipherBytes.Length);
                        cs.FlushFinalBlock();
                        value = Encoding.Unicode.GetString(ms.ToArray());
                    }
                }
            }

            return value;
        }

        public void Dispose()
        {

        }

    }
}

using System;

namespace Security_Legacy.Cryptography.Interfaces
{
    public interface IEncryptionProvider : IDisposable
    {
        string Decrypt(string cypheredText);
        string Encrypt(string plainText);
    }
}

新代码(.NET Core 6)

using DatabaseTableExport.Services.Cryptography.Interfaces;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace DatabaseTableExport.Services.Cryptography
{
    public class AesEncryption : IEncryptionProvider
    {
        private readonly byte[] _key;
        private readonly byte[] _iv;

        public AesEncryption(string key)
        {
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(key, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
            _key = pdb.GetBytes(32);
            _iv = pdb.GetBytes(16);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
        public string Encrypt(string value)
        {

            if (string.IsNullOrWhiteSpace(value))
            {
                return value;
            }

            byte[] clearBytes = Encoding.Unicode.GetBytes(value);

            using (Aes encryptor = Aes.Create())
            {
                if (encryptor != null)
                {
                    encryptor.Padding = PaddingMode.PKCS7;
                    using (MemoryStream ms = new MemoryStream())
                    using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(_key, _iv), CryptoStreamMode.Write))
                    {
                        cs.Write(clearBytes, 0, clearBytes.Length);
                        cs.FlushFinalBlock();
                        value = Convert.ToBase64String(ms.ToArray());
                    }
                }
            }

            return value;
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
        public string Decrypt(string value)
        {

            if (string.IsNullOrWhiteSpace(value))
            {
                return value;
            }
            byte[] cipherBytes = Convert.FromBase64String(value);

            using (Aes encryptor = Aes.Create())
            {
                if (encryptor != null)
                {
                    encryptor.Padding = PaddingMode.PKCS7;
                    using (MemoryStream ms = new MemoryStream())
                    using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(_key, _iv), CryptoStreamMode.Write))
                    {
                        try
                        {
                            cs.Write(cipherBytes, 0, cipherBytes.Length);
                            cs.FlushFinalBlock();
                            value = Encoding.Unicode.GetString(ms.ToArray());
                        }
                        catch (Exception e)
                        {
                            value = $"Failed to decrypt: {e.Message}";
                            var errorString = $"{e.Message}";
                        }

                    }
                }
            }

            return value;
        }

        public void Dispose()
        {
            // nothing to dispose
            throw new NotImplementedException();
        }
    }
}

using System;

namespace Security_Legacy.Cryptography.Interfaces
{
    public interface IEncryptionProvider : IDisposable
    {
        string Decrypt(string cypheredText);
        string Encrypt(string plainText);
    }
}

解决方案

问题根源在于Rfc2898DeriveBytes的默认迭代次数差异:

  • .NET Framework 4.6x中,Rfc2898DeriveBytes默认迭代次数为1000
  • .NET Core 2.0及以后版本中,默认迭代次数改为10000

由于代码未显式指定迭代次数,导致.NET Core环境生成的密钥(_key)和初始化向量(_iv)与.NET Framework环境不一致,最终解密时出现填充无效错误。

修改方法

在.NET Core版本的AesEncryption构造函数中,显式指定迭代次数为1000,与.NET Framework保持一致:

public AesEncryption(string key)
{
    // 显式设置迭代次数为1000,匹配.NET Framework默认值
    Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(
        key, 
        new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 }, 
        1000);
    _key = pdb.GetBytes(32);
    _iv = pdb.GetBytes(16);
}

验证

修改后,.NET Core环境可以正常解密原.NET Framework加密的数据;同时,.NET Core加密的数据也能在.NET Framework环境中正常解密,完全兼容原有逻辑。


内容的提问来源于stack exchange,提问作者Tyson Gibby

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 09:14:55