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

使用AES256加解密后明文不匹配,请求排查问题(附代码)

问题分析与修复方案

你遇到的解密后字符串不匹配问题,核心原因是加密后的字节数组被错误地用ASCII编码转换为字符串,导致数据丢失;另外还有几个细节需要调整,下面一步步帮你解决:

1. 核心错误:ASCII编码无法安全处理加密字节

加密后的字节数组包含大量非ASCII可打印字符,直接用Encoding.ASCII.GetString(encrypted)转换时,无法识别的字节会被强制替换为?(ASCII值63)。后续再用Encoding.ASCII.GetBytes(cipher)转回字节数组时,已经不是原始的加密数据了,自然解密不出正确结果。

正确的做法是用Base64编码处理二进制数据,它专门用来将字节安全转换为可打印字符串,不会丢失信息。

2. 代码修复步骤

修复Program.cs的加密解密流程

替换ASCII编码为Base64,同时统一使用UTF8编码处理字符串(支持更多字符,比ASCII更实用):

using System;
using System.Text;

namespace AESEncryptionUtility
{
    class Program
    {
        private static string _pass = "MasterPass";
        private static string _msg = "Mohit";
        private static byte[] key = EncryptionUtility.GenerateKey(_pass, 32);
        private static byte[] IV = EncryptionUtility.GenerateSalt(16);

        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            string encryptedBase64 = Encrypt(_msg);
            string decryptedString = Decrypt(encryptedBase64);
            
            Console.WriteLine($"原字符串:{_msg}");
            Console.WriteLine($"解密后字符串:{decryptedString}");
        }

        public static string Encrypt(string msg)
        {
            byte[] plainBytes = Encoding.UTF8.GetBytes(msg);
            byte[] encrypted = EncryptionUtility.Encrypt(plainBytes, key, IV);
            
            Console.WriteLine("加密后的字节:");
            foreach (var b in encrypted)
            {
                Console.Write(b + " ");
            }
            Console.WriteLine("\n");
            
            // 用Base64转换为可存储/传输的字符串
            return Convert.ToBase64String(encrypted);
        }

        public static string Decrypt(string cipherBase64)
        {
            // 从Base64转回原始加密字节
            byte[] cipherBytes = Convert.FromBase64String(cipherBase64);
            byte[] decryptedBytes = EncryptionUtility.Decrypt(cipherBytes, key, IV);
            
            Console.WriteLine("解密后的字节:");
            foreach (var b in decryptedBytes)
            {
                Console.Write(b + " ");
            }
            Console.WriteLine("\n");
            
            // 用UTF8转回字符串,和加密时编码一致
            return Encoding.UTF8.GetString(decryptedBytes);
        }
    }
}

修复EncryptionUtility.cs的细节

  • 把PaddingMode.Zeros改回PaddingMode.PKCS7:Zero padding无法区分原始数据末尾的空字符和填充的空字符,PKCS7是更安全、更通用的填充方式;
  • 优化GenerateKey方法:如果需要持久化密钥(比如下次解密复用),要把生成的salt保存下来,否则每次调用都会生成不同的密钥。

修改后的EncryptionUtility.cs:

using System;
using System.Security.Cryptography;

namespace AESEncryptionUtility
{
    public static class EncryptionUtility
    {
        public static byte[] Encrypt(byte[] plainBytes, byte[] key, byte[] IV)
        {
            using (AesCryptoServiceProvider aesAlgo = new AesCryptoServiceProvider())
            {
                aesAlgo.Key = key;
                aesAlgo.BlockSize = 128;
                aesAlgo.Mode = CipherMode.CBC;
                aesAlgo.Padding = PaddingMode.PKCS7; // 改用PKCS7填充
                aesAlgo.IV = IV;

                ICryptoTransform encryptor = aesAlgo.CreateEncryptor();
                return encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length);
            }
        }

        public static byte[] Decrypt(byte[] cipherBytes, byte[] key, byte[] IV)
        {
            using (AesCryptoServiceProvider aesAlgo = new AesCryptoServiceProvider())
            {
                aesAlgo.Key = key;
                aesAlgo.BlockSize = 128;
                aesAlgo.Mode = CipherMode.CBC;
                aesAlgo.Padding = PaddingMode.PKCS7; // 和加密端保持一致
                aesAlgo.IV = IV;

                ICryptoTransform decryptor = aesAlgo.CreateDecryptor();
                return decryptor.TransformFinalBlock(cipherBytes, 0, cipherBytes.Length);
            }
        }

        // 新增带salt输出的方法,方便持久化密钥
        public static byte[] GenerateKey(string masterPassword, int size, out byte[] salt) 
        {
            salt = GenerateSalt(size);
            Rfc2898DeriveBytes pbfdk = new Rfc2898DeriveBytes(masterPassword, salt, 20000);
            return pbfdk.GetBytes(size);
        }

        // 保留原有方法兼容现有代码
        public static byte[] GenerateKey(string masterPassword, int size)
        {
            return GenerateKey(masterPassword, size, out _);
        }

        public static byte[] GenerateSalt(int size)
        {
            using (RNGCryptoServiceProvider generator = new RNGCryptoServiceProvider())
            {
                byte[] salt = new byte[size];
                generator.GetNonZeroBytes(salt);
                return salt;
            }
        }
    }
}

3. 额外注意事项

  • 加密和解密必须使用相同的编码(这里统一用UTF8),避免出现乱码;
  • 实际应用中,IV和salt都需要和加密内容一起保存(比如存数据库或文件):IV应该每次加密都生成新的,而密钥生成依赖salt;
  • .NET Core/.NET 5+中推荐用RandomNumberGenerator替代RNGCryptoServiceProvider,安全性更高;
  • 你的代码已经正确使用了32字节密钥对应AES-256,这部分没问题。

修改完成后,解密后的字符串就会和原字符串完全匹配了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:08:26