使用BouncyCastle库加密文件时遇DER长度异常求助
RSA加密报错:
java.io.IOException: DER length more than 4 bytes 排查与解决 问题背景
使用BouncyCastle库加密文本文件时抛出上述错误,实现代码及公钥文件内容如下:
实现代码
public class RSAEncryptFile { public static void main(String[] args) { String publicKeyFilename = "/Users/Rajesh/Desktop/pubkey"; String inputFilename = "/Users/Rajesh/Desktop/test"; String encryptedFilename = "/Users/Rajesh/Desktop/javaprogram"; RSAEncryptFile rsaEncryptFile = new RSAEncryptFile(); publicKeyFilename = "/Users/Rajesh/Desktop/pubkey";; inputFilename = "/Users/Rajesh/Desktop/tesco.txt"; encryptedFilename = "/Users/Rajesh/Desktop/javaprogram"; rsaEncryptFile.encrypt(publicKeyFilename, inputFilename, encryptedFilename); } private void encrypt (String publicKeyFilename, String inputFilename, String encryptedFilename){ try { Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); String value = ""; String key = readFileAsString(publicKeyFilename); BASE64Decoder b64 = new BASE64Decoder(); AsymmetricKeyParameter publicKey = (AsymmetricKeyParameter) PublicKeyFactory.createKey(b64.decodeBuffer(key)); AsymmetricBlockCipher e = new RSAEngine(); e = new org.bouncycastle.crypto.encodings.PKCS1Encoding(e); e.init(true, publicKey); String inputdata = readFileAsString(inputFilename); byte[] messageBytes = inputdata.getBytes(); int i = 0; int len = e.getInputBlockSize(); while (i < messageBytes.length) { if (i + len > messageBytes.length) len = messageBytes.length - i; byte[] hexEncodedCipher = e.processBlock(messageBytes, i, len); value = value + getHexString(hexEncodedCipher); i += e.getInputBlockSize(); } System.out.println(value); BufferedWriter out = new BufferedWriter(new FileWriter(encryptedFilename)); out.write(value); out.close(); } catch (Exception e) { System.out.println(e); } } public static String getHexString(byte[] b) throws Exception { String result = ""; for (int i=0; i < b.length; i++) { result += Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 ); } return result; } private static String readFileAsString(String filePath) throws java.io.IOException{ StringBuffer fileData = new StringBuffer(1000); BufferedReader reader = new BufferedReader( new FileReader(filePath)); char[] buf = new char[1024]; int numRead=0; while((numRead=reader.read(buf)) != -1){ String readData = String.valueOf(buf, 0, numRead); fileData.append(readData); buf = new char[1024]; } reader.close(); System.out.println(fileData.toString()); return fileData.toString(); } }
公钥文件内容
pub dsa1024 2019-07-29 [SC] 4EB9C4A3CEF9CCA26C1446G7H1D511656GH98D9E uid [ultimate] TEST <TEST@test.com> sub elg4096 2019-07-29 [E]
问题根源
1. 公钥格式完全不匹配
你使用的是OpenPGP结构化公钥,包含用户ID、子密钥等多段信息,但代码中用PublicKeyFactory.createKey()尝试解析为RSA的DER编码公钥——该方法仅支持纯DER/Base64格式的单密钥数据,直接读取整个PGP公钥文件并Base64解码,必然导致DER格式解析失败。
2. 密钥算法与代码不兼容
公钥明确标注了dsa1024(签名密钥)和elg4096(加密子密钥),但代码中使用的是RSAEngine,DSA/ElGamal与RSA是不同的非对称加密算法,无法混用。
解决方法
方案一:改用BouncyCastle的PGP加密API
直接使用OpenPGP规范处理公钥和加密,步骤如下:
- 导入BouncyCastle的PGP相关依赖包
- 读取并解析PGP公钥环,提取加密子密钥
- 使用PGP加密流程处理文件
示例代码片段(读取PGP公钥):
FileInputStream keyIn = new FileInputStream(publicKeyFilename); PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection( PGPUtil.getDecoderStream(keyIn), new JcaKeyFingerprintCalculator()); keyIn.close(); // 查找可用的加密公钥 PGPPublicKey encKey = null; Iterator<PGPPublicKeyRing> rIt = pgpPub.getKeyRings(); while (rIt.hasNext() && encKey == null) { PGPPublicKeyRing kRing = rIt.next(); Iterator<PGPPublicKey> kIt = kRing.getPublicKeys(); while (kIt.hasNext()) { PGPPublicKey k = kIt.next(); if (k.isEncryptionKey()) { encKey = k; } } }
后续可基于encKey初始化PGP加密器,完成文件的加密(需遵循PGP规范的分块、压缩、封装流程)。
方案二:转换公钥格式
若无需OpenPGP特性,可通过工具从PGP公钥中导出纯ElGamal(或RSA)公钥的DER/Base64格式,再用原代码逻辑解析,但需注意算法匹配(代码中需替换为ElGamalEngine)。
其他代码优化点
- 字符串拼接
value = value + getHexString(...)效率极低,替换为StringBuilder - 弃用sun私有包的
BASE64Decoder,改用BouncyCastle的org.bouncycastle.util.encoders.Base64 - 分段加密时,需每次循环重新获取
len = e.getInputBlockSize(),避免循环中修改len导致后续块大小错误
内容的提问来源于stack exchange,提问作者hitesh
相关产品推荐
相关产品推荐

