Java中RSA结合对称密钥加解密文件时InvalidKeyException问题求助
解决RSA解密对称密钥时的
InvalidKeySpecException异常 问题根源分析
你的代码抛出invalid key format异常,核心原因和几个关键错误如下:
- 私钥加载逻辑错误:在
decryptSymmetricKey方法中,你读取的是publicKey.key文件,却用PKCS8EncodedKeySpec(私钥格式)来生成私钥。X509是公钥的标准格式,PKCS8是私钥的标准格式,两者不能混用。 - 解密方法逻辑冗余:
decryptSymmetricKey里调用encryptSymmetricKey(secKey)完全没必要,解密的前提是已有加密后的对称密钥,应该直接传入加密后的密钥字节数组,而非重新加密。 - IV未持久化:AES/CBC模式依赖IV(初始化向量),你当前仅在内存生成IV,未保存到文件,实际场景中重启程序后无法正确解密。
- 文件覆盖风险:main方法中直接将解密结果写回原输入文件,会覆盖原始数据,测试时需使用独立的输出文件。
修正后的代码
1. 修复私钥加载与解密方法
public static SecretKey decryptSymmetricKey(byte[] encryptedKey) throws NoSuchAlgorithmException, IOException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { // 读取私钥文件(注意是privateKey.key,不是公钥文件) byte[] privateKeyBytes = Files.readAllBytes(Paths.get("privateKey.key")); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes); PrivateKey privateKey = keyFactory.generatePrivate(keySpec); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] decryptedKey = cipher.doFinal(encryptedKey); return new SecretKeySpec(decryptedKey, 0, decryptedKey.length, "AES"); }
2. 添加IV的保存与加载方法
public static void saveIv(IvParameterSpec iv, File ivFile) throws IOException { Files.write(ivFile.toPath(), iv.getIV()); } public static IvParameterSpec loadIv(File ivFile) throws IOException { byte[] ivBytes = Files.readAllBytes(ivFile.toPath()); return new IvParameterSpec(ivBytes); }
3. 修正main方法的流程逻辑
public static void main(String[] args) throws Exception { SecretKey secKey = generateKey(128); IvParameterSpec iv = generateIv(); // 定义文件路径,避免覆盖原文件 File inputFile = new File("C:/Users/nm-ca/IdeaProjects/RSA/src/inputFile.txt"); File encryptedFile = new File("C:/Users/nm-ca/IdeaProjects/RSA/src/encryptedFile.txt"); File decryptedFile = new File("C:/Users/nm-ca/IdeaProjects/RSA/src/decryptedFile.txt"); File ivFile = new File("C:/Users/nm-ca/IdeaProjects/RSA/src/iv.dat"); File encryptedSymKeyFile = new File("C:/Users/nm-ca/IdeaProjects/RSA/src/encryptedSymKey.dat"); // 加密流程 encryptFile("AES/CBC/PKCS5Padding", secKey, iv, inputFile, encryptedFile); saveIv(iv, ivFile); byte[] encryptedSymKey = encryptSymmetricKey(secKey); Files.write(encryptedSymKeyFile.toPath(), encryptedSymKey); // 解密流程 byte[] loadedEncryptedSymKey = Files.readAllBytes(encryptedSymKeyFile.toPath()); SecretKey decryptedSecKey = decryptSymmetricKey(loadedEncryptedSymKey); IvParameterSpec loadedIv = loadIv(ivFile); decryptFile("AES/CBC/PKCS5Padding", decryptedSecKey, loadedIv, encryptedFile, decryptedFile); }
4. RSA密钥生成工具(需提前执行生成公/私钥文件)
public static void generateRSAKeys() throws NoSuchAlgorithmException, IOException { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(2048); // 推荐使用2048位及以上长度 KeyPair keyPair = keyPairGenerator.generateKeyPair(); // 保存公钥(X509格式) Files.write(Paths.get("publicKey.key"), keyPair.getPublic().getEncoded()); // 保存私钥(PKCS8格式) Files.write(Paths.get("privateKey.key"), keyPair.getPrivate().getEncoded()); }
关键注意事项
- 公钥和私钥必须配对生成:公钥用于加密对称密钥,私钥用于解密对称密钥,不能交叉使用。
- AES/CBC模式必须保存IV:解密时必须使用与加密时完全相同的IV,否则无法正确解密。
- 避免文件覆盖:测试阶段使用独立的加密/解密文件,防止原始数据丢失。
内容的提问来源于stack exchange,提问作者darkman106
相关产品推荐
相关产品推荐

