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

Android与.NET AES 256加密结果不匹配及填充错误求助

解决Android与.NET AES加密不匹配及Padding错误问题

嘿,我帮你梳理一下两端代码的核心问题,AES加密的一致性要求所有参数和流程完全对齐,哪怕一个细节不对都会导致结果不匹配,甚至解密时报Padding错误。下面是你的代码里的关键差异和修正方案:

核心问题拆解

1. 明文编码不统一

.NET里用的Encoding.Unicode其实就是UTF-16LE,你最初的Java代码用了UTF-8,后来虽然尝试改了,但其他参数没跟上,这会直接导致明文转字节数组就不一样。

2. PBKDF2密钥派生完全错了

  • 密码参数搞反了:你更新后的Java代码里,PBEKeySpec传的是strToEncrypt.toCharArray()(要加密的明文),但.NET端用的是固定密钥"password"!这是最致命的错误,直接导致两端生成的密钥完全不同,解密时自然会报Padding错误。
  • 哈希算法不一致:.NET的Rfc2898DeriveBytes默认用的是HMACSHA1,你一开始用了PBKDF2WithHmacSHA256,后来改对了,但要确保这个算法完全匹配。
  • 迭代次数之前不匹配:.NET默认迭代次数是1000,你最初Java代码用了65536,后来改回1000是对的。

3. IV生成逻辑不对

.NET是通过同一个Rfc2898DeriveBytes实例先取32字节的Key,再接着取16字节的IV;你最初用了全0的IV,后来尝试直接用salt当IV(但salt只有13字节,不够AES要求的16字节),这完全不符合.NET的逻辑。

4. URL编码的编码格式错了

.NET的Server.UrlEncode默认用UTF-8编码,你更新后的Java代码用了UTF_16LE做UrlEncode,这会导致最终的URL编码结果不一样。

修正后的Java代码

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class AESEncryptor {
    private static final String ENCRYPTION_KEY = "password"; // 和.NET的EncryptionKey完全一致
    // 完全照搬.NET的salt字节数组
    private static final byte[] SALT = {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76};
    private static final int ITERATION_COUNT = 1000; // .NET Rfc2898DeriveBytes默认迭代次数
    private static final int TOTAL_DERIVED_LENGTH = 384; // 32字节Key + 16字节IV = 48字节(384位)

    public static String encrypt(String strToEncrypt) {
        try {
            // 1. 派生密钥和IV:和.NET的Rfc2898DeriveBytes逻辑完全同步
            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            // 注意!这里传的是加密密钥的字符数组,不是要加密的明文!
            PBEKeySpec keySpec = new PBEKeySpec(ENCRYPTION_KEY.toCharArray(), SALT, ITERATION_COUNT, TOTAL_DERIVED_LENGTH);
            byte[] derivedBytes = factory.generateSecret(keySpec).getEncoded();
            
            // 拆分出Key和IV
            byte[] aesKey = new byte[32];
            byte[] aesIv = new byte[16];
            System.arraycopy(derivedBytes, 0, aesKey, 0, aesKey.length);
            System.arraycopy(derivedBytes, aesKey.length, aesIv, 0, aesIv.length);
            
            // 2. 初始化AES加密器:CBC模式+PKCS5Padding(和.NET的PKCS7Padding兼容)
            SecretKeySpec secretKey = new SecretKeySpec(aesKey, "AES");
            IvParameterSpec ivSpec = new IvParameterSpec(aesIv);
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
            
            // 3. 明文转字节数组:用和.NET一致的UTF-16LE
            byte[] plaintext = strToEncrypt.getBytes(StandardCharsets.UTF_16LE);
            byte[] encryptedData = cipher.doFinal(plaintext);
            
            // 4. 先Base64再URL编码:URL编码用UTF-8,和.NET一致
            String base64Str = Base64.getEncoder().encodeToString(encryptedData);
            return URLEncoder.encode(base64Str, StandardCharsets.UTF_8.name());
            
        } catch (Exception e) {
            System.out.println("加密出错:" + e.getMessage());
            return null;
        }
    }
}

验证和注意事项

  1. 参数全对齐:确保所有参数和.NET完全一致,包括salt、迭代次数、哈希算法、编码等,一个都不能错。
  2. 测试对比:用同一个明文(比如"test")分别运行.NET和修正后的Java代码,最终的URL编码结果应该完全相同。
  3. Padding错误原因:之前的核心问题是密钥派生错误,导致解密时用了错误的密钥,无法正确识别填充字节,所以报"Padding is invalid and cannot be removed",修正密钥后这个错误应该会消失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 20:12:45