Вопрос

I'm trying to use the non-deprecated constructors in bouncycastle version 1.49 but I'm having a hard time figuring out how to use the objects that these create, as it's a bit different from any of the tutorials I've found out on the web.

This is my code so far; can anyone tell me what I'm supposed to do with the PGPContentSigner and how I'm supposed to hook it up to the OutputStream? What I want to achieve is an attached signature on the data without having to encrypt the data to anyone in particular (much like gpg --clearsign -a <textfile>).

I have looked into ArmoredOutputStream and its method, beginClearText(int) looks promising, but just calling that, dumping the data into the output stream, calling endClearText, and then writing the signature bytes to the ArmoredOutputStream doesn't work. It looks as though there needs to be low-level manipulation of the stream, poking control bytes into the stream to signal the beginning of the signature, etc. It seems to me there ought to be some kind of fixture for hooking the signer and the armored output stream together that would take care of that packet juggling.

/**
 * Generate a signature for the given bytes so that they can be sent off and the recipient can verify
 * that the bytes have not been tampered with in transit.
 *
 * @param dataBytes the data to sign
 * @return the data along with the signature
 * @throws PGPException if there's a problem generating the signature
 */
public static byte[] clearSignBytes(byte[] dataBytes, PGPSecretKeyRingCollection skrCollection, String keyPass) throws PGPException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); // this is where we put the signed data

    try {
        // get our secret key so we can init the signature generator
        Iterator<PGPSecretKeyRing> it = skrCollection.getKeyRings();
        PGPSecretKeyRing skr = it.next();
        PGPSecretKey skey = skr.getSecretKey();
        PGPPrivateKey prKey = skey.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(keyPass.toCharArray()));
        BcPGPContentSignerBuilder signerBuilder = new BcPGPContentSignerBuilder(skey.getPublicKey().getAlgorithm(), PGPUtil.SHA256);
        PGPContentSigner signer = signerBuilder.build(PGPSignature.BINARY_DOCUMENT, prKey);

        // Now, we're supposed to write dataBytes somewhere and we're supposed to hand them to the signer somehow
        // and ultimately we're supposed to tell the signer to output a signature and we put the signature and
        // dataBytes together into baos.
        // TODO ??????
    } catch (Exception e) {
        __l.error("Exception generating signature", e);
        throw new PGPException("Exception while signing the data", e);
    }
    return baos.toByteArray();
}
Это было полезно?

Решение

Turns out I was not using the right classes to get the job done. Here is the relevant section of the method with code that actually works. I hope that this helps others who have the same confusion. After we've gotten the PGPPrivateKey prKey...

        PGPSignatureGenerator sGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(skey.getPublicKey().getAlgorithm(), PGPUtil.SHA256).setProvider("BC"));
        PGPSignatureSubpacketGenerator  spGen = new PGPSignatureSubpacketGenerator();

        sGen.init(PGPSignature.CANONICAL_TEXT_DOCUMENT, prKey);
        Iterator userIDs = skey.getPublicKey().getUserIDs();
        if (it.hasNext()) {
            spGen.setSignerUserID(false, (String)userIDs.next());
            sGen.setHashedSubpackets(spGen.generate());
        }

        ArmoredOutputStream aos = new ArmoredOutputStream(baos);
        aos.beginClearText(PGPUtil.SHA256);

        sGen.update(dataBytes);
        aos.write(dataBytes);

        aos.endClearText();

        BCPGOutputStream bOut = new BCPGOutputStream(aos);
        sGen.generate().encode(bOut);

        aos.flush();
        aos.close();
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top