mirror of
https://github.com/pgpainless/pgpainless.git
synced 2025-09-10 18:59:39 +02:00
Compare commits
No commits in common. "4b179d750a4618fb89ce79e11f8aeb738b847ad8" and "c8d6a3dc857b1e268cef4c3cbcf29d0ae3481947" have entirely different histories.
4b179d750a
...
c8d6a3dc85
59 changed files with 74 additions and 64 deletions
|
@ -139,12 +139,11 @@ class OpenPgpMessageInputStream(
|
||||||
|
|
||||||
// Comsume packets, potentially stepping into nested layers
|
// Comsume packets, potentially stepping into nested layers
|
||||||
layer@ while (run {
|
layer@ while (run {
|
||||||
packet =
|
packet = try {
|
||||||
try {
|
pIn.nextPacketTag()
|
||||||
pIn.nextPacketTag()
|
} catch (e: NoSuchElementException) {
|
||||||
} catch (e: NoSuchElementException) {
|
throw MalformedOpenPgpMessageException(e.message)
|
||||||
throw MalformedOpenPgpMessageException(e.message)
|
}
|
||||||
}
|
|
||||||
packet
|
packet
|
||||||
} != null) {
|
} != null) {
|
||||||
|
|
||||||
|
@ -211,24 +210,25 @@ class OpenPgpMessageInputStream(
|
||||||
syntaxVerifier.next(InputSymbol.LITERAL_DATA)
|
syntaxVerifier.next(InputSymbol.LITERAL_DATA)
|
||||||
val literalData = packetInputStream!!.readLiteralData()
|
val literalData = packetInputStream!!.readLiteralData()
|
||||||
|
|
||||||
val streamEncoding =
|
val streamEncoding = try {
|
||||||
try {
|
StreamEncoding.requireFromCode(literalData.format)
|
||||||
StreamEncoding.requireFromCode(literalData.format)
|
} catch (e: NoSuchElementException) {
|
||||||
} catch (e: NoSuchElementException) {
|
throw PGPException("Invalid stream encoding format encountered: ${literalData.format}; ${e.message}")
|
||||||
throw PGPException(
|
}
|
||||||
"Invalid stream encoding format encountered: ${literalData.format}; ${e.message}")
|
|
||||||
}
|
|
||||||
|
|
||||||
val fileName =
|
val fileName = try {
|
||||||
try {
|
literalData.fileName
|
||||||
literalData.fileName
|
} catch (e: IllegalArgumentException) {
|
||||||
} catch (e: IllegalArgumentException) {
|
// Non UTF8
|
||||||
// Non UTF8
|
throw PGPException("Cannot decode literal data filename: ${e.message}")
|
||||||
throw PGPException("Cannot decode literal data filename: ${e.message}")
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Extract Metadata
|
// Extract Metadata
|
||||||
layerMetadata.child = LiteralData(fileName, literalData.modificationTime, streamEncoding)
|
layerMetadata.child =
|
||||||
|
LiteralData(
|
||||||
|
fileName,
|
||||||
|
literalData.modificationTime,
|
||||||
|
streamEncoding)
|
||||||
|
|
||||||
nestedInputStream = literalData.inputStream
|
nestedInputStream = literalData.inputStream
|
||||||
}
|
}
|
||||||
|
@ -238,15 +238,17 @@ class OpenPgpMessageInputStream(
|
||||||
signatures.enterNesting()
|
signatures.enterNesting()
|
||||||
val compressedData = packetInputStream!!.readCompressedData()
|
val compressedData = packetInputStream!!.readCompressedData()
|
||||||
|
|
||||||
val compAlg =
|
val compAlg = try {
|
||||||
try {
|
CompressionAlgorithm.requireFromId(compressedData.algorithm)
|
||||||
CompressionAlgorithm.requireFromId(compressedData.algorithm)
|
} catch (e: NoSuchElementException) {
|
||||||
} catch (e: NoSuchElementException) {
|
throw PGPException(e.message)
|
||||||
throw PGPException(e.message)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Extract Metadata
|
// Extract Metadata
|
||||||
val compressionLayer = CompressedData(compAlg, layerMetadata.depth + 1)
|
val compressionLayer =
|
||||||
|
CompressedData(
|
||||||
|
compAlg,
|
||||||
|
layerMetadata.depth + 1)
|
||||||
|
|
||||||
LOGGER.debug(
|
LOGGER.debug(
|
||||||
"Compressed Data Packet (${compressionLayer.algorithm}) at depth ${layerMetadata.depth} encountered.")
|
"Compressed Data Packet (${compressionLayer.algorithm}) at depth ${layerMetadata.depth} encountered.")
|
||||||
|
@ -345,9 +347,7 @@ class OpenPgpMessageInputStream(
|
||||||
"Symmetrically Encrypted Data Packet at depth ${layerMetadata.depth} encountered.")
|
"Symmetrically Encrypted Data Packet at depth ${layerMetadata.depth} encountered.")
|
||||||
syntaxVerifier.next(InputSymbol.ENCRYPTED_DATA)
|
syntaxVerifier.next(InputSymbol.ENCRYPTED_DATA)
|
||||||
val encDataList = packetInputStream!!.readEncryptedDataList()
|
val encDataList = packetInputStream!!.readEncryptedDataList()
|
||||||
if (!encDataList.isIntegrityProtected &&
|
if (!encDataList.isIntegrityProtected && !encDataList.isEmpty && !encDataList.get(0).isAEAD) {
|
||||||
!encDataList.isEmpty &&
|
|
||||||
!encDataList.get(0).isAEAD) {
|
|
||||||
LOGGER.warn("Symmetrically Encrypted Data Packet is not integrity-protected.")
|
LOGGER.warn("Symmetrically Encrypted Data Packet is not integrity-protected.")
|
||||||
if (!options.isIgnoreMDCErrors()) {
|
if (!options.isIgnoreMDCErrors()) {
|
||||||
throw MessageNotIntegrityProtectedException()
|
throw MessageNotIntegrityProtectedException()
|
||||||
|
@ -569,14 +569,13 @@ class OpenPgpMessageInputStream(
|
||||||
pkesk: PGPPublicKeyEncryptedData
|
pkesk: PGPPublicKeyEncryptedData
|
||||||
): Boolean {
|
): Boolean {
|
||||||
try {
|
try {
|
||||||
val decrypted =
|
val decrypted = try {
|
||||||
try {
|
pkesk.getDataStream(decryptorFactory)
|
||||||
pkesk.getDataStream(decryptorFactory)
|
} catch (e: ClassCastException) {
|
||||||
} catch (e: ClassCastException) {
|
throw PGPException(e.message)
|
||||||
throw PGPException(e.message)
|
} catch (e: IllegalArgumentException) {
|
||||||
} catch (e: IllegalArgumentException) {
|
throw PGPException(e.message)
|
||||||
throw PGPException(e.message)
|
}
|
||||||
}
|
|
||||||
val sessionKey = SessionKey(pkesk.getSessionKey(decryptorFactory))
|
val sessionKey = SessionKey(pkesk.getSessionKey(decryptorFactory))
|
||||||
throwIfUnacceptable(sessionKey.algorithm)
|
throwIfUnacceptable(sessionKey.algorithm)
|
||||||
|
|
||||||
|
|
|
@ -165,13 +165,13 @@ class SignatureUtils {
|
||||||
// having them compressed,
|
// having them compressed,
|
||||||
// except for an attacker who is trying to exploit flaws in the decompression
|
// except for an attacker who is trying to exploit flaws in the decompression
|
||||||
// algorithm.
|
// algorithm.
|
||||||
// Therefore, we ignore compressed data packets without attempting
|
// Therefore, we ignore compressed data packets without attempting decompression.
|
||||||
// decompression.
|
|
||||||
if (nextObject is PGPCompressedData) {
|
if (nextObject is PGPCompressedData) {
|
||||||
// getInputStream() does not do decompression, contrary to getDataStream().
|
// getInputStream() does not do decompression, contrary to getDataStream().
|
||||||
Streams.drain(
|
Streams.drain(
|
||||||
(nextObject as PGPCompressedData)
|
(nextObject as PGPCompressedData)
|
||||||
.inputStream) // Skip packet without decompressing
|
.inputStream
|
||||||
|
) // Skip packet without decompressing
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextObject is PGPSignatureList) {
|
if (nextObject is PGPSignatureList) {
|
||||||
|
|
|
@ -247,8 +247,7 @@ class ArmorUtils {
|
||||||
.add(OpenPgpFingerprint.of(publicKey).prettyPrint())
|
.add(OpenPgpFingerprint.of(publicKey).prettyPrint())
|
||||||
// Primary / First User ID
|
// Primary / First User ID
|
||||||
(primary ?: first)?.let {
|
(primary ?: first)?.let {
|
||||||
headerMap
|
headerMap.getOrPut(HEADER_COMMENT) { mutableSetOf() }
|
||||||
.getOrPut(HEADER_COMMENT) { mutableSetOf() }
|
|
||||||
.add(it.replace("\n", "\\n").replace("\r", "\\r"))
|
.add(it.replace("\n", "\\n").replace("\r", "\\r"))
|
||||||
}
|
}
|
||||||
// X-1 further identities
|
// X-1 further identities
|
||||||
|
|
|
@ -6,13 +6,13 @@ package org.pgpainless.bouncycastle.fuzzing
|
||||||
|
|
||||||
import com.code_intelligence.jazzer.api.FuzzedDataProvider
|
import com.code_intelligence.jazzer.api.FuzzedDataProvider
|
||||||
import com.code_intelligence.jazzer.junit.FuzzTest
|
import com.code_intelligence.jazzer.junit.FuzzTest
|
||||||
import java.io.EOFException
|
|
||||||
import java.io.IOException
|
|
||||||
import org.bouncycastle.bcpg.ArmoredInputException
|
import org.bouncycastle.bcpg.ArmoredInputException
|
||||||
import org.bouncycastle.bcpg.UnsupportedPacketVersionException
|
import org.bouncycastle.bcpg.UnsupportedPacketVersionException
|
||||||
import org.bouncycastle.openpgp.PGPException
|
import org.bouncycastle.openpgp.PGPException
|
||||||
import org.bouncycastle.openpgp.PGPUtil
|
import org.bouncycastle.openpgp.PGPUtil
|
||||||
import org.bouncycastle.openpgp.bc.BcPGPObjectFactory
|
import org.bouncycastle.openpgp.bc.BcPGPObjectFactory
|
||||||
|
import java.io.EOFException
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
class PGPObjectFactoryFuzzingTest {
|
class PGPObjectFactoryFuzzingTest {
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
package org.pgpainless.sop
|
package org.pgpainless.sop
|
||||||
|
|
||||||
import java.io.BufferedOutputStream
|
import java.io.BufferedOutputStream
|
||||||
import java.io.IOException
|
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import kotlin.jvm.Throws
|
import kotlin.jvm.Throws
|
||||||
|
@ -15,6 +14,7 @@ import org.pgpainless.util.ArmoredOutputStreamFactory
|
||||||
import sop.Ready
|
import sop.Ready
|
||||||
import sop.exception.SOPGPException
|
import sop.exception.SOPGPException
|
||||||
import sop.operation.Armor
|
import sop.operation.Armor
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
/** Implementation of the `armor` operation using PGPainless. */
|
/** Implementation of the `armor` operation using PGPainless. */
|
||||||
class ArmorImpl : Armor {
|
class ArmorImpl : Armor {
|
||||||
|
@ -27,15 +27,14 @@ class ArmorImpl : Armor {
|
||||||
val bufferedOutputStream = BufferedOutputStream(outputStream)
|
val bufferedOutputStream = BufferedOutputStream(outputStream)
|
||||||
|
|
||||||
// Determine the nature of the given data
|
// Determine the nature of the given data
|
||||||
val openPgpIn =
|
val openPgpIn = OpenPgpInputStream(data, false).apply {
|
||||||
OpenPgpInputStream(data, false).apply {
|
try {
|
||||||
try {
|
inspectBuffer()
|
||||||
inspectBuffer()
|
} catch (e: IOException) {
|
||||||
} catch (e: IOException) {
|
// ignore
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
reset()
|
|
||||||
}
|
}
|
||||||
|
reset()
|
||||||
|
}
|
||||||
|
|
||||||
if (openPgpIn.isAsciiArmored) {
|
if (openPgpIn.isAsciiArmored) {
|
||||||
// armoring already-armored data is an idempotent operation
|
// armoring already-armored data is an idempotent operation
|
||||||
|
|
|
@ -4,13 +4,11 @@
|
||||||
|
|
||||||
package org.pgpainless.sop
|
package org.pgpainless.sop
|
||||||
|
|
||||||
|
import org.bouncycastle.bcpg.UnsupportedPacketVersionException
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.zip.ZipException
|
|
||||||
import kotlin.NoSuchElementException
|
|
||||||
import org.bouncycastle.bcpg.UnsupportedPacketVersionException
|
|
||||||
import org.bouncycastle.openpgp.PGPException
|
import org.bouncycastle.openpgp.PGPException
|
||||||
import org.bouncycastle.util.io.Streams
|
import org.bouncycastle.util.io.Streams
|
||||||
import org.pgpainless.PGPainless
|
import org.pgpainless.PGPainless
|
||||||
|
@ -27,6 +25,8 @@ import sop.SessionKey
|
||||||
import sop.exception.SOPGPException
|
import sop.exception.SOPGPException
|
||||||
import sop.operation.Decrypt
|
import sop.operation.Decrypt
|
||||||
import sop.util.UTF8Util
|
import sop.util.UTF8Util
|
||||||
|
import java.util.zip.ZipException
|
||||||
|
import kotlin.NoSuchElementException
|
||||||
|
|
||||||
/** Implementation of the `decrypt` operation using PGPainless. */
|
/** Implementation of the `decrypt` operation using PGPainless. */
|
||||||
class DecryptImpl : Decrypt {
|
class DecryptImpl : Decrypt {
|
||||||
|
@ -61,7 +61,8 @@ class DecryptImpl : Decrypt {
|
||||||
throw SOPGPException.BadData(e)
|
throw SOPGPException.BadData(e)
|
||||||
} catch (e: ModificationDetectionException) {
|
} catch (e: ModificationDetectionException) {
|
||||||
throw SOPGPException.BadData(e)
|
throw SOPGPException.BadData(e)
|
||||||
} finally {
|
}
|
||||||
|
finally {
|
||||||
// Forget passphrases after decryption
|
// Forget passphrases after decryption
|
||||||
protector.clear()
|
protector.clear()
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import java.io.IOException;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||||
|
|
||||||
public class ArmorFuzzTest {
|
public class AsciiArmorFuzzTest {
|
||||||
|
|
||||||
private final SOP sop = new SOPImpl();
|
private final SOP sop = new SOPImpl();
|
||||||
|
|
|
@ -6,8 +6,12 @@ package org.pgpainless.sop.fuzzing;
|
||||||
|
|
||||||
import com.code_intelligence.jazzer.api.FuzzedDataProvider;
|
import com.code_intelligence.jazzer.api.FuzzedDataProvider;
|
||||||
import com.code_intelligence.jazzer.junit.FuzzTest;
|
import com.code_intelligence.jazzer.junit.FuzzTest;
|
||||||
|
import org.bouncycastle.util.encoders.Hex;
|
||||||
import org.bouncycastle.util.io.Streams;
|
import org.bouncycastle.util.io.Streams;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.pgpainless.exception.MissingDecryptionMethodException;
|
||||||
|
import org.pgpainless.exception.ModificationDetectionException;
|
||||||
import org.pgpainless.sop.SOPImpl;
|
import org.pgpainless.sop.SOPImpl;
|
||||||
import sop.SOP;
|
import sop.SOP;
|
||||||
import sop.exception.SOPGPException;
|
import sop.exception.SOPGPException;
|
||||||
|
@ -17,14 +21,22 @@ import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
|
||||||
public class EncryptFuzzTest {
|
public class EncryptedMessageFuzzingTest {
|
||||||
|
|
||||||
private final SOP sop = new SOPImpl();
|
private final SOP sop = new SOPImpl();
|
||||||
private final String password = "sw0rdf1sh";
|
private final String password = "sw0rdf1sh";
|
||||||
|
@ -41,7 +53,7 @@ public class EncryptFuzzTest {
|
||||||
List<byte[]> keys = new ArrayList<>();
|
List<byte[]> keys = new ArrayList<>();
|
||||||
|
|
||||||
String dir = "/org/pgpainless/sop/fuzzing/testKeys";
|
String dir = "/org/pgpainless/sop/fuzzing/testKeys";
|
||||||
InputStream in = EncryptFuzzTest.class.getResourceAsStream(dir);
|
InputStream in = EncryptedMessageFuzzingTest.class.getResourceAsStream(dir);
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||||
|
|
||||||
String file;
|
String file;
|
||||||
|
@ -50,7 +62,7 @@ public class EncryptFuzzTest {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try(InputStream fIn = EncryptFuzzTest.class.getResourceAsStream(dir + "/" + file)) {
|
try(InputStream fIn = EncryptedMessageFuzzingTest.class.getResourceAsStream(dir + "/" + file)) {
|
||||||
byte[] b = Streams.readAll(fIn);
|
byte[] b = Streams.readAll(fIn);
|
||||||
keys.add(b);
|
keys.add(b);
|
||||||
}
|
}
|
|
@ -15,7 +15,7 @@ import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class VerifyFuzzTest {
|
public class SignatureFuzzTest {
|
||||||
|
|
||||||
private final SOP sop = new SOPImpl();
|
private final SOP sop = new SOPImpl();
|
||||||
private final byte[] data = "Hello, World!\n".getBytes(StandardCharsets.UTF_8);
|
private final byte[] data = "Hello, World!\n".getBytes(StandardCharsets.UTF_8);
|
Loading…
Add table
Add a link
Reference in a new issue