Java实现C# Rfc2898DeriveBytes解密报AES密钥长度无效错误
问题根因
- 构造AES密钥时错误传入了PBKDF2派生的完整48字节数据:你已经把派生结果拆分出了前32字节作为AES密钥、后16字节作为IV,但构造
SecretKeySpec时还是传入了完整的48字节的secretKey.getEncoded(),AES规范仅支持16/24/32字节长度的密钥,因此抛出长度无效异常。 - 额外存在两处和C#逻辑不匹配的问题,即便修复密钥长度也会解密失败:
- C#最终明文转字符串用的是
Encoding.Unicode(即UTF-16小端编码),Java代码中错误使用UTF-8解析明文字节 - 你拆分出的32字节密钥变量未被实际使用,相当于拆分逻辑完全无效
- C#最终明文转字符串用的是
修复后的Java代码
// 需和C#侧的密钥、盐完全一致 private static final String UrlEncryptionKey = "x0iiR!RG@753!"; private static final byte[] salt = new byte[] { 0x41, 0x71, 0x61, 0x6e, 0x21, 0x4d, 0x65, 0x64, 0x76, 0x64, 0x63, 0x62, 0x72 }; public static String Decrypt(String cipherText) throws Exception { SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); // 派生总长度32+16=48字节=384位,迭代次数1000和C#默认Rfc2898DeriveBytes逻辑一致 PBEKeySpec pbeKeySpec = new PBEKeySpec(UrlEncryptionKey.toCharArray(), salt, 1000, 384); Key secretKey = factory.generateSecret(pbeKeySpec); byte[] derived = secretKey.getEncoded(); // 拆分密钥和IV byte[] key = new byte[32]; byte[] iv = new byte[16]; System.arraycopy(derived, 0, key, 0, 32); System.arraycopy(derived, 32, iv, 0, 16); AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv); // 这里传入拆分后的32字节key,而非完整的派生结果数组 SecretKey secretKeyAES = new SecretKeySpec(key, "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, secretKeyAES, ivSpec); byte[] decoded = Base64.getDecoder().decode(cipherText); byte[] original = cipher.doFinal(decoded); // 替换为UTF-16LE编码解析明文,和C#的Encoding.Unicode逻辑对齐 return new String(original, "UTF-16LE"); }
补充注意点
- 如果你使用的是Java 8及以下版本,需要确认JDK已经安装了JCE无限制权限策略文件,否则AES-256会抛出权限相关异常;Java 9及以上版本默认开启无限制权限,不需要额外配置。
- 如果C#运行环境是.NET Core/.NET 5+,需要确认C#侧Rfc2898DeriveBytes是否显式指定了迭代次数和哈希算法,旧版.NET Framework默认是1000次HMACSHA1,新版.NET默认迭代次数更高,如果C#侧有自定义配置,Java侧要对应修改参数。
内容的提问来源于stack exchange,提问作者Black
相关产品推荐
相关产品推荐

