From eefb445916913cd1a35646570032846bdd785480 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Fri, 10 Jun 2022 16:16:37 +0200 Subject: [PATCH] Reformat and restructure exceptions --- .../cli/picocli/commands/InlineSignCmd.java | 24 +------- .../cli/picocli/commands/ArmorCmdTest.java | 6 +- .../cli/picocli/commands/DecryptCmdTest.java | 10 ++-- .../cli/picocli/commands/VerifyCmdTest.java | 4 +- .../java/sop/exception/SOPGPException.java | 9 ++- .../main/java/sop/operation/AbstractSign.java | 55 ++++++++----------- .../java/sop/operation/AbstractVerify.java | 21 +++++-- .../src/main/java/sop/operation/Armor.java | 18 +++++- .../src/main/java/sop/operation/Dearmor.java | 8 ++- .../src/main/java/sop/operation/Decrypt.java | 49 +++++++++++++---- .../main/java/sop/operation/DetachedSign.java | 38 ++++++++++++- .../java/sop/operation/DetachedVerify.java | 15 ++++- .../src/main/java/sop/operation/Encrypt.java | 53 ++++++++++++------ .../main/java/sop/operation/ExtractCert.java | 8 ++- .../main/java/sop/operation/GenerateKey.java | 18 ++++-- .../main/java/sop/operation/InlineDetach.java | 14 ++++- .../main/java/sop/operation/InlineSign.java | 37 ++++++++++++- .../main/java/sop/operation/InlineVerify.java | 8 ++- .../java/sop/operation/VerifySignatures.java | 14 +++-- 19 files changed, 286 insertions(+), 123 deletions(-) diff --git a/sop-java-picocli/src/main/java/sop/cli/picocli/commands/InlineSignCmd.java b/sop-java-picocli/src/main/java/sop/cli/picocli/commands/InlineSignCmd.java index 739bbf6..2cf5ebd 100644 --- a/sop-java-picocli/src/main/java/sop/cli/picocli/commands/InlineSignCmd.java +++ b/sop-java-picocli/src/main/java/sop/cli/picocli/commands/InlineSignCmd.java @@ -5,9 +5,7 @@ package sop.cli.picocli.commands; import picocli.CommandLine; -import sop.MicAlg; -import sop.ReadyWithResult; -import sop.SigningResult; +import sop.Ready; import sop.cli.picocli.SopCLI; import sop.enums.InlineSignAs; import sop.exception.SOPGPException; @@ -15,7 +13,6 @@ import sop.operation.InlineSign; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; import java.util.ArrayList; import java.util.List; @@ -43,18 +40,11 @@ public class InlineSignCmd extends AbstractSopCmd { paramLabel = "PASSWORD") List withKeyPassword = new ArrayList<>(); - @CommandLine.Option(names = "--micalg-out", - descriptionKey = "sop.inline-sign.usage.option.micalg", - paramLabel = "MICALG") - String micAlgOut; - @Override public void run() { InlineSign inlineSign = throwIfUnsupportedSubcommand( SopCLI.getSop().inlineSign(), "inline-sign"); - throwIfOutputExists(micAlgOut); - if (type != null) { try { inlineSign.mode(type); @@ -100,16 +90,8 @@ public class InlineSignCmd extends AbstractSopCmd { } try { - ReadyWithResult ready = inlineSign.data(System.in); - SigningResult result = ready.writeTo(System.out); - - MicAlg micAlg = result.getMicAlg(); - if (micAlgOut != null) { - // Write micalg out - OutputStream micAlgOutStream = getOutput(micAlgOut); - micAlg.writeTo(micAlgOutStream); - micAlgOutStream.close(); - } + Ready ready = inlineSign.data(System.in); + ready.writeTo(System.out); } catch (IOException e) { throw new RuntimeException(e); } 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 01aaa9a..e54597d 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 @@ -32,7 +32,7 @@ public class ArmorCmdTest { private SOP sop; @BeforeEach - public void mockComponents() throws SOPGPException.BadData { + public void mockComponents() throws SOPGPException.BadData, IOException { armor = mock(Armor.class); sop = mock(SOP.class); when(sop.armor()).thenReturn(armor); @@ -56,7 +56,7 @@ public class ArmorCmdTest { } @Test - public void assertDataIsAlwaysCalled() throws SOPGPException.BadData { + public void assertDataIsAlwaysCalled() throws SOPGPException.BadData, IOException { SopCLI.main(new String[] {"armor"}); verify(armor, times(1)).data((InputStream) any()); } @@ -77,7 +77,7 @@ public class ArmorCmdTest { @Test @ExpectSystemExitWithStatus(41) - public void ifBadDataExit41() throws SOPGPException.BadData { + public void ifBadDataExit41() throws SOPGPException.BadData, 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/DecryptCmdTest.java b/sop-java-picocli/src/test/java/sop/cli/picocli/commands/DecryptCmdTest.java index 605fbd5..5b5563e 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 @@ -48,7 +48,7 @@ public class DecryptCmdTest { private Decrypt decrypt; @BeforeEach - public void mockComponents() throws SOPGPException.UnsupportedOption, SOPGPException.MissingArg, SOPGPException.BadData, SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.PasswordNotHumanReadable, SOPGPException.CannotDecrypt { + public void mockComponents() throws SOPGPException.UnsupportedOption, SOPGPException.MissingArg, SOPGPException.BadData, SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.PasswordNotHumanReadable, SOPGPException.CannotDecrypt, IOException { SOP sop = mock(SOP.class); decrypt = mock(Decrypt.class); @@ -75,14 +75,14 @@ public class DecryptCmdTest { @Test @ExpectSystemExitWithStatus(19) - public void missingArgumentsExceptionCausesExit19() throws SOPGPException.MissingArg, SOPGPException.BadData, SOPGPException.CannotDecrypt { + public void missingArgumentsExceptionCausesExit19() throws SOPGPException.MissingArg, SOPGPException.BadData, SOPGPException.CannotDecrypt, IOException { 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 { + public void badDataExceptionCausesExit41() throws SOPGPException.MissingArg, SOPGPException.BadData, SOPGPException.CannotDecrypt, IOException { when(decrypt.ciphertext((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException())); SopCLI.main(new String[] {"decrypt"}); } @@ -223,14 +223,14 @@ public class DecryptCmdTest { @Test @ExpectSystemExitWithStatus(29) - public void assertUnableToDecryptExceptionResultsInExit29() throws SOPGPException.CannotDecrypt, SOPGPException.MissingArg, SOPGPException.BadData { + public void assertUnableToDecryptExceptionResultsInExit29() throws SOPGPException.CannotDecrypt, SOPGPException.MissingArg, SOPGPException.BadData, IOException { 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 { + public void assertNoSignatureExceptionCausesExit3() throws SOPGPException.CannotDecrypt, SOPGPException.MissingArg, SOPGPException.BadData, IOException { when(decrypt.ciphertext((InputStream) any())).thenReturn(new ReadyWithResult() { @Override public DecryptionResult writeTo(OutputStream outputStream) throws SOPGPException.NoSignature { 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 4b9c633..e0e2e07 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 @@ -145,7 +145,7 @@ public class VerifyCmdTest { @Test @ExpectSystemExitWithStatus(41) - public void cert_badDataCausesExit41() throws SOPGPException.BadData { + public void cert_badDataCausesExit41() throws SOPGPException.BadData, IOException { when(detachedVerify.cert((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException())); SopCLI.main(new String[] {"verify", signature.getAbsolutePath(), cert.getAbsolutePath()}); } @@ -158,7 +158,7 @@ public class VerifyCmdTest { @Test @ExpectSystemExitWithStatus(41) - public void signature_badDataCausesExit41() throws SOPGPException.BadData { + public void signature_badDataCausesExit41() throws SOPGPException.BadData, IOException { when(detachedVerify.signatures((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException())); SopCLI.main(new String[] {"verify", signature.getAbsolutePath(), cert.getAbsolutePath()}); } diff --git a/sop-java/src/main/java/sop/exception/SOPGPException.java b/sop-java/src/main/java/sop/exception/SOPGPException.java index 493ccb3..b0be447 100644 --- a/sop-java/src/main/java/sop/exception/SOPGPException.java +++ b/sop-java/src/main/java/sop/exception/SOPGPException.java @@ -240,7 +240,7 @@ public abstract class SOPGPException extends RuntimeException { } /** - * A KEYS input is protected (locked) with a password, and sop cannot unlock it. + * A KEYS input is protected (locked) with a password and sop failed to unlock it. */ public static class KeyIsProtected extends SOPGPException { @@ -313,8 +313,7 @@ public abstract class SOPGPException extends RuntimeException { } /** - * Key not signature-capable (e.g. expired, revoked, unacceptable usage flags) - * (sop sign and sop encrypt with --sign-with). + * Key not signature-capable (e.g. expired, revoked, unacceptable usage flags). */ public static class KeyCannotSign extends SOPGPException { @@ -324,8 +323,8 @@ public abstract class SOPGPException extends RuntimeException { super(); } - public KeyCannotSign(String s, KeyCannotSign keyCannotSign) { - super(s, keyCannotSign); + public KeyCannotSign(String s, Throwable throwable) { + super(s, throwable); } @Override diff --git a/sop-java/src/main/java/sop/operation/AbstractSign.java b/sop-java/src/main/java/sop/operation/AbstractSign.java index 9aba982..3f9d6fc 100644 --- a/sop-java/src/main/java/sop/operation/AbstractSign.java +++ b/sop-java/src/main/java/sop/operation/AbstractSign.java @@ -4,8 +4,6 @@ package sop.operation; -import sop.ReadyWithResult; -import sop.SigningResult; import sop.exception.SOPGPException; import java.io.ByteArrayInputStream; @@ -28,11 +26,16 @@ public interface AbstractSign { * @param key input stream containing encoded keys * @return builder instance * - * @throws sop.exception.SOPGPException.KeyIsProtected if the key is password protected + * @throws sop.exception.SOPGPException.KeyCannotSign if the key cannot be used for signing * @throws sop.exception.SOPGPException.BadData if the {@link InputStream} does not contain an OpenPGP key + * @throws sop.exception.SOPGPException.UnsupportedAsymmetricAlgo if the key uses an unsupported asymmetric algorithm * @throws IOException in case of an IO error */ - T key(InputStream key) throws SOPGPException.KeyIsProtected, SOPGPException.BadData, IOException; + T key(InputStream key) + throws SOPGPException.KeyCannotSign, + SOPGPException.BadData, + SOPGPException.UnsupportedAsymmetricAlgo, + IOException; /** * Add one or more signing keys. @@ -40,11 +43,16 @@ public interface AbstractSign { * @param key byte array containing encoded keys * @return builder instance * - * @throws sop.exception.SOPGPException.KeyIsProtected if the key is password protected + * @throws sop.exception.SOPGPException.KeyCannotSign if the key cannot be used for signing * @throws sop.exception.SOPGPException.BadData if the byte array does not contain an OpenPGP key + * @throws sop.exception.SOPGPException.UnsupportedAsymmetricAlgo if the key uses an unsupported asymmetric algorithm * @throws IOException in case of an IO error */ - default T key(byte[] key) throws SOPGPException.KeyIsProtected, SOPGPException.BadData, IOException { + default T key(byte[] key) + throws SOPGPException.KeyCannotSign, + SOPGPException.BadData, + SOPGPException.UnsupportedAsymmetricAlgo, + IOException { return key(new ByteArrayInputStream(key)); } @@ -53,8 +61,12 @@ public interface AbstractSign { * * @param password password * @return builder instance + * @throws sop.exception.SOPGPException.UnsupportedOption if key passwords are not supported + * @throws sop.exception.SOPGPException.PasswordNotHumanReadable if the provided passphrase is not human-readable */ - default T withKeyPassword(String password) { + default T withKeyPassword(String password) + throws SOPGPException.UnsupportedOption, + SOPGPException.PasswordNotHumanReadable { return withKeyPassword(password.getBytes(Charset.forName("UTF8"))); } @@ -63,30 +75,11 @@ public interface AbstractSign { * * @param password password * @return builder instance + * @throws sop.exception.SOPGPException.UnsupportedOption if key passwords are not supported + * @throws sop.exception.SOPGPException.PasswordNotHumanReadable if the provided passphrase is not human-readable */ - T withKeyPassword(byte[] password); + T withKeyPassword(byte[] password) + throws SOPGPException.UnsupportedOption, + SOPGPException.PasswordNotHumanReadable; - /** - * Signs data. - * - * @param data input stream containing data - * @return ready - * - * @throws IOException in case of an IO error - * @throws sop.exception.SOPGPException.ExpectedText if text data was expected, but binary data was encountered - */ - ReadyWithResult data(InputStream data) throws IOException, SOPGPException.ExpectedText; - - /** - * Signs data. - * - * @param data byte array containing data - * @return ready - * - * @throws IOException in case of an IO error - * @throws sop.exception.SOPGPException.ExpectedText if text data was expected, but binary data was encountered - */ - default ReadyWithResult data(byte[] data) throws IOException, SOPGPException.ExpectedText { - return data(new ByteArrayInputStream(data)); - } } diff --git a/sop-java/src/main/java/sop/operation/AbstractVerify.java b/sop-java/src/main/java/sop/operation/AbstractVerify.java index 8441996..51d84b7 100644 --- a/sop-java/src/main/java/sop/operation/AbstractVerify.java +++ b/sop-java/src/main/java/sop/operation/AbstractVerify.java @@ -7,6 +7,7 @@ package sop.operation; import sop.exception.SOPGPException; import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.InputStream; import java.util.Date; @@ -24,7 +25,8 @@ public interface AbstractVerify { * @param timestamp timestamp * @return builder instance */ - T notBefore(Date timestamp) throws SOPGPException.UnsupportedOption; + T notBefore(Date timestamp) + throws SOPGPException.UnsupportedOption; /** * Makes the SOP implementation consider signatures after this date invalid. @@ -32,23 +34,34 @@ public interface AbstractVerify { * @param timestamp timestamp * @return builder instance */ - T notAfter(Date timestamp) throws SOPGPException.UnsupportedOption; + T notAfter(Date timestamp) + throws SOPGPException.UnsupportedOption; /** * Add one or more verification cert. * * @param cert input stream containing the encoded certs * @return builder instance + * + * @throws sop.exception.SOPGPException.BadData if the input stream does not contain an OpenPGP certificate + * @throws IOException in case of an IO error */ - T cert(InputStream cert) throws SOPGPException.BadData; + T cert(InputStream cert) + throws SOPGPException.BadData, + IOException; /** * Add one or more verification cert. * * @param cert byte array containing the encoded certs * @return builder instance + * + * @throws sop.exception.SOPGPException.BadData if the byte array does not contain an OpenPGP certificate + * @throws IOException in case of an IO error */ - default T cert(byte[] cert) throws SOPGPException.BadData { + default T cert(byte[] cert) + throws SOPGPException.BadData, + IOException { return cert(new ByteArrayInputStream(cert)); } diff --git a/sop-java/src/main/java/sop/operation/Armor.java b/sop-java/src/main/java/sop/operation/Armor.java index dea3257..a625808 100644 --- a/sop-java/src/main/java/sop/operation/Armor.java +++ b/sop-java/src/main/java/sop/operation/Armor.java @@ -5,6 +5,7 @@ package sop.operation; import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.InputStream; import sop.Ready; @@ -19,23 +20,34 @@ public interface Armor { * @param label armor label * @return builder instance */ - Armor label(ArmorLabel label) throws SOPGPException.UnsupportedOption; + Armor label(ArmorLabel label) + throws SOPGPException.UnsupportedOption; /** * Armor the provided data. * * @param data input stream of unarmored OpenPGP data * @return armored data + * + * @throws sop.exception.SOPGPException.BadData if the data appears to be OpenPGP packets, but those are broken + * @throws IOException in case of an IO error */ - Ready data(InputStream data) throws SOPGPException.BadData; + Ready data(InputStream data) + throws SOPGPException.BadData, + IOException; /** * Armor the provided data. * * @param data unarmored OpenPGP data * @return armored data + * + * @throws sop.exception.SOPGPException.BadData if the data appears to be OpenPGP packets, but those are broken + * @throws IOException in case of an IO error */ - default Ready data(byte[] data) throws SOPGPException.BadData { + default Ready data(byte[] data) + throws SOPGPException.BadData, + IOException { 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 a7d2a46..380c4fc 100644 --- a/sop-java/src/main/java/sop/operation/Dearmor.java +++ b/sop-java/src/main/java/sop/operation/Dearmor.java @@ -22,7 +22,9 @@ public interface Dearmor { * @throws sop.exception.SOPGPException.BadData in case of non-OpenPGP data * @throws IOException in case of an IO error */ - Ready data(InputStream data) throws SOPGPException.BadData, IOException; + Ready data(InputStream data) + throws SOPGPException.BadData, + IOException; /** * Dearmor armored OpenPGP data. @@ -33,7 +35,9 @@ public interface Dearmor { * @throws sop.exception.SOPGPException.BadData in case of non-OpenPGP data * @throws IOException in case of an IO error */ - default Ready data(byte[] data) throws SOPGPException.BadData, IOException { + 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 1caba1b..d695032 100644 --- a/sop-java/src/main/java/sop/operation/Decrypt.java +++ b/sop-java/src/main/java/sop/operation/Decrypt.java @@ -46,10 +46,12 @@ public interface Decrypt { * @return builder instance * * @throws sop.exception.SOPGPException.BadData if the {@link InputStream} doesn't provide an OpenPGP certificate + * @throws sop.exception.SOPGPException.UnsupportedAsymmetricAlgo if the cert uses an unsupported asymmetric algorithm * @throws IOException in case of an IO error */ Decrypt verifyWithCert(InputStream cert) throws SOPGPException.BadData, + SOPGPException.UnsupportedAsymmetricAlgo, IOException; /** @@ -59,10 +61,13 @@ public interface Decrypt { * @return builder instance * * @throws sop.exception.SOPGPException.BadData if the byte array doesn't contain an OpenPGP certificate + * @throws sop.exception.SOPGPException.UnsupportedAsymmetricAlgo if the cert uses an unsupported asymmetric algorithm * @throws IOException in case of an IO error */ default Decrypt verifyWithCert(byte[] cert) - throws SOPGPException.BadData, IOException { + throws SOPGPException.BadData, + SOPGPException.UnsupportedAsymmetricAlgo, + IOException { return verifyWithCert(new ByteArrayInputStream(cert)); } @@ -98,10 +103,12 @@ public interface Decrypt { * * @throws sop.exception.SOPGPException.BadData if the {@link InputStream} does not provide an OpenPGP key * @throws sop.exception.SOPGPException.UnsupportedAsymmetricAlgo if the key uses an unsupported asymmetric algorithm + * @throws IOException in case of an IO error */ Decrypt withKey(InputStream key) throws SOPGPException.BadData, - SOPGPException.UnsupportedAsymmetricAlgo; + SOPGPException.UnsupportedAsymmetricAlgo, + IOException; /** * Adds one or more decryption key. @@ -109,14 +116,14 @@ public interface Decrypt { * @param key byte array containing the key(s) * @return builder instance * - * @throws sop.exception.SOPGPException.KeyIsProtected if the key is password protected * @throws sop.exception.SOPGPException.BadData if the byte array does not contain an OpenPGP key * @throws sop.exception.SOPGPException.UnsupportedAsymmetricAlgo if the key uses an unsupported asymmetric algorithm + * @throws IOException in case of an IO error */ default Decrypt withKey(byte[] key) - throws SOPGPException.KeyIsProtected, - SOPGPException.BadData, - SOPGPException.UnsupportedAsymmetricAlgo { + throws SOPGPException.BadData, + SOPGPException.UnsupportedAsymmetricAlgo, + IOException { return withKey(new ByteArrayInputStream(key)); } @@ -125,8 +132,12 @@ public interface Decrypt { * * @param password password * @return builder instance + * @throws sop.exception.SOPGPException.UnsupportedOption if the implementation does not support key passwords + * @throws sop.exception.SOPGPException.PasswordNotHumanReadable if the password is not human-readable */ - default Decrypt withKeyPassword(String password) { + default Decrypt withKeyPassword(String password) + throws SOPGPException.UnsupportedOption, + SOPGPException.PasswordNotHumanReadable { return withKeyPassword(password.getBytes(Charset.forName("UTF8"))); } @@ -135,8 +146,12 @@ public interface Decrypt { * * @param password password * @return builder instance + * @throws sop.exception.SOPGPException.UnsupportedOption if the implementation does not support key passwords + * @throws sop.exception.SOPGPException.PasswordNotHumanReadable if the password is not human-readable */ - Decrypt withKeyPassword(byte[] password); + Decrypt withKeyPassword(byte[] password) + throws SOPGPException.UnsupportedOption, + SOPGPException.PasswordNotHumanReadable; /** * Decrypts the given ciphertext, returning verification results and plaintext. @@ -144,11 +159,17 @@ public interface Decrypt { * @return ready with result * * @throws sop.exception.SOPGPException.BadData if the {@link InputStream} does not provide an OpenPGP message - * @throws sop.exception.SOPGPException.MissingArg in case of missing decryption method (password or key required) + * @throws sop.exception.SOPGPException.MissingArg if an argument required for decryption was not provided * @throws sop.exception.SOPGPException.CannotDecrypt in case decryption fails for some reason + * @throws sop.exception.SOPGPException.KeyIsProtected if the decryption key cannot be unlocked (e.g. missing passphrase) + * @throws IOException in case of an IO error */ ReadyWithResult ciphertext(InputStream ciphertext) - throws SOPGPException.BadData, SOPGPException.MissingArg, SOPGPException.CannotDecrypt; + throws SOPGPException.BadData, + SOPGPException.MissingArg, + SOPGPException.CannotDecrypt, + SOPGPException.KeyIsProtected, + IOException; /** * Decrypts the given ciphertext, returning verification results and plaintext. @@ -158,9 +179,15 @@ public interface Decrypt { * @throws sop.exception.SOPGPException.BadData if the byte array does not contain an encrypted OpenPGP message * @throws sop.exception.SOPGPException.MissingArg in case of missing decryption method (password or key required) * @throws sop.exception.SOPGPException.CannotDecrypt in case decryption fails for some reason + * @throws sop.exception.SOPGPException.KeyIsProtected if the decryption key cannot be unlocked (e.g. missing passphrase) + * @throws IOException in case of an IO error */ default ReadyWithResult ciphertext(byte[] ciphertext) - throws SOPGPException.BadData, SOPGPException.MissingArg, SOPGPException.CannotDecrypt { + throws SOPGPException.BadData, + SOPGPException.MissingArg, + SOPGPException.CannotDecrypt, + SOPGPException.KeyIsProtected, + IOException { return ciphertext(new ByteArrayInputStream(ciphertext)); } } diff --git a/sop-java/src/main/java/sop/operation/DetachedSign.java b/sop-java/src/main/java/sop/operation/DetachedSign.java index ba3de67..745077d 100644 --- a/sop-java/src/main/java/sop/operation/DetachedSign.java +++ b/sop-java/src/main/java/sop/operation/DetachedSign.java @@ -4,9 +4,13 @@ package sop.operation; +import sop.ReadyWithResult; +import sop.SigningResult; import sop.enums.SignAs; import sop.exception.SOPGPException; +import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.InputStream; public interface DetachedSign extends AbstractSign { @@ -20,6 +24,38 @@ public interface DetachedSign extends AbstractSign { * * @throws sop.exception.SOPGPException.UnsupportedOption if this option is not supported */ - DetachedSign mode(SignAs mode) throws SOPGPException.UnsupportedOption; + DetachedSign mode(SignAs mode) + throws SOPGPException.UnsupportedOption; + /** + * Signs data. + * + * @param data input stream containing data + * @return ready + * + * @throws IOException in case of an IO error + * @throws sop.exception.SOPGPException.KeyIsProtected if at least one signing key cannot be unlocked + * @throws sop.exception.SOPGPException.ExpectedText if text data was expected, but binary data was encountered + */ + ReadyWithResult data(InputStream data) + throws IOException, + SOPGPException.KeyIsProtected, + SOPGPException.ExpectedText; + + /** + * Signs data. + * + * @param data byte array containing data + * @return ready + * + * @throws IOException in case of an IO error + * @throws sop.exception.SOPGPException.KeyIsProtected if at least one signing key cannot be unlocked + * @throws sop.exception.SOPGPException.ExpectedText if text data was expected, but binary data was encountered + */ + default ReadyWithResult data(byte[] data) + throws IOException, + SOPGPException.KeyIsProtected, + SOPGPException.ExpectedText { + return data(new ByteArrayInputStream(data)); + } } diff --git a/sop-java/src/main/java/sop/operation/DetachedVerify.java b/sop-java/src/main/java/sop/operation/DetachedVerify.java index 3927729..9dee870 100644 --- a/sop-java/src/main/java/sop/operation/DetachedVerify.java +++ b/sop-java/src/main/java/sop/operation/DetachedVerify.java @@ -7,6 +7,7 @@ package sop.operation; import sop.exception.SOPGPException; import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.InputStream; /** @@ -19,16 +20,26 @@ public interface DetachedVerify extends AbstractVerify, VerifySi * @param signatures input stream containing encoded, detached signatures. * * @return builder instance + * + * @throws sop.exception.SOPGPException.BadData if the input stream does not contain OpenPGP signatures + * @throws IOException in case of an IO error */ - VerifySignatures signatures(InputStream signatures) throws SOPGPException.BadData; + VerifySignatures signatures(InputStream signatures) + throws SOPGPException.BadData, + IOException; /** * Provides the detached signatures. * @param signatures byte array containing encoded, detached signatures. * * @return builder instance + * + * @throws sop.exception.SOPGPException.BadData if the byte array does not contain OpenPGP signatures + * @throws IOException in case of an IO error */ - default VerifySignatures signatures(byte[] signatures) throws SOPGPException.BadData { + default VerifySignatures signatures(byte[] signatures) + throws SOPGPException.BadData, + IOException { return signatures(new ByteArrayInputStream(signatures)); } } diff --git a/sop-java/src/main/java/sop/operation/Encrypt.java b/sop-java/src/main/java/sop/operation/Encrypt.java index b82419c..09e5f12 100644 --- a/sop-java/src/main/java/sop/operation/Encrypt.java +++ b/sop-java/src/main/java/sop/operation/Encrypt.java @@ -39,16 +39,16 @@ public interface Encrypt { * @param key input stream containing the encoded signer key * @return builder instance * - * @throws sop.exception.SOPGPException.KeyIsProtected if the key is password protected - * @throws sop.exception.SOPGPException.KeyCannotSign if the key is not capable of signing + * @throws sop.exception.SOPGPException.KeyCannotSign if the key cannot be used for signing * @throws sop.exception.SOPGPException.UnsupportedAsymmetricAlgo if the key uses an unsupported asymmetric algorithm * @throws sop.exception.SOPGPException.BadData if the {@link InputStream} does not contain an OpenPGP key + * @throws IOException in case of an IO error */ Encrypt signWith(InputStream key) - throws SOPGPException.KeyIsProtected, - SOPGPException.KeyCannotSign, + throws SOPGPException.KeyCannotSign, SOPGPException.UnsupportedAsymmetricAlgo, - SOPGPException.BadData; + SOPGPException.BadData, + IOException; /** * Adds the signer key. @@ -56,16 +56,16 @@ public interface Encrypt { * @param key byte array containing the encoded signer key * @return builder instance * - * @throws sop.exception.SOPGPException.KeyIsProtected if the key is password protected - * @throws sop.exception.SOPGPException.KeyCannotSign if the key is not capable of signing + * @throws sop.exception.SOPGPException.KeyCannotSign if the key cannot be used for signing * @throws sop.exception.SOPGPException.UnsupportedAsymmetricAlgo if the key uses an unsupported asymmetric algorithm * @throws sop.exception.SOPGPException.BadData if the byte array does not contain an OpenPGP key + * @throws IOException in case of an IO error */ default Encrypt signWith(byte[] key) - throws SOPGPException.KeyIsProtected, - SOPGPException.KeyCannotSign, + throws SOPGPException.KeyCannotSign, SOPGPException.UnsupportedAsymmetricAlgo, - SOPGPException.BadData { + SOPGPException.BadData, + IOException { return signWith(new ByteArrayInputStream(key)); } @@ -74,18 +74,28 @@ public interface Encrypt { * * @param password password * @return builder instance + * + * @throws sop.exception.SOPGPException.PasswordNotHumanReadable if the password is not human-readable + * @throws sop.exception.SOPGPException.UnsupportedOption if key password are not supported */ - default Encrypt withKeyPassword(String password) { + default Encrypt withKeyPassword(String password) + throws SOPGPException.PasswordNotHumanReadable, + SOPGPException.UnsupportedOption { return withKeyPassword(password.getBytes(Charset.forName("UTF8"))); } /** - * Provide the password for the secret key used for sigining. + * Provide the password for the secret key used for signing. * * @param password password * @return builder instance + * + * @throws sop.exception.SOPGPException.PasswordNotHumanReadable if the password is not human-readable + * @throws sop.exception.SOPGPException.UnsupportedOption if key password are not supported */ - Encrypt withKeyPassword(byte[] password); + Encrypt withKeyPassword(byte[] password) + throws SOPGPException.PasswordNotHumanReadable, + SOPGPException.UnsupportedOption; /** * Encrypt with the given password. @@ -109,11 +119,13 @@ public interface Encrypt { * @throws sop.exception.SOPGPException.CertCannotEncrypt if the certificate is not encryption capable * @throws sop.exception.SOPGPException.UnsupportedAsymmetricAlgo if the certificate uses an unsupported asymmetric algorithm * @throws sop.exception.SOPGPException.BadData if the {@link InputStream} does not contain an OpenPGP certificate + * @throws IOException in case of an IO error */ Encrypt withCert(InputStream cert) throws SOPGPException.CertCannotEncrypt, SOPGPException.UnsupportedAsymmetricAlgo, - SOPGPException.BadData; + SOPGPException.BadData, + IOException; /** * Encrypt with the given cert. @@ -124,11 +136,13 @@ public interface Encrypt { * @throws sop.exception.SOPGPException.CertCannotEncrypt if the certificate is not encryption capable * @throws sop.exception.SOPGPException.UnsupportedAsymmetricAlgo if the certificate uses an unsupported asymmetric algorithm * @throws sop.exception.SOPGPException.BadData if the byte array does not contain an OpenPGP certificate + * @throws IOException in case of an IO error */ default Encrypt withCert(byte[] cert) throws SOPGPException.CertCannotEncrypt, SOPGPException.UnsupportedAsymmetricAlgo, - SOPGPException.BadData { + SOPGPException.BadData, + IOException { return withCert(new ByteArrayInputStream(cert)); } @@ -138,9 +152,11 @@ public interface Encrypt { * @return input stream containing the ciphertext * * @throws IOException in case of an IO error + * @throws sop.exception.SOPGPException.KeyIsProtected if at least one signing key cannot be unlocked */ Ready plaintext(InputStream plaintext) - throws IOException; + throws IOException, + SOPGPException.KeyIsProtected; /** * Encrypt the given data yielding the ciphertext. @@ -148,8 +164,11 @@ public interface Encrypt { * @return input stream containing the ciphertext * * @throws IOException in case of an IO error + * @throws sop.exception.SOPGPException.KeyIsProtected if at least one signing key cannot be unlocked */ - default Ready plaintext(byte[] plaintext) throws IOException { + default Ready plaintext(byte[] plaintext) + throws IOException, + SOPGPException.KeyIsProtected { 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 7ebc24c..a862d33 100644 --- a/sop-java/src/main/java/sop/operation/ExtractCert.java +++ b/sop-java/src/main/java/sop/operation/ExtractCert.java @@ -29,7 +29,9 @@ public interface ExtractCert { * @throws IOException in case of an IO error * @throws sop.exception.SOPGPException.BadData if the {@link InputStream} does not contain an OpenPGP key */ - Ready key(InputStream keyInputStream) throws IOException, SOPGPException.BadData; + Ready key(InputStream keyInputStream) + throws IOException, + SOPGPException.BadData; /** * Extract the cert(s) from the provided key(s). @@ -40,7 +42,9 @@ public interface ExtractCert { * @throws IOException in case of an IO error * @throws sop.exception.SOPGPException.BadData if the byte array does not contain an OpenPGP key */ - default Ready key(byte[] key) throws IOException, SOPGPException.BadData { + default Ready key(byte[] key) + throws IOException, + SOPGPException.BadData { return key(new ByteArrayInputStream(key)); } } diff --git a/sop-java/src/main/java/sop/operation/GenerateKey.java b/sop-java/src/main/java/sop/operation/GenerateKey.java index 39cf99c..af7275b 100644 --- a/sop-java/src/main/java/sop/operation/GenerateKey.java +++ b/sop-java/src/main/java/sop/operation/GenerateKey.java @@ -33,8 +33,13 @@ public interface GenerateKey { * * @param password password to protect the key * @return builder instance + * + * @throws sop.exception.SOPGPException.UnsupportedOption if key passwords are not supported + * @throws sop.exception.SOPGPException.PasswordNotHumanReadable if the password is not human-readable */ - GenerateKey withKeyPassword(String password); + GenerateKey withKeyPassword(String password) + throws SOPGPException.PasswordNotHumanReadable, + SOPGPException.UnsupportedOption; /** * Set a password for the key. @@ -42,10 +47,12 @@ public interface GenerateKey { * @param password password to protect the key * @return builder instance * - * @throws sop.exception.SOPGPException.PasswordNotHumanReadable in case of a non-UTF8 password + * @throws sop.exception.SOPGPException.PasswordNotHumanReadable if the password is not human-readable + * @throws sop.exception.SOPGPException.UnsupportedOption if key passwords are not supported */ default GenerateKey withKeyPassword(byte[] password) - throws SOPGPException.PasswordNotHumanReadable { + throws SOPGPException.PasswordNotHumanReadable, + SOPGPException.UnsupportedOption { return withKeyPassword(UTF8Util.decodeUTF8(password)); } @@ -58,5 +65,8 @@ public interface GenerateKey { * @throws sop.exception.SOPGPException.UnsupportedAsymmetricAlgo if the generated key uses an unsupported asymmetric algorithm * @throws IOException in case of an IO error */ - Ready generate() throws SOPGPException.MissingArg, SOPGPException.UnsupportedAsymmetricAlgo, IOException; + Ready generate() + throws SOPGPException.MissingArg, + SOPGPException.UnsupportedAsymmetricAlgo, + IOException; } diff --git a/sop-java/src/main/java/sop/operation/InlineDetach.java b/sop-java/src/main/java/sop/operation/InlineDetach.java index 080ca9f..aba40b1 100644 --- a/sop-java/src/main/java/sop/operation/InlineDetach.java +++ b/sop-java/src/main/java/sop/operation/InlineDetach.java @@ -10,6 +10,7 @@ import java.io.InputStream; import sop.ReadyWithResult; import sop.Signatures; +import sop.exception.SOPGPException; /** * Split cleartext signed messages up into data and signatures. @@ -23,13 +24,17 @@ public interface InlineDetach { InlineDetach noArmor(); /** - * Detach the provided cleartext signed message from its signatures. + * Detach the provided 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 + * @throws sop.exception.SOPGPException.BadData if the input stream does not contain a signed message */ - ReadyWithResult message(InputStream messageInputStream) throws IOException; + ReadyWithResult message(InputStream messageInputStream) + throws IOException, + SOPGPException.BadData; /** * Detach the provided cleartext signed message from its signatures. @@ -37,8 +42,11 @@ public interface InlineDetach { * @param message byte array containing the signed message * @return result containing the detached message * @throws IOException in case of an IO error + * @throws sop.exception.SOPGPException.BadData if the byte array does not contain a signed message */ - default ReadyWithResult message(byte[] message) throws IOException { + default ReadyWithResult message(byte[] message) + throws IOException, + SOPGPException.BadData { return message(new ByteArrayInputStream(message)); } } diff --git a/sop-java/src/main/java/sop/operation/InlineSign.java b/sop-java/src/main/java/sop/operation/InlineSign.java index 46bd0e1..d45aebd 100644 --- a/sop-java/src/main/java/sop/operation/InlineSign.java +++ b/sop-java/src/main/java/sop/operation/InlineSign.java @@ -4,9 +4,12 @@ package sop.operation; +import sop.Ready; import sop.enums.InlineSignAs; import sop.exception.SOPGPException; +import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.InputStream; public interface InlineSign extends AbstractSign { @@ -20,6 +23,38 @@ public interface InlineSign extends AbstractSign { * * @throws sop.exception.SOPGPException.UnsupportedOption if this option is not supported */ - InlineSign mode(InlineSignAs mode) throws SOPGPException.UnsupportedOption; + InlineSign mode(InlineSignAs mode) + throws SOPGPException.UnsupportedOption; + /** + * Signs data. + * + * @param data input stream containing data + * @return ready + * + * @throws IOException in case of an IO error + * @throws sop.exception.SOPGPException.KeyIsProtected if at least one signing key cannot be unlocked + * @throws sop.exception.SOPGPException.ExpectedText if text data was expected, but binary data was encountered + */ + Ready data(InputStream data) + throws IOException, + SOPGPException.KeyIsProtected, + SOPGPException.ExpectedText; + + /** + * Signs data. + * + * @param data byte array containing data + * @return ready + * + * @throws IOException in case of an IO error + * @throws sop.exception.SOPGPException.KeyIsProtected if at least one signing key cannot be unlocked + * @throws sop.exception.SOPGPException.ExpectedText if text data was expected, but binary data was encountered + */ + default Ready data(byte[] data) + throws IOException, + SOPGPException.KeyIsProtected, + SOPGPException.ExpectedText { + return data(new ByteArrayInputStream(data)); + } } diff --git a/sop-java/src/main/java/sop/operation/InlineVerify.java b/sop-java/src/main/java/sop/operation/InlineVerify.java index 3b8031d..ac662a0 100644 --- a/sop-java/src/main/java/sop/operation/InlineVerify.java +++ b/sop-java/src/main/java/sop/operation/InlineVerify.java @@ -30,7 +30,9 @@ public interface InlineVerify extends AbstractVerify { * @throws SOPGPException.BadData when the data is invalid OpenPGP data */ ReadyWithResult> data(InputStream data) - throws IOException, SOPGPException.NoSignature, SOPGPException.BadData; + throws IOException, + SOPGPException.NoSignature, + SOPGPException.BadData; /** * Provide the inline-signed data. @@ -44,7 +46,9 @@ public interface InlineVerify extends AbstractVerify { * @throws SOPGPException.BadData when the data is invalid OpenPGP data */ default ReadyWithResult> data(byte[] data) - throws IOException, SOPGPException.NoSignature, SOPGPException.BadData { + throws IOException, + SOPGPException.NoSignature, + SOPGPException.BadData { return data(new ByteArrayInputStream(data)); } } diff --git a/sop-java/src/main/java/sop/operation/VerifySignatures.java b/sop-java/src/main/java/sop/operation/VerifySignatures.java index d41a8ed..5181514 100644 --- a/sop-java/src/main/java/sop/operation/VerifySignatures.java +++ b/sop-java/src/main/java/sop/operation/VerifySignatures.java @@ -20,10 +20,13 @@ public interface VerifySignatures { * @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.NoSignature when no valid signature is found * @throws SOPGPException.BadData when the data is invalid OpenPGP data */ - List data(InputStream data) throws IOException, SOPGPException.NoSignature, SOPGPException.BadData; + List data(InputStream data) + throws IOException, + SOPGPException.NoSignature, + SOPGPException.BadData; /** * Provide the signed data (without signatures). @@ -31,10 +34,13 @@ public interface VerifySignatures { * @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.NoSignature when no valid signature is found * @throws SOPGPException.BadData when the data is invalid OpenPGP data */ - default List data(byte[] data) throws IOException, SOPGPException.NoSignature, SOPGPException.BadData { + default List data(byte[] data) + throws IOException, + SOPGPException.NoSignature, + SOPGPException.BadData { return data(new ByteArrayInputStream(data)); } }