React Native CryptoJS加密文本在C#解密报错:填充无效求排查
解决React Native CryptoJS AES加密与C#解密的Padding无效问题
你的C#解密代码和CryptoJS的默认加密逻辑存在多处不匹配,导致解密时触发"Padding is invalid"错误,具体问题及修正方案如下:
关键不匹配点
- 加密模式:CryptoJS.AES默认使用CBC模式,你的代码错误使用了ECB模式。
- 密钥/IV生成逻辑:CryptoJS直接传入字符串密钥时,采用OpenSSL的
EVP_BytesToKey算法生成密钥和IV,而非你代码中的PBKDF2。 - 密文格式处理:CryptoJS生成的Base64密文包含
Salted__前缀+随机盐+实际密文,你的代码未提取盐和有效密文,直接解密整个字节数组。
修正后的C#解密代码
1. 实现CryptoJS兼容的EVP_BytesToKey算法
private static (byte[] Key, byte[] IV) EVP_BytesToKey(string password, byte[] salt, int keySize, int ivSize) { List<byte> key = new List<byte>(); List<byte> iv = new List<byte>(); byte[] currentHash = Array.Empty<byte>(); byte[] passwordBytes = Encoding.UTF8.GetBytes(password); while (key.Count < keySize || iv.Count < ivSize) { using (MD5 md5 = MD5.Create()) { byte[] input = new byte[currentHash.Length + passwordBytes.Length + salt.Length]; Buffer.BlockCopy(currentHash, 0, input, 0, currentHash.Length); Buffer.BlockCopy(passwordBytes, 0, input, currentHash.Length, passwordBytes.Length); Buffer.BlockCopy(salt, 0, input, currentHash.Length + passwordBytes.Length, salt.Length); currentHash = md5.ComputeHash(input); key.AddRange(currentHash); if (iv.Count < ivSize) { iv.AddRange(currentHash); } } } return (key.Take(keySize).ToArray(), iv.Take(ivSize).ToArray()); }
2. 修正解密方法
public string Decrypt(string encryptedText, string secretKey) { byte[] encryptedBytes = Convert.FromBase64String(encryptedText); // 校验并解析CryptoJS密文格式:前8字节为"Salted__",接下来8字节是盐,剩余为实际密文 if (encryptedBytes.Length < 16 || !Encoding.ASCII.GetString(encryptedBytes, 0, 8).Equals("Salted__")) { throw new ArgumentException("无效的CryptoJS加密格式"); } byte[] salt = encryptedBytes.Skip(8).Take(8).ToArray(); byte[] actualCiphertext = encryptedBytes.Skip(16).ToArray(); using (AesCryptoServiceProvider aes = new AesCryptoServiceProvider()) { aes.KeySize = 256; aes.Mode = CipherMode.CBC; // 匹配CryptoJS默认模式 aes.Padding = PaddingMode.PKCS7; // 生成兼容的密钥和IV var (key, iv) = EVP_BytesToKey(secretKey, salt, aes.KeySize / 8, aes.BlockSize / 8); aes.Key = key; aes.IV = iv; // 执行解密 using (ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV)) using (MemoryStream msDecrypt = new MemoryStream(actualCiphertext)) using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) using (StreamReader srDecrypt = new StreamReader(csDecrypt)) { return srDecrypt.ReadToEnd(); } } }
注意事项
- 调用
Decrypt时,传入的secretKey必须和React Native中CryptoJS使用的密钥完全一致(你之前代码里硬编码了key = "my secret key",建议改为使用参数secretKey)。 - CryptoJS加密时如果手动指定了盐、模式或IV,C#代码需要同步对应参数。
内容的提问来源于stack exchange,提问作者Kunal
相关产品推荐
相关产品推荐

