mirror of
https://codeberg.org/PGPainless/bc-sop.git
synced 2025-09-10 19:59:40 +02:00
Rename modules
This commit is contained in:
parent
ec4bb0c5db
commit
a08340b4e1
33 changed files with 11 additions and 16 deletions
68
bc-sop-api/pom.xml
Normal file
68
bc-sop-api/pom.xml
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.pgpainless</groupId>
|
||||
<artifactId>bc-sop</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>bc-sop-api</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.pgpainless</groupId>
|
||||
<artifactId>sop-java</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.pgpainless</groupId>
|
||||
<artifactId>sop-java-testfixtures</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk18on</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcpg-jdk18on</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcutil-jdk18on</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<environmentVariables>
|
||||
<test.implementation>org.pgpainless.bouncycastle.sop.BouncyCastleSOPInstanceFactory</test.implementation>
|
||||
</environmentVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,139 @@
|
|||
package org.pgpainless.bouncycastle.sop;
|
||||
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPApi;
|
||||
import org.bouncycastle.openpgp.api.bc.BcOpenPGPApi;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.pgpainless.bouncycastle.sop.operation.BCArmor;
|
||||
import org.pgpainless.bouncycastle.sop.operation.BCDearmor;
|
||||
import org.pgpainless.bouncycastle.sop.operation.BCDecrypt;
|
||||
import org.pgpainless.bouncycastle.sop.operation.BCDetachedSign;
|
||||
import org.pgpainless.bouncycastle.sop.operation.BCDetachedVerify;
|
||||
import org.pgpainless.bouncycastle.sop.operation.BCEncrypt;
|
||||
import org.pgpainless.bouncycastle.sop.operation.BCExtractCert;
|
||||
import org.pgpainless.bouncycastle.sop.operation.BCGenerateKey;
|
||||
import org.pgpainless.bouncycastle.sop.operation.BCInlineSign;
|
||||
import org.pgpainless.bouncycastle.sop.operation.BCInlineVerify;
|
||||
import org.pgpainless.bouncycastle.sop.operation.BCListProfiles;
|
||||
import org.pgpainless.bouncycastle.sop.operation.BCVersion;
|
||||
import sop.SOP;
|
||||
import sop.exception.SOPGPException;
|
||||
import sop.operation.Armor;
|
||||
import sop.operation.ChangeKeyPassword;
|
||||
import sop.operation.Dearmor;
|
||||
import sop.operation.Decrypt;
|
||||
import sop.operation.DetachedSign;
|
||||
import sop.operation.DetachedVerify;
|
||||
import sop.operation.Encrypt;
|
||||
import sop.operation.ExtractCert;
|
||||
import sop.operation.GenerateKey;
|
||||
import sop.operation.InlineDetach;
|
||||
import sop.operation.InlineSign;
|
||||
import sop.operation.InlineVerify;
|
||||
import sop.operation.ListProfiles;
|
||||
import sop.operation.RevokeKey;
|
||||
import sop.operation.Version;
|
||||
|
||||
import java.security.Security;
|
||||
|
||||
public class BouncyCastleSOP implements SOP {
|
||||
|
||||
private final OpenPGPApi api;
|
||||
|
||||
public BouncyCastleSOP()
|
||||
{
|
||||
Security.removeProvider("BC");
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
this.api = new BcOpenPGPApi();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Armor armor() {
|
||||
return new BCArmor(api);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GenerateKey generateKey() {
|
||||
return new BCGenerateKey(api);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ExtractCert extractCert() {
|
||||
return new BCExtractCert(api);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DetachedSign detachedSign() {
|
||||
return new BCDetachedSign(api);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public InlineSign inlineSign() {
|
||||
return new BCInlineSign(api);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public InlineDetach inlineDetach() {
|
||||
throw new SOPGPException.UnsupportedSubcommand("inline-detach is not implemented.");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Encrypt encrypt() {
|
||||
return new BCEncrypt(api);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Decrypt decrypt() {
|
||||
return new BCDecrypt(api);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Dearmor dearmor() {
|
||||
return new BCDearmor(api);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ListProfiles listProfiles() {
|
||||
return new BCListProfiles(api);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public RevokeKey revokeKey() {
|
||||
throw new SOPGPException.UnsupportedSubcommand("revoke-key is not implemented.");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ChangeKeyPassword changeKeyPassword() {
|
||||
throw new SOPGPException.UnsupportedSubcommand("change-key-password is not implemented.");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Version version() {
|
||||
return new BCVersion(api);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DetachedVerify detachedVerify() {
|
||||
return new BCDetachedVerify(api);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public InlineVerify inlineVerify() {
|
||||
return new BCInlineVerify(api);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package org.pgpainless.bouncycastle.sop;
|
||||
|
||||
import sop.Verification;
|
||||
import sop.operation.DetachedVerify;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.SequenceInputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
public class DetachedVerifyTest {
|
||||
|
||||
static String SIG = "-----BEGIN PGP SIGNATURE-----\n" +
|
||||
"\n" +
|
||||
"wnUEABYKAB0WIQTrhbtfozp14V6UTmPyMVUMT0fjjgUCZ1mi4QAKCRDyMVUMT0fj\n" +
|
||||
"jun3AP9ZiRPXlow7ywR3D7nC4/GGUC+PueZ1GkcXDtE8zbAiTgEArkOQO8qhC0QG\n" +
|
||||
"K6TKEPJM07Zie/kgcGyh8HfSpbunwAXCwPMEAAEKAB0WIQTRpm4aI7GCyZgPeIz7\n" +
|
||||
"/MgqAV5zMAUCZ1mi4QAKCRD7/MgqAV5zMI51C/sFv6vjBbxdgNMp1qwJ3AqMhbtV\n" +
|
||||
"WJ7z8HJraT+dW0VKYmib7H7lL3x3gTC85VaOWGU3mqhxZLQVi6j99pbbZjGXJADF\n" +
|
||||
"e5E1S+tp6js56OI4fY/kchLMcz1JxgjSJPJnlyEXy5C2/2RlI1JmpUn6Y8YOlNhZ\n" +
|
||||
"Vbov36QB2ILt+k62ElQeHgWQYqWWMmxmdk9wipNKYfBoQNVwJNICDjI+XlwL4cGw\n" +
|
||||
"nyg3cdgkKXikPFEBhlApI5HmX4jOv68gReEMMTaZoQoRD8kzg9m7KC6BqHpG0TAZ\n" +
|
||||
"Bz5TzZrxW1LdXj/tKqNONcldHHzO4mZIUkdOowGMBmEf0kZ2nVHZGaWE1T7IqJPo\n" +
|
||||
"cIPtZB+EpDCcPQN35ekC0B1ilDd07IulNHOdbhI7xu0/eQb6dGpkzkak3OpWbGtX\n" +
|
||||
"rKfxljqLFTnnJfM95UlrlCWwEplRZ2q4QhXi8/mRM/Szz5D3KGd7hnLRnr42J4Dr\n" +
|
||||
"j/XWKoSXmFZ5t6CBq7BgubE1uO2ToRWOlas+jNE=\n" +
|
||||
"=bJ8+\n" +
|
||||
"-----END PGP SIGNATURE-----";
|
||||
static String ALICE = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" +
|
||||
"Comment: Alice's OpenPGP certificate\n" +
|
||||
"\n" +
|
||||
"mDMEXEcE6RYJKwYBBAHaRw8BAQdArjWwk3FAqyiFbFBKT4TzXcVBqPTB3gmzlC/U\n" +
|
||||
"b7O1u120JkFsaWNlIExvdmVsYWNlIDxhbGljZUBvcGVucGdwLmV4YW1wbGU+iJAE\n" +
|
||||
"ExYIADgCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQTrhbtfozp14V6UTmPy\n" +
|
||||
"MVUMT0fjjgUCXaWfOgAKCRDyMVUMT0fjjukrAPoDnHBSogOmsHOsd9qGsiZpgRnO\n" +
|
||||
"dypvbm+QtXZqth9rvwD9HcDC0tC+PHAsO7OTh1S1TC9RiJsvawAfCPaQZoed8gK4\n" +
|
||||
"OARcRwTpEgorBgEEAZdVAQUBAQdAQv8GIa2rSTzgqbXCpDDYMiKRVitCsy203x3s\n" +
|
||||
"E9+eviIDAQgHiHgEGBYIACAWIQTrhbtfozp14V6UTmPyMVUMT0fjjgUCXEcE6QIb\n" +
|
||||
"DAAKCRDyMVUMT0fjjlnQAQDFHUs6TIcxrNTtEZFjUFm1M0PJ1Dng/cDW4xN80fsn\n" +
|
||||
"0QEA22Kr7VkCjeAEC08VSTeV+QFsmz55/lntWkwYWhmvOgE=\n" +
|
||||
"=iIGO\n" +
|
||||
"-----END PGP PUBLIC KEY BLOCK-----";
|
||||
static String BOB = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" +
|
||||
"Comment: Bob's OpenPGP certificate\n" +
|
||||
"\n" +
|
||||
"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\n" +
|
||||
"NEJd3XZRzaXZE2aAMQ==\n" +
|
||||
"=NXei\n" +
|
||||
"-----END PGP PUBLIC KEY BLOCK-----";
|
||||
static String MSG = "Hello World :)";
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
BouncyCastleSOP sop = new BouncyCastleSOP();
|
||||
ByteArrayInputStream sigIn = new ByteArrayInputStream(SIG.getBytes(StandardCharsets.UTF_8));
|
||||
DetachedVerify verify = sop.detachedVerify();
|
||||
verify.signatures(sigIn);
|
||||
verify.cert(new ByteArrayInputStream(ALICE.getBytes(StandardCharsets.UTF_8)))
|
||||
.cert(new ByteArrayInputStream(BOB.getBytes(StandardCharsets.UTF_8)));
|
||||
List<Verification> verif = verify.data(new ByteArrayInputStream(MSG.getBytes(StandardCharsets.UTF_8)));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPSessionKey;
|
||||
import org.bouncycastle.openpgp.PGPSignatureException;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPApi;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPMessageInputStream;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPSignature;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
import sop.SessionKey;
|
||||
import sop.Verification;
|
||||
import sop.exception.SOPGPException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public abstract class AbstractBCOperation
|
||||
{
|
||||
protected final OpenPGPApi api;
|
||||
|
||||
protected AbstractBCOperation(OpenPGPApi api)
|
||||
{
|
||||
this.api = api;
|
||||
}
|
||||
|
||||
protected SessionKey getSessionKey(OpenPGPMessageInputStream.Result result)
|
||||
{
|
||||
PGPSessionKey sessionKey = result.getSessionKey();
|
||||
if (sessionKey == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new SessionKey((byte) sessionKey.getAlgorithm(), sessionKey.getKey());
|
||||
}
|
||||
|
||||
protected List<Verification> getVerifications(List<OpenPGPSignature.OpenPGPDocumentSignature> signatures)
|
||||
{
|
||||
List<Verification> verifications = new ArrayList<>();
|
||||
for (OpenPGPSignature.OpenPGPDocumentSignature sig : signatures)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (sig.isValid())
|
||||
{
|
||||
Verification verification = new Verification(sig.getCreationTime(),
|
||||
Hex.toHexString(sig.getIssuer().getKeyIdentifier().getFingerprint()).toUpperCase(Locale.ROOT),
|
||||
Hex.toHexString(sig.getIssuerCertificate().getFingerprint()).toUpperCase(Locale.ROOT));
|
||||
verifications.add(verification);
|
||||
}
|
||||
}
|
||||
catch (PGPSignatureException e)
|
||||
{
|
||||
// ignore malformed, invalid sig
|
||||
}
|
||||
}
|
||||
return verifications;
|
||||
}
|
||||
|
||||
protected OpenPGPCertificate parseCertificate(InputStream inputStream)
|
||||
{
|
||||
try {
|
||||
return api.readKeyOrCertificate().parseCertificate(inputStream);
|
||||
} catch (IOException e) {
|
||||
throw new SOPGPException.BadData(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected OpenPGPKey parseKey(InputStream inputStream)
|
||||
{
|
||||
try {
|
||||
return api.readKeyOrCertificate().parseKey(inputStream);
|
||||
} catch (IOException e) {
|
||||
throw new SOPGPException.BadData(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPApi;
|
||||
import org.bouncycastle.util.io.Streams;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import sop.Ready;
|
||||
import sop.exception.SOPGPException;
|
||||
import sop.operation.Armor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class BCArmor
|
||||
extends AbstractBCOperation
|
||||
implements Armor {
|
||||
|
||||
public BCArmor(OpenPGPApi api) {
|
||||
super(api);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Ready data(@NotNull InputStream inputStream) throws SOPGPException.BadData, IOException {
|
||||
return new Ready() {
|
||||
@Override
|
||||
public void writeTo(@NotNull OutputStream outputStream) throws IOException {
|
||||
ArmoredOutputStream aOut = ArmoredOutputStream.builder()
|
||||
.clearHeaders()
|
||||
.build(outputStream);
|
||||
Streams.pipeAll(inputStream, aOut);
|
||||
aOut.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import org.bouncycastle.bcpg.ArmoredInputStream;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPApi;
|
||||
import org.bouncycastle.util.io.Streams;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import sop.Ready;
|
||||
import sop.exception.SOPGPException;
|
||||
import sop.operation.Dearmor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class BCDearmor
|
||||
extends AbstractBCOperation
|
||||
implements Dearmor {
|
||||
|
||||
public BCDearmor(OpenPGPApi api) {
|
||||
super(api);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Ready data(@NotNull InputStream inputStream) throws SOPGPException.BadData, IOException {
|
||||
return new Ready() {
|
||||
@Override
|
||||
public void writeTo(@NotNull OutputStream outputStream) throws IOException {
|
||||
ArmoredInputStream aIn = new ArmoredInputStream(inputStream);
|
||||
Streams.pipeAll(aIn, outputStream);
|
||||
aIn.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPSessionKey;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPApi;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPMessageInputStream;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPMessageProcessor;
|
||||
import org.bouncycastle.util.io.Streams;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import sop.DecryptionResult;
|
||||
import sop.ReadyWithResult;
|
||||
import sop.SessionKey;
|
||||
import sop.exception.SOPGPException;
|
||||
import sop.operation.Decrypt;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Date;
|
||||
|
||||
public class BCDecrypt
|
||||
extends AbstractBCOperation
|
||||
implements Decrypt {
|
||||
|
||||
private final OpenPGPMessageProcessor processor;
|
||||
|
||||
private char[] keyPassword;
|
||||
|
||||
public BCDecrypt(OpenPGPApi api) {
|
||||
super(api);
|
||||
this.processor = api.decryptAndOrVerifyMessage();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ReadyWithResult<DecryptionResult> ciphertext(@NotNull InputStream inputStream) throws SOPGPException.BadData, SOPGPException.MissingArg, SOPGPException.CannotDecrypt, SOPGPException.KeyIsProtected, IOException {
|
||||
return new ReadyWithResult<>() {
|
||||
@Override
|
||||
public DecryptionResult writeTo(@NotNull OutputStream outputStream) throws IOException, SOPGPException {
|
||||
try {
|
||||
OpenPGPMessageInputStream mIn = processor.process(inputStream);
|
||||
Streams.pipeAll(mIn, outputStream);
|
||||
mIn.close();
|
||||
OpenPGPMessageInputStream.Result result = mIn.getResult();
|
||||
return new DecryptionResult(
|
||||
getSessionKey(result),
|
||||
getVerifications(result.getSignatures()));
|
||||
} catch (PGPException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Decrypt verifyNotBefore(@NotNull Date date) throws SOPGPException.UnsupportedOption {
|
||||
processor.verifyNotBefore(date);
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Decrypt verifyNotAfter(@NotNull Date date) throws SOPGPException.UnsupportedOption {
|
||||
processor.verifyNotAfter(date);
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Decrypt verifyWithCert(@NotNull InputStream inputStream) throws SOPGPException.BadData, SOPGPException.UnsupportedAsymmetricAlgo, IOException {
|
||||
processor.addVerificationCertificate(parseCertificate(inputStream));
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Decrypt withSessionKey(@NotNull SessionKey sessionKey) throws SOPGPException.UnsupportedOption {
|
||||
processor.setSessionKey(new PGPSessionKey(sessionKey.getAlgorithm(), sessionKey.getKey()));
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Decrypt withPassword(@NotNull String s) throws SOPGPException.PasswordNotHumanReadable, SOPGPException.UnsupportedOption {
|
||||
processor.addMessagePassphrase(s.toCharArray());
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Decrypt withKey(@NotNull InputStream inputStream) throws SOPGPException.BadData, SOPGPException.UnsupportedAsymmetricAlgo, IOException {
|
||||
processor.addDecryptionKey(parseKey(inputStream), keyPassword);
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Decrypt withKeyPassword(@NotNull byte[] bytes) throws SOPGPException.UnsupportedOption, SOPGPException.PasswordNotHumanReadable {
|
||||
String passphrase = new String(bytes);
|
||||
this.keyPassword = passphrase.toCharArray();
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
||||
import org.bouncycastle.bcpg.BCPGOutputStream;
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPApi;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPDetachedSignatureGenerator;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPSignature;
|
||||
import org.bouncycastle.openpgp.api.SignatureParameters;
|
||||
import org.bouncycastle.openpgp.api.exception.InvalidSigningKeyException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import sop.MicAlg;
|
||||
import sop.ReadyWithResult;
|
||||
import sop.SigningResult;
|
||||
import sop.enums.SignAs;
|
||||
import sop.exception.SOPGPException;
|
||||
import sop.operation.DetachedSign;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
|
||||
public class BCDetachedSign
|
||||
extends AbstractBCOperation
|
||||
implements DetachedSign {
|
||||
|
||||
private final OpenPGPDetachedSignatureGenerator sigGen;
|
||||
private boolean armored = true;
|
||||
private char[] keyPassword = null;
|
||||
|
||||
private int signatureMode = PGPSignature.BINARY_DOCUMENT;
|
||||
|
||||
public BCDetachedSign(OpenPGPApi api) {
|
||||
super(api);
|
||||
sigGen = api.createDetachedSignature();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ReadyWithResult<SigningResult> data(@NotNull InputStream inputStream) throws IOException, SOPGPException.KeyIsProtected, SOPGPException.ExpectedText {
|
||||
return new ReadyWithResult<SigningResult>() {
|
||||
@Override
|
||||
public SigningResult writeTo(@NotNull OutputStream outputStream) throws IOException, SOPGPException {
|
||||
try
|
||||
{
|
||||
List<OpenPGPSignature.OpenPGPDocumentSignature> signatures = sigGen.sign(inputStream);
|
||||
OutputStream aOut = null;
|
||||
OutputStream pOut;
|
||||
if (armored)
|
||||
{
|
||||
aOut = ArmoredOutputStream.builder()
|
||||
.clearHeaders()
|
||||
.build(outputStream);
|
||||
pOut = BCPGOutputStream.wrap(aOut);
|
||||
}
|
||||
else
|
||||
{
|
||||
pOut = BCPGOutputStream.wrap(outputStream);
|
||||
}
|
||||
|
||||
for (OpenPGPSignature.OpenPGPDocumentSignature sig : signatures)
|
||||
{
|
||||
pOut.write(sig.getSignature().getEncoded());
|
||||
}
|
||||
|
||||
pOut.close();
|
||||
if (aOut != null)
|
||||
{
|
||||
aOut.close();
|
||||
}
|
||||
|
||||
return new SigningResult(MicAlg.fromHashAlgorithmId(signatures.get(0).getSignature().getHashAlgorithm()));
|
||||
}
|
||||
catch (PGPException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DetachedSign mode(@NotNull SignAs signAs) throws SOPGPException.UnsupportedOption {
|
||||
switch (signAs)
|
||||
{
|
||||
case text:
|
||||
signatureMode = PGPSignature.CANONICAL_TEXT_DOCUMENT;
|
||||
break;
|
||||
case binary:
|
||||
signatureMode = PGPSignature.BINARY_DOCUMENT;
|
||||
break;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DetachedSign noArmor() {
|
||||
armored = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DetachedSign key(@NotNull InputStream inputStream) throws SOPGPException.KeyCannotSign, SOPGPException.BadData, SOPGPException.UnsupportedAsymmetricAlgo, IOException {
|
||||
try
|
||||
{
|
||||
OpenPGPKey key = parseKey(inputStream);
|
||||
OpenPGPKey.OpenPGPSecretKey signingKey = key.getSecretKey(key.getSigningKeys().get(0));
|
||||
sigGen.addSigningKey(signingKey,
|
||||
k -> keyPassword,
|
||||
new SignatureParameters.Callback() {
|
||||
@Override
|
||||
public SignatureParameters apply(SignatureParameters parameters) {
|
||||
return parameters.setSignatureType(signatureMode);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (InvalidSigningKeyException e)
|
||||
{
|
||||
throw new SOPGPException.KeyCannotSign("Key cannot sign", e);
|
||||
}
|
||||
catch (PGPException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DetachedSign withKeyPassword(@NotNull byte[] bytes) throws SOPGPException.UnsupportedOption, SOPGPException.PasswordNotHumanReadable {
|
||||
keyPassword = new String(bytes).toCharArray();
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import org.bouncycastle.openpgp.api.OpenPGPApi;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPDetachedSignatureProcessor;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPSignature;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import sop.Verification;
|
||||
import sop.exception.SOPGPException;
|
||||
import sop.operation.DetachedVerify;
|
||||
import sop.operation.VerifySignatures;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class BCDetachedVerify
|
||||
extends AbstractBCOperation
|
||||
implements DetachedVerify
|
||||
{
|
||||
|
||||
private final OpenPGPDetachedSignatureProcessor processor;
|
||||
|
||||
public BCDetachedVerify(OpenPGPApi api)
|
||||
{
|
||||
super(api);
|
||||
this.processor = api.verifyDetachedSignature();
|
||||
processor.setExceptionCallback(e -> System.err.println(e.getMessage()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public VerifySignatures signatures(@NotNull InputStream inputStream) throws SOPGPException.BadData, IOException {
|
||||
processor.addSignatures(inputStream);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DetachedVerify notBefore(@NotNull Date date) throws SOPGPException.UnsupportedOption {
|
||||
processor.verifyNotBefore(date);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DetachedVerify notAfter(@NotNull Date date) throws SOPGPException.UnsupportedOption {
|
||||
processor.verifyNotAfter(date);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DetachedVerify cert(@NotNull InputStream inputStream) throws SOPGPException.BadData, IOException {
|
||||
processor.addVerificationCertificate(parseCertificate(inputStream));
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<Verification> data(@NotNull InputStream inputStream) throws IOException, SOPGPException.NoSignature, SOPGPException.BadData {
|
||||
List<OpenPGPSignature.OpenPGPDocumentSignature> signatures = processor.process(inputStream);
|
||||
|
||||
List<Verification> verifications = getVerifications(signatures);
|
||||
if (verifications.isEmpty())
|
||||
{
|
||||
throw new SOPGPException.NoSignature();
|
||||
}
|
||||
return verifications;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPApi;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPMessageGenerator;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPMessageOutputStream;
|
||||
import org.bouncycastle.openpgp.api.exception.InvalidEncryptionKeyException;
|
||||
import org.bouncycastle.openpgp.api.exception.InvalidSigningKeyException;
|
||||
import org.bouncycastle.util.io.Streams;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import sop.EncryptionResult;
|
||||
import sop.ReadyWithResult;
|
||||
import sop.SessionKey;
|
||||
import sop.enums.EncryptAs;
|
||||
import sop.exception.SOPGPException;
|
||||
import sop.operation.Encrypt;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class BCEncrypt
|
||||
extends AbstractBCOperation
|
||||
implements Encrypt {
|
||||
private final OpenPGPMessageGenerator mGen;
|
||||
private char[] keyPassword;
|
||||
|
||||
public BCEncrypt(OpenPGPApi api) {
|
||||
super(api);
|
||||
this.mGen = api.signAndOrEncryptMessage();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Encrypt mode(@NotNull EncryptAs encryptAs) throws SOPGPException.UnsupportedOption {
|
||||
// TODO: Implement
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Encrypt noArmor() {
|
||||
mGen.setArmored(false);
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Encrypt signWith(@NotNull InputStream inputStream) throws SOPGPException.KeyCannotSign, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.BadData, IOException {
|
||||
try {
|
||||
mGen.addSigningKey(parseKey(inputStream), k -> keyPassword);
|
||||
} catch (InvalidSigningKeyException e) {
|
||||
throw new SOPGPException.KeyCannotSign("Key cannot sign", e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Encrypt withKeyPassword(@NotNull byte[] bytes) throws SOPGPException.PasswordNotHumanReadable, SOPGPException.UnsupportedOption {
|
||||
this.keyPassword = new String(bytes).toCharArray();
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Encrypt withPassword(@NotNull String s) throws SOPGPException.PasswordNotHumanReadable, SOPGPException.UnsupportedOption {
|
||||
mGen.addEncryptionPassphrase(s.toCharArray());
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Encrypt withCert(@NotNull InputStream inputStream) throws SOPGPException.CertCannotEncrypt, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.BadData, IOException {
|
||||
try {
|
||||
mGen.addEncryptionCertificate(parseCertificate(inputStream));
|
||||
} catch (InvalidEncryptionKeyException e) {
|
||||
throw new SOPGPException.CertCannotEncrypt("Certificate cannot encrypt", e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Encrypt profile(@NotNull String s) {
|
||||
// TODO: Implement
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ReadyWithResult<EncryptionResult> plaintext(@NotNull InputStream inputStream) throws IOException, SOPGPException.KeyIsProtected {
|
||||
return new ReadyWithResult<EncryptionResult>() {
|
||||
SessionKey sessionKey = null;
|
||||
@Override
|
||||
public EncryptionResult writeTo(@NotNull OutputStream outputStream) throws IOException, SOPGPException {
|
||||
mGen.setSessionKeyExtractionCallback(sk -> this.sessionKey = new SessionKey((byte) sk.getAlgorithm(), sk.getKey()));
|
||||
try {
|
||||
OpenPGPMessageOutputStream mOut = mGen.open(outputStream);
|
||||
Streams.pipeAll(inputStream, mOut);
|
||||
mOut.close();
|
||||
return new EncryptionResult(sessionKey);
|
||||
} catch (PGPException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
||||
import org.bouncycastle.openpgp.PGPObjectFactory;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPUtil;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPApi;
|
||||
import org.bouncycastle.openpgp.bc.BcPGPObjectFactory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import sop.Ready;
|
||||
import sop.exception.SOPGPException;
|
||||
import sop.operation.ExtractCert;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class BCExtractCert
|
||||
extends AbstractBCOperation
|
||||
implements ExtractCert {
|
||||
|
||||
private boolean armor = true;
|
||||
|
||||
public BCExtractCert(OpenPGPApi api) {
|
||||
super(api);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Ready key(@NotNull InputStream inputStream) throws IOException, SOPGPException.BadData {
|
||||
InputStream decodeIn = PGPUtil.getDecoderStream(inputStream);
|
||||
PGPObjectFactory objFac = new BcPGPObjectFactory(decodeIn);
|
||||
PGPSecretKeyRing secretKeys = (PGPSecretKeyRing) objFac.nextObject();
|
||||
|
||||
List<PGPPublicKey> list = new ArrayList<>();
|
||||
Iterator<PGPPublicKey> iterator = secretKeys.getPublicKeys();
|
||||
while (iterator.hasNext()) {
|
||||
list.add(iterator.next());
|
||||
}
|
||||
PGPPublicKeyRing publicKeys = new PGPPublicKeyRing(list);
|
||||
|
||||
return new Ready() {
|
||||
@Override
|
||||
public void writeTo(@NotNull OutputStream outputStream) throws IOException {
|
||||
if (armor) {
|
||||
ArmoredOutputStream aOut = ArmoredOutputStream.builder()
|
||||
.clearHeaders()
|
||||
.enableCRC(true)
|
||||
.build(outputStream);
|
||||
publicKeys.encode(aOut);
|
||||
aOut.close();
|
||||
} else {
|
||||
publicKeys.encode(outputStream);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ExtractCert noArmor() {
|
||||
this.armor = false;
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPApi;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPV6KeyGenerator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import sop.Ready;
|
||||
import sop.exception.SOPGPException;
|
||||
import sop.operation.GenerateKey;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Date;
|
||||
|
||||
public class BCGenerateKey
|
||||
extends AbstractBCOperation
|
||||
implements GenerateKey {
|
||||
|
||||
private boolean armor = true;
|
||||
private boolean signOnly = false;
|
||||
private String userId;
|
||||
private char[] passphrase;
|
||||
|
||||
public BCGenerateKey(OpenPGPApi api) {
|
||||
super(api);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Ready generate() throws SOPGPException.MissingArg, SOPGPException.UnsupportedAsymmetricAlgo, IOException {
|
||||
return new Ready()
|
||||
{
|
||||
@Override
|
||||
public void writeTo(@NotNull OutputStream outputStream) throws IOException
|
||||
{
|
||||
OpenPGPV6KeyGenerator generator = null;
|
||||
try {
|
||||
generator = api.generateKey(new Date());
|
||||
} catch (PGPException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
OpenPGPKey key;
|
||||
try
|
||||
{
|
||||
if (signOnly)
|
||||
{
|
||||
key = generator.signOnlyKey().build(passphrase);
|
||||
}
|
||||
else
|
||||
{
|
||||
key = generator.ed25519x25519Key(userId).build(passphrase);
|
||||
}
|
||||
}
|
||||
catch (PGPException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
if (armor)
|
||||
{
|
||||
outputStream.write(key.toAsciiArmoredString().getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
else
|
||||
{
|
||||
key.getPGPKeyRing().encode(outputStream);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GenerateKey noArmor() {
|
||||
this.armor = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GenerateKey userId(@NotNull String s) {
|
||||
this.userId = s;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GenerateKey withKeyPassword(@NotNull String s) throws SOPGPException.PasswordNotHumanReadable, SOPGPException.UnsupportedOption {
|
||||
this.passphrase = s.toCharArray();
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GenerateKey profile(@NotNull String s) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GenerateKey signingOnly() {
|
||||
this.signOnly = true;
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPApi;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPMessageGenerator;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPMessageOutputStream;
|
||||
import org.bouncycastle.openpgp.api.exception.InvalidSigningKeyException;
|
||||
import org.bouncycastle.util.io.Streams;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import sop.Ready;
|
||||
import sop.enums.InlineSignAs;
|
||||
import sop.exception.SOPGPException;
|
||||
import sop.operation.InlineSign;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class BCInlineSign
|
||||
extends AbstractBCOperation
|
||||
implements InlineSign
|
||||
{
|
||||
|
||||
private final OpenPGPMessageGenerator mGen;
|
||||
private char[] keyPassword;
|
||||
|
||||
public BCInlineSign(OpenPGPApi api) {
|
||||
super(api);
|
||||
this.mGen = api.signAndOrEncryptMessage();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Ready data(@NotNull InputStream inputStream) throws IOException, SOPGPException.KeyIsProtected, SOPGPException.ExpectedText {
|
||||
return new Ready() {
|
||||
@Override
|
||||
public void writeTo(@NotNull OutputStream outputStream) throws IOException {
|
||||
try {
|
||||
OpenPGPMessageOutputStream mOut = mGen.open(outputStream);
|
||||
Streams.pipeAll(inputStream, mOut);
|
||||
mOut.close();
|
||||
} catch (PGPException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public InlineSign mode(@NotNull InlineSignAs inlineSignAs) throws SOPGPException.UnsupportedOption {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InlineSign noArmor() {
|
||||
mGen.setArmored(false);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InlineSign key(@NotNull InputStream inputStream) throws SOPGPException.KeyCannotSign, SOPGPException.BadData, SOPGPException.UnsupportedAsymmetricAlgo, IOException {
|
||||
try {
|
||||
mGen.addSigningKey(api.readKeyOrCertificate().parseKey(inputStream), k -> keyPassword);
|
||||
} catch (InvalidSigningKeyException e) {
|
||||
throw new SOPGPException.KeyCannotSign("Key cannot sign.", e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InlineSign withKeyPassword(@NotNull byte[] bytes) throws SOPGPException.UnsupportedOption, SOPGPException.PasswordNotHumanReadable {
|
||||
this.keyPassword = new String(bytes).toCharArray();
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPApi;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPMessageInputStream;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPMessageProcessor;
|
||||
import org.bouncycastle.util.io.Streams;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import sop.ReadyWithResult;
|
||||
import sop.Verification;
|
||||
import sop.exception.SOPGPException;
|
||||
import sop.operation.InlineVerify;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class BCInlineVerify
|
||||
extends AbstractBCOperation
|
||||
implements InlineVerify {
|
||||
|
||||
private final OpenPGPMessageProcessor processor;
|
||||
|
||||
public BCInlineVerify(OpenPGPApi api) {
|
||||
super(api);
|
||||
this.processor = api.decryptAndOrVerifyMessage();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ReadyWithResult<List<Verification>> data(@NotNull InputStream inputStream) throws IOException, SOPGPException.NoSignature, SOPGPException.BadData {
|
||||
return new ReadyWithResult<>() {
|
||||
@Override
|
||||
public List<Verification> writeTo(@NotNull OutputStream outputStream) throws IOException, SOPGPException {
|
||||
try {
|
||||
OpenPGPMessageInputStream mIn = processor.process(inputStream);
|
||||
Streams.pipeAll(mIn, outputStream);
|
||||
mIn.close();
|
||||
OpenPGPMessageInputStream.Result result = mIn.getResult();
|
||||
List<Verification> verifications = getVerifications(result.getSignatures());
|
||||
if (verifications.isEmpty())
|
||||
{
|
||||
throw new SOPGPException.NoSignature();
|
||||
}
|
||||
return verifications;
|
||||
} catch (PGPException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public InlineVerify notBefore(@NotNull Date date) throws SOPGPException.UnsupportedOption {
|
||||
processor.verifyNotBefore(date);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InlineVerify notAfter(@NotNull Date date) throws SOPGPException.UnsupportedOption {
|
||||
processor.verifyNotAfter(date);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InlineVerify cert(@NotNull InputStream inputStream) throws SOPGPException.BadData, IOException {
|
||||
processor.addVerificationCertificate(api.readKeyOrCertificate().parseCertificate(inputStream));
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import org.bouncycastle.openpgp.api.OpenPGPApi;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import sop.Profile;
|
||||
import sop.operation.ListProfiles;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BCListProfiles
|
||||
extends AbstractBCOperation
|
||||
implements ListProfiles {
|
||||
|
||||
public BCListProfiles(OpenPGPApi api) {
|
||||
super(api);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<Profile> subcommand(@NotNull String s) {
|
||||
return List.of();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPApi;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import sop.exception.SOPGPException;
|
||||
import sop.operation.Version;
|
||||
|
||||
public class BCVersion
|
||||
extends AbstractBCOperation
|
||||
implements Version {
|
||||
|
||||
public BCVersion(OpenPGPApi api) {
|
||||
super(api);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getBackendVersion() {
|
||||
return "Bouncy Castle " + new BouncyCastleProvider().getVersionStr();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Bouncy Castle SOP";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return "1.0-SNAPSHOT"; // TODO: Extract from pom
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getExtendedVersion() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSopSpecRevisionNumber() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSopSpecImplementationIncomplete() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getSopSpecImplementationRemarks() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getSopVVersion() throws SOPGPException.UnsupportedOption {
|
||||
return "1.0";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package org.pgpainless.bouncycastle.sop;
|
||||
|
||||
import sop.SOP;
|
||||
import sop.testsuite.SOPInstanceFactory;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
public class BouncyCastleSOPInstanceFactory extends SOPInstanceFactory {
|
||||
|
||||
@Override
|
||||
public Map<String, SOP> provideSOPInstances() {
|
||||
return Collections.singletonMap("bcsop", new BouncyCastleSOP());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import sop.testsuite.operation.ArmorDearmorTest;
|
||||
|
||||
public class BCSopArmorDearmorTest extends ArmorDearmorTest {
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import sop.testsuite.operation.ChangeKeyPasswordTest;
|
||||
|
||||
public class BCSopChangeKeyPasswordTest extends ChangeKeyPasswordTest {
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import sop.testsuite.operation.DecryptWithSessionKeyTest;
|
||||
|
||||
public class BCSopDecryptWithSessionKeyTest extends DecryptWithSessionKeyTest {
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import sop.testsuite.operation.DetachedSignDetachedVerifyTest;
|
||||
|
||||
public class BCSopDetachedSignDetachedVerifyTest extends DetachedSignDetachedVerifyTest {
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import sop.testsuite.operation.EncryptDecryptTest;
|
||||
|
||||
public class BCSopEncryptDecryptTest extends EncryptDecryptTest {
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import sop.testsuite.operation.ExtractCertTest;
|
||||
|
||||
public class BCSopExtractCertTest extends ExtractCertTest {
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import sop.testsuite.operation.GenerateKeyTest;
|
||||
|
||||
public class BCSopGenerateKeyTest extends GenerateKeyTest {
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import sop.testsuite.operation.InlineSignInlineDetachDetachedVerifyTest;
|
||||
|
||||
public class BCSopInlineSignInlineDetachDetachedVerifyTest extends InlineSignInlineDetachDetachedVerifyTest {
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import sop.testsuite.operation.InlineSignInlineVerifyTest;
|
||||
|
||||
public class BCSopInlineSignInlineVerifyTest extends InlineSignInlineVerifyTest {
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import sop.testsuite.operation.RevokeKeyTest;
|
||||
|
||||
public class BCSopRevokeKeyTest extends RevokeKeyTest {
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package org.pgpainless.bouncycastle.sop.operation;
|
||||
|
||||
import sop.testsuite.operation.VersionTest;
|
||||
|
||||
public class BCSopVersionTest extends VersionTest {
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue