name.neuhalfen.projects.crypto.bouncycastle.openpgp.decrypting.SignatureValidatingInputStream Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bouncy-gpg Show documentation
Show all versions of bouncy-gpg Show documentation
Make using Bouncy Castle with OpenPGP fun again!
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;
}
}
}