Pergunta

I'm trying to create a signed and encrypted message using the BouncyCastle libraries, which I'm then testing out against gpg on the command line to confirm whether it's valid. However while it presents a PGP message that looks okay to the eye, gpg is having trouble decrypting it.

Java code:

public class main {

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

        BcPGPDataEncryptorBuilder dataEncryptor = new BcPGPDataEncryptorBuilder(PGPEncryptedData.CAST5);
        dataEncryptor.setWithIntegrityPacket(true);
        dataEncryptor.setSecureRandom(new SecureRandom());

        PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(dataEncryptor);
        encryptedDataGenerator.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(publicKey));

        OutputStream encryptedOut = encryptedDataGenerator.open(out, 4096);

        PGPCompressedDataGenerator compressedDataGenerator = new PGPCompressedDataGenerator(PGPCompressedData.UNCOMPRESSED);
        OutputStream compressedOut = compressedDataGenerator.open(encryptedOut, new byte[4096]);

        PGPContentSignerBuilder signerBuilder = new BcPGPContentSignerBuilder(publicKey.getAlgorithm(), HashAlgorithmTags.SHA1);

        PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(signerBuilder);
        signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, secretKey);

        boolean firstTime = true;
        Iterator<String> it = publicKey.getUserIDs();
        while (it.hasNext() && firstTime) {
            PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
            spGen.setSignerUserID(false, it.next());
            signatureGenerator.setHashedSubpackets(spGen.generate());
            firstTime = false;
        }
        signatureGenerator.generateOnePassVersion(false).encode(compressedOut);

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

        in.close();
        signatureGenerator.generate().encode(compressedOut);
        compressedDataGenerator.close();
        encryptedDataGenerator.close();
        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 {
            RSAKeyPairGenerator kpg = new RSAKeyPairGenerator();
            kpg.init(new RSAKeyGenerationParameters(BigInteger.valueOf(0x10001), new SecureRandom(), 1024, 90));
            BcPGPKeyPair kp = new BcPGPKeyPair(PGPPublicKey.RSA_GENERAL, kpg.generateKeyPair(), new Date());

            ByteArrayInputStream bais = new ByteArrayInputStream(inBytes);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            ArmoredInputStream ais = new ArmoredInputStream(new ByteArrayInputStream(PGPPublicKeyString.getBytes()));

            PGPPublicKeyRing pub = (PGPPublicKeyRing) new PGPObjectFactory(ais).nextObject();

            signEncryptMessage(bais, baos, pub.getPublicKey(), kp.getPrivateKey());

            System.out.println(new String(baos.toByteArray()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static final String PGPPublicKeyString = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n"
            + "Version: GnuPG v2.0.19 (GNU/Linux)\n"
            + "\n"
            + "mQENBFJLq9IBCADvxNEfagIpxX+8bgXqKKxhjvT0c5WbgkJFyIP8LzkAwTrtQWiT\n"
            + "+5kpIi3xxf94zz4EyuDF5bsEwIJRNvamqcSARxvlEh4U2mTxafl8D7bPhyi476fZ\n"
            + "iFQTwOrK6lAtEboSE+lRMUoB04Lmh0IluhWmKumA6vOI7Mlg0JMbdS9G27kSrhBq\n"
            + "/TfHzQmjbt5WsunKagetzAFM+PXsceD1Yg69GPkRluuXs5LsmSdMpMT7wcK+sZgI\n"
            + "v9+3DbXRxdTQLUWL0g1yE58vMTlbiQ7z5i1jMVMq1YSYmThEW+cnoRmUUsle99ly\n"
            + "IX6IE0gvMySYxIaXTx9LRE538bD2E4UN9bIrABEBAAG0GXJlYWwgbmFtZSA8ZW1h\n"
            + "aWxAYWRkcmVzcz6JATkEEwECACMFAlJLq9ICGwMHCwkIBwMCAQYVCAIJCgsEFgID\n"
            + "AQIeAQIXgAAKCRD/zlUK7kqMk8XGCADMxe3WAUdd+qg4gAL5s+F/ziPozV8cVNP+\n"
            + "ThCHMvNkhoCYswzc30YcGAAsttvgYq7RlyG5yFdXFbo8wMEdDS6rQ72Ya7atNqKN\n"
            + "CB8VV3e87iN+Nv66HyZ59++d0GNO+yFvebmJoyhI2qZ05ng0m9ApZMpCUflhreXE\n"
            + "8+bGCg4fDECmOPnzbx2W68nFFXJEP8M7Bk8bD62Jtxto/hjg12Sv3HCbQMahR3mH\n"
            + "eTIHQUbySAQYBrEyshiv1Rcq+VDAJjO6EtkhxSo0w6T/FI475EdVg45G49wZ/FuX\n"
            + "FmuRqzLT5HGICaICQVxvvcrQ0c5WNwN0lnomoGOxxU73z810L74VuQENBFJLq9IB\n"
            + "CADevC5hdZ6IC8Cq773YsEME6QzIvHwsMVFb3IuUd7h/ZgglGwer6RwPl6lzF7w3\n"
            + "hiFVNysrQ542yEmB3gYk1ha/IVl/+OQg9DiNwN2e2Z3sp7vqapi42Qnbbt4HyQUY\n"
            + "di7l8uQzhEbtuvbKX2w1/P2EF/jLXOu9lSz4ZltElt39IgWejYkpLwVO3b3qpt7e\n"
            + "fuC9nvy12rW7iSUg+czqB16OdO7qKT1xvrAuxTT0LsJpHO1xQt91II8vNOxLSOft\n"
            + "RnX8097Zl0B7UWNTsPeecYbenmcLRTWNbzZaPMbMqEgUYqQEXJerBUIIom+lhPhm\n"
            + "EUtcPdioBXZs0OrbDp1vvVIbABEBAAGJAR8EGAECAAkFAlJLq9ICGwwACgkQ/85V\n"
            + "Cu5KjJM5iAf+OAkj/H6+SuRif356KlZFWjSzOdVtQvV96DbRWq3M18owK8Vq+7ee\n"
            + "wfGFNlBBnnqH4rYyqQUvac+358A0M+1lKdZXHZTLmpi48NeXUGe3AffTaFq7uOJr\n"
            + "P/IvV+06hRBMlAzuwMswG6hFQ9hjIGhas8lImJZZiuFaIauhCOHKe7/Ai6qLw4F6\n"
            + "7+i6QzExeeVmyoEBGqGA1KKmNJgZSq53X3T6yOQmXmAADj7wh1YdWh1r2dHXPc14\n"
            + "L1zehpW1497Dj5Fi4FCNxaKp9NEnIM9Cvv+2XN8gP//R7q0Tia2J6uxDRmMbtFK2\n"
            + "xG2RMc1kGXlWvre1qNASvr2ru7lQoQU8Iw==\n"
            + "=IsmN\n"
            + "-----END PGP PUBLIC KEY BLOCK-----\n";
}

And the gpg command line output:

$ gpg -vvv -d test2
gpg: using character set `utf-8'
gpg: armor: BEGIN PGP MESSAGE
Version: BCPG v1.49
:pubkey enc packet: version 3, algo 1, keyid FFCE550AEE4A8C93
    data: [2048 bits]
gpg: armor header: 
gpg: public key is EE4A8C93

You need a passphrase to unlock the secret key for
user: "real name <email@address>"
2048-bit RSA key, ID EE4A8C93, created 2013-10-02

gpg: public key encrypted data: good DEK
:encrypted data packet:
    length: 4129
    mdc_method: 2
gpg: encrypted with 2048-bit RSA key, ID EE4A8C93, created 2013-10-02
      "real name <email@address>"
gpg: CAST5 encrypted data
:trust packet: flag=e8 sigcache=00
gpg: ring trust w/o key
gpg: mdc_packet with invalid encoding
gpg: decryption failed: Invalid packet

Any help would be appreciated.

Cheers

Ramo

Foi útil?

Solução

Duncan Jones put me on the right track in the comments. Here's the resulting function for anyone else who might need it.

public void signEncryptMessage(InputStream in, OutputStream out, String name) throws IOException, PGPException, SignatureException {
        out = new ArmoredOutputStream(out);

        PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(new JcePGPDataEncryptorBuilder(SYMM_ALG).setWithIntegrityPacket(true).setSecureRandom(rand).setProvider(PROVIDER));
        encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(keys.get(name)).setProvider(PROVIDER));

        OutputStream encryptedOut = encGen.open(out, new byte[BUFFER_SIZE]);
        OutputStream compressedData = new PGPCompressedDataGenerator(COMP_ALG).open(encryptedOut);

        PGPSignatureGenerator sGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(kp.getPrivateKey().getPublicKeyPacket().getAlgorithm(), HASH_ALG).setProvider(PROVIDER));
        sGen.init(PGPSignature.BINARY_DOCUMENT, kp.getPrivateKey());
        sGen.generateOnePassVersion(false).encode(compressedData);

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

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

        in.close();

        finalOut.close();
        sGen.generate().encode(compressedData);
        compressedData.close();
        encryptedOut.close();
        out.close();
    }

Now onto decryption!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top