Java Bouncycastle PGP解密和验证

Java Bouncycastle PGP解密和验证,java,encryption,bouncycastle,sign,pgp,Java,Encryption,Bouncycastle,Sign,Pgp,我试图使用java BouncyCastle库解密和验证PGP消息,但遇到了问题,抱怨PartialInputStream过早结束 我知道encrypt可以正常工作,因为我可以在命令行上使用gpg对使用encrypt函数创建的消息进行解密和验证 代码如下: public static void signEncryptMessage(InputStream in, OutputStream out, PGPPublicKey publicKey, PGPPrivateKey secretKey,

我试图使用java BouncyCastle库解密和验证PGP消息,但遇到了问题,抱怨PartialInputStream过早结束

我知道encrypt可以正常工作,因为我可以在命令行上使用gpg对使用encrypt函数创建的消息进行解密和验证

代码如下:

public static void signEncryptMessage(InputStream in, OutputStream out, PGPPublicKey publicKey, PGPPrivateKey secretKey, SecureRandom rand) throws Exception {
        out = new ArmoredOutputStream(out);

        PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(new BcPGPDataEncryptorBuilder(PGPEncryptedData.AES_256).setWithIntegrityPacket(true).setSecureRandom(rand));
        encryptedDataGenerator.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(publicKey));

        OutputStream compressedOut = new PGPCompressedDataGenerator(PGPCompressedData.ZIP).open(encryptedDataGenerator.open(out, 4096), new byte[4096]);

        PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(new BcPGPContentSignerBuilder(publicKey.getAlgorithm(), HashAlgorithmTags.SHA512));
        signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, secretKey);
        signatureGenerator.generateOnePassVersion(true).encode(compressedOut);

        OutputStream finalOut = new PGPLiteralDataGenerator().open(compressedOut, PGPLiteralData.BINARY, "", new Date(), new byte[4096]);

        byte[] buf = new byte[4096];
        int len;
        while ((len = in.read(buf)) > 0) {
            finalOut.write(buf, 0, len);
            signatureGenerator.update(buf, 0, len);
        }

        finalOut.close();
        in.close();
        signatureGenerator.generate().encode(compressedOut);
        compressedOut.close();
        encryptedDataGenerator.close();
        out.close();
    }

    public static void decryptVerifyMessage(InputStream in, OutputStream out, PGPPrivateKey secretKey, PGPPublicKey publicKey) throws Exception {
        in = new ArmoredInputStream(in);

        PGPObjectFactory pgpF = new PGPObjectFactory(in);
        PGPEncryptedDataList enc = (PGPEncryptedDataList) pgpF.nextObject();

        PGPObjectFactory plainFact = new PGPObjectFactory(((PGPPublicKeyEncryptedData) enc.getEncryptedDataObjects().next()).getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC").build(secretKey)));

        Object message = null;

        PGPOnePassSignatureList onePassSignatureList = null;
        PGPSignatureList signatureList = null;
        PGPCompressedData compressedData = null;

        message = plainFact.nextObject();
        ByteArrayOutputStream actualOutput = new ByteArrayOutputStream();

        while (message != null) {
            System.out.println(message.toString());
            if (message instanceof PGPCompressedData) {
                compressedData = (PGPCompressedData) message;
                plainFact = new PGPObjectFactory(compressedData.getDataStream());
                message = plainFact.nextObject();
                System.out.println(message.toString());
            }

            if (message instanceof PGPLiteralData) {
                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();
        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);
                System.out.println("verifier : " + 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();
                            System.out.println("Signed by " + userId);
                        }
                        System.out.println("Signature verified");
                    } else {
                        throw new SignatureException("Signature verification failed");
                    }
                }
            }

        }

        out.write(output);
        out.flush();
        out.close();
    }

    public static void main(String args[]) {
        Security.insertProviderAt(new BouncyCastleProvider(), 0);
        byte inBytes[] = "The quick brown fox jumps over the lazy dog.".getBytes();

        try {
            SecureRandom rand = new SecureRandom();

            RSAKeyPairGenerator kpg = new RSAKeyPairGenerator();
            kpg.init(new RSAKeyGenerationParameters(BigInteger.valueOf(0x10001), rand, 1024, 90));

            BcPGPKeyPair sender = new BcPGPKeyPair(PGPPublicKey.RSA_GENERAL, kpg.generateKeyPair(), new Date());
            BcPGPKeyPair recip = new BcPGPKeyPair(PGPPublicKey.RSA_GENERAL, kpg.generateKeyPair(), new Date());

            ByteArrayOutputStream sendMessage = new ByteArrayOutputStream();
            ByteArrayOutputStream recvMessage = new ByteArrayOutputStream();
            signEncryptMessage(new ByteArrayInputStream(inBytes), sendMessage, recip.getPublicKey(), sender.getPrivateKey(), rand);

            System.out.println(sendMessage.toString());

            decryptVerifyMessage(new ByteArrayInputStream(sendMessage.toByteArray()), recvMessage, recip.getPrivateKey(), sender.getPublicKey());

            System.out.println(recvMessage.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
有什么想法吗

旁注,这段解密代码来自于,稍作修改以适应:消息将只来自那个种加密方法,并直接处理密钥,而不是密钥流

干杯


Ramo

我最近尝试做同样的事情,并根据我在Bouncycastle示例中找到的代码和我在web上找到的教程将此方法组合在一起。出于我的目的,我的代码有一个具有公钥/私钥对的单例加密对象。在示例代码中,您可以替换

    INSTANCE._secretKeyRingCollection.getSecretKey(pbe.getKeyID());
用你的秘密钥匙。我已经用一个长期存在的过程测试了这个方法,该过程执行了几十次加密、签名/解密和验证操作,没有得到您看到的异常

public static void decryptAndVerify(InputStream in, OutputStream fOut, InputStream publicKeyIn) throws IOException, 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<PGPPublicKeyEncryptedData> it = enc.getEncryptedDataObjects();
    PGPPrivateKey sKey = null;
    PGPPublicKeyEncryptedData pbe = null;
    while (sKey == null && it.hasNext()) {
        pbe = it.next();
        PBESecretKeyDecryptor decryptor = new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(INSTANCE._secretKeyPass.toCharArray());
        PGPSecretKey psKey = INSTANCE._secretKeyRingCollection.getSecretKey(pbe.getKeyID());
        if (psKey != null) {
            sKey = psKey.extractPrivateKey(decryptor);
        }
    }
    if (sKey == null) {
        throw new IllegalArgumentException("Unable to find secret key to decrypt the message");
    }

    InputStream clear = pbe.getDataStream(new BcPublicKeyDataDecryptorFactory(sKey));

    PGPObjectFactory plainFact = new PGPObjectFactory(clear);

    Object message;

    PGPOnePassSignatureList onePassSignatureList = null;
    PGPSignatureList signatureList = null;
    PGPCompressedData compressedData;

    message = plainFact.nextObject();
    ByteArrayOutputStream actualOutput = new ByteArrayOutputStream();

    while (message != null) {
        __l.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);
            __l.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();
                        __l.trace(String.format("Signed by {%s}", userId));
                    }
                    __l.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();
    }
}
public static void decryptAndVerify(InputStream-in、OutputStream-fOut、InputStream-publicKeyIn)抛出IOException、SignatureException、PGPEException{
in=PGPUtil.getDecoderStream(in);
PGPObjectFactory pgpF=新的PGPObjectFactory(in);
PGPencryptedatalist enc;
对象o=pgpF.nextObject();
//
//第一个对象可能是PGP标记包。
//
if(o PGPEncryptedDataList的实例){
enc=(pGpencryptedatalist)o;
}否则{
enc=(pgpencryptedatalist)pgpF.nextObject();
}
//
//找到密匙
//
迭代器it=enc.getEncryptedDataObjects();
PGPPrivateKey sKey=null;
PGPPublicKeyEncryptedData pbe=null;
while(sKey==null&&it.hasNext()){
pbe=it.next();
PBESecretKeyDecryptor decryptor=新的BcPBESecretKeyDecryptorBuilder(新的BcPGPDigestCalculatorProvider()).build(实例._secretKeyPass.toCharray());
PGPSecretKey psKey=INSTANCE._secretKeyRingCollection.getSecretKey(pbe.getKeyID());
if(psKey!=null){
sKey=psKey.extractPrivateKey(解密程序);
}
}
if(sKey==null){
抛出新的IllegalArgumentException(“无法找到解密消息的密钥”);
}
InputStream clear=pbe.getDataStream(新的BcPublicKeyDataDecryptorFactory(sKey));
PGPObjectFactory plainFact=新的PGPObjectFactory(清除);
对象消息;
PGPOnePassSignatureList onePassSignatureList=null;
PGPSignatureList signatureList=null;
PGP压缩数据压缩数据压缩数据;
message=plainFact.nextObject();
ByteArrayOutputStream actualOutput=新建ByteArrayOutputStream();
while(消息!=null){
__l、 跟踪(message.toString());
if(PGPCompressedData的消息实例){
压缩数据=(PGPCompressedData)消息;
plainFact=新的PGPObjectFactory(compressedData.getDataStream());
message=plainFact.nextObject();
}
if(PGPLiteralData的消息实例){
//我得把它读一读,放在某个地方。
Streams.pipeAll(((PGPLiteralData)message.getInputStream(),actualOutput);
}else if(PGPOnePassSignatureList的消息实例){
onePassSignatureList=(PGPOnePassSignatureList)消息;
}else if(PGPSignatureList的消息实例){
signatureList=(PGPSignatureList)消息;
}否则{
抛出新的PGPException(“消息未知消息类型”);
}
message=plainFact.nextObject();
}
actualOutput.close();
PGPPublicKey publicKey=null;
字节[]输出=actualOutput.toByteArray();
如果(onePassSignatureList==null | | signatureList==null){
抛出新的PGP异常(“找不到可怜的PGP.签名”);
}否则{
对于(int i=0;i
您正在呼叫:

encryptedDataGenerator.open(out, 4096)
你的意思可能是:

encryptedDataGenerator.open(out, new byte[4096])
第一个版本给出了要打开的大小(这是错误的),第二个版本给出了字节缓冲区


(我知道这很古老,但来到这里是因为我在一些示例代码中遇到了同样的问题,其他人也可能遇到同样的问题)

让Bouncy Castle玩起来并不总是那么容易。Stackoverflow的代码狙击手使其工作正常,但它们大多是没有用户真正理解的神秘代码

问题是:在生产系统中,复制粘贴代码片段很快就会被复制
encryptedDataGenerator.open(out, new byte[4096])
final InputStream plaintextStream = BouncyGPG
               .decryptAndVerifyStream()
               .withConfig(keyringConfig)
               .andRequireSignatureFromAllKeys("sender@example.com")
               .fromEncryptedInputStream(cipherTextStream)
// in build.gradle add a dependency to bouncy castle and bouncy-gpg
//  ...
dependencies {
    compile 'org.bouncycastle:bcprov-jdk15on:1.56'
    compile 'org.bouncycastle:bcpg-jdk15on:1.56'
    //  ...
    compile 'name.neuhalfen.projects.crypto.bouncycastle.openpgp:bouncy-gpg:2.+'