Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I store and read PGP public keys as strings using Bouncycastle Java?

I have been trying to create, encode, store, retrieve, and decode a Bouncy Castle PGP public key. I get what appears to be the wrong output and an EOFException when I try to read the key back in. The key will be stored in a database as a string.

The original RSA encryption public key is extracted from the key ring as follows:

@SuppressWarnings("unchecked")
public PGPPublicKey getPublicKey() {
    PGPPublicKey pk = null;
    Iterator<PGPPublicKey> it = publicKeyRing.getPublicKeys();
    while (pk == null && it.hasNext()) {
        PGPPublicKey key = it.next();
        if (key.isEncryptionKey()) {
            pk = key;
        }
    }
    return pk;
}

It is encoded, ASCII armored, and stored as a string as follows:

    PGPPublicKey contactPK = realContact.getPublicKey();
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    ArmoredOutputStream armored = new ArmoredOutputStream(out);
    contactPK.encode(armored);
    armored.close();
    publicKey = new String(out.toByteArray(), Charset.forName("US-ASCII"));

This gets me a PGP message block where I would expect a PGP public key block:

-----BEGIN PGP MESSAGE-----\nVersion: BCPG v1.50\n\nuQINBFO8StkCEACQ4vrDnBTDjEvQkGwrAHuJSBZL8tNLxhZ9B74afhObhLVzW6ZB\nT3pk/5XcSPOTvcWd9k1yOKJUabCuF5ixFmMz+niFqUVQTtnl7aqOZ+GrDEzmoYmG\nNQROP0EiA1TWtm2+Ja0FqiJauXytt1sIF/Pr5L47FCjtmZKVoXTP8RVFfGLPB0kT\ndjOz53PaEE3GSValh85w24XIH2/gczURUnjphCX1bRwTFr14SfA9X/rFWqv9SqWQ\nV8OiIWrSiwNd5RLJ9q0B+viDzoxrjmnMJZikxhKiuNVKJCu2ccBdMrbW42iBM2w3\n

... (for brevity)

\n-----END PGP MESSAGE-----

When I try to read the string back in to recreate the public key, I get an EOFException:

// Import the public key.
ByteArrayInputStream in =
        new ByteArrayInputStream(stored.publicKey.getBytes(
                                                    Charset.forName("US-ASCII")));
// Needed to read ASCII armored keys
InputStream decoded = PGPUtil.getDecoderStream(in);
BCPGInputStream bcpgIn = new BCPGInputStream(decoded);
RSAPublicBCPGKey bcpgKey = new RSAPublicBCPGKey(bcpgIn);
PublicKeyPacket pkPacket = new PublicKeyPacket(PublicKeyAlgorithmTags.RSA_ENCRYPT,
                                                new Date(), bcpgKey);
publicKey = new PGPPublicKey(pkPacket, new BcKeyFingerprintCalculator());

The exception occurs when I create the RSAPublicBCPGKey.

I am doing something very wrong, but I can't figure out what it is. Can anyone help?

like image 246
SteveB Avatar asked Jul 09 '14 15:07

SteveB


2 Answers

Say you already have your pgp public key (ascii armored) in a String str:

    InputStream in=new ByteArrayInputStream(str.getBytes());
    in = org.bouncycastle.openpgp.PGPUtil.getDecoderStream(in);

    JcaPGPPublicKeyRingCollection pgpPub = new JcaPGPPublicKeyRingCollection(in);
    in.close();

    PGPPublicKey key = null;
    Iterator<PGPPublicKeyRing> rIt = pgpPub.getKeyRings();
    while (key == null && rIt.hasNext())
    {
        PGPPublicKeyRing kRing = rIt.next();
        Iterator<PGPPublicKey> kIt = kRing.getPublicKeys();
        while (key == null && kIt.hasNext())
        {
            PGPPublicKey k = kIt.next();

            if (k.isEncryptionKey())
            {
                key = k;
            }
        }
    }
    return key;

Now, your variable key will have your PGPPublicKey.

like image 67
ns123 Avatar answered Oct 23 '22 04:10

ns123


I ran into this issue, and it turned out that the Public Key Ring was actually the public key itself. When I was running the iterator I was actually getting subkeys (which turns into that message block instead of the public key block). If I'm not explaining that well, check out this explanation.

Assuming realContact is a public key ring that only contains subkeys, you don't actually need to run it through getPublicKey().

like image 1
Chase Street Dev Avatar answered Oct 23 '22 04:10

Chase Street Dev