1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-06-16 00:24:51 +02:00

Annotate methods with @Nonnull

This commit is contained in:
Paul Schaub 2023-11-15 13:39:26 +01:00
parent f07063d55f
commit 608ec0b7b0
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
16 changed files with 190 additions and 78 deletions

View file

@ -18,21 +18,26 @@ import sop.enums.ArmorLabel;
import sop.exception.SOPGPException; import sop.exception.SOPGPException;
import sop.operation.Armor; import sop.operation.Armor;
import javax.annotation.Nonnull;
/** /**
* Implementation of the <pre>armor</pre> operation using PGPainless. * Implementation of the <pre>armor</pre> operation using PGPainless.
*/ */
public class ArmorImpl implements Armor { public class ArmorImpl implements Armor {
@Nonnull
@Override @Override
public Armor label(ArmorLabel label) throws SOPGPException.UnsupportedOption { @Deprecated
public Armor label(@Nonnull ArmorLabel label) throws SOPGPException.UnsupportedOption {
throw new SOPGPException.UnsupportedOption("Setting custom Armor labels not supported."); throw new SOPGPException.UnsupportedOption("Setting custom Armor labels not supported.");
} }
@Nonnull
@Override @Override
public Ready data(InputStream data) throws SOPGPException.BadData { public Ready data(@Nonnull InputStream data) throws SOPGPException.BadData {
return new Ready() { return new Ready() {
@Override @Override
public void writeTo(OutputStream outputStream) throws IOException { public void writeTo(@Nonnull OutputStream outputStream) throws IOException {
// By buffering the output stream, we can improve performance drastically // By buffering the output stream, we can improve performance drastically
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);

View file

@ -24,32 +24,38 @@ import sop.Ready;
import sop.exception.SOPGPException; import sop.exception.SOPGPException;
import sop.operation.ChangeKeyPassword; import sop.operation.ChangeKeyPassword;
import javax.annotation.Nonnull;
public class ChangeKeyPasswordImpl implements ChangeKeyPassword { public class ChangeKeyPasswordImpl implements ChangeKeyPassword {
private final MatchMakingSecretKeyRingProtector oldProtector = new MatchMakingSecretKeyRingProtector(); private final MatchMakingSecretKeyRingProtector oldProtector = new MatchMakingSecretKeyRingProtector();
private Passphrase newPassphrase = Passphrase.emptyPassphrase(); private Passphrase newPassphrase = Passphrase.emptyPassphrase();
private boolean armor = true; private boolean armor = true;
@Nonnull
@Override @Override
public ChangeKeyPassword noArmor() { public ChangeKeyPassword noArmor() {
armor = false; armor = false;
return this; return this;
} }
@Nonnull
@Override @Override
public ChangeKeyPassword oldKeyPassphrase(String oldPassphrase) { public ChangeKeyPassword oldKeyPassphrase(@Nonnull String oldPassphrase) {
oldProtector.addPassphrase(Passphrase.fromPassword(oldPassphrase)); oldProtector.addPassphrase(Passphrase.fromPassword(oldPassphrase));
return this; return this;
} }
@Nonnull
@Override @Override
public ChangeKeyPassword newKeyPassphrase(String newPassphrase) { public ChangeKeyPassword newKeyPassphrase(@Nonnull String newPassphrase) {
this.newPassphrase = Passphrase.fromPassword(newPassphrase); this.newPassphrase = Passphrase.fromPassword(newPassphrase);
return this; return this;
} }
@Nonnull
@Override @Override
public Ready keys(InputStream inputStream) throws SOPGPException.KeyIsProtected { public Ready keys(@Nonnull InputStream inputStream) throws SOPGPException.KeyIsProtected {
SecretKeyRingProtector newProtector = SecretKeyRingProtector.unlockAnyKeyWith(newPassphrase); SecretKeyRingProtector newProtector = SecretKeyRingProtector.unlockAnyKeyWith(newPassphrase);
PGPSecretKeyRingCollection secretKeyRingCollection; PGPSecretKeyRingCollection secretKeyRingCollection;
try { try {
@ -76,7 +82,7 @@ public class ChangeKeyPasswordImpl implements ChangeKeyPassword {
final PGPSecretKeyRingCollection changedSecretKeyCollection = new PGPSecretKeyRingCollection(updatedSecretKeys); final PGPSecretKeyRingCollection changedSecretKeyCollection = new PGPSecretKeyRingCollection(updatedSecretKeys);
return new Ready() { return new Ready() {
@Override @Override
public void writeTo(OutputStream outputStream) throws IOException { public void writeTo(@Nonnull OutputStream outputStream) throws IOException {
if (armor) { if (armor) {
ArmoredOutputStream armorOut = ArmoredOutputStreamFactory.get(outputStream); ArmoredOutputStream armorOut = ArmoredOutputStreamFactory.get(outputStream);
changedSecretKeyCollection.encode(armorOut); changedSecretKeyCollection.encode(armorOut);

View file

@ -15,13 +15,16 @@ import sop.Ready;
import sop.exception.SOPGPException; import sop.exception.SOPGPException;
import sop.operation.Dearmor; import sop.operation.Dearmor;
import javax.annotation.Nonnull;
/** /**
* Implementation of the <pre>dearmor</pre> operation using PGPainless. * Implementation of the <pre>dearmor</pre> operation using PGPainless.
*/ */
public class DearmorImpl implements Dearmor { public class DearmorImpl implements Dearmor {
@Nonnull
@Override @Override
public Ready data(InputStream data) { public Ready data(@Nonnull InputStream data) {
InputStream decoder; InputStream decoder;
try { try {
decoder = PGPUtil.getDecoderStream(data); decoder = PGPUtil.getDecoderStream(data);
@ -31,7 +34,7 @@ public class DearmorImpl implements Dearmor {
return new Ready() { return new Ready() {
@Override @Override
public void writeTo(OutputStream outputStream) throws IOException { public void writeTo(@Nonnull OutputStream outputStream) throws IOException {
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
Streams.pipeAll(decoder, bufferedOutputStream); Streams.pipeAll(decoder, bufferedOutputStream);
bufferedOutputStream.flush(); bufferedOutputStream.flush();

View file

@ -7,7 +7,6 @@ package org.pgpainless.sop;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -33,6 +32,9 @@ import sop.SessionKey;
import sop.Verification; import sop.Verification;
import sop.exception.SOPGPException; import sop.exception.SOPGPException;
import sop.operation.Decrypt; import sop.operation.Decrypt;
import sop.util.UTF8Util;
import javax.annotation.Nonnull;
/** /**
* Implementation of the <pre>decrypt</pre> operation using PGPainless. * Implementation of the <pre>decrypt</pre> operation using PGPainless.
@ -42,20 +44,23 @@ public class DecryptImpl implements Decrypt {
private final ConsumerOptions consumerOptions = ConsumerOptions.get(); private final ConsumerOptions consumerOptions = ConsumerOptions.get();
private final MatchMakingSecretKeyRingProtector protector = new MatchMakingSecretKeyRingProtector(); private final MatchMakingSecretKeyRingProtector protector = new MatchMakingSecretKeyRingProtector();
@Nonnull
@Override @Override
public DecryptImpl verifyNotBefore(Date timestamp) throws SOPGPException.UnsupportedOption { public DecryptImpl verifyNotBefore(@Nonnull Date timestamp) throws SOPGPException.UnsupportedOption {
consumerOptions.verifyNotBefore(timestamp); consumerOptions.verifyNotBefore(timestamp);
return this; return this;
} }
@Nonnull
@Override @Override
public DecryptImpl verifyNotAfter(Date timestamp) throws SOPGPException.UnsupportedOption { public DecryptImpl verifyNotAfter(@Nonnull Date timestamp) throws SOPGPException.UnsupportedOption {
consumerOptions.verifyNotAfter(timestamp); consumerOptions.verifyNotAfter(timestamp);
return this; return this;
} }
@Nonnull
@Override @Override
public DecryptImpl verifyWithCert(InputStream certIn) throws SOPGPException.BadData, IOException { public DecryptImpl verifyWithCert(@Nonnull InputStream certIn) throws SOPGPException.BadData, IOException {
PGPPublicKeyRingCollection certs = KeyReader.readPublicKeys(certIn, true); PGPPublicKeyRingCollection certs = KeyReader.readPublicKeys(certIn, true);
if (certs != null) { if (certs != null) {
consumerOptions.addVerificationCerts(certs); consumerOptions.addVerificationCerts(certs);
@ -63,8 +68,9 @@ public class DecryptImpl implements Decrypt {
return this; return this;
} }
@Nonnull
@Override @Override
public DecryptImpl withSessionKey(SessionKey sessionKey) throws SOPGPException.UnsupportedOption { public DecryptImpl withSessionKey(@Nonnull SessionKey sessionKey) throws SOPGPException.UnsupportedOption {
consumerOptions.setSessionKey( consumerOptions.setSessionKey(
new org.pgpainless.util.SessionKey( new org.pgpainless.util.SessionKey(
SymmetricKeyAlgorithm.requireFromId(sessionKey.getAlgorithm()), SymmetricKeyAlgorithm.requireFromId(sessionKey.getAlgorithm()),
@ -72,8 +78,9 @@ public class DecryptImpl implements Decrypt {
return this; return this;
} }
@Nonnull
@Override @Override
public DecryptImpl withPassword(String password) { public DecryptImpl withPassword(@Nonnull String password) {
consumerOptions.addDecryptionPassphrase(Passphrase.fromPassword(password)); consumerOptions.addDecryptionPassphrase(Passphrase.fromPassword(password));
String withoutTrailingWhitespace = removeTrailingWhitespace(password); String withoutTrailingWhitespace = removeTrailingWhitespace(password);
if (!password.equals(withoutTrailingWhitespace)) { if (!password.equals(withoutTrailingWhitespace)) {
@ -91,8 +98,9 @@ public class DecryptImpl implements Decrypt {
return passphrase.substring(0, i); return passphrase.substring(0, i);
} }
@Nonnull
@Override @Override
public DecryptImpl withKey(InputStream keyIn) throws SOPGPException.BadData, IOException, SOPGPException.UnsupportedAsymmetricAlgo { public DecryptImpl withKey(@Nonnull InputStream keyIn) throws SOPGPException.BadData, IOException, SOPGPException.UnsupportedAsymmetricAlgo {
PGPSecretKeyRingCollection secretKeyCollection = KeyReader.readSecretKeys(keyIn, true); PGPSecretKeyRingCollection secretKeyCollection = KeyReader.readSecretKeys(keyIn, true);
for (PGPSecretKeyRing key : secretKeyCollection) { for (PGPSecretKeyRing key : secretKeyCollection) {
@ -102,15 +110,17 @@ public class DecryptImpl implements Decrypt {
return this; return this;
} }
@Nonnull
@Override @Override
public Decrypt withKeyPassword(byte[] password) { public Decrypt withKeyPassword(@Nonnull byte[] password) {
String string = new String(password, Charset.forName("UTF8")); String string = new String(password, UTF8Util.UTF8);
protector.addPassphrase(Passphrase.fromPassword(string)); protector.addPassphrase(Passphrase.fromPassword(string));
return this; return this;
} }
@Nonnull
@Override @Override
public ReadyWithResult<DecryptionResult> ciphertext(InputStream ciphertext) public ReadyWithResult<DecryptionResult> ciphertext(@Nonnull InputStream ciphertext)
throws SOPGPException.BadData, throws SOPGPException.BadData,
SOPGPException.MissingArg { SOPGPException.MissingArg {
@ -136,7 +146,7 @@ public class DecryptImpl implements Decrypt {
return new ReadyWithResult<DecryptionResult>() { return new ReadyWithResult<DecryptionResult>() {
@Override @Override
public DecryptionResult writeTo(OutputStream outputStream) throws IOException, SOPGPException.NoSignature { public DecryptionResult writeTo(@Nonnull OutputStream outputStream) throws IOException, SOPGPException.NoSignature {
Streams.pipeAll(decryptionStream, outputStream); Streams.pipeAll(decryptionStream, outputStream);
decryptionStream.close(); decryptionStream.close();
MessageMetadata metadata = decryptionStream.getMetadata(); MessageMetadata metadata = decryptionStream.getMetadata();

View file

@ -8,7 +8,6 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -35,6 +34,9 @@ import sop.SigningResult;
import sop.enums.SignAs; import sop.enums.SignAs;
import sop.exception.SOPGPException; import sop.exception.SOPGPException;
import sop.operation.DetachedSign; import sop.operation.DetachedSign;
import sop.util.UTF8Util;
import javax.annotation.Nonnull;
/** /**
* Implementation of the <pre>sign</pre> operation using PGPainless. * Implementation of the <pre>sign</pre> operation using PGPainless.
@ -42,7 +44,7 @@ import sop.operation.DetachedSign;
public class DetachedSignImpl implements DetachedSign { public class DetachedSignImpl implements DetachedSign {
private boolean armor = true; private boolean armor = true;
private SignAs mode = SignAs.Binary; private SignAs mode = SignAs.binary;
private final SigningOptions signingOptions = SigningOptions.get(); private final SigningOptions signingOptions = SigningOptions.get();
private final MatchMakingSecretKeyRingProtector protector = new MatchMakingSecretKeyRingProtector(); private final MatchMakingSecretKeyRingProtector protector = new MatchMakingSecretKeyRingProtector();
private final List<PGPSecretKeyRing> signingKeys = new ArrayList<>(); private final List<PGPSecretKeyRing> signingKeys = new ArrayList<>();
@ -54,13 +56,15 @@ public class DetachedSignImpl implements DetachedSign {
} }
@Override @Override
public DetachedSign mode(SignAs mode) { @Nonnull
public DetachedSign mode(@Nonnull SignAs mode) {
this.mode = mode; this.mode = mode;
return this; return this;
} }
@Override @Override
public DetachedSign key(InputStream keyIn) throws SOPGPException.KeyCannotSign, SOPGPException.BadData, IOException { @Nonnull
public DetachedSign key(@Nonnull InputStream keyIn) throws SOPGPException.KeyCannotSign, SOPGPException.BadData, IOException {
PGPSecretKeyRingCollection keys = KeyReader.readSecretKeys(keyIn, true); PGPSecretKeyRingCollection keys = KeyReader.readSecretKeys(keyIn, true);
for (PGPSecretKeyRing key : keys) { for (PGPSecretKeyRing key : keys) {
KeyRingInfo info = PGPainless.inspectKeyRing(key); KeyRingInfo info = PGPainless.inspectKeyRing(key);
@ -74,14 +78,16 @@ public class DetachedSignImpl implements DetachedSign {
} }
@Override @Override
public DetachedSign withKeyPassword(byte[] password) { @Nonnull
String string = new String(password, Charset.forName("UTF8")); public DetachedSign withKeyPassword(@Nonnull byte[] password) {
String string = new String(password, UTF8Util.UTF8);
protector.addPassphrase(Passphrase.fromPassword(string)); protector.addPassphrase(Passphrase.fromPassword(string));
return this; return this;
} }
@Override @Override
public ReadyWithResult<SigningResult> data(InputStream data) throws IOException { @Nonnull
public ReadyWithResult<SigningResult> data(@Nonnull InputStream data) throws IOException {
for (PGPSecretKeyRing key : signingKeys) { for (PGPSecretKeyRing key : signingKeys) {
try { try {
signingOptions.addDetachedSignature(protector, key, modeToSigType(mode)); signingOptions.addDetachedSignature(protector, key, modeToSigType(mode));
@ -101,7 +107,7 @@ public class DetachedSignImpl implements DetachedSign {
return new ReadyWithResult<SigningResult>() { return new ReadyWithResult<SigningResult>() {
@Override @Override
public SigningResult writeTo(OutputStream outputStream) throws IOException { public SigningResult writeTo(@Nonnull OutputStream outputStream) throws IOException {
if (signingStream.isClosed()) { if (signingStream.isClosed()) {
throw new IllegalStateException("EncryptionStream is already closed."); throw new IllegalStateException("EncryptionStream is already closed.");
@ -157,7 +163,7 @@ public class DetachedSignImpl implements DetachedSign {
} }
private static DocumentSignatureType modeToSigType(SignAs mode) { private static DocumentSignatureType modeToSigType(SignAs mode) {
return mode == SignAs.Binary ? DocumentSignatureType.BINARY_DOCUMENT return mode == SignAs.binary ? DocumentSignatureType.BINARY_DOCUMENT
: DocumentSignatureType.CANONICAL_TEXT_DOCUMENT; : DocumentSignatureType.CANONICAL_TEXT_DOCUMENT;
} }
} }

View file

@ -23,6 +23,8 @@ import sop.Verification;
import sop.exception.SOPGPException; import sop.exception.SOPGPException;
import sop.operation.DetachedVerify; import sop.operation.DetachedVerify;
import javax.annotation.Nonnull;
/** /**
* Implementation of the <pre>verify</pre> operation using PGPainless. * Implementation of the <pre>verify</pre> operation using PGPainless.
*/ */
@ -31,26 +33,30 @@ public class DetachedVerifyImpl implements DetachedVerify {
private final ConsumerOptions options = ConsumerOptions.get(); private final ConsumerOptions options = ConsumerOptions.get();
@Override @Override
public DetachedVerify notBefore(Date timestamp) throws SOPGPException.UnsupportedOption { @Nonnull
public DetachedVerify notBefore(@Nonnull Date timestamp) throws SOPGPException.UnsupportedOption {
options.verifyNotBefore(timestamp); options.verifyNotBefore(timestamp);
return this; return this;
} }
@Override @Override
public DetachedVerify notAfter(Date timestamp) throws SOPGPException.UnsupportedOption { @Nonnull
public DetachedVerify notAfter(@Nonnull Date timestamp) throws SOPGPException.UnsupportedOption {
options.verifyNotAfter(timestamp); options.verifyNotAfter(timestamp);
return this; return this;
} }
@Override @Override
public DetachedVerify cert(InputStream cert) throws SOPGPException.BadData, IOException { @Nonnull
public DetachedVerify cert(@Nonnull InputStream cert) throws SOPGPException.BadData, IOException {
PGPPublicKeyRingCollection certificates = KeyReader.readPublicKeys(cert, true); PGPPublicKeyRingCollection certificates = KeyReader.readPublicKeys(cert, true);
options.addVerificationCerts(certificates); options.addVerificationCerts(certificates);
return this; return this;
} }
@Override @Override
public DetachedVerifyImpl signatures(InputStream signatures) throws SOPGPException.BadData { @Nonnull
public DetachedVerifyImpl signatures(@Nonnull InputStream signatures) throws SOPGPException.BadData {
try { try {
options.addVerificationOfDetachedSignatures(signatures); options.addVerificationOfDetachedSignatures(signatures);
} catch (IOException | PGPException e) { } catch (IOException | PGPException e) {
@ -60,7 +66,8 @@ public class DetachedVerifyImpl implements DetachedVerify {
} }
@Override @Override
public List<Verification> data(InputStream data) throws IOException, SOPGPException.NoSignature, SOPGPException.BadData { @Nonnull
public List<Verification> data(@Nonnull InputStream data) throws IOException, SOPGPException.NoSignature, SOPGPException.BadData {
options.forceNonOpenPgpData(); options.forceNonOpenPgpData();
DecryptionStream decryptionStream; DecryptionStream decryptionStream;

View file

@ -7,7 +7,6 @@ package org.pgpainless.sop;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -30,12 +29,16 @@ import org.pgpainless.exception.WrongPassphraseException;
import org.pgpainless.key.OpenPgpFingerprint; import org.pgpainless.key.OpenPgpFingerprint;
import org.pgpainless.key.info.KeyRingInfo; import org.pgpainless.key.info.KeyRingInfo;
import org.pgpainless.util.Passphrase; import org.pgpainless.util.Passphrase;
import sop.EncryptionResult;
import sop.Profile; import sop.Profile;
import sop.Ready; import sop.ReadyWithResult;
import sop.enums.EncryptAs; import sop.enums.EncryptAs;
import sop.exception.SOPGPException; import sop.exception.SOPGPException;
import sop.operation.Encrypt; import sop.operation.Encrypt;
import sop.util.ProxyOutputStream; import sop.util.ProxyOutputStream;
import sop.util.UTF8Util;
import javax.annotation.Nonnull;
/** /**
* Implementation of the <pre>encrypt</pre> operation using PGPainless. * Implementation of the <pre>encrypt</pre> operation using PGPainless.
@ -52,23 +55,26 @@ public class EncryptImpl implements Encrypt {
private final Set<PGPSecretKeyRing> signingKeys = new HashSet<>(); private final Set<PGPSecretKeyRing> signingKeys = new HashSet<>();
private String profile = RFC4880_PROFILE.getName(); // TODO: Use in future releases private String profile = RFC4880_PROFILE.getName(); // TODO: Use in future releases
private EncryptAs encryptAs = EncryptAs.Binary; private EncryptAs encryptAs = EncryptAs.binary;
boolean armor = true; boolean armor = true;
@Nonnull
@Override @Override
public Encrypt noArmor() { public Encrypt noArmor() {
armor = false; armor = false;
return this; return this;
} }
@Nonnull
@Override @Override
public Encrypt mode(EncryptAs mode) throws SOPGPException.UnsupportedOption { public Encrypt mode(@Nonnull EncryptAs mode) throws SOPGPException.UnsupportedOption {
this.encryptAs = mode; this.encryptAs = mode;
return this; return this;
} }
@Nonnull
@Override @Override
public Encrypt signWith(InputStream keyIn) public Encrypt signWith(@Nonnull InputStream keyIn)
throws SOPGPException.KeyCannotSign, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.BadData, IOException { throws SOPGPException.KeyCannotSign, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.BadData, IOException {
if (signingOptions == null) { if (signingOptions == null) {
signingOptions = SigningOptions.get(); signingOptions = SigningOptions.get();
@ -89,21 +95,24 @@ public class EncryptImpl implements Encrypt {
return this; return this;
} }
@Nonnull
@Override @Override
public Encrypt withKeyPassword(byte[] password) { public Encrypt withKeyPassword(@Nonnull byte[] password) {
String passphrase = new String(password, Charset.forName("UTF8")); String passphrase = new String(password, UTF8Util.UTF8);
protector.addPassphrase(Passphrase.fromPassword(passphrase)); protector.addPassphrase(Passphrase.fromPassword(passphrase));
return this; return this;
} }
@Nonnull
@Override @Override
public Encrypt withPassword(String password) throws SOPGPException.PasswordNotHumanReadable, SOPGPException.UnsupportedOption { public Encrypt withPassword(@Nonnull String password) throws SOPGPException.PasswordNotHumanReadable, SOPGPException.UnsupportedOption {
encryptionOptions.addPassphrase(Passphrase.fromPassword(password)); encryptionOptions.addPassphrase(Passphrase.fromPassword(password));
return this; return this;
} }
@Nonnull
@Override @Override
public Encrypt withCert(InputStream cert) throws SOPGPException.CertCannotEncrypt, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.BadData { public Encrypt withCert(@Nonnull InputStream cert) throws SOPGPException.CertCannotEncrypt, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.BadData {
try { try {
PGPPublicKeyRingCollection certificates = KeyReader.readPublicKeys(cert, true); PGPPublicKeyRingCollection certificates = KeyReader.readPublicKeys(cert, true);
encryptionOptions.addRecipients(certificates); encryptionOptions.addRecipients(certificates);
@ -115,8 +124,9 @@ public class EncryptImpl implements Encrypt {
return this; return this;
} }
@Nonnull
@Override @Override
public Encrypt profile(String profileName) { public Encrypt profile(@Nonnull String profileName) {
// sanitize profile name to make sure we only accept supported profiles // sanitize profile name to make sure we only accept supported profiles
for (Profile profile : SUPPORTED_PROFILES) { for (Profile profile : SUPPORTED_PROFILES) {
if (profile.getName().equals(profileName)) { if (profile.getName().equals(profileName)) {
@ -130,8 +140,9 @@ public class EncryptImpl implements Encrypt {
throw new SOPGPException.UnsupportedProfile("encrypt", profileName); throw new SOPGPException.UnsupportedProfile("encrypt", profileName);
} }
@Nonnull
@Override @Override
public Ready plaintext(InputStream plaintext) throws IOException { public ReadyWithResult<sop.EncryptionResult> plaintext(@Nonnull InputStream plaintext) throws IOException {
if (!encryptionOptions.hasEncryptionMethod()) { if (!encryptionOptions.hasEncryptionMethod()) {
throw new SOPGPException.MissingArg("Missing encryption method."); throw new SOPGPException.MissingArg("Missing encryption method.");
} }
@ -146,7 +157,7 @@ public class EncryptImpl implements Encrypt {
signingOptions.addInlineSignature( signingOptions.addInlineSignature(
protector, protector,
signingKey, signingKey,
(encryptAs == EncryptAs.Binary ? DocumentSignatureType.BINARY_DOCUMENT : DocumentSignatureType.CANONICAL_TEXT_DOCUMENT) (encryptAs == EncryptAs.binary ? DocumentSignatureType.BINARY_DOCUMENT : DocumentSignatureType.CANONICAL_TEXT_DOCUMENT)
); );
} catch (KeyException.UnacceptableSigningKeyException e) { } catch (KeyException.UnacceptableSigningKeyException e) {
throw new SOPGPException.KeyCannotSign(); throw new SOPGPException.KeyCannotSign();
@ -163,12 +174,14 @@ public class EncryptImpl implements Encrypt {
.onOutputStream(proxy) .onOutputStream(proxy)
.withOptions(producerOptions); .withOptions(producerOptions);
return new Ready() { return new ReadyWithResult<EncryptionResult>() {
@Override @Override
public void writeTo(OutputStream outputStream) throws IOException { public EncryptionResult writeTo(@Nonnull OutputStream outputStream) throws IOException {
proxy.replaceOutputStream(outputStream); proxy.replaceOutputStream(outputStream);
Streams.pipeAll(plaintext, encryptionStream); Streams.pipeAll(plaintext, encryptionStream);
encryptionStream.close(); encryptionStream.close();
// TODO: Extract and emit SessionKey
return new EncryptionResult(null);
} }
}; };
} catch (PGPException e) { } catch (PGPException e) {
@ -178,9 +191,9 @@ public class EncryptImpl implements Encrypt {
private static StreamEncoding encryptAsToStreamEncoding(EncryptAs encryptAs) { private static StreamEncoding encryptAsToStreamEncoding(EncryptAs encryptAs) {
switch (encryptAs) { switch (encryptAs) {
case Binary: case binary:
return StreamEncoding.BINARY; return StreamEncoding.BINARY;
case Text: case text:
return StreamEncoding.UTF8; return StreamEncoding.UTF8;
} }
throw new IllegalArgumentException("Invalid value encountered: " + encryptAs); throw new IllegalArgumentException("Invalid value encountered: " + encryptAs);

View file

@ -19,6 +19,8 @@ import sop.Ready;
import sop.exception.SOPGPException; import sop.exception.SOPGPException;
import sop.operation.ExtractCert; import sop.operation.ExtractCert;
import javax.annotation.Nonnull;
/** /**
* Implementation of the <pre>extract-cert</pre> operation using PGPainless. * Implementation of the <pre>extract-cert</pre> operation using PGPainless.
*/ */
@ -27,13 +29,15 @@ public class ExtractCertImpl implements ExtractCert {
private boolean armor = true; private boolean armor = true;
@Override @Override
@Nonnull
public ExtractCert noArmor() { public ExtractCert noArmor() {
armor = false; armor = false;
return this; return this;
} }
@Override @Override
public Ready key(InputStream keyInputStream) throws IOException, SOPGPException.BadData { @Nonnull
public Ready key(@Nonnull InputStream keyInputStream) throws IOException, SOPGPException.BadData {
PGPSecretKeyRingCollection keys = KeyReader.readSecretKeys(keyInputStream, true); PGPSecretKeyRingCollection keys = KeyReader.readSecretKeys(keyInputStream, true);
List<PGPPublicKeyRing> certs = new ArrayList<>(); List<PGPPublicKeyRing> certs = new ArrayList<>();
@ -44,7 +48,7 @@ public class ExtractCertImpl implements ExtractCert {
return new Ready() { return new Ready() {
@Override @Override
public void writeTo(OutputStream outputStream) throws IOException { public void writeTo(@Nonnull OutputStream outputStream) throws IOException {
for (PGPPublicKeyRing cert : certs) { for (PGPPublicKeyRing cert : certs) {
OutputStream out = armor ? ArmorUtils.toAsciiArmoredStream(cert, outputStream) : outputStream; OutputStream out = armor ? ArmorUtils.toAsciiArmoredStream(cert, outputStream) : outputStream;

View file

@ -31,6 +31,8 @@ import sop.Ready;
import sop.exception.SOPGPException; import sop.exception.SOPGPException;
import sop.operation.GenerateKey; import sop.operation.GenerateKey;
import javax.annotation.Nonnull;
/** /**
* Implementation of the <pre>generate-key</pre> operation using PGPainless. * Implementation of the <pre>generate-key</pre> operation using PGPainless.
*/ */
@ -48,25 +50,29 @@ public class GenerateKeyImpl implements GenerateKey {
private String profile = CURVE25519_PROFILE.getName(); private String profile = CURVE25519_PROFILE.getName();
@Override @Override
@Nonnull
public GenerateKey noArmor() { public GenerateKey noArmor() {
this.armor = false; this.armor = false;
return this; return this;
} }
@Override @Override
public GenerateKey userId(String userId) { @Nonnull
public GenerateKey userId(@Nonnull String userId) {
this.userIds.add(userId); this.userIds.add(userId);
return this; return this;
} }
@Override @Override
public GenerateKey withKeyPassword(String password) { @Nonnull
public GenerateKey withKeyPassword(@Nonnull String password) {
this.passphrase = Passphrase.fromPassword(password); this.passphrase = Passphrase.fromPassword(password);
return this; return this;
} }
@Override @Override
public GenerateKey profile(String profileName) { @Nonnull
public GenerateKey profile(@Nonnull String profileName) {
// Sanitize the profile name to make sure we support the given profile // Sanitize the profile name to make sure we support the given profile
for (Profile profile : SUPPORTED_PROFILES) { for (Profile profile : SUPPORTED_PROFILES) {
if (profile.getName().equals(profileName)) { if (profile.getName().equals(profileName)) {
@ -81,18 +87,20 @@ public class GenerateKeyImpl implements GenerateKey {
} }
@Override @Override
@Nonnull
public GenerateKey signingOnly() { public GenerateKey signingOnly() {
signingOnly = true; signingOnly = true;
return this; return this;
} }
@Override @Override
@Nonnull
public Ready generate() throws SOPGPException.MissingArg, SOPGPException.UnsupportedAsymmetricAlgo { public Ready generate() throws SOPGPException.MissingArg, SOPGPException.UnsupportedAsymmetricAlgo {
try { try {
final PGPSecretKeyRing key = generateKeyWithProfile(profile, userIds, passphrase, signingOnly); final PGPSecretKeyRing key = generateKeyWithProfile(profile, userIds, passphrase, signingOnly);
return new Ready() { return new Ready() {
@Override @Override
public void writeTo(OutputStream outputStream) throws IOException { public void writeTo(@Nonnull OutputStream outputStream) throws IOException {
if (armor) { if (armor) {
ArmoredOutputStream armoredOutputStream = ArmorUtils.toAsciiArmoredStream(key, outputStream); ArmoredOutputStream armoredOutputStream = ArmorUtils.toAsciiArmoredStream(key, outputStream);
key.encode(armoredOutputStream); key.encode(armoredOutputStream);

View file

@ -30,6 +30,8 @@ import sop.Signatures;
import sop.exception.SOPGPException; import sop.exception.SOPGPException;
import sop.operation.InlineDetach; import sop.operation.InlineDetach;
import javax.annotation.Nonnull;
/** /**
* Implementation of the <pre>inline-detach</pre> operation using PGPainless. * Implementation of the <pre>inline-detach</pre> operation using PGPainless.
*/ */
@ -38,20 +40,22 @@ public class InlineDetachImpl implements InlineDetach {
private boolean armor = true; private boolean armor = true;
@Override @Override
@Nonnull
public InlineDetach noArmor() { public InlineDetach noArmor() {
this.armor = false; this.armor = false;
return this; return this;
} }
@Override @Override
public ReadyWithResult<Signatures> message(InputStream messageInputStream) { @Nonnull
public ReadyWithResult<Signatures> message(@Nonnull InputStream messageInputStream) {
return new ReadyWithResult<Signatures>() { return new ReadyWithResult<Signatures>() {
private final ByteArrayOutputStream sigOut = new ByteArrayOutputStream(); private final ByteArrayOutputStream sigOut = new ByteArrayOutputStream();
@Override @Override
public Signatures writeTo(OutputStream messageOutputStream) public Signatures writeTo(@Nonnull OutputStream messageOutputStream)
throws SOPGPException.NoSignature, IOException { throws SOPGPException.NoSignature, IOException {
PGPSignatureList signatures = null; PGPSignatureList signatures = null;
@ -142,7 +146,7 @@ public class InlineDetachImpl implements InlineDetach {
return new Signatures() { return new Signatures() {
@Override @Override
public void writeTo(OutputStream signatureOutputStream) throws IOException { public void writeTo(@Nonnull OutputStream signatureOutputStream) throws IOException {
Streams.pipeAll(new ByteArrayInputStream(sigOut.toByteArray()), signatureOutputStream); Streams.pipeAll(new ByteArrayInputStream(sigOut.toByteArray()), signatureOutputStream);
} }
}; };

View file

@ -7,7 +7,6 @@ package org.pgpainless.sop;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -28,6 +27,9 @@ import sop.Ready;
import sop.enums.InlineSignAs; import sop.enums.InlineSignAs;
import sop.exception.SOPGPException; import sop.exception.SOPGPException;
import sop.operation.InlineSign; import sop.operation.InlineSign;
import sop.util.UTF8Util;
import javax.annotation.Nonnull;
/** /**
* Implementation of the <pre>inline-sign</pre> operation using PGPainless. * Implementation of the <pre>inline-sign</pre> operation using PGPainless.
@ -41,19 +43,22 @@ public class InlineSignImpl implements InlineSign {
private final List<PGPSecretKeyRing> signingKeys = new ArrayList<>(); private final List<PGPSecretKeyRing> signingKeys = new ArrayList<>();
@Override @Override
public InlineSign mode(InlineSignAs mode) throws SOPGPException.UnsupportedOption { @Nonnull
public InlineSign mode(@Nonnull InlineSignAs mode) throws SOPGPException.UnsupportedOption {
this.mode = mode; this.mode = mode;
return this; return this;
} }
@Override @Override
@Nonnull
public InlineSign noArmor() { public InlineSign noArmor() {
this.armor = false; this.armor = false;
return this; return this;
} }
@Override @Override
public InlineSign key(InputStream keyIn) throws SOPGPException.KeyCannotSign, SOPGPException.BadData, IOException { @Nonnull
public InlineSign key(@Nonnull InputStream keyIn) throws SOPGPException.KeyCannotSign, SOPGPException.BadData, IOException {
PGPSecretKeyRingCollection keys = KeyReader.readSecretKeys(keyIn, true); PGPSecretKeyRingCollection keys = KeyReader.readSecretKeys(keyIn, true);
for (PGPSecretKeyRing key : keys) { for (PGPSecretKeyRing key : keys) {
KeyRingInfo info = PGPainless.inspectKeyRing(key); KeyRingInfo info = PGPainless.inspectKeyRing(key);
@ -67,14 +72,16 @@ public class InlineSignImpl implements InlineSign {
} }
@Override @Override
public InlineSign withKeyPassword(byte[] password) { @Nonnull
String string = new String(password, Charset.forName("UTF8")); public InlineSign withKeyPassword(@Nonnull byte[] password) {
String string = new String(password, UTF8Util.UTF8);
protector.addPassphrase(Passphrase.fromPassword(string)); protector.addPassphrase(Passphrase.fromPassword(string));
return this; return this;
} }
@Override @Override
public Ready data(InputStream data) throws SOPGPException.KeyIsProtected, SOPGPException.ExpectedText { @Nonnull
public Ready data(@Nonnull InputStream data) throws SOPGPException.KeyIsProtected, SOPGPException.ExpectedText {
for (PGPSecretKeyRing key : signingKeys) { for (PGPSecretKeyRing key : signingKeys) {
try { try {
if (mode == InlineSignAs.clearsigned) { if (mode == InlineSignAs.clearsigned) {
@ -99,7 +106,7 @@ public class InlineSignImpl implements InlineSign {
return new Ready() { return new Ready() {
@Override @Override
public void writeTo(OutputStream outputStream) throws IOException, SOPGPException.NoSignature { public void writeTo(@Nonnull OutputStream outputStream) throws IOException, SOPGPException.NoSignature {
try { try {
EncryptionStream signingStream = PGPainless.encryptAndOrSign() EncryptionStream signingStream = PGPainless.encryptAndOrSign()
.onOutputStream(outputStream) .onOutputStream(outputStream)

View file

@ -26,6 +26,8 @@ import sop.Verification;
import sop.exception.SOPGPException; import sop.exception.SOPGPException;
import sop.operation.InlineVerify; import sop.operation.InlineVerify;
import javax.annotation.Nonnull;
/** /**
* Implementation of the <pre>inline-verify</pre> operation using PGPainless. * Implementation of the <pre>inline-verify</pre> operation using PGPainless.
*/ */
@ -34,29 +36,33 @@ public class InlineVerifyImpl implements InlineVerify {
private final ConsumerOptions options = ConsumerOptions.get(); private final ConsumerOptions options = ConsumerOptions.get();
@Override @Override
public InlineVerify notBefore(Date timestamp) throws SOPGPException.UnsupportedOption { @Nonnull
public InlineVerify notBefore(@Nonnull Date timestamp) throws SOPGPException.UnsupportedOption {
options.verifyNotBefore(timestamp); options.verifyNotBefore(timestamp);
return this; return this;
} }
@Override @Override
public InlineVerify notAfter(Date timestamp) throws SOPGPException.UnsupportedOption { @Nonnull
public InlineVerify notAfter(@Nonnull Date timestamp) throws SOPGPException.UnsupportedOption {
options.verifyNotAfter(timestamp); options.verifyNotAfter(timestamp);
return this; return this;
} }
@Override @Override
public InlineVerify cert(InputStream cert) throws SOPGPException.BadData, IOException { @Nonnull
public InlineVerify cert(@Nonnull InputStream cert) throws SOPGPException.BadData, IOException {
PGPPublicKeyRingCollection certificates = KeyReader.readPublicKeys(cert, true); PGPPublicKeyRingCollection certificates = KeyReader.readPublicKeys(cert, true);
options.addVerificationCerts(certificates); options.addVerificationCerts(certificates);
return this; return this;
} }
@Override @Override
public ReadyWithResult<List<Verification>> data(InputStream data) throws SOPGPException.NoSignature, SOPGPException.BadData { @Nonnull
public ReadyWithResult<List<Verification>> data(@Nonnull InputStream data) throws SOPGPException.NoSignature, SOPGPException.BadData {
return new ReadyWithResult<List<Verification>>() { return new ReadyWithResult<List<Verification>>() {
@Override @Override
public List<Verification> writeTo(OutputStream outputStream) throws IOException, SOPGPException.NoSignature { public List<Verification> writeTo(@Nonnull OutputStream outputStream) throws IOException, SOPGPException.NoSignature {
DecryptionStream decryptionStream; DecryptionStream decryptionStream;
try { try {
decryptionStream = PGPainless.decryptAndOrVerify() decryptionStream = PGPainless.decryptAndOrVerify()

View file

@ -10,6 +10,8 @@ import sop.Profile;
import sop.exception.SOPGPException; import sop.exception.SOPGPException;
import sop.operation.ListProfiles; import sop.operation.ListProfiles;
import javax.annotation.Nonnull;
/** /**
* Implementation of the <pre>list-profiles</pre> operation using PGPainless. * Implementation of the <pre>list-profiles</pre> operation using PGPainless.
* *
@ -17,10 +19,8 @@ import sop.operation.ListProfiles;
public class ListProfilesImpl implements ListProfiles { public class ListProfilesImpl implements ListProfiles {
@Override @Override
public List<Profile> subcommand(String command) { @Nonnull
if (command == null) { public List<Profile> subcommand(@Nonnull String command) {
throw new SOPGPException.UnsupportedProfile("null");
}
switch (command) { switch (command) {
case "generate-key": case "generate-key":

View file

@ -32,11 +32,15 @@ import sop.exception.SOPGPException;
import sop.operation.RevokeKey; import sop.operation.RevokeKey;
import sop.util.UTF8Util; import sop.util.UTF8Util;
import javax.annotation.Nonnull;
public class RevokeKeyImpl implements RevokeKey { public class RevokeKeyImpl implements RevokeKey {
private final MatchMakingSecretKeyRingProtector protector = new MatchMakingSecretKeyRingProtector(); private final MatchMakingSecretKeyRingProtector protector = new MatchMakingSecretKeyRingProtector();
private boolean armor = true; private boolean armor = true;
@Override
@Nonnull
public RevokeKey noArmor() { public RevokeKey noArmor() {
this.armor = false; this.armor = false;
return this; return this;
@ -50,7 +54,9 @@ public class RevokeKeyImpl implements RevokeKey {
* @throws sop.exception.SOPGPException.UnsupportedOption if the implementation does not support key passwords * @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 * @throws sop.exception.SOPGPException.PasswordNotHumanReadable if the password is not human-readable
*/ */
public RevokeKey withKeyPassword(byte[] password) @Override
@Nonnull
public RevokeKey withKeyPassword(@Nonnull byte[] password)
throws SOPGPException.UnsupportedOption, throws SOPGPException.UnsupportedOption,
SOPGPException.PasswordNotHumanReadable { SOPGPException.PasswordNotHumanReadable {
String string; String string;
@ -63,7 +69,9 @@ public class RevokeKeyImpl implements RevokeKey {
return this; return this;
} }
public Ready keys(InputStream keys) throws SOPGPException.BadData { @Override
@Nonnull
public Ready keys(@Nonnull InputStream keys) throws SOPGPException.BadData {
PGPSecretKeyRingCollection secretKeyRings; PGPSecretKeyRingCollection secretKeyRings;
try { try {
secretKeyRings = KeyReader.readSecretKeys(keys, true); secretKeyRings = KeyReader.readSecretKeys(keys, true);
@ -100,7 +108,7 @@ public class RevokeKeyImpl implements RevokeKey {
return new Ready() { return new Ready() {
@Override @Override
public void writeTo(OutputStream outputStream) throws IOException { public void writeTo(@Nonnull OutputStream outputStream) throws IOException {
PGPPublicKeyRingCollection certificateCollection = new PGPPublicKeyRingCollection(revocationCertificates); PGPPublicKeyRingCollection certificateCollection = new PGPPublicKeyRingCollection(revocationCertificates);
if (armor) { if (armor) {
ArmoredOutputStream out = ArmoredOutputStreamFactory.get(outputStream); ArmoredOutputStream out = ArmoredOutputStreamFactory.get(outputStream);

View file

@ -22,6 +22,8 @@ import sop.operation.ListProfiles;
import sop.operation.RevokeKey; import sop.operation.RevokeKey;
import sop.operation.Version; import sop.operation.Version;
import javax.annotation.Nonnull;
/** /**
* Implementation of the <pre>sop</pre> API using PGPainless. * Implementation of the <pre>sop</pre> API using PGPainless.
* <pre> {@code * <pre> {@code
@ -35,86 +37,103 @@ public class SOPImpl implements SOP {
} }
@Override @Override
@Nonnull
public Version version() { public Version version() {
return new VersionImpl(); return new VersionImpl();
} }
@Override @Override
@Nonnull
public GenerateKey generateKey() { public GenerateKey generateKey() {
return new GenerateKeyImpl(); return new GenerateKeyImpl();
} }
@Override @Override
@Nonnull
public ExtractCert extractCert() { public ExtractCert extractCert() {
return new ExtractCertImpl(); return new ExtractCertImpl();
} }
@Override @Override
@Nonnull
public DetachedSign sign() { public DetachedSign sign() {
return detachedSign(); return detachedSign();
} }
@Override @Override
@Nonnull
public DetachedSign detachedSign() { public DetachedSign detachedSign() {
return new DetachedSignImpl(); return new DetachedSignImpl();
} }
@Override @Override
@Nonnull
public InlineSign inlineSign() { public InlineSign inlineSign() {
return new InlineSignImpl(); return new InlineSignImpl();
} }
@Override @Override
@Nonnull
public DetachedVerify verify() { public DetachedVerify verify() {
return detachedVerify(); return detachedVerify();
} }
@Override @Override
@Nonnull
public DetachedVerify detachedVerify() { public DetachedVerify detachedVerify() {
return new DetachedVerifyImpl(); return new DetachedVerifyImpl();
} }
@Override @Override
@Nonnull
public InlineVerify inlineVerify() { public InlineVerify inlineVerify() {
return new InlineVerifyImpl(); return new InlineVerifyImpl();
} }
@Override @Override
@Nonnull
public Encrypt encrypt() { public Encrypt encrypt() {
return new EncryptImpl(); return new EncryptImpl();
} }
@Override @Override
@Nonnull
public Decrypt decrypt() { public Decrypt decrypt() {
return new DecryptImpl(); return new DecryptImpl();
} }
@Override @Override
@Nonnull
public Armor armor() { public Armor armor() {
return new ArmorImpl(); return new ArmorImpl();
} }
@Override @Override
@Nonnull
public Dearmor dearmor() { public Dearmor dearmor() {
return new DearmorImpl(); return new DearmorImpl();
} }
@Override @Override
@Nonnull
public ListProfiles listProfiles() { public ListProfiles listProfiles() {
return new ListProfilesImpl(); return new ListProfilesImpl();
} }
@Override @Override
@Nonnull
public RevokeKey revokeKey() { public RevokeKey revokeKey() {
return new RevokeKeyImpl(); return new RevokeKeyImpl();
} }
@Override @Override
@Nonnull
public ChangeKeyPassword changeKeyPassword() { public ChangeKeyPassword changeKeyPassword() {
return new ChangeKeyPasswordImpl(); return new ChangeKeyPasswordImpl();
} }
@Override @Override
@Nonnull
public InlineDetach inlineDetach() { public InlineDetach inlineDetach() {
return new InlineDetachImpl(); return new InlineDetachImpl();
} }

View file

@ -12,6 +12,8 @@ import java.util.Properties;
import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sop.operation.Version; import sop.operation.Version;
import javax.annotation.Nonnull;
/** /**
* Implementation of the <pre>version</pre> operation using PGPainless. * Implementation of the <pre>version</pre> operation using PGPainless.
*/ */
@ -21,11 +23,13 @@ public class VersionImpl implements Version {
private static final int SOP_VERSION = 7; private static final int SOP_VERSION = 7;
@Override @Override
@Nonnull
public String getName() { public String getName() {
return "PGPainless-SOP"; return "PGPainless-SOP";
} }
@Override @Override
@Nonnull
public String getVersion() { public String getVersion() {
// See https://stackoverflow.com/a/50119235 // See https://stackoverflow.com/a/50119235
String version; String version;
@ -44,11 +48,13 @@ public class VersionImpl implements Version {
} }
@Override @Override
@Nonnull
public String getBackendVersion() { public String getBackendVersion() {
return "PGPainless " + getVersion(); return "PGPainless " + getVersion();
} }
@Override @Override
@Nonnull
public String getExtendedVersion() { public String getExtendedVersion() {
double bcVersion = new BouncyCastleProvider().getVersion(); double bcVersion = new BouncyCastleProvider().getVersion();
String FORMAT_VERSION = String.format("%02d", SOP_VERSION); String FORMAT_VERSION = String.format("%02d", SOP_VERSION);