Node.js aes-js加密后.NET端AES解密结果不一致问题问询
AES跨Node.js与.NET加解密兼容实现方案
不匹配根因
- 加密模式不一致:Node.js端使用AES-OFB模式,C#默认使用CBC模式,模式不同输出结果完全不相关
- 填充规则不一致:OFB属于流加密模式,不需要对明文做块填充,C#默认开启PKCS7填充,会额外追加填充字节
- 输出编码不一致:Node.js端最终输出十六进制编码的字符串,C#原代码错误将加密二进制字节直接用UTF8转字符串,编码规则不统一
- 原C#代码存在笔误:Main方法中定义的明文字段为
plain,调用加密方法时错误写为plano,本身会触发编译错误
兼容实现代码
Node.js加密端(修复笔误,核心逻辑保持不变)
const aesjs = require('aes-js'); const key = "01234567890123456789012345678901"; const iv = "0123456789012345"; function cryptTokn(text){ var keyBytes = aesjs.utils.utf8.toBytes(key); var ivBytes = aesjs.utils.utf8.toBytes(iv); var textBytes = aesjs.utils.utf8.toBytes(text); var aesOfb= new aesjs.ModeOfOperation.ofb(keyBytes, ivBytes); var encryptedBytes = aesOfb.encrypt(textBytes); // 输出十六进制字符串,和C#端保持一致 var encryptedHex = aesjs.utils.hex.fromBytes(encryptedBytes); console.log(encryptedHex); return encryptedHex; }
C#端(同时兼容.NET Framework、.NET Core/.NET 5+,支持加密+解密)
using System; using System.Security.Cryptography; using System.Text; class AesCrossPlatform { private static readonly byte[] key = Encoding.UTF8.GetBytes("01234567890123456789012345678901"); private static readonly byte[] iv = Encoding.UTF8.GetBytes("0123456789012345"); static void Main(string[] args) { Console.WriteLine("输入要加密的文本:"); string plainText = Console.ReadLine(); // 加密测试 string encryptedHex = Encrypt(plainText); Console.WriteLine($"加密后十六进制字符串:{encryptedHex}"); // 解密测试(可直接解密Node.js返回的十六进制字符串) string decryptedText = Decrypt(encryptedHex); Console.WriteLine($"解密后原文:{decryptedText}"); } // 加密方法,返回十六进制字符串,和Node.js输出完全对齐 static string Encrypt(string plainText) { byte[] plainBytes = Encoding.UTF8.GetBytes(plainText); using (Aes aes = Aes.Create()) { aes.Key = key; aes.IV = iv; aes.Mode = CipherMode.OFB; aes.Padding = PaddingMode.None; ICryptoTransform encryptor = aes.CreateEncryptor(); byte[] encryptedBytes = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length); return BitConverter.ToString(encryptedBytes).Replace("-", "").ToLower(); } } // 解密方法,直接输入Node.js返回的十六进制字符串即可完成解密 static string Decrypt(string encryptedHex) { // 把十六进制字符串转成字节数组 int length = encryptedHex.Length / 2; byte[] encryptedBytes = new byte[length]; for (int i = 0; i < length; i++) { encryptedBytes[i] = Convert.ToByte(encryptedHex.Substring(i * 2, 2), 16); } using (Aes aes = Aes.Create()) { aes.Key = key; aes.IV = iv; aes.Mode = CipherMode.OFB; aes.Padding = PaddingMode.None; ICryptoTransform decryptor = aes.CreateDecryptor(); byte[] decryptedBytes = decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length); return Encoding.UTF8.GetString(decryptedBytes); } } }
注意事项
- 密钥、IV必须两端完全一致,转字节时统一使用UTF8编码
- OFB模式不需要填充,两端必须同时关闭填充配置,否则会出现解密乱码
- 如果需要替换为Base64编码传输,只需同步修改两端的字节转字符串、字符串转字节逻辑即可,加解密核心逻辑无需修改
内容的提问来源于stack exchange,提问作者TaKeR
相关产品推荐
相关产品推荐

