From 15736586dd901fabecb99288e9cdf23f68bf40a1 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Sun, 10 Oct 2021 16:34:17 +0200 Subject: [PATCH] SOP: Add convenience methods to deal with byte arrays --- .../java/org/pgpainless/sop/ArmorTest.java | 5 +- .../DetachInbandSignatureAndMessageTest.java | 78 +++++++++++++++ .../sop/EncryptDecryptRoundTripTest.java | 96 ++++++++++--------- .../org/pgpainless/sop/ExtractCertTest.java | 5 +- .../java/org/pgpainless/sop/SignTest.java | 53 +++++----- .../cli/picocli/commands/ArmorCmdTest.java | 7 +- .../cli/picocli/commands/DearmorCmdTest.java | 7 +- .../cli/picocli/commands/DecryptCmdTest.java | 25 ++--- .../cli/picocli/commands/EncryptCmdTest.java | 21 ++-- .../picocli/commands/ExtractCertCmdTest.java | 7 +- .../sop/cli/picocli/commands/SignCmdTest.java | 11 ++- .../cli/picocli/commands/VerifyCmdTest.java | 17 ++-- .../src/main/java/sop/ByteArrayAndResult.java | 26 +++++ sop-java/src/main/java/sop/Ready.java | 12 +++ .../src/main/java/sop/ReadyWithResult.java | 13 ++- .../src/main/java/sop/operation/Armor.java | 11 +++ .../src/main/java/sop/operation/Dearmor.java | 11 +++ .../src/main/java/sop/operation/Decrypt.java | 35 +++++++ .../DetachInbandSignatureAndMessage.java | 22 +++++ .../src/main/java/sop/operation/Encrypt.java | 37 +++++++ .../main/java/sop/operation/ExtractCert.java | 13 ++- .../src/main/java/sop/operation/Sign.java | 21 ++++ .../src/main/java/sop/operation/Verify.java | 21 ++++ .../java/sop/operation/VerifySignatures.java | 23 +++++ .../java/sop/util/ReadyWithResultTest.java | 2 +- 25 files changed, 451 insertions(+), 128 deletions(-) create mode 100644 pgpainless-sop/src/test/java/org/pgpainless/sop/DetachInbandSignatureAndMessageTest.java diff --git a/pgpainless-sop/src/test/java/org/pgpainless/sop/ArmorTest.java b/pgpainless-sop/src/test/java/org/pgpainless/sop/ArmorTest.java index 24cb5908..ad6da440 100644 --- a/pgpainless-sop/src/test/java/org/pgpainless/sop/ArmorTest.java +++ b/pgpainless-sop/src/test/java/org/pgpainless/sop/ArmorTest.java @@ -7,7 +7,6 @@ package org.pgpainless.sop; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.security.InvalidAlgorithmParameterException; @@ -33,13 +32,13 @@ public class ArmorTest { byte[] knownGoodArmor = ArmorUtils.toAsciiArmoredString(data).getBytes(StandardCharsets.UTF_8); byte[] armored = new SOPImpl() .armor() - .data(new ByteArrayInputStream(data)) + .data(data) .getBytes(); assertArrayEquals(knownGoodArmor, armored); byte[] dearmored = new SOPImpl().dearmor() - .data(new ByteArrayInputStream(knownGoodArmor)) + .data(knownGoodArmor) .getBytes(); assertArrayEquals(data, dearmored); diff --git a/pgpainless-sop/src/test/java/org/pgpainless/sop/DetachInbandSignatureAndMessageTest.java b/pgpainless-sop/src/test/java/org/pgpainless/sop/DetachInbandSignatureAndMessageTest.java new file mode 100644 index 00000000..06c11226 --- /dev/null +++ b/pgpainless-sop/src/test/java/org/pgpainless/sop/DetachInbandSignatureAndMessageTest.java @@ -0,0 +1,78 @@ +// SPDX-FileCopyrightText: 2021 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.sop; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPSecretKeyRing; +import org.bouncycastle.util.io.Streams; +import org.junit.jupiter.api.Test; +import org.pgpainless.PGPainless; +import org.pgpainless.algorithm.DocumentSignatureType; +import org.pgpainless.encryption_signing.EncryptionStream; +import org.pgpainless.encryption_signing.ProducerOptions; +import org.pgpainless.encryption_signing.SigningOptions; +import org.pgpainless.key.OpenPgpV4Fingerprint; +import org.pgpainless.key.protection.SecretKeyRingProtector; +import sop.ByteArrayAndResult; +import sop.SOP; +import sop.Signatures; +import sop.Verification; + +public class DetachInbandSignatureAndMessageTest { + + @Test + public void testDetachingOfInbandSignaturesAndMessage() throws IOException, PGPException { + SOP sop = new SOPImpl(); + byte[] key = sop.generateKey() + .userId("Alice ") + .generate() + .getBytes(); + byte[] cert = sop.extractCert().key(key).getBytes(); + PGPSecretKeyRing secretKey = PGPainless.readKeyRing().secretKeyRing(key); + + // 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(); + + // actually detach the message + ByteArrayAndResult detachedMsg = sop.detachInbandSignatureAndMessage() + .message(out.toByteArray()) + .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()); + assertEquals(new OpenPgpV4Fingerprint(secretKey).toString(), verificationList.get(0).getSigningCertFingerprint()); + assertArrayEquals(data, message); + } +} diff --git a/pgpainless-sop/src/test/java/org/pgpainless/sop/EncryptDecryptRoundTripTest.java b/pgpainless-sop/src/test/java/org/pgpainless/sop/EncryptDecryptRoundTripTest.java index 9ef84724..f6f6c235 100644 --- a/pgpainless-sop/src/test/java/org/pgpainless/sop/EncryptDecryptRoundTripTest.java +++ b/pgpainless-sop/src/test/java/org/pgpainless/sop/EncryptDecryptRoundTripTest.java @@ -8,10 +8,11 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; +import org.bouncycastle.util.io.Streams; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import sop.ByteArrayAndResult; @@ -36,34 +37,35 @@ public class EncryptDecryptRoundTripTest { .generate() .getBytes(); aliceCert = sop.extractCert() - .key(new ByteArrayInputStream(aliceKey)) + .key(aliceKey) .getBytes(); bobKey = sop.generateKey() .userId("Bob ") .generate() .getBytes(); bobCert = sop.extractCert() - .key(new ByteArrayInputStream(bobKey)) + .key(bobKey) .getBytes(); } @Test public void basicRoundTripWithKey() throws IOException, SOPGPException.CertCannotSign { byte[] encrypted = sop.encrypt() - .signWith(new ByteArrayInputStream(aliceKey)) - .withCert(new ByteArrayInputStream(aliceCert)) - .withCert(new ByteArrayInputStream(bobCert)) - .plaintext(new ByteArrayInputStream(message)) + .signWith(aliceKey) + .withCert(aliceCert) + .withCert(bobCert) + .plaintext(message) .getBytes(); ByteArrayAndResult bytesAndResult = sop.decrypt() - .withKey(new ByteArrayInputStream(bobKey)) - .verifyWithCert(new ByteArrayInputStream(aliceCert)) - .ciphertext(new ByteArrayInputStream(encrypted)) - .toBytes(); + .withKey(bobKey) + .verifyWithCert(aliceCert) + .ciphertext(encrypted) + .toByteArrayAndResult(); - byte[] decrypted = bytesAndResult.getBytes(); - assertArrayEquals(message, decrypted); + ByteArrayOutputStream decrypted = new ByteArrayOutputStream(); + Streams.pipeAll(bytesAndResult.getInputStream(), decrypted); + assertArrayEquals(message, decrypted.toByteArray()); DecryptionResult result = bytesAndResult.getResult(); assertEquals(1, result.getVerifications().size()); @@ -78,20 +80,20 @@ public class EncryptDecryptRoundTripTest { .getBytes(); byte[] aliceCertNoArmor = sop.extractCert() .noArmor() - .key(new ByteArrayInputStream(aliceKeyNoArmor)) + .key(aliceKeyNoArmor) .getBytes(); byte[] encrypted = sop.encrypt() - .signWith(new ByteArrayInputStream(aliceKeyNoArmor)) - .withCert(new ByteArrayInputStream(aliceCertNoArmor)) + .signWith(aliceKeyNoArmor) + .withCert(aliceCertNoArmor) .noArmor() - .plaintext(new ByteArrayInputStream(message)) + .plaintext(message) .getBytes(); ByteArrayAndResult bytesAndResult = sop.decrypt() - .withKey(new ByteArrayInputStream(aliceKeyNoArmor)) - .verifyWithCert(new ByteArrayInputStream(aliceCertNoArmor)) - .ciphertext(new ByteArrayInputStream(encrypted)) - .toBytes(); + .withKey(aliceKeyNoArmor) + .verifyWithCert(aliceCertNoArmor) + .ciphertext(encrypted) + .toByteArrayAndResult(); byte[] decrypted = bytesAndResult.getBytes(); assertArrayEquals(message, decrypted); @@ -104,13 +106,13 @@ public class EncryptDecryptRoundTripTest { public void basicRoundTripWithPassword() throws IOException { byte[] encrypted = sop.encrypt() .withPassword("passphr4s3") - .plaintext(new ByteArrayInputStream(message)) + .plaintext(message) .getBytes(); ByteArrayAndResult bytesAndResult = sop.decrypt() .withPassword("passphr4s3") - .ciphertext(new ByteArrayInputStream(encrypted)) - .toBytes(); + .ciphertext(encrypted) + .toByteArrayAndResult(); byte[] decrypted = bytesAndResult.getBytes(); assertArrayEquals(message, decrypted); @@ -121,15 +123,15 @@ public class EncryptDecryptRoundTripTest { @Test public void roundTripWithDecryptionPasswordContainingWhitespace() throws IOException { - byte[] encrypted = sop.encrypt() - .withPassword("passphr4s3") - .plaintext(new ByteArrayInputStream(message)) - .getBytes(); - ByteArrayAndResult bytesAndResult = sop.decrypt() .withPassword("passphr4s3 ") // whitespace is removed - .ciphertext(new ByteArrayInputStream(encrypted)) - .toBytes(); + .ciphertext( + sop.encrypt() + .withPassword("passphr4s3") + .plaintext(message) + .getInputStream() + ) + .toByteArrayAndResult(); byte[] decrypted = bytesAndResult.getBytes(); assertArrayEquals(message, decrypted); @@ -142,13 +144,13 @@ public class EncryptDecryptRoundTripTest { public void roundTripWithEncryptionPasswordContainingWhitespace() throws IOException { byte[] encrypted = sop.encrypt() .withPassword("passphr4s3 ") - .plaintext(new ByteArrayInputStream(message)) + .plaintext(message) .getBytes(); ByteArrayAndResult bytesAndResult = sop.decrypt() .withPassword("passphr4s3 ") - .ciphertext(new ByteArrayInputStream(encrypted)) - .toBytes(); + .ciphertext(encrypted) + .toByteArrayAndResult(); byte[] decrypted = bytesAndResult.getBytes(); assertArrayEquals(message, decrypted); @@ -160,29 +162,29 @@ public class EncryptDecryptRoundTripTest { @Test public void encrypt_decryptAndVerifyYieldsNoSignatureException() throws IOException { byte[] encrypted = sop.encrypt() - .withCert(new ByteArrayInputStream(bobCert)) - .plaintext(new ByteArrayInputStream(message)) + .withCert(bobCert) + .plaintext(message) .getBytes(); assertThrows(SOPGPException.NoSignature.class, () -> sop .decrypt() - .withKey(new ByteArrayInputStream(bobKey)) - .verifyWithCert(new ByteArrayInputStream(aliceCert)) - .ciphertext(new ByteArrayInputStream(encrypted)) - .toBytes()); + .withKey(bobKey) + .verifyWithCert(aliceCert) + .ciphertext(encrypted) + .toByteArrayAndResult()); } @Test public void encrypt_decryptWithoutKeyOrPassphraseYieldsMissingArgException() throws IOException { byte[] encrypted = sop.encrypt() - .withCert(new ByteArrayInputStream(bobCert)) - .plaintext(new ByteArrayInputStream(message)) + .withCert(bobCert) + .plaintext(message) .getBytes(); assertThrows(SOPGPException.MissingArg.class, () -> sop .decrypt() - .ciphertext(new ByteArrayInputStream(encrypted)) - .toBytes()); + .ciphertext(encrypted) + .toByteArrayAndResult()); } @Test @@ -192,7 +194,7 @@ public class EncryptDecryptRoundTripTest { System.arraycopy(bobKey, 0, keys, aliceKey.length, bobKey.length); assertThrows(SOPGPException.BadData.class, () -> sop.decrypt() - .withKey(new ByteArrayInputStream(keys))); + .withKey(keys)); } @Test @@ -225,12 +227,12 @@ public class EncryptDecryptRoundTripTest { "-----END PGP PRIVATE KEY BLOCK-----"; assertThrows(SOPGPException.KeyIsProtected.class, () -> sop.decrypt() - .withKey(new ByteArrayInputStream(passwordProtectedKey.getBytes(StandardCharsets.UTF_8)))); + .withKey(passwordProtectedKey.getBytes(StandardCharsets.UTF_8))); } @Test public void verifyWith_noDataThrowsBadData() { assertThrows(SOPGPException.BadData.class, () -> sop.decrypt() - .verifyWithCert(new ByteArrayInputStream(new byte[0]))); + .verifyWithCert(new byte[0])); } } diff --git a/pgpainless-sop/src/test/java/org/pgpainless/sop/ExtractCertTest.java b/pgpainless-sop/src/test/java/org/pgpainless/sop/ExtractCertTest.java index 41546fe7..84a1f471 100644 --- a/pgpainless-sop/src/test/java/org/pgpainless/sop/ExtractCertTest.java +++ b/pgpainless-sop/src/test/java/org/pgpainless/sop/ExtractCertTest.java @@ -7,7 +7,6 @@ package org.pgpainless.sop; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -76,13 +75,13 @@ public class ExtractCertTest { assertArrayEquals( cert.getBytes(StandardCharsets.UTF_8), sop.extractCert() - .key(new ByteArrayInputStream(key.getBytes(StandardCharsets.UTF_8))) + .key(key.getBytes(StandardCharsets.UTF_8)) .getBytes()); } @Test public void emptyKeyDataYieldsBadData() { assertThrows(SOPGPException.BadData.class, () -> sop.extractCert() - .key(new ByteArrayInputStream(new byte[0]))); + .key(new byte[0])); } } diff --git a/pgpainless-sop/src/test/java/org/pgpainless/sop/SignTest.java b/pgpainless-sop/src/test/java/org/pgpainless/sop/SignTest.java index cf9f3ddd..3167618c 100644 --- a/pgpainless-sop/src/test/java/org/pgpainless/sop/SignTest.java +++ b/pgpainless-sop/src/test/java/org/pgpainless/sop/SignTest.java @@ -9,7 +9,6 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.security.InvalidAlgorithmParameterException; @@ -47,7 +46,7 @@ public class SignTest { .generate() .getBytes(); cert = sop.extractCert() - .key(new ByteArrayInputStream(key)) + .key(key) .getBytes(); data = "Hello, World\n".getBytes(StandardCharsets.UTF_8); } @@ -55,18 +54,18 @@ public class SignTest { @Test public void signArmored() throws IOException { byte[] signature = sop.sign() - .key(new ByteArrayInputStream(key)) - .data(new ByteArrayInputStream(data)) + .key(key) + .data(data) .getBytes(); assertTrue(new String(signature).startsWith("-----BEGIN PGP SIGNATURE-----")); List verifications = sop.verify() - .cert(new ByteArrayInputStream(cert)) + .cert(cert) .notAfter(new Date(new Date().getTime() + 10000)) .notBefore(new Date(new Date().getTime() - 10000)) - .signatures(new ByteArrayInputStream(signature)) - .data(new ByteArrayInputStream(data)); + .signatures(signature) + .data(data); assertEquals(1, verifications.size()); } @@ -74,19 +73,19 @@ public class SignTest { @Test public void signUnarmored() throws IOException { byte[] signature = sop.sign() - .key(new ByteArrayInputStream(key)) + .key(key) .noArmor() - .data(new ByteArrayInputStream(data)) + .data(data) .getBytes(); assertFalse(new String(signature).startsWith("-----BEGIN PGP SIGNATURE-----")); List verifications = sop.verify() - .cert(new ByteArrayInputStream(cert)) + .cert(cert) .notAfter(new Date(new Date().getTime() + 10000)) .notBefore(new Date(new Date().getTime() - 10000)) - .signatures(new ByteArrayInputStream(signature)) - .data(new ByteArrayInputStream(data)); + .signatures(signature) + .data(data); assertEquals(1, verifications.size()); } @@ -94,40 +93,40 @@ public class SignTest { @Test public void rejectSignatureAsTooOld() throws IOException { byte[] signature = sop.sign() - .key(new ByteArrayInputStream(key)) - .data(new ByteArrayInputStream(data)) + .key(key) + .data(data) .getBytes(); assertThrows(SOPGPException.NoSignature.class, () -> sop.verify() - .cert(new ByteArrayInputStream(cert)) + .cert(cert) .notAfter(new Date(new Date().getTime() - 10000)) // Sig is older - .signatures(new ByteArrayInputStream(signature)) - .data(new ByteArrayInputStream(data))); + .signatures(signature) + .data(data)); } @Test public void rejectSignatureAsTooYoung() throws IOException { byte[] signature = sop.sign() - .key(new ByteArrayInputStream(key)) - .data(new ByteArrayInputStream(data)) + .key(key) + .data(data) .getBytes(); assertThrows(SOPGPException.NoSignature.class, () -> sop.verify() - .cert(new ByteArrayInputStream(cert)) + .cert(cert) .notBefore(new Date(new Date().getTime() + 10000)) // Sig is younger - .signatures(new ByteArrayInputStream(signature)) - .data(new ByteArrayInputStream(data))); + .signatures(signature) + .data(data)); } @Test public void mode() throws IOException, PGPException { byte[] signature = sop.sign() .mode(SignAs.Text) - .key(new ByteArrayInputStream(key)) - .data(new ByteArrayInputStream(data)) + .key(key) + .data(data) .getBytes(); - PGPSignature sig = SignatureUtils.readSignatures(new ByteArrayInputStream(signature)).get(0); + PGPSignature sig = SignatureUtils.readSignatures(signature).get(0); assertEquals(SignatureType.CANONICAL_TEXT_DOCUMENT.getCode(), sig.getSignatureType()); } @@ -138,7 +137,7 @@ public class SignTest { PGPSecretKeyRingCollection collection = new PGPSecretKeyRingCollection(Arrays.asList(key1, key2)); byte[] keys = collection.getEncoded(); - assertThrows(SOPGPException.BadData.class, () -> sop.sign().key(new ByteArrayInputStream(keys))); + assertThrows(SOPGPException.BadData.class, () -> sop.sign().key(keys)); } @Test @@ -147,7 +146,7 @@ public class SignTest { .modernKeyRing("Alice", "passphrase"); byte[] bytes = key.getEncoded(); - assertThrows(SOPGPException.KeyIsProtected.class, () -> sop.sign().key(new ByteArrayInputStream(bytes))); + assertThrows(SOPGPException.KeyIsProtected.class, () -> sop.sign().key(bytes)); } } diff --git a/sop-java-picocli/src/test/java/sop/cli/picocli/commands/ArmorCmdTest.java b/sop-java-picocli/src/test/java/sop/cli/picocli/commands/ArmorCmdTest.java index 62adf056..01aaa9a5 100644 --- a/sop-java-picocli/src/test/java/sop/cli/picocli/commands/ArmorCmdTest.java +++ b/sop-java-picocli/src/test/java/sop/cli/picocli/commands/ArmorCmdTest.java @@ -12,6 +12,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import com.ginsberg.junit.exit.ExpectSystemExitWithStatus; @@ -35,7 +36,7 @@ public class ArmorCmdTest { armor = mock(Armor.class); sop = mock(SOP.class); when(sop.armor()).thenReturn(armor); - when(armor.data(any())).thenReturn(nopReady()); + when(armor.data((InputStream) any())).thenReturn(nopReady()); SopCLI.setSopInstance(sop); } @@ -57,7 +58,7 @@ public class ArmorCmdTest { @Test public void assertDataIsAlwaysCalled() throws SOPGPException.BadData { SopCLI.main(new String[] {"armor"}); - verify(armor, times(1)).data(any()); + verify(armor, times(1)).data((InputStream) any()); } @Test @@ -77,7 +78,7 @@ public class ArmorCmdTest { @Test @ExpectSystemExitWithStatus(41) public void ifBadDataExit41() throws SOPGPException.BadData { - when(armor.data(any())).thenThrow(new SOPGPException.BadData(new IOException())); + when(armor.data((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException())); SopCLI.main(new String[] {"armor"}); } diff --git a/sop-java-picocli/src/test/java/sop/cli/picocli/commands/DearmorCmdTest.java b/sop-java-picocli/src/test/java/sop/cli/picocli/commands/DearmorCmdTest.java index fc1f713b..aaad201b 100644 --- a/sop-java-picocli/src/test/java/sop/cli/picocli/commands/DearmorCmdTest.java +++ b/sop-java-picocli/src/test/java/sop/cli/picocli/commands/DearmorCmdTest.java @@ -11,6 +11,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import com.ginsberg.junit.exit.ExpectSystemExitWithStatus; @@ -31,7 +32,7 @@ public class DearmorCmdTest { public void mockComponents() throws IOException, SOPGPException.BadData { sop = mock(SOP.class); dearmor = mock(Dearmor.class); - when(dearmor.data(any())).thenReturn(nopReady()); + when(dearmor.data((InputStream) any())).thenReturn(nopReady()); when(sop.dearmor()).thenReturn(dearmor); SopCLI.setSopInstance(sop); @@ -48,13 +49,13 @@ public class DearmorCmdTest { @Test public void assertDataIsCalled() throws IOException, SOPGPException.BadData { SopCLI.main(new String[] {"dearmor"}); - verify(dearmor, times(1)).data(any()); + verify(dearmor, times(1)).data((InputStream) any()); } @Test @ExpectSystemExitWithStatus(41) public void assertBadDataCausesExit41() throws IOException, SOPGPException.BadData { - when(dearmor.data(any())).thenThrow(new SOPGPException.BadData(new IOException("invalid armor"))); + when(dearmor.data((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException("invalid armor"))); SopCLI.main(new String[] {"dearmor"}); } } diff --git a/sop-java-picocli/src/test/java/sop/cli/picocli/commands/DecryptCmdTest.java b/sop-java-picocli/src/test/java/sop/cli/picocli/commands/DecryptCmdTest.java index 89ba709a..507b6723 100644 --- a/sop-java-picocli/src/test/java/sop/cli/picocli/commands/DecryptCmdTest.java +++ b/sop-java-picocli/src/test/java/sop/cli/picocli/commands/DecryptCmdTest.java @@ -18,6 +18,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -55,8 +56,8 @@ public class DecryptCmdTest { when(decrypt.verifyNotBefore(any())).thenReturn(decrypt); when(decrypt.withPassword(any())).thenReturn(decrypt); when(decrypt.withSessionKey(any())).thenReturn(decrypt); - when(decrypt.withKey(any())).thenReturn(decrypt); - when(decrypt.ciphertext(any())).thenReturn(nopReadyWithResult()); + when(decrypt.withKey((InputStream) any())).thenReturn(decrypt); + when(decrypt.ciphertext((InputStream) any())).thenReturn(nopReadyWithResult()); when(sop.decrypt()).thenReturn(decrypt); @@ -75,14 +76,14 @@ public class DecryptCmdTest { @Test @ExpectSystemExitWithStatus(19) public void missingArgumentsExceptionCausesExit19() throws SOPGPException.MissingArg, SOPGPException.BadData, SOPGPException.CannotDecrypt { - when(decrypt.ciphertext(any())).thenThrow(new SOPGPException.MissingArg("Missing arguments.")); + when(decrypt.ciphertext((InputStream) any())).thenThrow(new SOPGPException.MissingArg("Missing arguments.")); SopCLI.main(new String[] {"decrypt"}); } @Test @ExpectSystemExitWithStatus(41) public void badDataExceptionCausesExit41() throws SOPGPException.MissingArg, SOPGPException.BadData, SOPGPException.CannotDecrypt { - when(decrypt.ciphertext(any())).thenThrow(new SOPGPException.BadData(new IOException())); + when(decrypt.ciphertext((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException())); SopCLI.main(new String[] {"decrypt"}); } @@ -187,7 +188,7 @@ public class DecryptCmdTest { @Test public void assertSessionKeyIsProperlyWrittenToSessionKeyFile() throws SOPGPException.CannotDecrypt, SOPGPException.MissingArg, SOPGPException.BadData, IOException { byte[] key = "C7CBDAF42537776F12509B5168793C26B93294E5ABDFA73224FB0177123E9137".getBytes(StandardCharsets.UTF_8); - when(decrypt.ciphertext(any())).thenReturn(new ReadyWithResult() { + when(decrypt.ciphertext((InputStream) any())).thenReturn(new ReadyWithResult() { @Override public DecryptionResult writeTo(OutputStream outputStream) { return new DecryptionResult( @@ -220,14 +221,14 @@ public class DecryptCmdTest { @Test @ExpectSystemExitWithStatus(29) public void assertUnableToDecryptExceptionResultsInExit29() throws SOPGPException.CannotDecrypt, SOPGPException.MissingArg, SOPGPException.BadData { - when(decrypt.ciphertext(any())).thenThrow(new SOPGPException.CannotDecrypt()); + when(decrypt.ciphertext((InputStream) any())).thenThrow(new SOPGPException.CannotDecrypt()); SopCLI.main(new String[] {"decrypt"}); } @Test @ExpectSystemExitWithStatus(3) public void assertNoSignatureExceptionCausesExit3() throws SOPGPException.CannotDecrypt, SOPGPException.MissingArg, SOPGPException.BadData { - when(decrypt.ciphertext(any())).thenReturn(new ReadyWithResult() { + when(decrypt.ciphertext((InputStream) any())).thenReturn(new ReadyWithResult() { @Override public DecryptionResult writeTo(OutputStream outputStream) throws SOPGPException.NoSignature { throw new SOPGPException.NoSignature(); @@ -239,7 +240,7 @@ public class DecryptCmdTest { @Test @ExpectSystemExitWithStatus(41) public void badDataInVerifyWithCausesExit41() throws IOException, SOPGPException.BadData { - when(decrypt.verifyWithCert(any())).thenThrow(new SOPGPException.BadData(new IOException())); + when(decrypt.verifyWithCert((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException())); File tempFile = File.createTempFile("verify-with-", ".tmp"); SopCLI.main(new String[] {"decrypt", "--verify-with", tempFile.getAbsolutePath()}); } @@ -268,7 +269,7 @@ public class DecryptCmdTest { } verifyOut.deleteOnExit(); Date date = UTCUtil.parseUTCDate("2021-07-11T20:58:23Z"); - when(decrypt.ciphertext(any())).thenReturn(new ReadyWithResult() { + when(decrypt.ciphertext((InputStream) any())).thenReturn(new ReadyWithResult() { @Override public DecryptionResult writeTo(OutputStream outputStream) { return new DecryptionResult(null, Collections.singletonList( @@ -308,7 +309,7 @@ public class DecryptCmdTest { @Test @ExpectSystemExitWithStatus(41) public void assertBadDataInKeysResultsInExit41() throws SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.BadData, IOException { - when(decrypt.withKey(any())).thenThrow(new SOPGPException.BadData(new IOException())); + when(decrypt.withKey((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException())); File tempKeyFile = File.createTempFile("key-", ".tmp"); SopCLI.main(new String[] {"decrypt", tempKeyFile.getAbsolutePath()}); } @@ -322,7 +323,7 @@ public class DecryptCmdTest { @Test @ExpectSystemExitWithStatus(67) public void assertProtectedKeyCausesExit67() throws IOException, SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.BadData { - when(decrypt.withKey(any())).thenThrow(new SOPGPException.KeyIsProtected()); + when(decrypt.withKey((InputStream) any())).thenThrow(new SOPGPException.KeyIsProtected()); File tempKeyFile = File.createTempFile("key-", ".tmp"); SopCLI.main(new String[] {"decrypt", tempKeyFile.getAbsolutePath()}); } @@ -330,7 +331,7 @@ public class DecryptCmdTest { @Test @ExpectSystemExitWithStatus(13) public void assertUnsupportedAlgorithmExceptionCausesExit13() throws SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.BadData, IOException { - when(decrypt.withKey(any())).thenThrow(new SOPGPException.UnsupportedAsymmetricAlgo("Unsupported asymmetric algorithm.", new IOException())); + when(decrypt.withKey((InputStream) any())).thenThrow(new SOPGPException.UnsupportedAsymmetricAlgo("Unsupported asymmetric algorithm.", new IOException())); File tempKeyFile = File.createTempFile("key-", ".tmp"); SopCLI.main(new String[] {"decrypt", tempKeyFile.getAbsolutePath()}); } diff --git a/sop-java-picocli/src/test/java/sop/cli/picocli/commands/EncryptCmdTest.java b/sop-java-picocli/src/test/java/sop/cli/picocli/commands/EncryptCmdTest.java index 0300305d..cfa8a3f6 100644 --- a/sop-java-picocli/src/test/java/sop/cli/picocli/commands/EncryptCmdTest.java +++ b/sop-java-picocli/src/test/java/sop/cli/picocli/commands/EncryptCmdTest.java @@ -13,6 +13,7 @@ import static org.mockito.Mockito.when; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import com.ginsberg.junit.exit.ExpectSystemExitWithStatus; @@ -32,7 +33,7 @@ public class EncryptCmdTest { @BeforeEach public void mockComponents() throws IOException { encrypt = mock(Encrypt.class); - when(encrypt.plaintext(any())).thenReturn(new Ready() { + when(encrypt.plaintext((InputStream) any())).thenReturn(new Ready() { @Override public void writeTo(OutputStream outputStream) { @@ -95,7 +96,7 @@ public class EncryptCmdTest { File keyFile2 = File.createTempFile("sign-with-2-", ".asc"); SopCLI.main(new String[] {"encrypt", "--with-password", "password", "--sign-with", keyFile1.getAbsolutePath(), "--sign-with", keyFile2.getAbsolutePath()}); - verify(encrypt, times(2)).signWith(any()); + verify(encrypt, times(2)).signWith((InputStream) any()); } @Test @@ -107,7 +108,7 @@ public class EncryptCmdTest { @Test @ExpectSystemExitWithStatus(67) public void signWith_keyIsProtectedCausesExit67() throws SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.CertCannotSign, SOPGPException.BadData, IOException { - when(encrypt.signWith(any())).thenThrow(new SOPGPException.KeyIsProtected()); + when(encrypt.signWith((InputStream) any())).thenThrow(new SOPGPException.KeyIsProtected()); File keyFile = File.createTempFile("sign-with", ".asc"); SopCLI.main(new String[] {"encrypt", "--sign-with", keyFile.getAbsolutePath(), "--with-password", "starship"}); } @@ -115,7 +116,7 @@ public class EncryptCmdTest { @Test @ExpectSystemExitWithStatus(13) public void signWith_unsupportedAsymmetricAlgoCausesExit13() throws SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.CertCannotSign, SOPGPException.BadData, IOException { - when(encrypt.signWith(any())).thenThrow(new SOPGPException.UnsupportedAsymmetricAlgo("Unsupported asymmetric algorithm.", new Exception())); + when(encrypt.signWith((InputStream) any())).thenThrow(new SOPGPException.UnsupportedAsymmetricAlgo("Unsupported asymmetric algorithm.", new Exception())); File keyFile = File.createTempFile("sign-with", ".asc"); SopCLI.main(new String[] {"encrypt", "--with-password", "123456", "--sign-with", keyFile.getAbsolutePath()}); } @@ -123,7 +124,7 @@ public class EncryptCmdTest { @Test @ExpectSystemExitWithStatus(1) public void signWith_certCannotSignCausesExit1() throws IOException, SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.CertCannotSign, SOPGPException.BadData { - when(encrypt.signWith(any())).thenThrow(new SOPGPException.CertCannotSign()); + when(encrypt.signWith((InputStream) any())).thenThrow(new SOPGPException.CertCannotSign()); File keyFile = File.createTempFile("sign-with", ".asc"); SopCLI.main(new String[] {"encrypt", "--with-password", "dragon", "--sign-with", keyFile.getAbsolutePath()}); } @@ -131,7 +132,7 @@ public class EncryptCmdTest { @Test @ExpectSystemExitWithStatus(41) public void signWith_badDataCausesExit41() throws SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.CertCannotSign, SOPGPException.BadData, IOException { - when(encrypt.signWith(any())).thenThrow(new SOPGPException.BadData(new IOException())); + when(encrypt.signWith((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException())); File keyFile = File.createTempFile("sign-with", ".asc"); SopCLI.main(new String[] {"encrypt", "--with-password", "orange", "--sign-with", keyFile.getAbsolutePath()}); } @@ -145,7 +146,7 @@ public class EncryptCmdTest { @Test @ExpectSystemExitWithStatus(13) public void cert_unsupportedAsymmetricAlgorithmCausesExit13() throws IOException, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.CertCannotEncrypt, SOPGPException.BadData { - when(encrypt.withCert(any())).thenThrow(new SOPGPException.UnsupportedAsymmetricAlgo("Unsupported asymmetric algorithm.", new Exception())); + when(encrypt.withCert((InputStream) any())).thenThrow(new SOPGPException.UnsupportedAsymmetricAlgo("Unsupported asymmetric algorithm.", new Exception())); File certFile = File.createTempFile("cert", ".asc"); SopCLI.main(new String[] {"encrypt", certFile.getAbsolutePath()}); } @@ -153,7 +154,7 @@ public class EncryptCmdTest { @Test @ExpectSystemExitWithStatus(17) public void cert_certCannotEncryptCausesExit17() throws IOException, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.CertCannotEncrypt, SOPGPException.BadData { - when(encrypt.withCert(any())).thenThrow(new SOPGPException.CertCannotEncrypt("Certificate cannot encrypt.", new Exception())); + when(encrypt.withCert((InputStream) any())).thenThrow(new SOPGPException.CertCannotEncrypt("Certificate cannot encrypt.", new Exception())); File certFile = File.createTempFile("cert", ".asc"); SopCLI.main(new String[] {"encrypt", certFile.getAbsolutePath()}); } @@ -161,7 +162,7 @@ public class EncryptCmdTest { @Test @ExpectSystemExitWithStatus(41) public void cert_badDataCausesExit41() throws IOException, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.CertCannotEncrypt, SOPGPException.BadData { - when(encrypt.withCert(any())).thenThrow(new SOPGPException.BadData(new IOException())); + when(encrypt.withCert((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException())); File certFile = File.createTempFile("cert", ".asc"); SopCLI.main(new String[] {"encrypt", certFile.getAbsolutePath()}); } @@ -181,7 +182,7 @@ public class EncryptCmdTest { @Test @ExpectSystemExitWithStatus(1) public void writeTo_ioExceptionCausesExit1() throws IOException { - when(encrypt.plaintext(any())).thenReturn(new Ready() { + when(encrypt.plaintext((InputStream) any())).thenReturn(new Ready() { @Override public void writeTo(OutputStream outputStream) throws IOException { throw new IOException(); diff --git a/sop-java-picocli/src/test/java/sop/cli/picocli/commands/ExtractCertCmdTest.java b/sop-java-picocli/src/test/java/sop/cli/picocli/commands/ExtractCertCmdTest.java index be602e72..382fe300 100644 --- a/sop-java-picocli/src/test/java/sop/cli/picocli/commands/ExtractCertCmdTest.java +++ b/sop-java-picocli/src/test/java/sop/cli/picocli/commands/ExtractCertCmdTest.java @@ -12,6 +12,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import com.ginsberg.junit.exit.ExpectSystemExitWithStatus; @@ -30,7 +31,7 @@ public class ExtractCertCmdTest { @BeforeEach public void mockComponents() throws IOException, SOPGPException.BadData { extractCert = mock(ExtractCert.class); - when(extractCert.key(any())).thenReturn(new Ready() { + when(extractCert.key((InputStream) any())).thenReturn(new Ready() { @Override public void writeTo(OutputStream outputStream) { } @@ -57,7 +58,7 @@ public class ExtractCertCmdTest { @Test @ExpectSystemExitWithStatus(1) public void key_ioExceptionCausesExit1() throws IOException, SOPGPException.BadData { - when(extractCert.key(any())).thenReturn(new Ready() { + when(extractCert.key((InputStream) any())).thenReturn(new Ready() { @Override public void writeTo(OutputStream outputStream) throws IOException { throw new IOException(); @@ -69,7 +70,7 @@ public class ExtractCertCmdTest { @Test @ExpectSystemExitWithStatus(41) public void key_badDataCausesExit41() throws IOException, SOPGPException.BadData { - when(extractCert.key(any())).thenThrow(new SOPGPException.BadData(new IOException())); + when(extractCert.key((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException())); SopCLI.main(new String[] {"extract-cert"}); } } diff --git a/sop-java-picocli/src/test/java/sop/cli/picocli/commands/SignCmdTest.java b/sop-java-picocli/src/test/java/sop/cli/picocli/commands/SignCmdTest.java index fdd376b1..8de61409 100644 --- a/sop-java-picocli/src/test/java/sop/cli/picocli/commands/SignCmdTest.java +++ b/sop-java-picocli/src/test/java/sop/cli/picocli/commands/SignCmdTest.java @@ -13,6 +13,7 @@ import static org.mockito.Mockito.when; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import com.ginsberg.junit.exit.ExpectSystemExitWithStatus; @@ -32,7 +33,7 @@ public class SignCmdTest { @BeforeEach public void mockComponents() throws IOException, SOPGPException.ExpectedText { sign = mock(Sign.class); - when(sign.data(any())).thenReturn(new Ready() { + when(sign.data((InputStream) any())).thenReturn(new Ready() { @Override public void writeTo(OutputStream outputStream) { @@ -76,14 +77,14 @@ public class SignCmdTest { @Test @ExpectSystemExitWithStatus(1) public void key_keyIsProtectedCausesExit1() throws SOPGPException.KeyIsProtected, IOException, SOPGPException.BadData { - when(sign.key(any())).thenThrow(new SOPGPException.KeyIsProtected()); + when(sign.key((InputStream) any())).thenThrow(new SOPGPException.KeyIsProtected()); SopCLI.main(new String[] {"sign", keyFile.getAbsolutePath()}); } @Test @ExpectSystemExitWithStatus(41) public void key_badDataCausesExit41() throws SOPGPException.KeyIsProtected, IOException, SOPGPException.BadData { - when(sign.key(any())).thenThrow(new SOPGPException.BadData(new IOException())); + when(sign.key((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException())); SopCLI.main(new String[] {"sign", keyFile.getAbsolutePath()}); } @@ -108,7 +109,7 @@ public class SignCmdTest { @Test @ExpectSystemExitWithStatus(1) public void data_ioExceptionCausesExit1() throws IOException, SOPGPException.ExpectedText { - when(sign.data(any())).thenReturn(new Ready() { + when(sign.data((InputStream) any())).thenReturn(new Ready() { @Override public void writeTo(OutputStream outputStream) throws IOException { throw new IOException(); @@ -120,7 +121,7 @@ public class SignCmdTest { @Test @ExpectSystemExitWithStatus(53) public void data_expectedTextExceptionCausesExit53() throws IOException, SOPGPException.ExpectedText { - when(sign.data(any())).thenThrow(new SOPGPException.ExpectedText()); + when(sign.data((InputStream) any())).thenThrow(new SOPGPException.ExpectedText()); SopCLI.main(new String[] {"sign", keyFile.getAbsolutePath()}); } } diff --git a/sop-java-picocli/src/test/java/sop/cli/picocli/commands/VerifyCmdTest.java b/sop-java-picocli/src/test/java/sop/cli/picocli/commands/VerifyCmdTest.java index 99098d76..028d2451 100644 --- a/sop-java-picocli/src/test/java/sop/cli/picocli/commands/VerifyCmdTest.java +++ b/sop-java-picocli/src/test/java/sop/cli/picocli/commands/VerifyCmdTest.java @@ -14,6 +14,7 @@ import static org.mockito.Mockito.when; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.io.PrintStream; import java.util.Arrays; import java.util.Collections; @@ -47,9 +48,9 @@ public class VerifyCmdTest { verify = mock(Verify.class); when(verify.notBefore(any())).thenReturn(verify); when(verify.notAfter(any())).thenReturn(verify); - when(verify.cert(any())).thenReturn(verify); - when(verify.signatures(any())).thenReturn(verify); - when(verify.data(any())).thenReturn( + when(verify.cert((InputStream) any())).thenReturn(verify); + when(verify.signatures((InputStream) any())).thenReturn(verify); + when(verify.data((InputStream) any())).thenReturn( Collections.singletonList( new Verification( UTCUtil.parseUTCDate("2019-10-29T18:36:45Z"), @@ -146,7 +147,7 @@ public class VerifyCmdTest { @Test @ExpectSystemExitWithStatus(41) public void cert_badDataCausesExit41() throws SOPGPException.BadData { - when(verify.cert(any())).thenThrow(new SOPGPException.BadData(new IOException())); + when(verify.cert((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException())); SopCLI.main(new String[] {"verify", signature.getAbsolutePath(), cert.getAbsolutePath()}); } @@ -159,27 +160,27 @@ public class VerifyCmdTest { @Test @ExpectSystemExitWithStatus(41) public void signature_badDataCausesExit41() throws SOPGPException.BadData { - when(verify.signatures(any())).thenThrow(new SOPGPException.BadData(new IOException())); + when(verify.signatures((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException())); SopCLI.main(new String[] {"verify", signature.getAbsolutePath(), cert.getAbsolutePath()}); } @Test @ExpectSystemExitWithStatus(3) public void data_noSignaturesCausesExit3() throws SOPGPException.NoSignature, IOException, SOPGPException.BadData { - when(verify.data(any())).thenThrow(new SOPGPException.NoSignature()); + when(verify.data((InputStream) any())).thenThrow(new SOPGPException.NoSignature()); SopCLI.main(new String[] {"verify", signature.getAbsolutePath(), cert.getAbsolutePath()}); } @Test @ExpectSystemExitWithStatus(41) public void data_badDataCausesExit41() throws SOPGPException.NoSignature, IOException, SOPGPException.BadData { - when(verify.data(any())).thenThrow(new SOPGPException.BadData(new IOException())); + when(verify.data((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException())); SopCLI.main(new String[] {"verify", signature.getAbsolutePath(), cert.getAbsolutePath()}); } @Test public void resultIsPrintedProperly() throws SOPGPException.NoSignature, IOException, SOPGPException.BadData { - when(verify.data(any())).thenReturn(Arrays.asList( + when(verify.data((InputStream) any())).thenReturn(Arrays.asList( new Verification(UTCUtil.parseUTCDate("2019-10-29T18:36:45Z"), "EB85BB5FA33A75E15E944E63F231550C4F47E38E", "EB85BB5FA33A75E15E944E63F231550C4F47E38E"), diff --git a/sop-java/src/main/java/sop/ByteArrayAndResult.java b/sop-java/src/main/java/sop/ByteArrayAndResult.java index 709836d2..fd2b39a7 100644 --- a/sop-java/src/main/java/sop/ByteArrayAndResult.java +++ b/sop-java/src/main/java/sop/ByteArrayAndResult.java @@ -4,6 +4,13 @@ package sop; +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +/** + * Tuple of a byte array and associated result object. + * @param type of result + */ public class ByteArrayAndResult { private final byte[] bytes; @@ -14,11 +21,30 @@ public class ByteArrayAndResult { this.result = result; } + /** + * Return the byte array part. + * + * @return bytes + */ public byte[] getBytes() { return bytes; } + /** + * Return the result part. + * + * @return result + */ public T getResult() { return result; } + + /** + * Return the byte array part as an {@link InputStream}. + * + * @return input stream + */ + public InputStream getInputStream() { + return new ByteArrayInputStream(getBytes()); + } } diff --git a/sop-java/src/main/java/sop/Ready.java b/sop-java/src/main/java/sop/Ready.java index d234f911..71ab26ec 100644 --- a/sop-java/src/main/java/sop/Ready.java +++ b/sop-java/src/main/java/sop/Ready.java @@ -4,8 +4,10 @@ package sop; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; public abstract class Ready { @@ -30,4 +32,14 @@ public abstract class Ready { writeTo(bytes); return bytes.toByteArray(); } + + /** + * Return an input stream containing the data. + * + * @return input stream + * @throws IOException in case of an IO error + */ + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(getBytes()); + } } diff --git a/sop-java/src/main/java/sop/ReadyWithResult.java b/sop-java/src/main/java/sop/ReadyWithResult.java index c932b639..753d41d1 100644 --- a/sop-java/src/main/java/sop/ReadyWithResult.java +++ b/sop-java/src/main/java/sop/ReadyWithResult.java @@ -20,11 +20,20 @@ public abstract class ReadyWithResult { * @return result, eg. signatures * * @throws IOException in case of an IO error - * @throws SOPGPException.NoSignature + * @throws SOPGPException.NoSignature if there are no valid signatures found */ public abstract T writeTo(OutputStream outputStream) throws IOException, SOPGPException.NoSignature; - public ByteArrayAndResult toBytes() throws IOException, SOPGPException.NoSignature { + /** + * Return the data as a {@link ByteArrayAndResult}. + * Calling {@link ByteArrayAndResult#getBytes()} will give you access to the data as byte array, while + * {@link ByteArrayAndResult#getResult()} will grant access to the appended result. + * + * @return byte array and result + * @throws IOException in case of an IO error + * @throws SOPGPException.NoSignature if there are no valid signatures found + */ + public ByteArrayAndResult toByteArrayAndResult() throws IOException, SOPGPException.NoSignature { ByteArrayOutputStream bytes = new ByteArrayOutputStream(); T result = writeTo(bytes); return new ByteArrayAndResult<>(bytes.toByteArray(), result); diff --git a/sop-java/src/main/java/sop/operation/Armor.java b/sop-java/src/main/java/sop/operation/Armor.java index 8aa06614..dea3257a 100644 --- a/sop-java/src/main/java/sop/operation/Armor.java +++ b/sop-java/src/main/java/sop/operation/Armor.java @@ -4,6 +4,7 @@ package sop.operation; +import java.io.ByteArrayInputStream; import java.io.InputStream; import sop.Ready; @@ -27,4 +28,14 @@ public interface Armor { * @return armored data */ Ready data(InputStream data) throws SOPGPException.BadData; + + /** + * Armor the provided data. + * + * @param data unarmored OpenPGP data + * @return armored data + */ + default Ready data(byte[] data) throws SOPGPException.BadData { + return data(new ByteArrayInputStream(data)); + } } diff --git a/sop-java/src/main/java/sop/operation/Dearmor.java b/sop-java/src/main/java/sop/operation/Dearmor.java index 91004b7d..35eceb56 100644 --- a/sop-java/src/main/java/sop/operation/Dearmor.java +++ b/sop-java/src/main/java/sop/operation/Dearmor.java @@ -4,6 +4,7 @@ package sop.operation; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -19,4 +20,14 @@ public interface Dearmor { * @return input stream of unarmored data */ Ready data(InputStream data) throws SOPGPException.BadData, IOException; + + /** + * Dearmor armored OpenPGP data. + * + * @param data armored OpenPGP data + * @return input stream of unarmored data + */ + default Ready data(byte[] data) throws SOPGPException.BadData, IOException { + return data(new ByteArrayInputStream(data)); + } } diff --git a/sop-java/src/main/java/sop/operation/Decrypt.java b/sop-java/src/main/java/sop/operation/Decrypt.java index 944ab9ce..4cbd6f35 100644 --- a/sop-java/src/main/java/sop/operation/Decrypt.java +++ b/sop-java/src/main/java/sop/operation/Decrypt.java @@ -4,6 +4,7 @@ package sop.operation; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Date; @@ -43,6 +44,17 @@ public interface Decrypt { throws SOPGPException.BadData, IOException; + /** + * Adds the verification cert. + * + * @param cert byte array containing the cert + * @return builder instance + */ + default Decrypt verifyWithCert(byte[] cert) + throws SOPGPException.BadData, IOException { + return verifyWithCert(new ByteArrayInputStream(cert)); + } + /** * Tries to decrypt with the given session key. * @@ -73,6 +85,19 @@ public interface Decrypt { SOPGPException.BadData, SOPGPException.UnsupportedAsymmetricAlgo; + /** + * Adds the decryption key. + * + * @param key byte array containing the key + * @return builder instance + */ + default Decrypt withKey(byte[] key) + throws SOPGPException.KeyIsProtected, + SOPGPException.BadData, + SOPGPException.UnsupportedAsymmetricAlgo { + return withKey(new ByteArrayInputStream(key)); + } + /** * Decrypts the given ciphertext, returning verification results and plaintext. * @param ciphertext ciphertext @@ -80,4 +105,14 @@ public interface Decrypt { */ ReadyWithResult ciphertext(InputStream ciphertext) throws SOPGPException.BadData, SOPGPException.MissingArg, SOPGPException.CannotDecrypt; + + /** + * Decrypts the given ciphertext, returning verification results and plaintext. + * @param ciphertext ciphertext + * @return ready with result + */ + default ReadyWithResult ciphertext(byte[] ciphertext) + throws SOPGPException.BadData, SOPGPException.MissingArg, SOPGPException.CannotDecrypt { + return ciphertext(new ByteArrayInputStream(ciphertext)); + } } diff --git a/sop-java/src/main/java/sop/operation/DetachInbandSignatureAndMessage.java b/sop-java/src/main/java/sop/operation/DetachInbandSignatureAndMessage.java index c240382b..46bd3f77 100644 --- a/sop-java/src/main/java/sop/operation/DetachInbandSignatureAndMessage.java +++ b/sop-java/src/main/java/sop/operation/DetachInbandSignatureAndMessage.java @@ -4,6 +4,7 @@ package sop.operation; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -12,8 +13,29 @@ import sop.Signatures; public interface DetachInbandSignatureAndMessage { + /** + * Do not wrap the signatures in ASCII armor. + * @return builder + */ DetachInbandSignatureAndMessage noArmor(); + /** + * Detach the provided cleartext signed message from its signatures. + * + * @param messageInputStream input stream containing the signed message + * @return result containing the detached message + * @throws IOException in case of an IO error + */ ReadyWithResult message(InputStream messageInputStream) throws IOException; + /** + * Detach the provided cleartext signed message from its signatures. + * + * @param message byte array containing the signed message + * @return result containing the detached message + * @throws IOException in case of an IO error + */ + default ReadyWithResult message(byte[] message) throws IOException { + return message(new ByteArrayInputStream(message)); + } } diff --git a/sop-java/src/main/java/sop/operation/Encrypt.java b/sop-java/src/main/java/sop/operation/Encrypt.java index b1491fd9..b5a92b25 100644 --- a/sop-java/src/main/java/sop/operation/Encrypt.java +++ b/sop-java/src/main/java/sop/operation/Encrypt.java @@ -4,6 +4,7 @@ package sop.operation; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -41,6 +42,20 @@ public interface Encrypt { SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.BadData; + /** + * Adds the signer key. + * + * @param key byte array containing the encoded signer key + * @return builder instance + */ + default Encrypt signWith(byte[] key) + throws SOPGPException.KeyIsProtected, + SOPGPException.CertCannotSign, + SOPGPException.UnsupportedAsymmetricAlgo, + SOPGPException.BadData { + return signWith(new ByteArrayInputStream(key)); + } + /** * Encrypt with the given password. * @@ -62,6 +77,19 @@ public interface Encrypt { SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.BadData; + /** + * Encrypt with the given cert. + * + * @param cert byte array containing the encoded cert. + * @return builder instance + */ + default Encrypt withCert(byte[] cert) + throws SOPGPException.CertCannotEncrypt, + SOPGPException.UnsupportedAsymmetricAlgo, + SOPGPException.BadData { + return withCert(new ByteArrayInputStream(cert)); + } + /** * Encrypt the given data yielding the ciphertext. * @param plaintext plaintext @@ -69,4 +97,13 @@ public interface Encrypt { */ Ready plaintext(InputStream plaintext) throws IOException; + + /** + * Encrypt the given data yielding the ciphertext. + * @param plaintext plaintext + * @return input stream containing the ciphertext + */ + default Ready plaintext(byte[] plaintext) throws IOException { + return plaintext(new ByteArrayInputStream(plaintext)); + } } diff --git a/sop-java/src/main/java/sop/operation/ExtractCert.java b/sop-java/src/main/java/sop/operation/ExtractCert.java index 31b0a5fb..7a0de5c6 100644 --- a/sop-java/src/main/java/sop/operation/ExtractCert.java +++ b/sop-java/src/main/java/sop/operation/ExtractCert.java @@ -4,6 +4,7 @@ package sop.operation; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -23,7 +24,17 @@ public interface ExtractCert { * Extract the cert from the provided key. * * @param keyInputStream input stream containing the encoding of an OpenPGP key - * @return input stream containing the encoding of the keys cert + * @return result containing the encoding of the keys cert */ Ready key(InputStream keyInputStream) throws IOException, SOPGPException.BadData; + + /** + * Extract the cert from the provided key. + * + * @param key byte array containing the encoding of an OpenPGP key + * @return result containing the encoding of the keys cert + */ + default Ready key(byte[] key) throws IOException, SOPGPException.BadData { + return key(new ByteArrayInputStream(key)); + } } diff --git a/sop-java/src/main/java/sop/operation/Sign.java b/sop-java/src/main/java/sop/operation/Sign.java index 707f6f4e..9b9c3a6f 100644 --- a/sop-java/src/main/java/sop/operation/Sign.java +++ b/sop-java/src/main/java/sop/operation/Sign.java @@ -4,6 +4,7 @@ package sop.operation; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -37,6 +38,16 @@ public interface Sign { */ Sign key(InputStream key) throws SOPGPException.KeyIsProtected, SOPGPException.BadData, IOException; + /** + * Adds the signer key. + * + * @param key byte array containing encoded key + * @return builder instance + */ + default Sign key(byte[] key) throws SOPGPException.KeyIsProtected, SOPGPException.BadData, IOException { + return key(new ByteArrayInputStream(key)); + } + /** * Signs data. * @@ -44,4 +55,14 @@ public interface Sign { * @return ready */ Ready data(InputStream data) throws IOException, SOPGPException.ExpectedText; + + /** + * Signs data. + * + * @param data byte array containing data + * @return ready + */ + default Ready data(byte[] data) throws IOException, SOPGPException.ExpectedText { + return data(new ByteArrayInputStream(data)); + } } diff --git a/sop-java/src/main/java/sop/operation/Verify.java b/sop-java/src/main/java/sop/operation/Verify.java index b59fadfa..30905de2 100644 --- a/sop-java/src/main/java/sop/operation/Verify.java +++ b/sop-java/src/main/java/sop/operation/Verify.java @@ -4,6 +4,7 @@ package sop.operation; +import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.Date; @@ -35,6 +36,16 @@ public interface Verify extends VerifySignatures { */ Verify cert(InputStream cert) throws SOPGPException.BadData; + /** + * Adds the verification cert. + * + * @param cert byte array containing the encoded cert + * @return builder instance + */ + default Verify cert(byte[] cert) throws SOPGPException.BadData { + return cert(new ByteArrayInputStream(cert)); + } + /** * Provides the signatures. * @param signatures input stream containing encoded, detached signatures. @@ -43,4 +54,14 @@ public interface Verify extends VerifySignatures { */ VerifySignatures signatures(InputStream signatures) throws SOPGPException.BadData; + /** + * Provides the signatures. + * @param signatures byte array containing encoded, detached signatures. + * + * @return builder instance + */ + default VerifySignatures signatures(byte[] signatures) throws SOPGPException.BadData { + return signatures(new ByteArrayInputStream(signatures)); + } + } diff --git a/sop-java/src/main/java/sop/operation/VerifySignatures.java b/sop-java/src/main/java/sop/operation/VerifySignatures.java index 6d10e4d6..d41a8edd 100644 --- a/sop-java/src/main/java/sop/operation/VerifySignatures.java +++ b/sop-java/src/main/java/sop/operation/VerifySignatures.java @@ -4,6 +4,7 @@ package sop.operation; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; @@ -13,5 +14,27 @@ import sop.exception.SOPGPException; public interface VerifySignatures { + /** + * Provide the signed data (without signatures). + * + * @param data signed data + * @return list of signature verifications + * @throws IOException in case of an IO error + * @throws SOPGPException.NoSignature when no signature is found + * @throws SOPGPException.BadData when the data is invalid OpenPGP data + */ List data(InputStream data) throws IOException, SOPGPException.NoSignature, SOPGPException.BadData; + + /** + * Provide the signed data (without signatures). + * + * @param data signed data + * @return list of signature verifications + * @throws IOException in case of an IO error + * @throws SOPGPException.NoSignature when no signature is found + * @throws SOPGPException.BadData when the data is invalid OpenPGP data + */ + default List data(byte[] data) throws IOException, SOPGPException.NoSignature, SOPGPException.BadData { + return data(new ByteArrayInputStream(data)); + } } diff --git a/sop-java/src/test/java/sop/util/ReadyWithResultTest.java b/sop-java/src/test/java/sop/util/ReadyWithResultTest.java index 668fec09..97841fa8 100644 --- a/sop-java/src/test/java/sop/util/ReadyWithResultTest.java +++ b/sop-java/src/test/java/sop/util/ReadyWithResultTest.java @@ -37,7 +37,7 @@ public class ReadyWithResultTest { } }; - ByteArrayAndResult> bytesAndResult = readyWithResult.toBytes(); + ByteArrayAndResult> bytesAndResult = readyWithResult.toByteArrayAndResult(); assertArrayEquals(data, bytesAndResult.getBytes()); assertEquals(result, bytesAndResult.getResult()); }