如何解密签名的pgp加密文件?

如何使用BouncyCastle Java API解密和validation使用PGP加密的文件?

加密代码:

 private static void encryptFile(OutputStream out, String fileName, PGPPublicKey encKey, PGPSecretKey pgpSec, boolean armor, boolean withIntegrityCheck, char[] pass) throws IOException, NoSuchProviderException { if (armor) { out = new ArmoredOutputStream(out); } try { PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator( new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setWithIntegrityPacket(withIntegrityCheck).setSecureRandom( new SecureRandom()) .setProvider("BC")); encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encKey).setProvider("BC")); OutputStream encryptedOut = encGen.open(out, new byte[BUFFER_SIZE]); PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(PGPCompressedData.ZIP); OutputStream compressedData = comData.open(encryptedOut); //OutputStream compressedData = encryptedOut; PGPPrivateKey pgpPrivKey = pgpSec.extractPrivateKey( new JcePBESecretKeyDecryptorBuilder().setProvider("BC").build(pass)); PGPSignatureGenerator sGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder( pgpSec.getPublicKey().getAlgorithm(), PGPUtil.SHA1).setProvider("BC")); sGen.init(PGPSignature.BINARY_DOCUMENT, pgpPrivKey); Iterator it = pgpSec.getPublicKey().getUserIDs(); if (it.hasNext()) { PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); spGen.setSignerUserID(false, (String) it.next()); sGen.setHashedSubpackets(spGen.generate()); } //BCPGOutputStream bOut = new BCPGOutputStream(compressedData); sGen.generateOnePassVersion(false).encode(compressedData); // bOut File file = new File(fileName); PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator(); OutputStream lOut = lGen.open(compressedData, PGPLiteralData.BINARY, file.getName(), new Date(), new byte[BUFFER_SIZE]); //bOut FileInputStream fIn = new FileInputStream(file); int ch; while ((ch = fIn.read()) >= 0) { lOut.write(ch); sGen.update((byte) ch); } fIn.close(); lOut.close(); lGen.close(); sGen.generate().encode(compressedData); //bOut.close(); comData.close(); compressedData.close(); encryptedOut.close(); encGen.close(); if (armor) { out.close(); } } catch (PGPException e) { System.err.println(e); if (e.getUnderlyingException() != null) { e.getUnderlyingException().printStackTrace(); } } catch (SignatureException e) { System.err.println(e); } } 

解密代码:

 public static void decryptFile(InputStream in, InputStream keyIn, char[] passwd, OutputStream fOut, InputStream publicKeyIn) throws IOException, NoSuchProviderException, SignatureException, PGPException { in = PGPUtil.getDecoderStream(in); PGPObjectFactory pgpF = new PGPObjectFactory(in); PGPEncryptedDataList enc; Object o = pgpF.nextObject(); // // the first object might be a PGP marker packet. // if (o instanceof PGPEncryptedDataList) { enc = (PGPEncryptedDataList) o; } else { enc = (PGPEncryptedDataList) pgpF.nextObject(); } // // find the secret key // Iterator it = enc.getEncryptedDataObjects(); PGPPrivateKey sKey = null; PGPPublicKeyEncryptedData pbe = null; PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyIn)); while (sKey == null && it.hasNext()) { pbe = (PGPPublicKeyEncryptedData) it.next(); sKey = PGPTools.findSecretKey(pgpSec, pbe.getKeyID(), passwd); } if (sKey == null) { throw new IllegalArgumentException("secret key for message not found."); } InputStream clear = pbe.getDataStream( new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC").build(sKey)); PGPObjectFactory plainFact = new PGPObjectFactory(clear); Object message = null; PGPOnePassSignatureList onePassSignatureList = null; PGPSignatureList signatureList = null; PGPCompressedData compressedData = null; message = plainFact.nextObject(); ByteArrayOutputStream actualOutput = new ByteArrayOutputStream(); while (message != null) { log.trace(message.toString()); if (message instanceof PGPCompressedData) { compressedData = (PGPCompressedData) message; plainFact = new PGPObjectFactory(compressedData.getDataStream()); message = plainFact.nextObject(); } if (message instanceof PGPLiteralData) { // have to read it and keep it somewhere. Streams.pipeAll(((PGPLiteralData) message).getInputStream(), actualOutput); } else if (message instanceof PGPOnePassSignatureList) { onePassSignatureList = (PGPOnePassSignatureList) message; } else if (message instanceof PGPSignatureList) { signatureList = (PGPSignatureList) message; } else { throw new PGPException("message unknown message type."); } message = plainFact.nextObject(); } actualOutput.close(); PGPPublicKey publicKey = null; byte[] output = actualOutput.toByteArray(); if (onePassSignatureList == null || signatureList == null) { throw new PGPException("Poor PGP. Signatures not found."); } else { for (int i = 0; i < onePassSignatureList.size(); i++) { PGPOnePassSignature ops = onePassSignatureList.get(0); log.trace("verifier : " + ops.getKeyID()); PGPPublicKeyRingCollection pgpRing = new PGPPublicKeyRingCollection( PGPUtil.getDecoderStream(publicKeyIn)); publicKey = pgpRing.getPublicKey(ops.getKeyID()); if (publicKey != null) { ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider("BC"), publicKey); ops.update(output); PGPSignature signature = signatureList.get(i); if (ops.verify(signature)) { Iterator userIds = publicKey.getUserIDs(); while (userIds.hasNext()) { String userId = (String) userIds.next(); log.trace("Signed by {}", userId); } log.trace("Signature verified"); } else { throw new SignatureException("Signature verification failed"); } } } } if (pbe.isIntegrityProtected() && !pbe.verify()) { throw new PGPException("Data is integrity protected but integrity is lost."); } else if (publicKey == null) { throw new SignatureException("Signature not found"); } else { fOut.write(output); fOut.flush(); fOut.close(); } } 

作为参考,这是PGPTools.findSecretKey所做的:

 public static PGPPrivateKey findSecretKey(InputStream keyIn, long keyID, char[] pass) throws IOException, PGPException { PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyIn)); PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID); if (pgpSecKey == null) return null; PBESecretKeyDecryptor decryptor = new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(pass); return pgpSecKey.extractPrivateKey(decryptor); } 

通过查看BouncyCastle示例,我遇到了同样的问题。

我的目标是在服务中制作两种方法:

  • decryptAndVerify(InputStream,PGPPublicKey,PGPPrivateKey,Passphrase)
  • signAndEncrypt(InputStream,OutputStream,PGPPrivateKey,PGPPublicKey,Passphrase)

对于第一种方法:

我将此示例中的verifyFile与此处的decryptFile混合在一起

对于第二种方法,我从这篇博客中作了例子。