1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-12-23 19:38:00 +01:00

Add option to force handling of data as non-openpgp

This commit is contained in:
Paul Schaub 2022-04-22 21:33:13 +02:00
parent 8172aa1083
commit 230725f6ff
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
3 changed files with 38 additions and 37 deletions

View file

@ -36,6 +36,7 @@ public class ConsumerOptions {
private boolean ignoreMDCErrors = false; private boolean ignoreMDCErrors = false;
private boolean forceNonOpenPgpData = false;
private Date verifyNotBefore = null; private Date verifyNotBefore = null;
private Date verifyNotAfter = new Date(); private Date verifyNotAfter = new Date();
@ -296,6 +297,21 @@ public class ConsumerOptions {
return ignoreMDCErrors; return ignoreMDCErrors;
} }
/**
* Force PGPainless to handle the data provided by the {@link InputStream} as non-OpenPGP data.
* This workaround might come in handy if PGPainless accidentally mistakes the data for binary OpenPGP data.
*
* @return options
*/
public ConsumerOptions forceNonOpenPgpData() {
this.forceNonOpenPgpData = true;
return this;
}
boolean isForceNonOpenPgpData() {
return forceNonOpenPgpData;
}
/** /**
* Specify the {@link MissingKeyPassphraseStrategy}. * Specify the {@link MissingKeyPassphraseStrategy}.
* This strategy defines, how missing passphrases for unlocking secret keys are handled. * This strategy defines, how missing passphrases for unlocking secret keys are handled.

View file

@ -134,7 +134,7 @@ public final class DecryptionStreamFactory {
PGPObjectFactory objectFactory; PGPObjectFactory objectFactory;
// Non-OpenPGP data. We are probably verifying detached signatures // Non-OpenPGP data. We are probably verifying detached signatures
if (openPgpIn.isNonOpenPgp()) { if (openPgpIn.isNonOpenPgp() || options.isForceNonOpenPgpData()) {
outerDecodingStream = openPgpIn; outerDecodingStream = openPgpIn;
pgpInStream = wrapInVerifySignatureStream(outerDecodingStream, null); pgpInStream = wrapInVerifySignatureStream(outerDecodingStream, null);
return new DecryptionStream(pgpInStream, resultBuilder, integrityProtectedEncryptedInputStream, null); return new DecryptionStream(pgpInStream, resultBuilder, integrityProtectedEncryptedInputStream, null);

View file

@ -18,7 +18,7 @@ public class OpenPgpInputStream extends BufferedInputStream {
private static final byte[] ARMOR_HEADER = "-----BEGIN PGP ".getBytes(Charset.forName("UTF8")); private static final byte[] ARMOR_HEADER = "-----BEGIN PGP ".getBytes(Charset.forName("UTF8"));
// Buffer beginning bytes of the data // Buffer beginning bytes of the data
public static final int MAX_BUFFER_SIZE = 8192; public static final int MAX_BUFFER_SIZE = 8192 * 2;
private final byte[] buffer; private final byte[] buffer;
private final int bufferLen; private final int bufferLen;
@ -53,6 +53,14 @@ public class OpenPgpInputStream extends BufferedInputStream {
return false; return false;
} }
/**
* This method is still brittle.
* Basically we try to parse OpenPGP packets from the buffer.
* If we run into exceptions, then we know that the data is non-OpenPGP'ish.
*
* This breaks down though if we read plausible garbage where the data accidentally makes sense,
* or valid, yet incomplete packets (remember, we are still only working on a portion of the data).
*/
private void determineIsBinaryOpenPgp() { private void determineIsBinaryOpenPgp() {
if (bufferLen == -1) { if (bufferLen == -1) {
// Empty data // Empty data
@ -62,47 +70,24 @@ public class OpenPgpInputStream extends BufferedInputStream {
try { try {
ByteArrayInputStream bufferIn = new ByteArrayInputStream(buffer, 0, bufferLen); ByteArrayInputStream bufferIn = new ByteArrayInputStream(buffer, 0, bufferLen);
PGPObjectFactory objectFactory = ImplementationFactory.getInstance().getPGPObjectFactory(bufferIn); PGPObjectFactory objectFactory = ImplementationFactory.getInstance().getPGPObjectFactory(bufferIn);
boolean containsPackets = false;
while (objectFactory.nextObject() != null) { while (objectFactory.nextObject() != null) {
// read all packets in buffer containsPackets = true;
// read all packets in buffer - hope to confirm invalid data via thrown IOExceptions
} }
containsOpenPgpPackets = true; containsOpenPgpPackets = containsPackets;
} catch (IOException e) { } catch (IOException e) {
if (e.getMessage().contains("premature end of stream in PartialInputStream")) { String msg = e.getMessage();
// We *probably* hit valid, but large OpenPGP data
// If true, we *probably* hit valid, but large OpenPGP data (not sure though) :/
// Otherwise we hit garbage and can be sure that this is no OpenPGP data \o/
containsOpenPgpPackets = (msg != null && msg.contains("premature end of stream in PartialInputStream"));
// This is not an optimal way of determining the nature of data, but probably the best // This is not an optimal way of determining the nature of data, but probably the best
// we can get from BC. // we can do :/
containsOpenPgpPackets = true;
} }
// else: seemingly random, non-OpenPGP data
}
}
private boolean startsWith(byte[] bytes, byte[] subsequence, int bufferLen) {
return indexOfSubsequence(bytes, subsequence, bufferLen) == 0;
}
private int indexOfSubsequence(byte[] bytes, byte[] subsequence, int bufferLen) {
if (bufferLen == -1) {
return -1;
}
// Naive implementation
// TODO: Could be improved by using e.g. Knuth-Morris-Pratt algorithm.
for (int i = 0; i < bufferLen; i++) {
if ((i + subsequence.length) <= bytes.length) {
boolean found = true;
for (int j = 0; j < subsequence.length; j++) {
if (bytes[i + j] != subsequence[j]) {
found = false;
break;
}
}
if (found) {
return i;
}
}
}
return -1;
} }
private boolean startsWithIgnoringWhitespace(byte[] bytes, byte[] subsequence, int bufferLen) { private boolean startsWithIgnoringWhitespace(byte[] bytes, byte[] subsequence, int bufferLen) {