mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-12-22 19:08:00 +01:00
Experimental support for inline-sign, inline-verify
This commit is contained in:
parent
dd26b5230d
commit
0b69e18715
11 changed files with 222 additions and 87 deletions
|
@ -43,7 +43,7 @@ public class ArmorTest {
|
|||
@FailOnSystemExit
|
||||
public void armorSecretKey() throws IOException, PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException {
|
||||
PGPSecretKeyRing secretKey = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("alice@pgpainless.org", null);
|
||||
.modernKeyRing("alice@pgpainless.org");
|
||||
byte[] bytes = secretKey.getEncoded();
|
||||
|
||||
System.setIn(new ByteArrayInputStream(bytes));
|
||||
|
@ -59,7 +59,7 @@ public class ArmorTest {
|
|||
@FailOnSystemExit
|
||||
public void armorPublicKey() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException {
|
||||
PGPSecretKeyRing secretKey = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("alice@pgpainless.org", null);
|
||||
.modernKeyRing("alice@pgpainless.org");
|
||||
PGPPublicKeyRing publicKey = PGPainless.extractCertificate(secretKey);
|
||||
byte[] bytes = publicKey.getEncoded();
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ public class DearmorTest {
|
|||
@FailOnSystemExit
|
||||
public void dearmorSecretKey() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException {
|
||||
PGPSecretKeyRing secretKey = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("alice@pgpainless.org", null);
|
||||
.modernKeyRing("alice@pgpainless.org");
|
||||
String armored = PGPainless.asciiArmor(secretKey);
|
||||
|
||||
System.setIn(new ByteArrayInputStream(armored.getBytes(StandardCharsets.UTF_8)));
|
||||
|
@ -59,7 +59,7 @@ public class DearmorTest {
|
|||
@FailOnSystemExit
|
||||
public void dearmorCertificate() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException {
|
||||
PGPSecretKeyRing secretKey = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("alice@pgpainless.org", null);
|
||||
.modernKeyRing("alice@pgpainless.org");
|
||||
PGPPublicKeyRing certificate = PGPainless.extractCertificate(secretKey);
|
||||
String armored = PGPainless.asciiArmor(certificate);
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ public class DetachInbandSignatureAndMessageTest {
|
|||
|
||||
// Detach
|
||||
File tempSigFile = new File(tempDir, "sig.out");
|
||||
PGPainlessCLI.main(new String[] {"detach-inband-signature-and-message", "--signatures-out=" + tempSigFile.getAbsolutePath()});
|
||||
PGPainlessCLI.main(new String[] {"inline-detach", "--signatures-out=" + tempSigFile.getAbsolutePath()});
|
||||
|
||||
// Test equality with expected values
|
||||
assertEquals(CLEAR_SIGNED_BODY, msgOut.toString());
|
||||
|
@ -150,7 +150,7 @@ public class DetachInbandSignatureAndMessageTest {
|
|||
|
||||
// Detach
|
||||
File tempSigFile = new File(tempDir, "sig.asc");
|
||||
PGPainlessCLI.main(new String[] {"detach-inband-signature-and-message", "--signatures-out=" + tempSigFile.getAbsolutePath(), "--no-armor"});
|
||||
PGPainlessCLI.main(new String[] {"inline-detach", "--signatures-out=" + tempSigFile.getAbsolutePath(), "--no-armor"});
|
||||
|
||||
// Test equality with expected values
|
||||
assertEquals(CLEAR_SIGNED_BODY, msgOut.toString());
|
||||
|
@ -187,7 +187,7 @@ public class DetachInbandSignatureAndMessageTest {
|
|||
// Detach
|
||||
File existingSigFile = new File(tempDir, "sig.existing");
|
||||
assertTrue(existingSigFile.createNewFile());
|
||||
PGPainlessCLI.main(new String[] {"detach-inband-signature-and-message", "--signatures-out=" + existingSigFile.getAbsolutePath()});
|
||||
PGPainlessCLI.main(new String[] {"inline-detach", "--signatures-out=" + existingSigFile.getAbsolutePath()});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ public class SignVerifyTest {
|
|||
File aliceKeyFile = new File(tempDir, "alice.key");
|
||||
assertTrue(aliceKeyFile.createNewFile());
|
||||
PGPSecretKeyRing aliceKeys = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("alice", null);
|
||||
.modernKeyRing("alice");
|
||||
OutputStream aliceKeyOut = new FileOutputStream(aliceKeyFile);
|
||||
Streams.pipeAll(new ByteArrayInputStream(aliceKeys.getEncoded()), aliceKeyOut);
|
||||
aliceKeyOut.close();
|
||||
|
@ -108,7 +108,7 @@ public class SignVerifyTest {
|
|||
String[] split = verification.split(" ");
|
||||
OpenPgpV4Fingerprint primaryKeyFingerprint = new OpenPgpV4Fingerprint(aliceKeys);
|
||||
OpenPgpV4Fingerprint signingKeyFingerprint = new OpenPgpV4Fingerprint(new KeyRingInfo(alicePub, new Date()).getSigningSubkeys().get(0));
|
||||
assertEquals(signingKeyFingerprint.toString(), split[1].trim());
|
||||
assertEquals(signingKeyFingerprint.toString(), split[1].trim(), verification);
|
||||
assertEquals(primaryKeyFingerprint.toString(), split[2].trim());
|
||||
|
||||
// Test micalg output
|
||||
|
|
|
@ -134,7 +134,7 @@ public class SignUsingPublicKeyBehaviorTest {
|
|||
assertTrue(sigFile.createNewFile());
|
||||
FileOutputStream sigOut = new FileOutputStream(sigFile);
|
||||
System.setOut(new PrintStream(sigOut));
|
||||
PGPainlessCLI.execute("sign", "--armor", aliceKeyFile.getAbsolutePath());
|
||||
PGPainlessCLI.main(new String[] {"sign", "--armor", aliceKeyFile.getAbsolutePath()});
|
||||
|
||||
System.setIn(originalIn);
|
||||
}
|
||||
|
|
|
@ -10,9 +10,7 @@ import java.io.OutputStream;
|
|||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||
|
@ -39,7 +37,6 @@ import sop.operation.Decrypt;
|
|||
public class DecryptImpl implements Decrypt {
|
||||
|
||||
private final ConsumerOptions consumerOptions = new ConsumerOptions();
|
||||
private final Set<PGPSecretKeyRing> keys = new HashSet<>();
|
||||
private final MatchMakingSecretKeyRingProtector protector = new MatchMakingSecretKeyRingProtector();
|
||||
|
||||
@Override
|
||||
|
@ -105,7 +102,8 @@ public class DecryptImpl implements Decrypt {
|
|||
PGPSecretKeyRingCollection secretKeyCollection = PGPainless.readKeyRing()
|
||||
.secretKeyRingCollection(keyIn);
|
||||
for (PGPSecretKeyRing key : secretKeyCollection) {
|
||||
keys.add(key);
|
||||
protector.addSecretKey(key);
|
||||
consumerOptions.addDecryptionKey(key, protector);
|
||||
}
|
||||
} catch (IOException | PGPException e) {
|
||||
throw new SOPGPException.BadData(e);
|
||||
|
@ -124,10 +122,6 @@ public class DecryptImpl implements Decrypt {
|
|||
public ReadyWithResult<DecryptionResult> ciphertext(InputStream ciphertext)
|
||||
throws SOPGPException.BadData,
|
||||
SOPGPException.MissingArg {
|
||||
for (PGPSecretKeyRing key : keys) {
|
||||
protector.addSecretKey(key);
|
||||
consumerOptions.addDecryptionKey(key, protector);
|
||||
}
|
||||
|
||||
if (consumerOptions.getDecryptionKeys().isEmpty() && consumerOptions.getDecryptionPassphrases().isEmpty() && consumerOptions.getSessionKey() == null) {
|
||||
throw new SOPGPException.MissingArg("Missing decryption key, passphrase or session key.");
|
||||
|
@ -145,6 +139,7 @@ public class DecryptImpl implements Decrypt {
|
|||
} catch (PGPException | IOException e) {
|
||||
throw new SOPGPException.BadData(e);
|
||||
} finally {
|
||||
// Forget passphrases after decryption
|
||||
protector.clear();
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import java.io.ByteArrayOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -24,9 +25,8 @@ import org.pgpainless.encryption_signing.ProducerOptions;
|
|||
import org.pgpainless.encryption_signing.SigningOptions;
|
||||
import org.pgpainless.exception.KeyException;
|
||||
import org.pgpainless.key.SubkeyIdentifier;
|
||||
import org.pgpainless.key.info.KeyRingInfo;
|
||||
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||
import org.pgpainless.util.ArmoredOutputStreamFactory;
|
||||
import org.pgpainless.util.Passphrase;
|
||||
import sop.MicAlg;
|
||||
import sop.ReadyWithResult;
|
||||
import sop.SigningResult;
|
||||
|
@ -39,6 +39,7 @@ public class DetachedSignImpl implements DetachedSign {
|
|||
private boolean armor = true;
|
||||
private SignAs mode = SignAs.Binary;
|
||||
private final SigningOptions signingOptions = new SigningOptions();
|
||||
private final MatchMakingSecretKeyRingProtector protector = new MatchMakingSecretKeyRingProtector();
|
||||
|
||||
@Override
|
||||
public DetachedSign noArmor() {
|
||||
|
@ -58,11 +59,8 @@ public class DetachedSignImpl implements DetachedSign {
|
|||
PGPSecretKeyRingCollection keys = PGPainless.readKeyRing().secretKeyRingCollection(keyIn);
|
||||
|
||||
for (PGPSecretKeyRing key : keys) {
|
||||
KeyRingInfo info = new KeyRingInfo(key);
|
||||
if (!info.isFullyDecrypted()) {
|
||||
throw new SOPGPException.KeyIsProtected();
|
||||
}
|
||||
signingOptions.addDetachedSignature(SecretKeyRingProtector.unprotectedKeys(), key, modeToSigType(mode));
|
||||
protector.addSecretKey(key);
|
||||
signingOptions.addDetachedSignature(protector, key, modeToSigType(mode));
|
||||
}
|
||||
} catch (PGPException | KeyException e) {
|
||||
throw new SOPGPException.BadData(e);
|
||||
|
@ -72,7 +70,9 @@ public class DetachedSignImpl implements DetachedSign {
|
|||
|
||||
@Override
|
||||
public DetachedSign withKeyPassword(byte[] password) {
|
||||
return null;
|
||||
String string = new String(password, Charset.forName("UTF8"));
|
||||
protector.addPassphrase(Passphrase.fromPassword(string));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -96,6 +96,9 @@ public class DetachedSignImpl implements DetachedSign {
|
|||
signingStream.close();
|
||||
EncryptionResult encryptionResult = signingStream.getResult();
|
||||
|
||||
// forget passphrases
|
||||
protector.clear();
|
||||
|
||||
List<PGPSignature> signatures = new ArrayList<>();
|
||||
for (SubkeyIdentifier key : encryptionResult.getDetachedSignatures().keySet()) {
|
||||
signatures.addAll(encryptionResult.getDetachedSignatures().get(key));
|
||||
|
|
|
@ -8,8 +8,6 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||
|
@ -25,18 +23,16 @@ import org.pgpainless.encryption_signing.ProducerOptions;
|
|||
import org.pgpainless.encryption_signing.SigningOptions;
|
||||
import org.pgpainless.exception.WrongPassphraseException;
|
||||
import org.pgpainless.util.Passphrase;
|
||||
import sop.util.ProxyOutputStream;
|
||||
import sop.Ready;
|
||||
import sop.enums.EncryptAs;
|
||||
import sop.exception.SOPGPException;
|
||||
import sop.operation.Encrypt;
|
||||
import sop.util.ProxyOutputStream;
|
||||
|
||||
public class EncryptImpl implements Encrypt {
|
||||
|
||||
EncryptionOptions encryptionOptions = new EncryptionOptions();
|
||||
SigningOptions signingOptions = null;
|
||||
|
||||
Set<PGPSecretKeyRing> signingKeys = new HashSet<>();
|
||||
MatchMakingSecretKeyRingProtector protector = new MatchMakingSecretKeyRingProtector();
|
||||
|
||||
private EncryptAs encryptAs = EncryptAs.Binary;
|
||||
|
@ -55,17 +51,34 @@ public class EncryptImpl implements Encrypt {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Encrypt signWith(InputStream keyIn) throws SOPGPException.KeyCannotSign, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.BadData {
|
||||
public Encrypt signWith(InputStream keyIn)
|
||||
throws SOPGPException.KeyCannotSign, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.BadData {
|
||||
if (signingOptions == null) {
|
||||
signingOptions = SigningOptions.get();
|
||||
}
|
||||
|
||||
try {
|
||||
PGPSecretKeyRingCollection keys = PGPainless.readKeyRing().secretKeyRingCollection(keyIn);
|
||||
if (keys.size() != 1) {
|
||||
throw new SOPGPException.BadData(new AssertionError("Exactly one secret key at a time expected. Got " + keys.size()));
|
||||
}
|
||||
|
||||
if (signingOptions == null) {
|
||||
signingOptions = SigningOptions.get();
|
||||
PGPSecretKeyRing signingKey = keys.iterator().next();
|
||||
protector.addSecretKey(signingKey);
|
||||
|
||||
try {
|
||||
signingOptions.addInlineSignature(
|
||||
protector,
|
||||
signingKey,
|
||||
(encryptAs == EncryptAs.Binary ? DocumentSignatureType.BINARY_DOCUMENT : DocumentSignatureType.CANONICAL_TEXT_DOCUMENT)
|
||||
);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new SOPGPException.KeyCannotSign();
|
||||
} catch (WrongPassphraseException e) {
|
||||
throw new SOPGPException.KeyIsProtected();
|
||||
} catch (PGPException e) {
|
||||
throw new SOPGPException.BadData(e);
|
||||
}
|
||||
signingKeys.add(keys.getKeyRings().next());
|
||||
} catch (IOException | PGPException e) {
|
||||
throw new SOPGPException.BadData(e);
|
||||
}
|
||||
|
@ -100,26 +113,6 @@ public class EncryptImpl implements Encrypt {
|
|||
|
||||
@Override
|
||||
public Ready plaintext(InputStream plaintext) throws IOException {
|
||||
for (PGPSecretKeyRing signingKey : signingKeys) {
|
||||
protector.addSecretKey(signingKey);
|
||||
}
|
||||
|
||||
if (signingOptions != null) {
|
||||
try {
|
||||
signingOptions.addInlineSignatures(
|
||||
protector,
|
||||
signingKeys,
|
||||
(encryptAs == EncryptAs.Binary ? DocumentSignatureType.BINARY_DOCUMENT : DocumentSignatureType.CANONICAL_TEXT_DOCUMENT)
|
||||
);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new SOPGPException.KeyCannotSign();
|
||||
} catch (WrongPassphraseException e) {
|
||||
throw new SOPGPException.KeyIsProtected();
|
||||
} catch (PGPException e) {
|
||||
throw new SOPGPException.BadData(e);
|
||||
}
|
||||
}
|
||||
|
||||
ProducerOptions producerOptions = signingOptions != null ?
|
||||
ProducerOptions.signAndEncrypt(encryptionOptions, signingOptions) :
|
||||
ProducerOptions.encrypt(encryptionOptions);
|
||||
|
|
|
@ -4,39 +4,139 @@
|
|||
|
||||
package org.pgpainless.sop;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.bouncycastle.util.io.Streams;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.algorithm.DocumentSignatureType;
|
||||
import org.pgpainless.encryption_signing.EncryptionResult;
|
||||
import org.pgpainless.encryption_signing.EncryptionStream;
|
||||
import org.pgpainless.encryption_signing.ProducerOptions;
|
||||
import org.pgpainless.encryption_signing.SigningOptions;
|
||||
import org.pgpainless.exception.KeyException;
|
||||
import org.pgpainless.key.SubkeyIdentifier;
|
||||
import org.pgpainless.util.Passphrase;
|
||||
import sop.MicAlg;
|
||||
import sop.ReadyWithResult;
|
||||
import sop.SigningResult;
|
||||
import sop.enums.InlineSignAs;
|
||||
import sop.exception.SOPGPException;
|
||||
import sop.operation.DetachedSign;
|
||||
import sop.operation.InlineSign;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class InlineSignImpl implements InlineSign {
|
||||
|
||||
private boolean armor = true;
|
||||
private InlineSignAs mode = InlineSignAs.Binary;
|
||||
private final SigningOptions signingOptions = new SigningOptions();
|
||||
private final MatchMakingSecretKeyRingProtector protector = new MatchMakingSecretKeyRingProtector();
|
||||
|
||||
@Override
|
||||
public DetachedSign mode(InlineSignAs mode) throws SOPGPException.UnsupportedOption {
|
||||
return null;
|
||||
public InlineSign mode(InlineSignAs mode) throws SOPGPException.UnsupportedOption {
|
||||
this.mode = mode;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DetachedSign noArmor() {
|
||||
return null;
|
||||
public InlineSign noArmor() {
|
||||
this.armor = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InlineSign key(InputStream key) throws SOPGPException.KeyIsProtected, SOPGPException.BadData, IOException {
|
||||
return null;
|
||||
public InlineSign key(InputStream keyIn) throws SOPGPException.KeyIsProtected, SOPGPException.BadData, IOException {
|
||||
try {
|
||||
PGPSecretKeyRingCollection keys = PGPainless.readKeyRing().secretKeyRingCollection(keyIn);
|
||||
|
||||
for (PGPSecretKeyRing key : keys) {
|
||||
protector.addSecretKey(key);
|
||||
if (mode == InlineSignAs.CleartextSigned) {
|
||||
signingOptions.addDetachedSignature(protector, key, DocumentSignatureType.BINARY_DOCUMENT);
|
||||
} else {
|
||||
signingOptions.addInlineSignature(protector, key, modeToSigType(mode));
|
||||
}
|
||||
}
|
||||
} catch (PGPException | KeyException e) {
|
||||
throw new SOPGPException.BadData(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InlineSign withKeyPassword(byte[] password) {
|
||||
return null;
|
||||
String string = new String(password, Charset.forName("UTF8"));
|
||||
protector.addPassphrase(Passphrase.fromPassword(string));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadyWithResult<SigningResult> data(InputStream data) throws IOException, SOPGPException.ExpectedText {
|
||||
return null;
|
||||
|
||||
ProducerOptions producerOptions = ProducerOptions.sign(signingOptions);
|
||||
if (mode == InlineSignAs.CleartextSigned) {
|
||||
producerOptions.setCleartextSigned();
|
||||
producerOptions.setAsciiArmor(true);
|
||||
} else {
|
||||
producerOptions.setAsciiArmor(armor);
|
||||
}
|
||||
|
||||
return new ReadyWithResult<SigningResult>() {
|
||||
@Override
|
||||
public SigningResult writeTo(OutputStream outputStream) throws IOException, SOPGPException.NoSignature {
|
||||
try {
|
||||
EncryptionStream signingStream = PGPainless.encryptAndOrSign()
|
||||
.onOutputStream(outputStream)
|
||||
.withOptions(producerOptions);
|
||||
|
||||
if (signingStream.isClosed()) {
|
||||
throw new IllegalStateException("EncryptionStream is already closed.");
|
||||
}
|
||||
|
||||
Streams.pipeAll(data, signingStream);
|
||||
signingStream.close();
|
||||
EncryptionResult encryptionResult = signingStream.getResult();
|
||||
|
||||
// forget passphrases
|
||||
protector.clear();
|
||||
|
||||
List<PGPSignature> signatures = new ArrayList<>();
|
||||
for (SubkeyIdentifier key : encryptionResult.getDetachedSignatures().keySet()) {
|
||||
signatures.addAll(encryptionResult.getDetachedSignatures().get(key));
|
||||
}
|
||||
|
||||
return SigningResult.builder()
|
||||
.setMicAlg(micAlgFromSignatures(signatures))
|
||||
.build();
|
||||
} catch (PGPException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private MicAlg micAlgFromSignatures(Iterable<PGPSignature> signatures) {
|
||||
int algorithmId = 0;
|
||||
for (PGPSignature signature : signatures) {
|
||||
int sigAlg = signature.getHashAlgorithm();
|
||||
if (algorithmId == 0 || algorithmId == sigAlg) {
|
||||
algorithmId = sigAlg;
|
||||
} else {
|
||||
return MicAlg.empty();
|
||||
}
|
||||
}
|
||||
return algorithmId == 0 ? MicAlg.empty() : MicAlg.fromHashAlgorithmId(algorithmId);
|
||||
}
|
||||
|
||||
private static DocumentSignatureType modeToSigType(InlineSignAs mode) {
|
||||
return mode == InlineSignAs.Binary ? DocumentSignatureType.BINARY_DOCUMENT
|
||||
: DocumentSignatureType.CANONICAL_TEXT_DOCUMENT;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,15 @@
|
|||
|
||||
package org.pgpainless.sop;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.bouncycastle.util.io.Streams;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.decryption_verification.ConsumerOptions;
|
||||
import org.pgpainless.decryption_verification.DecryptionStream;
|
||||
import org.pgpainless.decryption_verification.OpenPgpMetadata;
|
||||
import org.pgpainless.key.SubkeyIdentifier;
|
||||
import sop.ReadyWithResult;
|
||||
import sop.Verification;
|
||||
import sop.exception.SOPGPException;
|
||||
|
@ -11,27 +20,75 @@ import sop.operation.InlineVerify;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class InlineVerifyImpl implements InlineVerify {
|
||||
@Override
|
||||
public ReadyWithResult<List<Verification>> data(InputStream data) throws IOException, SOPGPException.NoSignature, SOPGPException.BadData {
|
||||
return null;
|
||||
}
|
||||
|
||||
private final ConsumerOptions options = new ConsumerOptions();
|
||||
|
||||
@Override
|
||||
public InlineVerify notBefore(Date timestamp) throws SOPGPException.UnsupportedOption {
|
||||
return null;
|
||||
options.verifyNotBefore(timestamp);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InlineVerify notAfter(Date timestamp) throws SOPGPException.UnsupportedOption {
|
||||
return null;
|
||||
options.verifyNotAfter(timestamp);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InlineVerify cert(InputStream cert) throws SOPGPException.BadData {
|
||||
return null;
|
||||
PGPPublicKeyRingCollection certificates;
|
||||
try {
|
||||
certificates = PGPainless.readKeyRing().publicKeyRingCollection(cert);
|
||||
} catch (IOException | PGPException e) {
|
||||
throw new SOPGPException.BadData(e);
|
||||
}
|
||||
options.addVerificationCerts(certificates);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadyWithResult<List<Verification>> data(InputStream data) throws IOException, SOPGPException.NoSignature, SOPGPException.BadData {
|
||||
return new ReadyWithResult<List<Verification>>() {
|
||||
@Override
|
||||
public List<Verification> writeTo(OutputStream outputStream) throws IOException, SOPGPException.NoSignature {
|
||||
DecryptionStream decryptionStream;
|
||||
try {
|
||||
decryptionStream = PGPainless.decryptAndOrVerify()
|
||||
.onInputStream(data)
|
||||
.withOptions(options);
|
||||
|
||||
Streams.pipeAll(decryptionStream, outputStream);
|
||||
decryptionStream.close();
|
||||
|
||||
OpenPgpMetadata metadata = decryptionStream.getResult();
|
||||
List<Verification> verificationList = new ArrayList<>();
|
||||
|
||||
for (SubkeyIdentifier verifiedSigningKey : metadata.getVerifiedSignatures().keySet()) {
|
||||
PGPSignature signature = metadata.getVerifiedSignatures().get(verifiedSigningKey);
|
||||
verificationList.add(new Verification(
|
||||
signature.getCreationTime(),
|
||||
verifiedSigningKey.getSubkeyFingerprint().toString(),
|
||||
verifiedSigningKey.getPrimaryKeyFingerprint().toString()));
|
||||
}
|
||||
|
||||
if (!options.getCertificates().isEmpty()) {
|
||||
if (verificationList.isEmpty()) {
|
||||
throw new SOPGPException.NoSignature();
|
||||
}
|
||||
}
|
||||
|
||||
return verificationList;
|
||||
} catch (PGPException e) {
|
||||
throw new SOPGPException.BadData(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,17 +11,13 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.algorithm.SignatureType;
|
||||
import org.pgpainless.signature.SignatureUtils;
|
||||
import sop.SOP;
|
||||
|
@ -128,13 +124,4 @@ public class SignTest {
|
|||
assertEquals(SignatureType.CANONICAL_TEXT_DOCUMENT.getCode(), sig.getSignatureType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rejectEncryptedKey() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException {
|
||||
PGPSecretKeyRing key = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("Alice", "passphrase");
|
||||
byte[] bytes = key.getEncoded();
|
||||
|
||||
assertThrows(SOPGPException.KeyIsProtected.class, () -> sop.sign().key(bytes));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue