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

name.neuhalfen.projects.crypto.bouncycastle.openpgp.decrypting.SignatureValidatingInputStream Maven / Gradle / Ivy

The newest version!
package name.neuhalfen.projects.crypto.bouncycastle.openpgp.decrypting;

import static java.util.Objects.requireNonNull;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.SignatureException;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nonnull;
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.validation.SignatureValidationStrategy;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPObjectFactory;
import org.bouncycastle.openpgp.PGPOnePassSignature;

@SuppressWarnings("PMD.ShortVariable")
final class SignatureValidatingInputStream extends FilterInputStream {

  private final DecryptionState state;
  private final SignatureValidationStrategy signatureValidationStrategy;

  /**
   * Creates a SignatureValidatingInputStream by assigning the  argument
   * inputStream to the field this.inputStream so as to remember it for
   * later use.
   *
   * @param inputStream the underlying input stream, or null if this instance is to
   *     be
   *     created without an underlying stream.
   */
  SignatureValidatingInputStream(InputStream inputStream, DecryptionState state,
      SignatureValidationStrategy signatureValidationStrategy) {
    super(inputStream);
    requireNonNull(state, "state must not be null");
    requireNonNull(signatureValidationStrategy,
        "signatureValidationStrategy must not be null");

    this.state = state;
    this.signatureValidationStrategy = signatureValidationStrategy;
  }

  @Override
  public int read() throws IOException {
    final int data = super.read();
    final boolean endOfStream = data == -1;
    if (endOfStream) {
      validateSignature();
    } else {
      state.updateOnePassSignatures((byte) data);
    }
    return data;
  }

  @Override
  public int read(@Nonnull byte[] b) throws IOException {
    return read(b, 0, b.length);
  }

  @Override
  public int read(@Nonnull byte[] b, int off, int len) throws IOException {
    final int read = super.read(b, off, len);

    final boolean endOfStream = read == -1;
    if (endOfStream) {
      validateSignature();
    } else {
      state.updateOnePassSignatures(b, off, read);
    }
    return read;
  }

  /**
   * Ensure that at least ONE signature is valid.
   *
   * @throws IOException No valid signature found
   */
  private void validateSignature() throws IOException {
    try {
      signatureValidationStrategy
          .validateSignatures(state.getSignatureFactory(), state.getOnePassSignatures());
    } catch (PGPException | SignatureException e) {
      throw new IOException(e.getMessage(), e);
    }

  }

  @Override
  public long skip(long n) throws IOException {
    throw new UnsupportedOperationException("Skipping not supported");
  }

  @SuppressWarnings("PMD.AvoidSynchronizedAtMethodLevel")
  @Override
  public synchronized void mark(int readlimit) {
    throw new UnsupportedOperationException("mark not supported");
  }

  @SuppressWarnings("PMD.AvoidSynchronizedAtMethodLevel")
  @Override
  public synchronized void reset() throws IOException {
    throw new UnsupportedOperationException("reset not supported");
  }

  @Override
  public boolean markSupported() {
    return false;
  }

  @SuppressWarnings("PMD.DefaultPackage")
  static final class DecryptionState {

    private final Map onePassSignatures = new HashMap<>();
    private PGPObjectFactory signatureFactory;

    @SuppressWarnings("PMD.DefaultPackage")
    PGPObjectFactory getSignatureFactory() {
      return signatureFactory;
    }

    @SuppressWarnings("PMD.DefaultPackage")
    void setSignatureFactory(PGPObjectFactory signatureFactory) {
      this.signatureFactory = signatureFactory;
    }


    @SuppressWarnings("PMD.DefaultPackage")
    void updateOnePassSignatures(byte data) {
      for (final PGPOnePassSignature sig : onePassSignatures.values()) {
        sig.update(data);
      }
    }

    @SuppressWarnings("PMD.DefaultPackage")
    void updateOnePassSignatures(byte[] b, int off, int len) {
      for (final PGPOnePassSignature sig : onePassSignatures.values()) {
        sig.update(b, off, len);
      }
    }

    @SuppressWarnings("PMD.DefaultPackage")
    Map getOnePassSignatures() {
      return onePassSignatures;
    }

    /*
     * @pre: the public key for the keyId is in our keyring.
     */
    @SuppressWarnings("PMD.DefaultPackage")
    void addSignature(PGPOnePassSignature signature) {
      onePassSignatures.put(signature.getKeyID(), signature);
    }

    @SuppressWarnings("PMD.DefaultPackage")
    int numVerifiableSignatures() {
      return onePassSignatures.size();
    }

    @SuppressWarnings("PMD.DefaultPackage")
    boolean hasVerifiableSignatures() {
      return numVerifiableSignatures() > 0;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy