使用MSCAPI解密文件时抛出“参数不正确”异常求助
解决MSCAPI解密RSA加密文件时的“参数不正确”异常
问题根源
- 跨Provider兼容差异:加密使用默认SunJCE Provider,解密使用SunMSCAPI Provider,两者对RSA/PKCS1Padding的实现细节存在差异,导致2048位及以上高长度密钥解密时触发参数错误。
- 未处理RSA块大小限制:RSA是块加密算法,不同密钥长度对应最大明文/密文长度有限制(例如2048位RSA+PKCS1Padding的最大明文长度为245字节),原工具类直接对整个文件内容做加解密,小文件在1024位密钥下能正常运行,但高长度密钥下触发MSCAPI的参数校验失败。
修复方案
1. 统一加解密使用SunMSCAPI Provider
修改RSAEncryptUtil的encrypt方法,指定与解密一致的Provider,消除跨实现的兼容问题:
public static byte[] encrypt(byte[] text, PublicKey key) throws Exception { byte[] cipherText = null; // 指定SunMSCAPI Provider,和解密逻辑保持统一 Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "SunMSCAPI"); cipher.init(Cipher.ENCRYPT_MODE, key); cipherText = cipher.doFinal(text); return cipherText; }
2. 实现分段加解密逻辑
针对RSA的块大小限制,修改加解密方法为分段处理,适配不同长度的密钥:
分段加密代码
public static byte[] encrypt(byte[] text, PublicKey key) throws Exception { Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "SunMSCAPI"); cipher.init(Cipher.ENCRYPT_MODE, key); int keyByteLength = key.getEncoded().length; int maxPlaintextBlockSize = keyByteLength - 11; // PKCS1Padding占用11字节 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); int offset = 0; while (offset < text.length) { int blockSize = Math.min(text.length - offset, maxPlaintextBlockSize); byte[] encryptedBlock = cipher.doFinal(text, offset, blockSize); outputStream.write(encryptedBlock); offset += blockSize; } return outputStream.toByteArray(); }
分段解密代码
public static byte[] decrypt(byte[] text, PrivateKey key) throws Exception { Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "SunMSCAPI"); cipher.init(Cipher.DECRYPT_MODE, key); int keyByteLength = key.getEncoded().length; int cipherBlockSize = keyByteLength; // RSA密文块大小等于密钥字节长度 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); int offset = 0; while (offset < text.length) { int blockSize = Math.min(text.length - offset, cipherBlockSize); byte[] decryptedBlock = cipher.doFinal(text, offset, blockSize); outputStream.write(decryptedBlock); offset += blockSize; } return outputStream.toByteArray(); }
3. 确认私钥访问权限
如果Windows密钥容器中的私钥设置了保护密码,需在获取私钥时传入正确密码:
// 替换为实际私钥密码的字符数组 KeyStore.PasswordProtection keyPassword = new KeyStore.PasswordProtection("your-key-password".toCharArray());
验证步骤
- 使用Windows-MY中2048位及以上的RSA密钥重新运行代码,确认解密无异常。
- 测试不同大小的文件,验证分段加解密逻辑的稳定性。
内容的提问来源于stack exchange,提问作者Papp Zoltán
相关产品推荐
相关产品推荐

