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

me.sniggle.pgp.crypt.PGPMessageSigner Maven / Gradle / Ivy

package me.sniggle.pgp.crypt;

import me.sniggle.pgp.crypt.internal.BasePGPCommon;
import me.sniggle.pgp.crypt.internal.io.IOUtils;
import org.bouncycastle.bcpg.ArmoredInputStream;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.BCPGOutputStream;
import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.openpgp.*;
import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilder;
import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;

/**
 * The the library dependent implementation of a MessageSigner
 *
 * @author iulius
 */
public class PGPMessageSigner extends BasePGPCommon implements MessageSigner {

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

  /**
   * @see MessageSigner#verifyMessage(InputStream, InputStream, InputStream)
   *
   * @param publicKeyOfSender
   *    the public key of the sender of the message
   * @param message
   *    the message / data to verify
   * @param signatureStream
   *    the (detached) signature
   * @return
   */
  @Override
  public boolean verifyMessage(InputStream publicKeyOfSender, InputStream message, InputStream signatureStream) {
    LOGGER.trace("verifyMessage(InputStream, InputStream, InputStream)");
    LOGGER.trace("Public Key: {}, Data: {}, Signature: {}",
        publicKeyOfSender == null ? "not set" : "set", message == null ? "not set" : "set", signatureStream == null ? "not set" : "set");
    boolean result = false;
    LOGGER.debug("Wrapping signature stream in ArmoredInputStream");
    try( InputStream armordPublicKeyStream = new ArmoredInputStream(signatureStream) ) {
      Object pgpObject;
      PGPObjectFactory pgpObjectFactory = new PGPObjectFactory(armordPublicKeyStream, new BcKeyFingerprintCalculator());
      LOGGER.debug("Iterating over PGP objects in stream");
      while( (pgpObject = pgpObjectFactory.nextObject()) != null ) {
        if( pgpObject instanceof PGPSignatureList ) {
          LOGGER.debug("Signature List found");
          PGPSignatureList signatureList = (PGPSignatureList)pgpObject;
          LOGGER.debug("Iterating over signature list");
          Iterator signatureIterator = signatureList.iterator();
          while( signatureIterator.hasNext() ) {
            LOGGER.debug("Checking next signature");
            final PGPSignature signature = signatureIterator.next();
            PGPPublicKey pgpPublicKey = findPublicKey(publicKeyOfSender, new KeyFilter() {
              @Override
              public boolean accept(PGPPublicKey pgpKey) {
                return pgpKey.getKeyID() == signature.getKeyID();
              }
            });
            if( pgpPublicKey != null ) {
              signature.init(new BcPGPContentVerifierBuilderProvider(), pgpPublicKey);
              LOGGER.debug("Processing signature data");
              IOUtils.process(message, new IOUtils.StreamHandler() {
                @Override
                public void handleStreamBuffer(byte[] buffer, int offset, int length) throws IOException {
                  signature.update(buffer, offset, length);
                }
              });
              result = signature.verify();
              LOGGER.info("Verify Signature: {}", result);
            } else {
              LOGGER.warn("No public key found for signature. Key ID: {}", signature.getKeyID());
            }
          }
        }
      }
    } catch (IOException | PGPException e) {
      LOGGER.error("{}", e.getMessage());
      result &= false;
    }
    return result;
  }

  /**
   * @see MessageSigner#signMessage(InputStream, String, String, InputStream, OutputStream)
   *
   * @param privateKeyOfSender
   *    the private key of the sender
   * @param userIdForPrivateKey
   *    the user id of the sender
   * @param passwordOfPrivateKey
   *    the password for the private key
   * @param message
   *    the message / data to verify
   * @param signature
   *    the (detached) signature
   * @return
   */
  @Override
  public boolean signMessage(InputStream privateKeyOfSender, final String userIdForPrivateKey, String passwordOfPrivateKey, InputStream message, OutputStream signature) {
    LOGGER.trace("signMessage(InputStream, String, String, InputStream, OutputStream)");
    LOGGER.trace("Private Key: {}, User ID: {}, Password: {}, Data: {}, Signature: {}",
        privateKeyOfSender == null ? "not set" : "set", userIdForPrivateKey, passwordOfPrivateKey == null ? "not set" : "********",
        message == null ? "not set" : "set", signature == null ? "not set" : "set");
    boolean result = false;
    try {
      LOGGER.debug("Retrieving Private Key");
      PGPPrivateKey privateKey = findPrivateKey(privateKeyOfSender, passwordOfPrivateKey,  new KeyFilter() {

        @Override
        public boolean accept(PGPSecretKey secretKey) {
          boolean result = secretKey.isSigningKey();
          if( result ) {
            Iterator userIdIterator = secretKey.getUserIDs();
            boolean containsUserId = false;
            while( userIdIterator.hasNext() && !containsUserId ) {
              containsUserId |= userIdForPrivateKey.equals(userIdIterator.next());
            }
          }
          return result;
        }
      });
      LOGGER.debug("Initializing signature generator");
      final PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(new BcPGPContentSignerBuilder(privateKey.getPublicKeyPacket().getAlgorithm(), HashAlgorithmTags.SHA256));
      signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, privateKey);
      LOGGER.debug("Wrapping signature stream in ArmoredOutputStream and PGOutputStream");
      try( BCPGOutputStream outputStream = new BCPGOutputStream( new ArmoredOutputStream(signature)) ) {
        IOUtils.process(message, new IOUtils.StreamHandler() {

          @Override
          public void handleStreamBuffer(byte[] buffer, int offset, int length) throws IOException {
            signatureGenerator.update(buffer, offset, length);
          }

        });
        LOGGER.info("Writing signature out");
        signatureGenerator.generate().encode(outputStream);
      }
      result = true;
    } catch (IOException | PGPException e) {
      result &= false;
      LOGGER.error("{}", e.getMessage());
    }
    return result;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy