diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStreamFactory.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStreamFactory.java index 686876a9..685417fa 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStreamFactory.java +++ b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStreamFactory.java @@ -15,6 +15,7 @@ */ package org.pgpainless.decryption_verification; +import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -59,6 +60,7 @@ import org.pgpainless.algorithm.StreamEncoding; import org.pgpainless.algorithm.SymmetricKeyAlgorithm; import org.pgpainless.exception.MessageNotIntegrityProtectedException; import org.pgpainless.exception.MissingDecryptionMethodException; +import org.pgpainless.exception.MissingLiteralDataException; import org.pgpainless.exception.UnacceptableAlgorithmException; import org.pgpainless.implementation.ImplementationFactory; import org.pgpainless.key.OpenPgpV4Fingerprint; @@ -91,7 +93,8 @@ public final class DecryptionStreamFactory { public static DecryptionStream create(@Nonnull InputStream inputStream, @Nonnull ConsumerOptions options) throws PGPException, IOException { - InputStream pgpInputStream = inputStream; + BufferedInputStream bufferedIn = new BufferedInputStream(inputStream); + bufferedIn.mark(200); DecryptionStreamFactory factory = new DecryptionStreamFactory(options); for (PGPSignature signature : options.getDetachedSignatures()) { @@ -106,10 +109,19 @@ public final class DecryptionStreamFactory { } PGPObjectFactory objectFactory = new PGPObjectFactory( - PGPUtil.getDecoderStream(inputStream), keyFingerprintCalculator); - pgpInputStream = factory.processPGPPackets(objectFactory, 1); + PGPUtil.getDecoderStream(bufferedIn), keyFingerprintCalculator); - return new DecryptionStream(pgpInputStream, factory.resultBuilder, factory.integrityProtectedStreams); + try { + // Parse OpenPGP message + inputStream = factory.processPGPPackets(objectFactory, 1); + } catch (MissingLiteralDataException e) { + // Not an OpenPGP message. Reset the buffered stream to parse the message as arbitrary binary data + // to allow for detached signature verification. + bufferedIn.reset(); + inputStream = bufferedIn; + } + + return new DecryptionStream(inputStream, factory.resultBuilder, factory.integrityProtectedStreams); } private InputStream processPGPPackets(@Nonnull PGPObjectFactory objectFactory, int depth) throws IOException, PGPException { @@ -132,7 +144,7 @@ public final class DecryptionStreamFactory { } } - throw new PGPException("No Literal Data Packet found"); + throw new MissingLiteralDataException("No Literal Data Packet found"); } private InputStream processPGPEncryptedDataList(PGPEncryptedDataList pgpEncryptedDataList, int depth) diff --git a/pgpainless-core/src/main/java/org/pgpainless/exception/MissingLiteralDataException.java b/pgpainless-core/src/main/java/org/pgpainless/exception/MissingLiteralDataException.java new file mode 100644 index 00000000..aca46a41 --- /dev/null +++ b/pgpainless-core/src/main/java/org/pgpainless/exception/MissingLiteralDataException.java @@ -0,0 +1,28 @@ +/* + * Copyright 2021 Paul Schaub. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.pgpainless.exception; + +import org.bouncycastle.openpgp.PGPException; + +/** + * Exception that gets thrown if a {@link org.bouncycastle.bcpg.LiteralDataPacket} is expected, but not found. + */ +public class MissingLiteralDataException extends PGPException { + + public MissingLiteralDataException(String message) { + super(message); + } +}