neuhalje/bouncy-gpg

KeySelectionStrategy that receive keys

herbertpimentel opened this issue · 5 comments

I cant find a way to define a keystregy any other beyond by email, this is a problem because I don't know name ID of the key sent to me. I only need to use this public key to encrypt to my sender.

In the end would be awesome have an option to KeySelectionStrategy such as:

byte[] myOwnPrivateKey = DB.getMyPrivateKey();
byte[] customerPublicKey = DB.getCustomerPrivateKey();

final OutputStream encryptionStream = BouncyGPG
        .encryptToStream()
        .toRecipient(customerPublicKey)
        .andSignWith(myOwnPrivateKey)
        .armorAsciiOutput()
        .andWriteTo(buffer);

I am sorry, this may is a stupid question but I really don't know how to deal with it.

The easiest way to to that would be to use the InMemoryKeyring and call getPublicKeyRings() / getSecretKeyRings().

Then, to Demeters utmost horror, call .getKeyRings().next().getSecretKey().getUserIDs().next() to get the user Ids of the keys.

If this does not work reliably (e.g. you cannot distinguish your and the customers key) have a look at the source code that parses the keys.

@herbertpimentel , try this. The (ugly..) magic is in firstUidForKeyRings(...). The rest is standard encryption.

  /**
   * Send a message by extracting the userIds from the keys themselves.
   */
  @Test
  public void extractingUserIdFromKeyExample()
      throws IOException, PGPException, NoSuchAlgorithmException, SignatureException, NoSuchProviderException {

    // sender needs his own public and private key, and the recipients public kjey
    final byte[] recipientPubKey = ExampleMessages.PUBKEY_RECIPIENT.getBytes();

    final byte[] senderPublicKey = ExampleMessages.PUBKEY_SENDER.getBytes();
    final byte[] senderPrivateKey = ExampleMessages.SECRET_KEY_SENDER.getBytes();

    final String senderPrivateKeyPassphrase = "sender";

    // Prepare the keyring
    final InMemoryKeyring keyring = KeyringConfigs
        .forGpgExportedKeys(KeyringConfigCallbacks.withPassword(senderPrivateKeyPassphrase));

    keyring.addPublicKey(recipientPubKey);

    keyring.addSecretKey(senderPrivateKey);

    // at this stage the public keyring, and the private keyring contain only ONE key
    final String sendersPrivateKeyUserId = firstUidForKeyRings(keyring.getSecretKeyRings());
    final String recipientsPublicKeyUserId = firstUidForKeyRings(keyring.getPublicKeyRings());

    // Hack: we add the senders public key after extracting the recipients userid
    // Alternatively we could parse the keys "ba hand"
    keyring.addPublicKey(senderPublicKey);

    final ByteArrayOutputStream encryptedData = new ByteArrayOutputStream();

    try (
        final OutputStream encryptionStream = BouncyGPG
            .encryptToStream()
            .withConfig(keyring)
            .withStrongAlgorithms()
            .toRecipient(recipientsPublicKeyUserId)
            .andSignWith(sendersPrivateKeyUserId)
            .armorAsciiOutput()
            .andWriteTo(encryptedData);
        final ByteArrayInputStream plaintext = new ByteArrayInputStream("Hello world".getBytes())
    ) {
      Streams.pipeAll(plaintext, encryptionStream);
    }

    encryptedData.close();
    byte[] chipertext = encryptedData.toByteArray();
  }

  /*
   * return the first userid of the first key in the first keyring.
   */
  private String firstUidForKeyRings(Iterable<? extends PGPKeyRing> keyRings) {
    // Watch Demeters Law scream in agony

    final Iterator<? extends PGPKeyRing> keyRingIterator = keyRings.iterator();
    final PGPKeyRing firstKeyRing = keyRingIterator.next();
    assertFalse("Not stable with more than one keyring",keyRingIterator.hasNext());

    final PGPPublicKey firstKeyInFirstKeyring = firstKeyRing.getPublicKey();

    // any userid of this key will suffice
    return firstKeyInFirstKeyring.getUserIDs().next();
  }

@herbertpimentel : did you get a chance to try the workaround?

@herbertpimentel : did you get a chance to try the workaround?

Sorry, I will try it out. But I have accomplished my task using a product library.

Closing due to no reply