All Downloads are FREE. Search and download functionalities are using the official Maven repository.

me.sniggle.pgp.crypt.internal.BasePGPCommon Maven / Gradle / Ivy

The newest version!
package me.sniggle.pgp.crypt.internal;

import org.bouncycastle.bcpg.ArmoredInputStream;
import org.bouncycastle.openpgp.*;
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder;
import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.security.SecureRandom;
import java.util.Iterator;

/**
 * Helper class centralizing access to commonly used PGP function by (all) PGP classes
 *
 * @author iulius
 */
public abstract class BasePGPCommon {

  private static final Logger LOGGER = LoggerFactory.getLogger(BasePGPCommon.class);

  /**
   * A functional interface to find the correct PGP key
   *
   * @param  should be PGPPublicKey or PGPSecretKey
   */
  protected interface KeyFilter {

    /**
     *
     * @param pgpKey
     *    the PGP key to check
     * @return true if the PGP key matches the selection criteria
     */
    boolean accept(T pgpKey);

  }

  private boolean unlimitedEncryptionStrength = false;
  private int compressionAlgorithm = AlgorithmSelection.getDefaultCompressionAlgorithm();

  protected BasePGPCommon() {
  }

  /**
   * accessor to the compression algorithm
   *
   * @return the compression algorithm to use
   */
  protected int getCompressionAlgorithm() {
    return compressionAlgorithm;
  }

  /**
   * set the compression algorithm
   *
   * @param compressionAlgorithm
   *    the compression algorithm constant
   */
  public void setCompressionAlgorithm(int compressionAlgorithm) {
    this.compressionAlgorithm = compressionAlgorithm;
  }

  /**
   *  retrieve the appropriate secret key from the secret key ring collection
   *  based on the key filter
   *
   * @param secretKeyRingCollection
   *    the PGP secret key ring collection
   * @param keyFilter
   *    the key filter to apply
   * @return the secret key or null if none matches the filter
   * @throws PGPException
   */
  protected PGPSecretKey retrieveSecretKey(PGPSecretKeyRingCollection secretKeyRingCollection, KeyFilter keyFilter) throws PGPException {
    LOGGER.trace("retrieveSecretKey(PGPSecretKeyRingCollection, KeyFilter)");
    LOGGER.trace("Secret KeyRing Collection: {}, Key Filter: {}", secretKeyRingCollection == null ? "not set" : "set", keyFilter == null ? "not set" : "set");
    PGPSecretKey result = null;
    Iterator secretKeyRingIterator = secretKeyRingCollection.getKeyRings();
    PGPSecretKeyRing secretKeyRing = null;
    LOGGER.debug("Iterating secret key ring");
    while( result == null && secretKeyRingIterator.hasNext() ) {
      secretKeyRing = secretKeyRingIterator.next();
      Iterator secretKeyIterator = secretKeyRing.getSecretKeys();
      LOGGER.debug("Iterating secret keys in key ring");
      while( secretKeyIterator.hasNext() ) {
        PGPSecretKey secretKey = secretKeyIterator.next();
        LOGGER.info("Found secret key: {}", secretKey.getKeyID());
        LOGGER.debug("Checking secret key with filter");
        if (keyFilter.accept(secretKey)) {
          LOGGER.info("Key {} selected from secret key ring");
          result = secretKey;
        }
      }
    }
    return result;
  }

  /**
   * helper method to read the secret key
   *
   * @param secretKey
   *    the secret key stream
   * @param userId
   *    the user id
   * @return the applicable secret key or null if none is part of the stream for the user id
   * @throws IOException
   * @throws PGPException
   */
  protected PGPSecretKey findSecretKey(InputStream secretKey, final String userId) throws IOException, PGPException {
    LOGGER.trace("findSecretKey(InputStream, String)");
    LOGGER.trace("Secret Key: {}, User ID: {}", secretKey == null ? "not set" : "set", userId);
    return findSecretKey(secretKey, new KeyFilter() {

      @Override
      public boolean accept(PGPSecretKey secretKey) {
        boolean result = false;
        Iterator userIdIterator = secretKey.getUserIDs();
        while( userIdIterator.hasNext() && !result) {
          result |= userId.equals(userIdIterator.next());
        }
        return result;
      }

    });
  }

  /**
   * helper method to read a specific secret key
   *
   * @param secretKey
   *    the secret key stream
   * @param keyId
   *    the key id
   * @return the applicable secret key or null if none is part of the stream for the key id
   * @throws IOException
   * @throws PGPException
   */
  protected PGPSecretKey findSecretKey(InputStream secretKey, final long keyId) throws IOException, PGPException {
    LOGGER.trace("findSecretKey(InputStream, long)");
    LOGGER.trace("Secret Key: {}, Key ID: {}", secretKey == null ? "not set" : "set", keyId);
    return findSecretKey(secretKey, new KeyFilter() {
      @Override
      public boolean accept(PGPSecretKey secretKey) {
        return secretKey.getKeyID() == keyId;
      }
    });
  }

  /**
   * reads the given secret key and applies the provided key filter
   *
   * @param secretKey
   *    the secret key stream
   * @param keyFilter
   *    the filter to apply on the stream
   * @return the secret key or null if none matches the filter acceptance criteria
   * @throws IOException
   * @throws PGPException
   */
  protected PGPSecretKey findSecretKey(InputStream secretKey, KeyFilter keyFilter) throws IOException, PGPException {
    LOGGER.trace("findSecretKey(InputStream, KeyFilter)");
    PGPSecretKey result = null;
    LOGGER.debug("Wrapping secret key stream in ArmoredInputStream");
    try( InputStream armoredSecretKey = new ArmoredInputStream(secretKey) ) {
      LOGGER.debug("Creating PGPSecretKeyRingCollection");
      PGPSecretKeyRingCollection keyRingCollection = new PGPSecretKeyRingCollection(armoredSecretKey, new BcKeyFingerprintCalculator());
      result = retrieveSecretKey(keyRingCollection, keyFilter);
    }
    return result;
  }

  /**
   * read a private key and unlock it with the given password
   *
   * @param secretKey
   *    the secret key stream
   * @param userId
   *    the required user id
   * @param password
   *    the password to unlock the private key
   * @return the applicable private key or null if none is found
   * @throws PGPException
   * @throws IOException
   */
  protected PGPPrivateKey findPrivateKey(InputStream secretKey, final String userId, String password) throws PGPException, IOException {
    LOGGER.trace("findPrivateKey(InputStream, String, String)");
    LOGGER.trace("Secret Key: {}, User ID: {}, Password: {}", secretKey == null ? "not set" : "set", userId, password == null ? "not set" : "********");
    return findPrivateKey(secretKey, password, new KeyFilter() {

      @Override
      public boolean accept(PGPSecretKey secretKey) {
        boolean result = false;
        Iterator userIdIterator = secretKey.getUserIDs();
        while (!result && userIdIterator.hasNext()) {
          result = userId.equals(userIdIterator.next());
        }
        return result;
      }

    });
  }

  /**
   * read a private key and unlock it with the given password
   *
   * @param secretKey
   *    the secret key stream
   * @param keyId
   *    the required key id
   * @param password
   *    the password to unlock the private key
   * @return the applicable private key or null if none is found
   * @throws PGPException
   * @throws IOException
   */
  protected PGPPrivateKey findPrivateKey(InputStream secretKey, final long keyId, String password) throws PGPException, IOException {
    LOGGER.trace("findPrivateKey(InputStream, long, String)");
    LOGGER.trace("Secret Key: {}, Key ID: {}, Password: {}", secretKey == null ? "not set" : "set", keyId, password == null ? "not set" : "********");
    return findPrivateKey(secretKey, password, new KeyFilter() {
      @Override
      public boolean accept(PGPSecretKey secretKey) {
        return secretKey.getKeyID() == keyId;
      }
    });
  }

  /**
   * read a private key and unlock it with the given password
   *
   * @param secretKey
   *    the secret key stream
   * @param password
   *    the password to use to unlock the private key
   * @param keyFilter
   *    the filter ot find the appropriate key
   * @return the appropriate private key  or null if none matches the filter
   * @throws IOException
   * @throws PGPException
   */
  protected PGPPrivateKey findPrivateKey(InputStream secretKey, String password, KeyFilter keyFilter) throws IOException, PGPException {
    LOGGER.trace("findPrivateKey(InputStream, String, KeyFilter)");
    LOGGER.trace("Secret Key: {}, Password: {}, KeyFilter: {}", secretKey == null ? "not set" : "set", password == null ? "not set" : "********", keyFilter == null ? "not set" : "set");
    return findPrivateKey(findSecretKey(secretKey, keyFilter), password);
  }

  /**
   * read the private key from the given secret key
   *
   * @param pgpSecretKey
   *    the secret key
   * @param password
   *    the password to unlock the private key
   * @return the unlocked private key
   * @throws PGPException
   */
  protected PGPPrivateKey findPrivateKey(PGPSecretKey pgpSecretKey, String password) throws PGPException {
    LOGGER.trace("findPrivateKey(PGPSecretKey, String)");
    LOGGER.trace("Secret Key: {}, Password: {}", pgpSecretKey == null ? "not set" : "set", password == null ? "not set" : "********");
    PGPPrivateKey result = null;
    PBESecretKeyDecryptor pbeSecretKeyDecryptor = new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(password.toCharArray());
    LOGGER.info("Extracting private key");
    result = pgpSecretKey.extractPrivateKey(pbeSecretKeyDecryptor);
    if( result == null && LOGGER.isErrorEnabled() ) {
      LOGGER.error("No private key could be extracted");
    }
    return result;
  }

  /**
   * reads the public key from the given stream
   *
   * @param publicKey
   *    the input key stream
   * @param keyFilter
   *    the filter to apply
   * @return the matching PGP public key
   */
  protected PGPPublicKey findPublicKey(InputStream publicKey, KeyFilter keyFilter ) {
    LOGGER.trace("findPublicKey(InputStream, KeyFilter)");
    LOGGER.trace("Public Key: {}, Key Filter: {}", publicKey == null ? "not set" : "set", keyFilter == null ? "not set" : "set");
    return retrievePublicKey(readPublicKeyRing(publicKey), keyFilter);
  }

  /**
   * reads the PGP public key from a PublicKeyRing
   *
   * @param publicKeyRing
   *    the source public key ring
   * @param keyFilter
   *    the filter to apply
   * @return the matching PGP public or null if none matches
   */
  protected PGPPublicKey retrievePublicKey(PGPPublicKeyRing publicKeyRing, KeyFilter keyFilter) {
    LOGGER.trace("retrievePublicKey(PGPPublicKeyRing, KeyFilter)");
    PGPPublicKey result = null;
    Iterator publicKeyIterator = publicKeyRing.getPublicKeys();
    LOGGER.debug("Iterating through public keys in public key ring");
    while( result == null && publicKeyIterator.hasNext() ) {
      PGPPublicKey key = publicKeyIterator.next();
      LOGGER.info("Found secret key: {}", key.getKeyID());
      LOGGER.debug("Checking public key with filter");
      if( keyFilter.accept(key) ) {
        LOGGER.info("Public key {} selected from key ring", key.getKeyID());
        result = key;
      }
    }
    return result;
  }

  /**
   * reads the public key ring from the input stream
   *
   * @param publicKey
   *    the public key stream
   * @return the public key ring
   */
  protected PGPPublicKeyRing readPublicKeyRing(InputStream publicKey) {
    LOGGER.trace("readPublicKeyRing(InputStream)");
    PGPPublicKeyRing result = null;
    LOGGER.debug("Wrapping public key stream in decoder stream");
    try( InputStream decoderStream = PGPUtil.getDecoderStream(publicKey) ) {
      LOGGER.debug("Creating PGP Object Factory");
      PGPObjectFactory pgpObjectFactory = new PGPObjectFactory(decoderStream, new BcKeyFingerprintCalculator());
      Object o = null;
      LOGGER.debug("Looking up PGP Public KeyRing");
      while( (o = pgpObjectFactory.nextObject()) != null && result == null ) {
        if( o instanceof PGPPublicKeyRing ) {
          LOGGER.info("PGP Public KeyRing retrieved");
          result = (PGPPublicKeyRing)o;
        }
      }
    } catch (IOException e) {
      LOGGER.error("{}", e.getMessage());
    }
    return result;
  }

  /**
   * accessor to the secure random generator
   *
   * @return the secure random generator
   */
  protected SecureRandom getSecureRandom() {
    return new SecureRandom();
  }

  /**
   * setter for the unlimited strength encryption flag
   *
   * @param unlimitedEncryptionStrength
   */
  public void setUnlimitedEncryptionStrength(boolean unlimitedEncryptionStrength) {
    this.unlimitedEncryptionStrength = unlimitedEncryptionStrength;
  }

  /**
   * the accessor of the unlimited encryption strength
   *
   * @return the value of the flag
   */
  protected boolean isUnlimitedEncryptionStrength() {
    return unlimitedEncryptionStrength;
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy