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

React Native加密数据在.NET 7解密报错:填充无效问题求助

解决React Native与.NET 7 AES加解密的「Padding is invalid and cannot be removed.」错误

问题根源

出现该错误的核心是前后端加解密参数完全不匹配,具体问题如下:

  • IV长度违规:AES-CBC要求IV必须为16字节(128位),前端生成了17字节的IV,直接导致加密数据格式异常
  • IV使用逻辑错误:后端未使用前端加密时生成的随机IV,反而用密钥派生函数生成IV,完全不符合AES-CBC规范
  • 密钥不一致:前端直接使用原始密钥,后端通过PBKDF2派生密钥,两者密钥完全不匹配
  • 数据格式处理错误:前端未将IV转为Base64字符串传输,后端无法解析;同时加密结果重复调用toString()属于冗余操作

修正后的React Native加密代码

import CryptoJS from 'crypto-js';
import { key } from '../../secretKey'; // 确保此处key与后端密钥派生规则一致

export function Encrypt(data) {
  // 生成符合AES-CBC要求的16字节随机IV
  const iv = CryptoJS.lib.WordArray.random(16);

  // 加密数据,若后端用PBKDF2派生密钥,前端需执行相同派生逻辑
  const encryptedData = CryptoJS.AES.encrypt(data, key, {
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7,
    iv: iv,
  }).toString();

  return {
    cipherText: encryptedData, // 直接使用加密后的字符串,无需重复toString()
    iv: iv.toString(CryptoJS.enc.Base64) // 将IV转为Base64字符串,方便后端解析
  };
}

修正后的.NET 7解密代码

DecryptionHandler.cs

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public static class EncryptionHandler
{
    // 前后端必须使用完全一致的密钥派生参数
    private static byte[] DeriveKeyFromPassword(string password)
    {
        var salt = Encoding.UTF8.GetBytes("your-shared-secure-salt"); // 禁止使用空盐,盐需前后端一致
        var iterations = 10000; // 提高迭代次数增强安全性
        var desiredKeyLength = 16;
        var hashMethod = HashAlgorithmName.SHA384;
        return Rfc2898DeriveBytes.Pbkdf2(Encoding.UTF8.GetBytes(password), // 统一使用UTF-8编码,避免差异
                                         salt,
                                         iterations,
                                         hashMethod,
                                         desiredKeyLength);
    }

    // 修改方法,接收前端传来的密文和IV
    public static string DecryptStringAES(string cipherText, string ivBase64)
    {
        var keyBytes = DeriveKeyFromPassword(keySecret); // 派生密钥,与前端逻辑一致
        var ivBytes = Convert.FromBase64String(ivBase64); // 解析前端传来的Base64格式IV

        var encryptedBytes = Convert.FromBase64String(cipherText);
        return DecryptStringFromBytes(encryptedBytes, keyBytes, ivBytes);
    }

    private static string DecryptStringFromBytes(byte[] cipherText, byte[] key, byte[] iv)
    {
        if (cipherText == null || cipherText.Length <= 0)
            throw new ArgumentNullException(nameof(cipherText));
        if (key == null || key.Length <= 0)
            throw new ArgumentNullException(nameof(key));
        if (iv == null || iv.Length <= 0)
            throw new ArgumentNullException(nameof(iv));

        string plaintext = null;

        // 使用官方推荐的Aes类替代已过时的RijndaelManaged
        using (var aes = Aes.Create())
        {
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;
            aes.KeySize = 128;
            aes.BlockSize = 128;

            aes.Key = key;
            aes.IV = iv;

            var decryptor = aes.CreateDecryptor(aes.Key, aes.IV);

            try
            {
                using (var msDecrypt = new MemoryStream(cipherText))
                using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                using (var srDecrypt = new StreamReader(csDecrypt))
                {
                    plaintext = srDecrypt.ReadToEnd();
                }
            }
            catch (Exception ex)
            {
                plaintext = ex.Message;
            }
        }

        return plaintext;
    }
}

API控制器代码修改

// 确保模型包含正确的字段名(修正拼写:cipher而非chiper)
public class RegisterModel
{
    public string CipherText { get; set; }
    public string Iv { get; set; }
}

[HttpPost("decrypt")]
public IActionResult Decrypt([FromBody] RegisterModel model)
{
    string decryptedData = EncryptionHandler.DecryptStringAES(model.CipherText, model.Iv);
    return Ok(new { decryptedData });
}

核心安全规范

  • IV必须随机唯一:每次加密生成新的随机IV,绝不能重复使用
  • 密钥派生完全一致:前后端的派生算法、盐、迭代次数、编码格式必须完全匹配
  • 禁用空盐:PBKDF2空盐会大幅降低安全性,必须使用保密的共享盐
  • 统一编码格式:字符串转字节时统一使用UTF-8,避免编码差异导致密钥不匹配
  • 使用官方推荐API:.NET中优先使用Aes.Create()替代已过时的RijndaelManaged

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 04:37:49