1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2025-09-09 18:29:39 +02:00

Port OpenPGPInputStream to Kotlin as OpenPGPAnimalSnifferInputStream

This commit is contained in:
Paul Schaub 2025-05-08 14:38:48 +02:00
parent 3a0ee1c101
commit 702db4d75c
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
8 changed files with 340 additions and 367 deletions

View file

@ -1,340 +0,0 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.decryption_verification;
import static org.bouncycastle.bcpg.PacketTags.AEAD_ENC_DATA;
import static org.bouncycastle.bcpg.PacketTags.COMPRESSED_DATA;
import static org.bouncycastle.bcpg.PacketTags.EXPERIMENTAL_1;
import static org.bouncycastle.bcpg.PacketTags.EXPERIMENTAL_2;
import static org.bouncycastle.bcpg.PacketTags.EXPERIMENTAL_3;
import static org.bouncycastle.bcpg.PacketTags.EXPERIMENTAL_4;
import static org.bouncycastle.bcpg.PacketTags.LITERAL_DATA;
import static org.bouncycastle.bcpg.PacketTags.MARKER;
import static org.bouncycastle.bcpg.PacketTags.MOD_DETECTION_CODE;
import static org.bouncycastle.bcpg.PacketTags.ONE_PASS_SIGNATURE;
import static org.bouncycastle.bcpg.PacketTags.PADDING;
import static org.bouncycastle.bcpg.PacketTags.PUBLIC_KEY;
import static org.bouncycastle.bcpg.PacketTags.PUBLIC_KEY_ENC_SESSION;
import static org.bouncycastle.bcpg.PacketTags.PUBLIC_SUBKEY;
import static org.bouncycastle.bcpg.PacketTags.RESERVED;
import static org.bouncycastle.bcpg.PacketTags.SECRET_KEY;
import static org.bouncycastle.bcpg.PacketTags.SECRET_SUBKEY;
import static org.bouncycastle.bcpg.PacketTags.SIGNATURE;
import static org.bouncycastle.bcpg.PacketTags.SYMMETRIC_KEY_ENC;
import static org.bouncycastle.bcpg.PacketTags.SYMMETRIC_KEY_ENC_SESSION;
import static org.bouncycastle.bcpg.PacketTags.SYM_ENC_INTEGRITY_PRO;
import static org.bouncycastle.bcpg.PacketTags.TRUST;
import static org.bouncycastle.bcpg.PacketTags.USER_ATTRIBUTE;
import static org.bouncycastle.bcpg.PacketTags.USER_ID;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import org.bouncycastle.bcpg.AEADEncDataPacket;
import org.bouncycastle.bcpg.BCPGInputStream;
import org.bouncycastle.bcpg.CompressedDataPacket;
import org.bouncycastle.bcpg.LiteralDataPacket;
import org.bouncycastle.bcpg.MarkerPacket;
import org.bouncycastle.bcpg.OnePassSignaturePacket;
import org.bouncycastle.bcpg.Packet;
import org.bouncycastle.bcpg.PacketFormat;
import org.bouncycastle.bcpg.PublicKeyEncSessionPacket;
import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.bcpg.SecretKeyPacket;
import org.bouncycastle.bcpg.SignaturePacket;
import org.bouncycastle.bcpg.SymmetricEncIntegrityPacket;
import org.bouncycastle.bcpg.SymmetricKeyEncSessionPacket;
import org.bouncycastle.bcpg.UnsupportedPacketVersionException;
import org.bouncycastle.openpgp.PGPCompressedData;
import org.bouncycastle.openpgp.PGPEncryptedData;
import org.bouncycastle.openpgp.PGPLiteralData;
import org.bouncycastle.openpgp.PGPOnePassSignature;
import org.bouncycastle.util.Arrays;
import org.pgpainless.algorithm.AEADAlgorithm;
import org.pgpainless.algorithm.CompressionAlgorithm;
import org.pgpainless.algorithm.HashAlgorithm;
import org.pgpainless.algorithm.PublicKeyAlgorithm;
import org.pgpainless.algorithm.SignatureType;
import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
/**
* InputStream used to determine the nature of potential OpenPGP data.
*/
public class OpenPgpInputStream extends BufferedInputStream {
@SuppressWarnings("CharsetObjectCanBeUsed")
private static final byte[] ARMOR_HEADER = "-----BEGIN PGP ".getBytes(Charset.forName("UTF8"));
// Buffer beginning bytes of the data
public static final int MAX_BUFFER_SIZE = 8192 * 2;
private final byte[] buffer;
private final int bufferLen;
private boolean containsArmorHeader;
private boolean containsOpenPgpPackets;
private boolean isLikelyOpenPgpMessage;
public OpenPgpInputStream(InputStream in, boolean check) throws IOException {
super(in, MAX_BUFFER_SIZE);
mark(MAX_BUFFER_SIZE);
buffer = new byte[MAX_BUFFER_SIZE];
bufferLen = read(buffer);
reset();
if (check) {
inspectBuffer();
}
}
public OpenPgpInputStream(InputStream in) throws IOException {
this(in, true);
}
private void inspectBuffer() throws IOException {
if (checkForAsciiArmor()) {
return;
}
checkForBinaryOpenPgp();
}
private boolean checkForAsciiArmor() {
if (startsWithIgnoringWhitespace(buffer, ARMOR_HEADER, bufferLen)) {
containsArmorHeader = true;
return true;
}
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.
* <p>
* 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 checkForBinaryOpenPgp() throws IOException {
if (bufferLen == -1) {
// Empty data
return;
}
ByteArrayInputStream bufferIn = new ByteArrayInputStream(buffer, 0, bufferLen);
BCPGInputStream pIn = new BCPGInputStream(bufferIn);
try {
nonExhaustiveParseAndCheckPlausibility(pIn);
} catch (IOException | UnsupportedPacketVersionException | NegativeArraySizeException e) {
return;
}
}
private void nonExhaustiveParseAndCheckPlausibility(BCPGInputStream packetIn)
throws IOException {
Packet packet = packetIn.readPacket();
switch (packet.getPacketTag()) {
case PUBLIC_KEY_ENC_SESSION:
PublicKeyEncSessionPacket pkesk = (PublicKeyEncSessionPacket) packet;
if (PublicKeyAlgorithm.fromId(pkesk.getAlgorithm()) == null) {
return;
}
break;
case SIGNATURE:
SignaturePacket sig = (SignaturePacket) packet;
if (SignatureType.fromCode(sig.getSignatureType()) == null) {
return;
}
if (PublicKeyAlgorithm.fromId(sig.getKeyAlgorithm()) == null) {
return;
}
if (HashAlgorithm.fromId(sig.getHashAlgorithm()) == null) {
return;
}
break;
case ONE_PASS_SIGNATURE:
OnePassSignaturePacket ops = (OnePassSignaturePacket) packet;
if (SignatureType.fromCode(ops.getSignatureType()) == null) {
return;
}
if (PublicKeyAlgorithm.fromId(ops.getKeyAlgorithm()) == null) {
return;
}
if (HashAlgorithm.fromId(ops.getHashAlgorithm()) == null) {
return;
}
break;
case SYMMETRIC_KEY_ENC_SESSION:
SymmetricKeyEncSessionPacket skesk = (SymmetricKeyEncSessionPacket) packet;
if (SymmetricKeyAlgorithm.fromId(skesk.getEncAlgorithm()) == null) {
return;
}
break;
case SECRET_KEY:
SecretKeyPacket secKey = (SecretKeyPacket) packet;
PublicKeyPacket sPubKey = secKey.getPublicKeyPacket();
if (PublicKeyAlgorithm.fromId(sPubKey.getAlgorithm()) == null) {
return;
}
if (sPubKey.getVersion() < 3 && sPubKey.getVersion() > 6) {
return;
}
break;
case PUBLIC_KEY:
PublicKeyPacket pubKey = (PublicKeyPacket) packet;
if (PublicKeyAlgorithm.fromId(pubKey.getAlgorithm()) == null) {
return;
}
if (pubKey.getVersion() < 3 && pubKey.getVersion() > 6) {
return;
}
break;
case COMPRESSED_DATA:
CompressedDataPacket comp = (CompressedDataPacket) packet;
if (CompressionAlgorithm.fromId(comp.getAlgorithm()) == null) {
return;
}
break;
case SYMMETRIC_KEY_ENC:
// Not much we can check here
break;
case MARKER:
MarkerPacket m = (MarkerPacket) packet;
if (!Arrays.areEqual(
m.getEncoded(PacketFormat.CURRENT),
new byte[] {(byte) 0xca, 0x03, 0x50, 0x47, 0x50})) {
return;
}
break;
case LITERAL_DATA:
LiteralDataPacket lit = (LiteralDataPacket) packet;
if (lit.getFormat() != 'b' &&
lit.getFormat() != 'u' &&
lit.getFormat() != 't' &&
lit.getFormat() != 'l' &&
lit.getFormat() != '1' &&
lit.getFormat() != 'm') {
return;
}
break;
case SYM_ENC_INTEGRITY_PRO:
SymmetricEncIntegrityPacket seipd = (SymmetricEncIntegrityPacket) packet;
if (seipd.getVersion() == SymmetricEncIntegrityPacket.VERSION_1) {
break; // not much to check here
}
if (seipd.getVersion() != SymmetricEncIntegrityPacket.VERSION_2) {
if (SymmetricKeyAlgorithm.fromId(seipd.getCipherAlgorithm()) == null) {
return;
}
if (AEADAlgorithm.fromId(seipd.getAeadAlgorithm()) == null) {
return;
}
}
break;
case AEAD_ENC_DATA:
AEADEncDataPacket oed = (AEADEncDataPacket) packet;
if (SymmetricKeyAlgorithm.fromId(oed.getAlgorithm()) == null) {
return;
}
break;
case RESERVED: // this Packet Type ID MUST NOT be used
case PUBLIC_SUBKEY: // Never found at the start of a stream
case SECRET_SUBKEY: // Never found at the start of a stream
case TRUST: // Never found at the start of a stream
case MOD_DETECTION_CODE: // At the end of SED data - Never found at the start of a stream
case USER_ID: // Never found at the start of a stream
case USER_ATTRIBUTE: // Never found at the start of a stream
case PADDING: // At the end of messages (optionally padded message) or certificates
case EXPERIMENTAL_1: // experimental
case EXPERIMENTAL_2: // experimental
case EXPERIMENTAL_3: // experimental
case EXPERIMENTAL_4: // experimental
containsOpenPgpPackets = true;
isLikelyOpenPgpMessage = false;
return;
default:
return;
}
containsOpenPgpPackets = true;
if (packet.getPacketTag() != SYMMETRIC_KEY_ENC) {
isLikelyOpenPgpMessage = true;
}
}
private boolean startsWithIgnoringWhitespace(byte[] bytes, byte[] subsequence, int bufferLen) {
if (bufferLen == -1) {
return false;
}
for (int i = 0; i < bufferLen; i++) {
// Working on bytes is not trivial with unicode data, but its good enough here
if (Character.isWhitespace(bytes[i])) {
continue;
}
if ((i + subsequence.length) > bytes.length) {
return false;
}
for (int j = 0; j < subsequence.length; j++) {
if (bytes[i + j] != subsequence[j]) {
return false;
}
}
return true;
}
return false;
}
public boolean isAsciiArmored() {
return containsArmorHeader;
}
/**
* Return true, if the data is possibly binary OpenPGP.
* The criterion for this are less strict than for {@link #isLikelyOpenPgpMessage()},
* as it also accepts other OpenPGP packets at the beginning of the data stream.
* <p>
* Use with caution.
*
* @return true if data appears to be binary OpenPGP data
*/
public boolean isBinaryOpenPgp() {
return containsOpenPgpPackets;
}
/**
* Returns true, if the underlying data is very likely (more than 99,9%) an OpenPGP message.
* OpenPGP Message means here that it starts with either an {@link PGPEncryptedData},
* {@link PGPCompressedData}, {@link PGPOnePassSignature} or {@link PGPLiteralData} packet.
* The plausibility of these data packets is checked as far as possible.
*
* @return true if likely OpenPGP message
*/
public boolean isLikelyOpenPgpMessage() {
return isLikelyOpenPgpMessage;
}
public boolean isNonOpenPgp() {
return !isAsciiArmored() && !isBinaryOpenPgp();
}
}

View file

@ -1,8 +0,0 @@
// SPDX-FileCopyrightText: 2018 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
/**
* Classes used to decryption and verification of OpenPGP encrypted / signed data.
*/
package org.pgpainless.decryption_verification;

View file

@ -0,0 +1,321 @@
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.decryption_verification
import java.io.BufferedInputStream
import java.io.ByteArrayInputStream
import java.io.InputStream
import org.bouncycastle.bcpg.AEADEncDataPacket
import org.bouncycastle.bcpg.BCPGInputStream
import org.bouncycastle.bcpg.CompressedDataPacket
import org.bouncycastle.bcpg.LiteralDataPacket
import org.bouncycastle.bcpg.MarkerPacket
import org.bouncycastle.bcpg.OnePassSignaturePacket
import org.bouncycastle.bcpg.PacketFormat
import org.bouncycastle.bcpg.PacketTags.AEAD_ENC_DATA
import org.bouncycastle.bcpg.PacketTags.COMPRESSED_DATA
import org.bouncycastle.bcpg.PacketTags.EXPERIMENTAL_1
import org.bouncycastle.bcpg.PacketTags.EXPERIMENTAL_2
import org.bouncycastle.bcpg.PacketTags.EXPERIMENTAL_3
import org.bouncycastle.bcpg.PacketTags.EXPERIMENTAL_4
import org.bouncycastle.bcpg.PacketTags.LITERAL_DATA
import org.bouncycastle.bcpg.PacketTags.MARKER
import org.bouncycastle.bcpg.PacketTags.MOD_DETECTION_CODE
import org.bouncycastle.bcpg.PacketTags.ONE_PASS_SIGNATURE
import org.bouncycastle.bcpg.PacketTags.PADDING
import org.bouncycastle.bcpg.PacketTags.PUBLIC_KEY
import org.bouncycastle.bcpg.PacketTags.PUBLIC_KEY_ENC_SESSION
import org.bouncycastle.bcpg.PacketTags.PUBLIC_SUBKEY
import org.bouncycastle.bcpg.PacketTags.RESERVED
import org.bouncycastle.bcpg.PacketTags.SECRET_KEY
import org.bouncycastle.bcpg.PacketTags.SECRET_SUBKEY
import org.bouncycastle.bcpg.PacketTags.SIGNATURE
import org.bouncycastle.bcpg.PacketTags.SYMMETRIC_KEY_ENC
import org.bouncycastle.bcpg.PacketTags.SYMMETRIC_KEY_ENC_SESSION
import org.bouncycastle.bcpg.PacketTags.SYM_ENC_INTEGRITY_PRO
import org.bouncycastle.bcpg.PacketTags.TRUST
import org.bouncycastle.bcpg.PacketTags.USER_ATTRIBUTE
import org.bouncycastle.bcpg.PacketTags.USER_ID
import org.bouncycastle.bcpg.PublicKeyEncSessionPacket
import org.bouncycastle.bcpg.PublicKeyPacket
import org.bouncycastle.bcpg.SecretKeyPacket
import org.bouncycastle.bcpg.SignaturePacket
import org.bouncycastle.bcpg.SymmetricEncIntegrityPacket
import org.bouncycastle.bcpg.SymmetricKeyEncSessionPacket
import org.bouncycastle.util.Arrays
import org.pgpainless.algorithm.AEADAlgorithm
import org.pgpainless.algorithm.CompressionAlgorithm
import org.pgpainless.algorithm.HashAlgorithm
import org.pgpainless.algorithm.PublicKeyAlgorithm
import org.pgpainless.algorithm.SignatureType
import org.pgpainless.algorithm.SymmetricKeyAlgorithm
/**
* InputStream used to determine the nature of potential OpenPGP data.
*
* @param input underlying input stream
* @param check whether to perform the costly checking inside the constructor
*/
class OpenPGPAnimalSnifferInputStream(input: InputStream, check: Boolean) :
BufferedInputStream(input) {
private val buffer: ByteArray
private val bufferLen: Int
private var containsArmorHeader: Boolean = false
private var containsOpenPgpPackets: Boolean = false
private var resemblesMessage: Boolean = false
init {
mark(MAX_BUFFER_SIZE)
buffer = ByteArray(MAX_BUFFER_SIZE)
bufferLen = read(buffer)
reset()
if (check) {
inspectBuffer()
}
}
constructor(input: InputStream) : this(input, true)
/** Return true, if the underlying data is ASCII armored. */
val isAsciiArmored: Boolean
get() = containsArmorHeader
/**
* Return true, if the data is possibly binary OpenPGP. The criterion for this are less strict
* than for [resemblesMessage], as it also accepts other OpenPGP packets at the beginning of the
* data stream.
*
* <p>
* Use with caution.
*
* @return true if data appears to be binary OpenPGP data
*/
val isBinaryOpenPgp: Boolean
get() = containsOpenPgpPackets
/**
* Returns true, if the underlying data is very likely (more than 99,9%) an OpenPGP message.
* OpenPGP Message means here that it starts with either a [PGPEncryptedData],
* [PGPCompressedData], [PGPOnePassSignature] or [PGPLiteralData] packet. The plausibility of
* these data packets is checked as far as possible.
*
* @return true if likely OpenPGP message
*/
val isLikelyOpenPgpMessage: Boolean
get() = resemblesMessage
/** Return true, if the underlying data is non-OpenPGP data. */
val isNonOpenPgp: Boolean
get() = !isAsciiArmored && !isBinaryOpenPgp
/** Costly perform a plausibility check of the first encountered OpenPGP packet. */
fun inspectBuffer() {
if (checkForAsciiArmor()) {
return
}
checkForBinaryOpenPgp()
}
private fun checkForAsciiArmor(): Boolean {
if (startsWithIgnoringWhitespace(buffer, ARMOR_HEADER, bufferLen)) {
containsArmorHeader = true
return true
}
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.
*
* <p>
* 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 fun checkForBinaryOpenPgp() {
if (bufferLen == -1) {
// empty data
return
}
val bufferIn = ByteArrayInputStream(buffer, 0, bufferLen)
val pIn = BCPGInputStream(bufferIn)
try {
nonExhaustiveParseAndCheckPlausibility(pIn)
} catch (e: Exception) {
return
}
}
private fun nonExhaustiveParseAndCheckPlausibility(packetIn: BCPGInputStream) {
val packet = packetIn.readPacket()
when (packet.packetTag) {
PUBLIC_KEY_ENC_SESSION -> {
packet as PublicKeyEncSessionPacket
if (PublicKeyAlgorithm.fromId(packet.algorithm) == null) {
return
}
}
SIGNATURE -> {
packet as SignaturePacket
if (SignatureType.fromCode(packet.signatureType) == null) {
return
}
if (PublicKeyAlgorithm.fromId(packet.keyAlgorithm) == null) {
return
}
if (HashAlgorithm.fromId(packet.hashAlgorithm) == null) {
return
}
}
ONE_PASS_SIGNATURE -> {
packet as OnePassSignaturePacket
if (SignatureType.fromCode(packet.signatureType) == null) {
return
}
if (PublicKeyAlgorithm.fromId(packet.keyAlgorithm) == null) {
return
}
if (HashAlgorithm.fromId(packet.hashAlgorithm) == null) {
return
}
}
SYMMETRIC_KEY_ENC_SESSION -> {
packet as SymmetricKeyEncSessionPacket
if (SymmetricKeyAlgorithm.fromId(packet.encAlgorithm) == null) {
return
}
}
SECRET_KEY -> {
packet as SecretKeyPacket
val publicKey = packet.publicKeyPacket
if (PublicKeyAlgorithm.fromId(publicKey.algorithm) == null) {
return
}
if (publicKey.version !in 3..6) {
return
}
}
PUBLIC_KEY -> {
packet as PublicKeyPacket
if (PublicKeyAlgorithm.fromId(packet.algorithm) == null) {
return
}
if (packet.version !in 3..6) {
return
}
}
COMPRESSED_DATA -> {
packet as CompressedDataPacket
if (CompressionAlgorithm.fromId(packet.algorithm) == null) {
return
}
}
SYMMETRIC_KEY_ENC -> {
// Not much we can check here
}
MARKER -> {
packet as MarkerPacket
if (!Arrays.areEqual(
packet.getEncoded(PacketFormat.CURRENT),
byteArrayOf(0xca.toByte(), 0x03, 0x50, 0x47, 0x50),
)) {
return
}
}
LITERAL_DATA -> {
packet as LiteralDataPacket
if (packet.format.toChar() !in charArrayOf('b', 'u', 't', 'l', '1', 'm')) {
return
}
}
SYM_ENC_INTEGRITY_PRO -> {
packet as SymmetricEncIntegrityPacket
if (packet.version !in
intArrayOf(
SymmetricEncIntegrityPacket.VERSION_1,
SymmetricEncIntegrityPacket.VERSION_2)) {
return
}
if (packet.version == SymmetricEncIntegrityPacket.VERSION_2) {
if (SymmetricKeyAlgorithm.fromId(packet.cipherAlgorithm) == null) {
return
}
if (AEADAlgorithm.fromId(packet.aeadAlgorithm) == null) {
return
}
}
}
AEAD_ENC_DATA -> {
packet as AEADEncDataPacket
if (SymmetricKeyAlgorithm.fromId(packet.algorithm.toInt()) == null) {
return
}
}
RESERVED, // this Packet Type ID MUST NOT be used
PUBLIC_SUBKEY, // Never found at the start of a stream
SECRET_SUBKEY, // Never found at the start of a stream
TRUST, // Never found at the start of a stream
MOD_DETECTION_CODE, // At the end of SED data - Never found at the start of a stream
USER_ID, // Never found at the start of a stream
USER_ATTRIBUTE, // Never found at the start of a stream
PADDING, // At the end of messages (optionally padded message) or certificates
EXPERIMENTAL_1, // experimental
EXPERIMENTAL_2, // experimental
EXPERIMENTAL_3, // experimental
EXPERIMENTAL_4 -> { // experimental
containsOpenPgpPackets = true
resemblesMessage = false
return
}
else -> return
}
containsOpenPgpPackets = true
if (packet.packetTag != SYMMETRIC_KEY_ENC) {
resemblesMessage = true
}
}
private fun startsWithIgnoringWhitespace(
bytes: ByteArray,
subSequence: CharSequence,
bufferLen: Int
): Boolean {
if (bufferLen == -1) {
return false
}
for (i in 0 until bufferLen) {
// Working on bytes is not trivial with unicode data, but its good enough here
if (Character.isWhitespace(bytes[i].toInt())) {
continue
}
if ((i + subSequence.length) > bytes.size) {
return false
}
for (j in subSequence.indices) {
if (bytes[i + j].toInt().toChar() != subSequence[j]) {
return false
}
}
return true
}
return false
}
companion object {
const val ARMOR_HEADER = "-----BEGIN PGP "
const val MAX_BUFFER_SIZE = 8192 * 2
}
}

View file

@ -1114,7 +1114,7 @@ class OpenPgpMessageInputStream(
metadata: Layer, metadata: Layer,
api: PGPainless api: PGPainless
): OpenPgpMessageInputStream { ): OpenPgpMessageInputStream {
val openPgpIn = OpenPgpInputStream(inputStream) val openPgpIn = OpenPGPAnimalSnifferInputStream(inputStream)
openPgpIn.reset() openPgpIn.reset()
if (openPgpIn.isNonOpenPgp || options.isForceNonOpenPgpData()) { if (openPgpIn.isNonOpenPgp || options.isForceNonOpenPgpData()) {

View file

@ -21,7 +21,7 @@ import org.bouncycastle.openpgp.PGPSignature
import org.bouncycastle.openpgp.PGPUtil import org.bouncycastle.openpgp.PGPUtil
import org.bouncycastle.util.io.Streams import org.bouncycastle.util.io.Streams
import org.pgpainless.algorithm.HashAlgorithm import org.pgpainless.algorithm.HashAlgorithm
import org.pgpainless.decryption_verification.OpenPgpInputStream import org.pgpainless.decryption_verification.OpenPGPAnimalSnifferInputStream
import org.pgpainless.key.OpenPgpFingerprint import org.pgpainless.key.OpenPgpFingerprint
import org.pgpainless.key.util.KeyRingUtils import org.pgpainless.key.util.KeyRingUtils
@ -422,7 +422,7 @@ class ArmorUtils {
@JvmStatic @JvmStatic
@Throws(IOException::class) @Throws(IOException::class)
fun getDecoderStream(inputStream: InputStream): InputStream = fun getDecoderStream(inputStream: InputStream): InputStream =
OpenPgpInputStream(inputStream).let { OpenPGPAnimalSnifferInputStream(inputStream).let {
if (it.isAsciiArmored) { if (it.isAsciiArmored) {
PGPUtil.getDecoderStream(ArmoredInputStreamFactory.get(it)) PGPUtil.getDecoderStream(ArmoredInputStreamFactory.get(it))
} else { } else {

View file

@ -30,7 +30,7 @@ import org.pgpainless.encryption_signing.ProducerOptions;
import org.pgpainless.encryption_signing.SigningOptions; import org.pgpainless.encryption_signing.SigningOptions;
import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector;
public class OpenPgpInputStreamTest { public class OpenPGPAnimalSnifferInputStreamTest {
private static final Random RANDOM = new Random(); private static final Random RANDOM = new Random();
@ -40,7 +40,7 @@ public class OpenPgpInputStreamTest {
RANDOM.nextBytes(randomBytes); RANDOM.nextBytes(randomBytes);
ByteArrayInputStream randomIn = new ByteArrayInputStream(randomBytes); ByteArrayInputStream randomIn = new ByteArrayInputStream(randomBytes);
OpenPgpInputStream openPgpInputStream = new OpenPgpInputStream(randomIn); OpenPGPAnimalSnifferInputStream openPgpInputStream = new OpenPGPAnimalSnifferInputStream(randomIn);
assertFalse(openPgpInputStream.isAsciiArmored()); assertFalse(openPgpInputStream.isAsciiArmored());
assertFalse(openPgpInputStream.isLikelyOpenPgpMessage(), assertFalse(openPgpInputStream.isLikelyOpenPgpMessage(),
Hex.toHexString(randomBytes, 0, 150)); Hex.toHexString(randomBytes, 0, 150));
@ -56,7 +56,7 @@ public class OpenPgpInputStreamTest {
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
byte[] randomBytes = new byte[OpenPgpInputStream.MAX_BUFFER_SIZE * 10]; byte[] randomBytes = new byte[OpenPGPAnimalSnifferInputStream.MAX_BUFFER_SIZE * 10];
RANDOM.nextBytes(randomBytes); RANDOM.nextBytes(randomBytes);
ByteArrayOutputStream compressedDataPacket = new ByteArrayOutputStream(); ByteArrayOutputStream compressedDataPacket = new ByteArrayOutputStream();
@ -65,7 +65,7 @@ public class OpenPgpInputStreamTest {
compressor.write(randomBytes); compressor.write(randomBytes);
compressor.close(); compressor.close();
OpenPgpInputStream inputStream = new OpenPgpInputStream(new ByteArrayInputStream(compressedDataPacket.toByteArray())); OpenPGPAnimalSnifferInputStream inputStream = new OpenPGPAnimalSnifferInputStream(new ByteArrayInputStream(compressedDataPacket.toByteArray()));
assertFalse(inputStream.isAsciiArmored()); assertFalse(inputStream.isAsciiArmored());
assertFalse(inputStream.isNonOpenPgp()); assertFalse(inputStream.isNonOpenPgp());
assertTrue(inputStream.isBinaryOpenPgp()); assertTrue(inputStream.isBinaryOpenPgp());
@ -90,7 +90,7 @@ public class OpenPgpInputStreamTest {
"-----END PGP MESSAGE-----"; "-----END PGP MESSAGE-----";
ByteArrayInputStream asciiIn = new ByteArrayInputStream(asciiArmoredMessage.getBytes(StandardCharsets.UTF_8)); ByteArrayInputStream asciiIn = new ByteArrayInputStream(asciiArmoredMessage.getBytes(StandardCharsets.UTF_8));
OpenPgpInputStream openPgpInputStream = new OpenPgpInputStream(asciiIn); OpenPGPAnimalSnifferInputStream openPgpInputStream = new OpenPGPAnimalSnifferInputStream(asciiIn);
assertTrue(openPgpInputStream.isAsciiArmored()); assertTrue(openPgpInputStream.isAsciiArmored());
assertFalse(openPgpInputStream.isNonOpenPgp()); assertFalse(openPgpInputStream.isNonOpenPgp());
@ -663,9 +663,9 @@ public class OpenPgpInputStreamTest {
@Test @Test
public void longAsciiArmoredMessageIsAsciiArmored() throws IOException { public void longAsciiArmoredMessageIsAsciiArmored() throws IOException {
byte[] asciiArmoredBytes = longAsciiArmoredMessage.getBytes(StandardCharsets.UTF_8); byte[] asciiArmoredBytes = longAsciiArmoredMessage.getBytes(StandardCharsets.UTF_8);
assertTrue(asciiArmoredBytes.length > OpenPgpInputStream.MAX_BUFFER_SIZE); assertTrue(asciiArmoredBytes.length > OpenPGPAnimalSnifferInputStream.MAX_BUFFER_SIZE);
ByteArrayInputStream asciiIn = new ByteArrayInputStream(asciiArmoredBytes); ByteArrayInputStream asciiIn = new ByteArrayInputStream(asciiArmoredBytes);
OpenPgpInputStream openPgpInputStream = new OpenPgpInputStream(asciiIn); OpenPGPAnimalSnifferInputStream openPgpInputStream = new OpenPGPAnimalSnifferInputStream(asciiIn);
assertTrue(openPgpInputStream.isAsciiArmored()); assertTrue(openPgpInputStream.isAsciiArmored());
assertFalse(openPgpInputStream.isNonOpenPgp()); assertFalse(openPgpInputStream.isNonOpenPgp());
@ -694,7 +694,7 @@ public class OpenPgpInputStreamTest {
byte[] binaryBytes = binaryOut.toByteArray(); byte[] binaryBytes = binaryOut.toByteArray();
ByteArrayInputStream binaryIn = new ByteArrayInputStream(binaryBytes); ByteArrayInputStream binaryIn = new ByteArrayInputStream(binaryBytes);
OpenPgpInputStream openPgpInputStream = new OpenPgpInputStream(binaryIn); OpenPGPAnimalSnifferInputStream openPgpInputStream = new OpenPGPAnimalSnifferInputStream(binaryIn);
assertTrue(openPgpInputStream.isBinaryOpenPgp()); assertTrue(openPgpInputStream.isBinaryOpenPgp());
assertFalse(openPgpInputStream.isAsciiArmored()); assertFalse(openPgpInputStream.isAsciiArmored());
@ -714,7 +714,7 @@ public class OpenPgpInputStreamTest {
byte[] binaryBytes = binaryOut.toByteArray(); byte[] binaryBytes = binaryOut.toByteArray();
ByteArrayInputStream binaryIn = new ByteArrayInputStream(binaryBytes); ByteArrayInputStream binaryIn = new ByteArrayInputStream(binaryBytes);
OpenPgpInputStream openPgpInputStream = new OpenPgpInputStream(binaryIn); OpenPGPAnimalSnifferInputStream openPgpInputStream = new OpenPGPAnimalSnifferInputStream(binaryIn);
assertTrue(openPgpInputStream.isBinaryOpenPgp()); assertTrue(openPgpInputStream.isBinaryOpenPgp());
assertFalse(openPgpInputStream.isAsciiArmored()); assertFalse(openPgpInputStream.isAsciiArmored());
@ -728,7 +728,7 @@ public class OpenPgpInputStreamTest {
@Test @Test
public void emptyStreamTest() throws IOException { public void emptyStreamTest() throws IOException {
ByteArrayInputStream in = new ByteArrayInputStream(new byte[0]); ByteArrayInputStream in = new ByteArrayInputStream(new byte[0]);
OpenPgpInputStream openPgpInputStream = new OpenPgpInputStream(in); OpenPGPAnimalSnifferInputStream openPgpInputStream = new OpenPGPAnimalSnifferInputStream(in);
assertFalse(openPgpInputStream.isBinaryOpenPgp()); assertFalse(openPgpInputStream.isBinaryOpenPgp());
assertFalse(openPgpInputStream.isAsciiArmored()); assertFalse(openPgpInputStream.isAsciiArmored());
@ -755,7 +755,7 @@ public class OpenPgpInputStreamTest {
byte[] binary = signedOut.toByteArray(); byte[] binary = signedOut.toByteArray();
OpenPgpInputStream openPgpIn = new OpenPgpInputStream(new ByteArrayInputStream(binary)); OpenPGPAnimalSnifferInputStream openPgpIn = new OpenPGPAnimalSnifferInputStream(new ByteArrayInputStream(binary));
assertFalse(openPgpIn.isAsciiArmored()); assertFalse(openPgpIn.isAsciiArmored());
assertTrue(openPgpIn.isLikelyOpenPgpMessage()); assertTrue(openPgpIn.isLikelyOpenPgpMessage());
} }

View file

@ -10,7 +10,7 @@ import java.io.OutputStream
import kotlin.jvm.Throws import kotlin.jvm.Throws
import org.bouncycastle.util.io.Streams import org.bouncycastle.util.io.Streams
import org.pgpainless.PGPainless import org.pgpainless.PGPainless
import org.pgpainless.decryption_verification.OpenPgpInputStream import org.pgpainless.decryption_verification.OpenPGPAnimalSnifferInputStream
import org.pgpainless.util.ArmoredOutputStreamFactory import org.pgpainless.util.ArmoredOutputStreamFactory
import sop.Ready import sop.Ready
import sop.exception.SOPGPException import sop.exception.SOPGPException
@ -27,7 +27,7 @@ class ArmorImpl(private val api: PGPainless) : 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 = OpenPgpInputStream(data) val openPgpIn = OpenPGPAnimalSnifferInputStream(data)
openPgpIn.reset() openPgpIn.reset()
if (openPgpIn.isAsciiArmored) { if (openPgpIn.isAsciiArmored) {

View file

@ -15,7 +15,7 @@ import org.bouncycastle.openpgp.PGPOnePassSignatureList
import org.bouncycastle.openpgp.PGPSignatureList import org.bouncycastle.openpgp.PGPSignatureList
import org.bouncycastle.util.io.Streams import org.bouncycastle.util.io.Streams
import org.pgpainless.PGPainless import org.pgpainless.PGPainless
import org.pgpainless.decryption_verification.OpenPgpInputStream import org.pgpainless.decryption_verification.OpenPGPAnimalSnifferInputStream
import org.pgpainless.decryption_verification.cleartext_signatures.ClearsignedMessageUtil import org.pgpainless.decryption_verification.cleartext_signatures.ClearsignedMessageUtil
import org.pgpainless.exception.WrongConsumingMethodException import org.pgpainless.exception.WrongConsumingMethodException
import org.pgpainless.util.ArmoredOutputStreamFactory import org.pgpainless.util.ArmoredOutputStreamFactory
@ -35,7 +35,7 @@ class InlineDetachImpl(private val api: PGPainless) : InlineDetach {
private val sigOut = ByteArrayOutputStream() private val sigOut = ByteArrayOutputStream()
override fun writeTo(outputStream: OutputStream): Signatures { override fun writeTo(outputStream: OutputStream): Signatures {
var pgpIn = OpenPgpInputStream(messageInputStream) var pgpIn = OpenPGPAnimalSnifferInputStream(messageInputStream)
if (pgpIn.isNonOpenPgp) { if (pgpIn.isNonOpenPgp) {
throw SOPGPException.BadData("Data appears to be non-OpenPGP.") throw SOPGPException.BadData("Data appears to be non-OpenPGP.")
} }
@ -61,7 +61,7 @@ class InlineDetachImpl(private val api: PGPainless) : InlineDetach {
} }
// else just dearmor // else just dearmor
pgpIn = OpenPgpInputStream(armorIn) pgpIn = OpenPGPAnimalSnifferInputStream(armorIn)
} }
// If data was not using cleartext signature framework // If data was not using cleartext signature framework