diff --git a/bcsop-cli/pom.xml b/bcsop-cli/pom.xml
index 03173ba..d17fabe 100644
--- a/bcsop-cli/pom.xml
+++ b/bcsop-cli/pom.xml
@@ -10,14 +10,25 @@
bcsop-cli
+ jar
21
21
UTF-8
+ 0.10.4
+ bcsop-cli-native
+ org.pgpainless.BcSopCLI
+ 21.0.0
+
+ org.graalvm.nativeimage
+ svm
+ ${graal.version}
+ provided
+
org.pgpainless
bcsop
@@ -43,11 +54,51 @@
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 3.11.0
+
+
+
+ info.picocli
+ picocli-codegen
+ 4.6.3
+
+
+
+
+
+
+
org.apache.maven.plugins
maven-assembly-plugin
@@ -58,7 +109,7 @@
- org.pgpainless.BcSopCLI
+ ${mainClass}
@@ -72,6 +123,144 @@
+
+
+
+ org.graalvm.nativeimage
+ native-image-maven-plugin
+ ${graal.version}
+
+ ${imageName}
+ ${mainClass}
+
+
+
+
+ native-image
+
+ package
+
+
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 3.0.0
+
+
+ generateGraalReflectionConfig
+ process-classes
+
+ java
+
+
+ true
+ true
+ picocli.codegen.aot.graalvm.ReflectionConfigGenerator
+
+ --output=bcsop-cli/target/classes/META-INF/native-image/${project.groupId}/${project.artifactId}/reflect-config.json
+
+ sop.cli.picocli.SopCLI
+
+
+
+
+
+ generateGraalDynamicProxyConfig
+ process-classes
+
+ java
+
+
+ true
+ true
+ picocli.codegen.aot.graalvm.DynamicProxyConfigGenerator
+
+ --output=bcsop-cli/target/classes/META-INF/native-image/${project.groupId}/${project.artifactId}/proxy-config.json
+
+ sop.cli.picocli.SopCLI
+
+
+
+
+
+ generateGraalResourceConfig
+ process-classes
+
+ java
+
+
+ true
+ true
+ picocli.codegen.aot.graalvm.ResourceConfigGenerator
+
+ --output=bcsop-cli/target/classes/META-INF/native-image/${project.groupId}/${project.artifactId}/resource-config.json
+
+ sop.cli.picocli.SopCLI
+
+
+
+
+
+
+
+ info.picocli
+ picocli-codegen
+ 4.6.3
+ jar
+
+
+
-
\ No newline at end of file
+
diff --git a/bcsop-cli/src/main/java/org/pgpainless/BcSopCLI.java b/bcsop-cli/src/main/java/org/pgpainless/BcSopCLI.java
index 725d47d..bf21034 100644
--- a/bcsop-cli/src/main/java/org/pgpainless/BcSopCLI.java
+++ b/bcsop-cli/src/main/java/org/pgpainless/BcSopCLI.java
@@ -1,14 +1,27 @@
package org.pgpainless;
import org.pgpainless.bouncycastle.sop.BouncyCastleSOP;
+import picocli.CommandLine;
+import sop.cli.picocli.SOPExceptionExitCodeMapper;
+import sop.cli.picocli.SOPExecutionExceptionHandler;
import sop.cli.picocli.SopCLI;
-public class BcSopCLI {
+public class BcSopCLI extends SopCLI {
public static void main(String[] args) {
SopCLI.EXECUTABLE_NAME = "bc-sop";
SopCLI.setSopInstance(new BouncyCastleSOP());
- int exitCode = SopCLI.execute(args);
- System.exit(exitCode);
+ System.exit(run(args));
+ }
+
+ public static int run(String[] args)
+ {
+ CommandLine cmd = new CommandLine(SopCLI.class);
+ cmd.getSubcommands().get("generate-completion").getCommandSpec().usageMessage().hidden(true);
+ cmd.setCommandName("bcsop");
+ cmd.setExecutionExceptionHandler(new SOPExecutionExceptionHandler());
+ cmd.setExitCodeExceptionMapper(new SOPExceptionExitCodeMapper());
+ cmd.setCaseInsensitiveEnumValuesAllowed(true);
+ return cmd.execute(args);
}
}
\ No newline at end of file
diff --git a/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/AbstractBCOperation.java b/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/AbstractBCOperation.java
index 9a37617..026c7a3 100644
--- a/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/AbstractBCOperation.java
+++ b/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/AbstractBCOperation.java
@@ -23,10 +23,10 @@ public abstract class AbstractBCOperation
return new SessionKey((byte) sessionKey.getAlgorithm(), sessionKey.getKey());
}
- protected List getVerifications(OpenPGPMessageInputStream.Result result)
+ protected List getVerifications(List signatures)
{
List verifications = new ArrayList<>();
- for (OpenPGPSignature.OpenPGPDocumentSignature sig : result.getSignatures())
+ for (OpenPGPSignature.OpenPGPDocumentSignature sig : signatures)
{
if (sig.isValid())
{
diff --git a/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCArmor.java b/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCArmor.java
index cdc1a16..28706ed 100644
--- a/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCArmor.java
+++ b/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCArmor.java
@@ -4,7 +4,6 @@ import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.util.io.Streams;
import org.jetbrains.annotations.NotNull;
import sop.Ready;
-import sop.enums.ArmorLabel;
import sop.exception.SOPGPException;
import sop.operation.Armor;
@@ -30,10 +29,4 @@ public class BCArmor
}
};
}
-
- @NotNull
- @Override
- public Armor label(@NotNull ArmorLabel armorLabel) throws SOPGPException.UnsupportedOption {
- throw new SOPGPException.UnsupportedOption("Custom labels not supported.");
- }
}
diff --git a/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCDecrypt.java b/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCDecrypt.java
index 7b65fad..4042899 100644
--- a/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCDecrypt.java
+++ b/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCDecrypt.java
@@ -26,8 +26,7 @@ public class BCDecrypt
private Date notBefore = new Date(Long.MAX_VALUE); // end of time
private Date notAfter = new Date(); // now
- private final List encryptionKeys = new ArrayList<>();
- private final List encryptionKeyPassphrases = new ArrayList<>();
+ private char[] keyPassword;
private final OpenPGPMessageProcessor processor = new OpenPGPMessageProcessor();
@@ -35,7 +34,7 @@ public class BCDecrypt
@NotNull
@Override
public ReadyWithResult ciphertext(@NotNull InputStream inputStream) throws SOPGPException.BadData, SOPGPException.MissingArg, SOPGPException.CannotDecrypt, SOPGPException.KeyIsProtected, IOException {
- return new ReadyWithResult() {
+ return new ReadyWithResult<>() {
@Override
public DecryptionResult writeTo(@NotNull OutputStream outputStream) throws IOException, SOPGPException {
try {
@@ -45,7 +44,7 @@ public class BCDecrypt
OpenPGPMessageInputStream.Result result = mIn.getResult();
return new DecryptionResult(
getSessionKey(result),
- getVerifications(result));
+ getVerifications(result.getSignatures()));
} catch (PGPException e) {
throw new RuntimeException(e);
}
@@ -93,7 +92,7 @@ public class BCDecrypt
@Override
public Decrypt withKey(@NotNull InputStream inputStream) throws SOPGPException.BadData, SOPGPException.UnsupportedAsymmetricAlgo, IOException {
OpenPGPKey key = OpenPGPKey.fromInputStream(inputStream);
- processor.addDecryptionKey(key);
+ processor.addDecryptionKey(key, keyPassword);
return this;
}
@@ -101,7 +100,7 @@ public class BCDecrypt
@Override
public Decrypt withKeyPassword(@NotNull byte[] bytes) throws SOPGPException.UnsupportedOption, SOPGPException.PasswordNotHumanReadable {
String passphrase = new String(bytes);
- this.encryptionKeyPassphrases.add(passphrase);
+ this.keyPassword = passphrase.toCharArray();
return this;
}
}
diff --git a/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCDetachedSign.java b/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCDetachedSign.java
index 87562cd..f046414 100644
--- a/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCDetachedSign.java
+++ b/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCDetachedSign.java
@@ -26,6 +26,7 @@ public class BCDetachedSign
private final OpenPGPDetachedSignatureGenerator sigGen = new OpenPGPDetachedSignatureGenerator();
private boolean armored = true;
+ private char[] keyPassword = null;
@NotNull
@Override
@@ -96,7 +97,7 @@ public class BCDetachedSign
public DetachedSign key(@NotNull InputStream inputStream) throws SOPGPException.KeyCannotSign, SOPGPException.BadData, SOPGPException.UnsupportedAsymmetricAlgo, IOException {
try
{
- sigGen.addSigningKey(OpenPGPKey.fromInputStream(inputStream), null);
+ sigGen.addSigningKey(OpenPGPKey.fromInputStream(inputStream), keyPassword);
}
catch (InvalidSigningKeyException e)
{
@@ -111,6 +112,7 @@ public class BCDetachedSign
@Override
public DetachedSign withKeyPassword(@NotNull byte[] bytes) throws SOPGPException.UnsupportedOption, SOPGPException.PasswordNotHumanReadable {
+ keyPassword = new String(bytes).toCharArray();
return this;
}
}
diff --git a/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCDetachedVerify.java b/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCDetachedVerify.java
index e3d3a28..f838159 100644
--- a/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCDetachedVerify.java
+++ b/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCDetachedVerify.java
@@ -56,16 +56,10 @@ public class BCDetachedVerify
public List data(@NotNull InputStream inputStream) throws IOException, SOPGPException.NoSignature, SOPGPException.BadData {
List signatures = processor.verify(inputStream);
- List verifications = new ArrayList<>();
- for (OpenPGPSignature.OpenPGPDocumentSignature signature : signatures)
+ List verifications = getVerifications(signatures);
+ if (verifications.isEmpty())
{
- if (signature.isValidAt(signature.getCreationTime()))
- {
- verifications.add(new Verification(
- signature.getCreationTime(),
- Hex.toHexString(signature.getIssuer().getKeyIdentifier().getFingerprint()),
- Hex.toHexString(signature.getIssuerCertificate().getFingerprint())));
- }
+ throw new SOPGPException.NoSignature();
}
return verifications;
}
diff --git a/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCEncrypt.java b/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCEncrypt.java
index f34cca8..44f3ea6 100644
--- a/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCEncrypt.java
+++ b/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCEncrypt.java
@@ -2,6 +2,7 @@ package org.pgpainless.bouncycastle.sop.operation;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.api.OpenPGPCertificate;
+import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.bouncycastle.openpgp.api.OpenPGPMessageGenerator;
import org.bouncycastle.openpgp.api.OpenPGPMessageOutputStream;
import org.bouncycastle.util.io.Streams;
@@ -22,6 +23,7 @@ public class BCEncrypt
implements Encrypt {
private final OpenPGPMessageGenerator mGen;
+ private char[] keyPassword;
public BCEncrypt()
{
@@ -45,12 +47,15 @@ public class BCEncrypt
@NotNull
@Override
public Encrypt signWith(@NotNull InputStream inputStream) throws SOPGPException.KeyCannotSign, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.BadData, IOException {
+ OpenPGPKey key = OpenPGPKey.fromInputStream(inputStream);
+ mGen.addSigningKey(key, k -> keyPassword);
return this;
}
@NotNull
@Override
public Encrypt withKeyPassword(@NotNull byte[] bytes) throws SOPGPException.PasswordNotHumanReadable, SOPGPException.UnsupportedOption {
+ this.keyPassword = new String(bytes).toCharArray();
return this;
}
diff --git a/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCGenerateKey.java b/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCGenerateKey.java
index 946b868..7d8a4e5 100644
--- a/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCGenerateKey.java
+++ b/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCGenerateKey.java
@@ -33,23 +33,33 @@ public class BCGenerateKey
public void writeTo(@NotNull OutputStream outputStream) throws IOException
{
OpenPGPV6KeyGenerator generator = new BcOpenPGPV6KeyGenerator(new Date());
+ OpenPGPKey key;
try
{
- PGPSecretKeyRing keyRing = generator.ed25519x25519Key(userId, passphrase);
- OpenPGPKey key = new OpenPGPKey(keyRing);
- if (armor)
+ if (signOnly)
{
- outputStream.write(key.toAsciiArmoredString().getBytes(StandardCharsets.UTF_8));
+ PGPSecretKeyRing keyRing = generator.signOnlyKey(passphrase);
+ key = new OpenPGPKey(keyRing);
}
else
{
- keyRing.encode(outputStream);
+ PGPSecretKeyRing keyRing = generator.ed25519x25519Key(userId, passphrase);
+ key = new OpenPGPKey(keyRing);
}
}
catch (PGPException e)
{
throw new RuntimeException(e);
}
+
+ if (armor)
+ {
+ outputStream.write(key.toAsciiArmoredString().getBytes(StandardCharsets.UTF_8));
+ }
+ else
+ {
+ key.getPGPKeyRing().encode(outputStream);
+ }
}
};
}
diff --git a/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCInlineSign.java b/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCInlineSign.java
index a8f3892..3f187fe 100644
--- a/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCInlineSign.java
+++ b/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCInlineSign.java
@@ -17,9 +17,11 @@ import java.io.OutputStream;
public class BCInlineSign
extends AbstractBCOperation
- implements InlineSign {
+ implements InlineSign
+{
private final OpenPGPMessageGenerator mGen = new OpenPGPMessageGenerator();
+ private char[] keyPassword;
@NotNull
@Override
@@ -52,12 +54,13 @@ public class BCInlineSign
@Override
public InlineSign key(@NotNull InputStream inputStream) throws SOPGPException.KeyCannotSign, SOPGPException.BadData, SOPGPException.UnsupportedAsymmetricAlgo, IOException {
- mGen.addSigningKey(OpenPGPKey.fromInputStream(inputStream));
+ mGen.addSigningKey(OpenPGPKey.fromInputStream(inputStream), k -> keyPassword);
return this;
}
@Override
public InlineSign withKeyPassword(@NotNull byte[] bytes) throws SOPGPException.UnsupportedOption, SOPGPException.PasswordNotHumanReadable {
+ this.keyPassword = new String(bytes).toCharArray();
return this;
}
}
diff --git a/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCInlineVerify.java b/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCInlineVerify.java
index a747bea..ecbe6af 100644
--- a/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCInlineVerify.java
+++ b/bcsop/src/main/java/org/pgpainless/bouncycastle/sop/operation/BCInlineVerify.java
@@ -26,7 +26,7 @@ public class BCInlineVerify
@NotNull
@Override
public ReadyWithResult> data(@NotNull InputStream inputStream) throws IOException, SOPGPException.NoSignature, SOPGPException.BadData {
- return new ReadyWithResult>() {
+ return new ReadyWithResult<>() {
@Override
public List writeTo(@NotNull OutputStream outputStream) throws IOException, SOPGPException {
try {
@@ -34,7 +34,12 @@ public class BCInlineVerify
Streams.pipeAll(mIn, outputStream);
mIn.close();
OpenPGPMessageInputStream.Result result = mIn.getResult();
- return getVerifications(result);
+ List verifications = getVerifications(result.getSignatures());
+ if (verifications.isEmpty())
+ {
+ throw new SOPGPException.NoSignature();
+ }
+ return verifications;
} catch (PGPException e) {
throw new RuntimeException(e);
}
diff --git a/pom.xml b/pom.xml
index 38a5952..6ba8e59 100644
--- a/pom.xml
+++ b/pom.xml
@@ -48,12 +48,12 @@
org.pgpainless
sop-java
- 10.0.0
+ 10.0.3-SNAPSHOT
org.pgpainless
sop-java-picocli
- 10.0.0
+ 10.0.3-SNAPSHOT