mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-11-20 11:22:05 +01:00
Test for detection of uncompressed, signed messages, and improve decryption of seip messages
This commit is contained in:
parent
7b7707b3a9
commit
64a50266f1
3 changed files with 46 additions and 8 deletions
|
@ -140,7 +140,10 @@ public final class DecryptionStreamFactory {
|
||||||
return new DecryptionStream(pgpInStream, resultBuilder, integrityProtectedEncryptedInputStream, null);
|
return new DecryptionStream(pgpInStream, resultBuilder, integrityProtectedEncryptedInputStream, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (openPgpIn.isLikelyOpenPgpMessage()) {
|
// Data appears to be OpenPGP message,
|
||||||
|
// or we handle it as such, since user provided a session-key for decryption
|
||||||
|
if (openPgpIn.isLikelyOpenPgpMessage() ||
|
||||||
|
(openPgpIn.isBinaryOpenPgp() && options.getSessionKey() != null)) {
|
||||||
outerDecodingStream = openPgpIn;
|
outerDecodingStream = openPgpIn;
|
||||||
objectFactory = ImplementationFactory.getInstance().getPGPObjectFactory(outerDecodingStream);
|
objectFactory = ImplementationFactory.getInstance().getPGPObjectFactory(outerDecodingStream);
|
||||||
// Parse OpenPGP message
|
// Parse OpenPGP message
|
||||||
|
|
|
@ -77,14 +77,14 @@ public class OpenPgpInputStream extends BufferedInputStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void inspectBuffer() throws IOException {
|
private void inspectBuffer() throws IOException {
|
||||||
if (determineIsArmored()) {
|
if (checkForAsciiArmor()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
determineIsBinaryOpenPgp();
|
checkForBinaryOpenPgp();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean determineIsArmored() {
|
private boolean checkForAsciiArmor() {
|
||||||
if (startsWithIgnoringWhitespace(buffer, ARMOR_HEADER, bufferLen)) {
|
if (startsWithIgnoringWhitespace(buffer, ARMOR_HEADER, bufferLen)) {
|
||||||
containsArmorHeader = true;
|
containsArmorHeader = true;
|
||||||
return true;
|
return true;
|
||||||
|
@ -100,7 +100,7 @@ public class OpenPgpInputStream extends BufferedInputStream {
|
||||||
* This breaks down though if we read plausible garbage where the data accidentally makes sense,
|
* 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).
|
* or valid, yet incomplete packets (remember, we are still only working on a portion of the data).
|
||||||
*/
|
*/
|
||||||
private void determineIsBinaryOpenPgp() throws IOException {
|
private void checkForBinaryOpenPgp() throws IOException {
|
||||||
if (bufferLen == -1) {
|
if (bufferLen == -1) {
|
||||||
// Empty data
|
// Empty data
|
||||||
return;
|
return;
|
||||||
|
@ -210,7 +210,6 @@ public class OpenPgpInputStream extends BufferedInputStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
containsOpenPgpPackets = true;
|
containsOpenPgpPackets = true;
|
||||||
isLikelyOpenPgpMessage = true;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SYMMETRIC_KEY_ENC_SESSION:
|
case SYMMETRIC_KEY_ENC_SESSION:
|
||||||
|
@ -295,6 +294,8 @@ public class OpenPgpInputStream extends BufferedInputStream {
|
||||||
case SYMMETRIC_KEY_ENC:
|
case SYMMETRIC_KEY_ENC:
|
||||||
// No data to compare :(
|
// No data to compare :(
|
||||||
containsOpenPgpPackets = true;
|
containsOpenPgpPackets = true;
|
||||||
|
// While this is a valid OpenPGP message, enabling the line below would lead to too many false positives
|
||||||
|
// isLikelyOpenPgpMessage = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MARKER:
|
case MARKER:
|
||||||
|
|
|
@ -13,20 +13,30 @@ import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import org.bouncycastle.bcpg.ArmoredInputStream;
|
import org.bouncycastle.bcpg.ArmoredInputStream;
|
||||||
import org.bouncycastle.bcpg.CompressionAlgorithmTags;
|
import org.bouncycastle.bcpg.CompressionAlgorithmTags;
|
||||||
import org.bouncycastle.openpgp.PGPCompressedDataGenerator;
|
import org.bouncycastle.openpgp.PGPCompressedDataGenerator;
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
import org.bouncycastle.util.io.Streams;
|
import org.bouncycastle.util.io.Streams;
|
||||||
import org.junit.jupiter.api.RepeatedTest;
|
import org.junit.jupiter.api.RepeatedTest;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.pgpainless.PGPainless;
|
||||||
|
import org.pgpainless.algorithm.CompressionAlgorithm;
|
||||||
|
import org.pgpainless.encryption_signing.EncryptionStream;
|
||||||
|
import org.pgpainless.encryption_signing.ProducerOptions;
|
||||||
|
import org.pgpainless.encryption_signing.SigningOptions;
|
||||||
|
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||||
|
|
||||||
public class OpenPgpInputStreamTest {
|
public class OpenPgpInputStreamTest {
|
||||||
|
|
||||||
private static final Random RANDOM = new Random();
|
private static final Random RANDOM = new Random();
|
||||||
|
|
||||||
@RepeatedTest(10)
|
@RepeatedTest(100)
|
||||||
public void randomBytesDoNotContainOpenPgpData() throws IOException {
|
public void randomBytesDoNotContainOpenPgpData() throws IOException {
|
||||||
byte[] randomBytes = new byte[1000000];
|
byte[] randomBytes = new byte[1000000];
|
||||||
RANDOM.nextBytes(randomBytes);
|
RANDOM.nextBytes(randomBytes);
|
||||||
|
@ -43,7 +53,7 @@ public class OpenPgpInputStreamTest {
|
||||||
assertArrayEquals(randomBytes, outBytes);
|
assertArrayEquals(randomBytes, outBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RepeatedTest(10)
|
@Test
|
||||||
public void largeCompressedDataIsBinaryOpenPgp() throws IOException {
|
public void largeCompressedDataIsBinaryOpenPgp() throws IOException {
|
||||||
// Since we are compressing RANDOM data, the output will likely be roughly the same size
|
// Since we are compressing RANDOM data, the output will likely be roughly the same size
|
||||||
// So we very likely will end up with data larger than the MAX_BUFFER_SIZE
|
// So we very likely will end up with data larger than the MAX_BUFFER_SIZE
|
||||||
|
@ -725,4 +735,28 @@ public class OpenPgpInputStreamTest {
|
||||||
assertFalse(openPgpInputStream.isAsciiArmored());
|
assertFalse(openPgpInputStream.isAsciiArmored());
|
||||||
assertTrue(openPgpInputStream.isNonOpenPgp());
|
assertTrue(openPgpInputStream.isNonOpenPgp());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSignedMessageConsumption() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException {
|
||||||
|
ByteArrayInputStream plaintext = new ByteArrayInputStream("Hello, World!\n".getBytes(StandardCharsets.UTF_8));
|
||||||
|
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
|
||||||
|
.modernKeyRing("Sigmund <sigmund@exmplample.com>", null);
|
||||||
|
|
||||||
|
ByteArrayOutputStream signedOut = new ByteArrayOutputStream();
|
||||||
|
EncryptionStream signer = PGPainless.encryptAndOrSign()
|
||||||
|
.onOutputStream(signedOut)
|
||||||
|
.withOptions(ProducerOptions.sign(new SigningOptions()
|
||||||
|
.addSignature(SecretKeyRingProtector.unprotectedKeys(), secretKeys))
|
||||||
|
.setAsciiArmor(false)
|
||||||
|
.overrideCompressionAlgorithm(CompressionAlgorithm.UNCOMPRESSED));
|
||||||
|
|
||||||
|
Streams.pipeAll(plaintext, signer);
|
||||||
|
signer.close();
|
||||||
|
|
||||||
|
byte[] binary = signedOut.toByteArray();
|
||||||
|
|
||||||
|
OpenPgpInputStream openPgpIn = new OpenPgpInputStream(new ByteArrayInputStream(binary));
|
||||||
|
assertFalse(openPgpIn.isAsciiArmored());
|
||||||
|
assertTrue(openPgpIn.isLikelyOpenPgpMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue