diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/cleartext_signatures/ClearsignedMessageUtil.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/cleartext_signatures/ClearsignedMessageUtil.java index ee166c99..cd0f6b35 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/cleartext_signatures/ClearsignedMessageUtil.java +++ b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/cleartext_signatures/ClearsignedMessageUtil.java @@ -42,7 +42,13 @@ public final class ClearsignedMessageUtil { public static PGPSignatureList detachSignaturesFromInbandClearsignedMessage(InputStream clearsignedInputStream, OutputStream messageOutputStream) throws IOException, WrongConsumingMethodException { - ArmoredInputStream in = ArmoredInputStreamFactory.get(clearsignedInputStream); + ArmoredInputStream in; + if (clearsignedInputStream instanceof ArmoredInputStream) { + in = (ArmoredInputStream) clearsignedInputStream; + } else { + in = ArmoredInputStreamFactory.get(clearsignedInputStream); + } + if (!in.isClearText()) { throw new WrongConsumingMethodException("Message is not using the Cleartext Signature Framework."); } diff --git a/pgpainless-sop/src/main/java/org/pgpainless/sop/InlineDetachImpl.java b/pgpainless-sop/src/main/java/org/pgpainless/sop/InlineDetachImpl.java index f23434c2..517f9e9e 100644 --- a/pgpainless-sop/src/main/java/org/pgpainless/sop/InlineDetachImpl.java +++ b/pgpainless-sop/src/main/java/org/pgpainless/sop/InlineDetachImpl.java @@ -14,8 +14,8 @@ import org.bouncycastle.bcpg.ArmoredOutputStream; import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignatureList; import org.bouncycastle.util.io.Streams; -import org.pgpainless.exception.WrongConsumingMethodException; import org.pgpainless.decryption_verification.cleartext_signatures.ClearsignedMessageUtil; +import org.pgpainless.exception.WrongConsumingMethodException; import org.pgpainless.util.ArmoredOutputStreamFactory; import sop.ReadyWithResult; import sop.Signatures; diff --git a/pgpainless-sop/src/test/java/org/pgpainless/sop/SignTest.java b/pgpainless-sop/src/test/java/org/pgpainless/sop/DetachedSignTest.java similarity index 99% rename from pgpainless-sop/src/test/java/org/pgpainless/sop/SignTest.java rename to pgpainless-sop/src/test/java/org/pgpainless/sop/DetachedSignTest.java index 7e2d55dd..c6fcc267 100644 --- a/pgpainless-sop/src/test/java/org/pgpainless/sop/SignTest.java +++ b/pgpainless-sop/src/test/java/org/pgpainless/sop/DetachedSignTest.java @@ -25,7 +25,7 @@ import sop.Verification; import sop.enums.SignAs; import sop.exception.SOPGPException; -public class SignTest { +public class DetachedSignTest { private static SOP sop; private static byte[] key; diff --git a/pgpainless-sop/src/test/java/org/pgpainless/sop/DetachInbandSignatureAndMessageTest.java b/pgpainless-sop/src/test/java/org/pgpainless/sop/InlineDetachTest.java similarity index 59% rename from pgpainless-sop/src/test/java/org/pgpainless/sop/DetachInbandSignatureAndMessageTest.java rename to pgpainless-sop/src/test/java/org/pgpainless/sop/InlineDetachTest.java index b76f069c..9df0345a 100644 --- a/pgpainless-sop/src/test/java/org/pgpainless/sop/DetachInbandSignatureAndMessageTest.java +++ b/pgpainless-sop/src/test/java/org/pgpainless/sop/InlineDetachTest.java @@ -29,12 +29,13 @@ import sop.ByteArrayAndResult; import sop.SOP; import sop.Signatures; import sop.Verification; +import sop.enums.InlineSignAs; -public class DetachInbandSignatureAndMessageTest { +public class InlineDetachTest { + private static final SOP sop = new SOPImpl(); @Test - public void testDetachingOfInbandSignaturesAndMessage() throws IOException, PGPException { - SOP sop = new SOPImpl(); + public void detachCleartextSignedMessage() throws IOException { byte[] key = sop.generateKey() .userId("Alice ") .generate() @@ -44,22 +45,15 @@ public class DetachInbandSignatureAndMessageTest { // Create a cleartext signed message byte[] data = "Hello, World\n".getBytes(StandardCharsets.UTF_8); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - EncryptionStream signingStream = PGPainless.encryptAndOrSign() - .onOutputStream(out) - .withOptions( - ProducerOptions.sign( - SigningOptions.get() - .addDetachedSignature(SecretKeyRingProtector.unprotectedKeys(), - secretKey, DocumentSignatureType.BINARY_DOCUMENT) - ).setCleartextSigned()); - - Streams.pipeAll(new ByteArrayInputStream(data), signingStream); - signingStream.close(); + byte[] cleartextSigned = sop.inlineSign() + .key(key) + .withKeyPassword("sw0rdf1sh") + .mode(InlineSignAs.CleartextSigned) + .data(data).getBytes(); // actually detach the message ByteArrayAndResult detachedMsg = sop.inlineDetach() - .message(out.toByteArray()) + .message(cleartextSigned) .toByteArrayAndResult(); byte[] message = detachedMsg.getBytes(); @@ -75,4 +69,35 @@ public class DetachInbandSignatureAndMessageTest { assertEquals(new OpenPgpV4Fingerprint(secretKey).toString(), verificationList.get(0).getSigningCertFingerprint()); assertArrayEquals(data, message); } + + @Test + public void detachInbandSignedMessage() throws IOException { + byte[] key = sop.generateKey() + .userId("Alice ") + .generate() + .getBytes(); + byte[] cert = sop.extractCert().key(key).getBytes(); + + byte[] data = "Hello, World\n".getBytes(StandardCharsets.UTF_8); + byte[] inlineSigned = sop.inlineSign() + .key(key) + .data(data).getBytes(); + + // actually detach the message + ByteArrayAndResult detachedMsg = sop.inlineDetach() + .message(inlineSigned) + .toByteArrayAndResult(); + + byte[] message = detachedMsg.getBytes(); + byte[] signature = detachedMsg.getResult().getBytes(); + + List verificationList = sop.verify() + .cert(cert) + .signatures(signature) + .data(message); + + assertFalse(verificationList.isEmpty()); + assertEquals(1, verificationList.size()); + assertArrayEquals(data, message); + } } diff --git a/pgpainless-sop/src/test/java/org/pgpainless/sop/InlineSignVerifyRoundtripTest.java b/pgpainless-sop/src/test/java/org/pgpainless/sop/InlineSignVerifyRoundtripTest.java new file mode 100644 index 00000000..ee892501 --- /dev/null +++ b/pgpainless-sop/src/test/java/org/pgpainless/sop/InlineSignVerifyRoundtripTest.java @@ -0,0 +1,81 @@ +// SPDX-FileCopyrightText: 2022 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.sop; + +import org.junit.jupiter.api.Test; +import sop.ByteArrayAndResult; +import sop.SOP; +import sop.Verification; +import sop.enums.InlineSignAs; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; + +public class InlineSignVerifyRoundtripTest { + + private static final SOP sop = new SOPImpl(); + + @Test + public void testInlineSignAndVerifyWithCleartextSignatures() throws IOException { + byte[] key = sop.generateKey() + .userId("Werner") + .withKeyPassword("sw0rdf1sh") + .generate().getBytes(); + + byte[] cert = sop.extractCert() + .key(key).getBytes(); + + byte[] message = "If you want something different, create a new protocol but don't try to\npush it onto a working system.\n".getBytes(StandardCharsets.UTF_8); + + byte[] inlineSigned = sop.inlineSign() + .key(key) + .withKeyPassword("sw0rdf1sh") + .mode(InlineSignAs.CleartextSigned) + .data(message).getBytes(); + + ByteArrayAndResult> result = sop.inlineVerify() + .cert(cert) + .data(inlineSigned) + .toByteArrayAndResult(); + + byte[] verified = result.getBytes(); + + assertFalse(result.getResult().isEmpty()); + assertArrayEquals(message, verified); + } + + @Test + public void testInlineSignAndVerifyWithBinarySignatures() throws IOException { + byte[] key = sop.generateKey() + .userId("Werner") + .withKeyPassword("sw0rdf1sh") + .generate().getBytes(); + + byte[] cert = sop.extractCert() + .key(key).getBytes(); + + byte[] message = "Yes, this is what has been deployed worldwide for years in millions of\ninstallations (decryption wise) and is meanwhile in active use.\n".getBytes(StandardCharsets.UTF_8); + + byte[] inlineSigned = sop.inlineSign() + .key(key) + .withKeyPassword("sw0rdf1sh") + .data(message).getBytes(); + + ByteArrayAndResult> result = sop.inlineVerify() + .cert(cert) + .data(inlineSigned) + .toByteArrayAndResult(); + + byte[] verified = result.getBytes(); + + assertFalse(result.getResult().isEmpty()); + assertArrayEquals(message, verified); + } + +}