mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-11-12 15:32:06 +01:00
Wip: Introduce MessageMetadata class
This commit is contained in:
parent
efdf2bca0d
commit
5c93eb3705
5 changed files with 498 additions and 128 deletions
|
@ -0,0 +1,249 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.decryption_verification;
|
||||||
|
|
||||||
|
import org.pgpainless.algorithm.CompressionAlgorithm;
|
||||||
|
import org.pgpainless.algorithm.StreamEncoding;
|
||||||
|
import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
|
||||||
|
import org.pgpainless.util.SessionKey;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
|
public class MessageMetadata {
|
||||||
|
|
||||||
|
protected Message message;
|
||||||
|
|
||||||
|
public MessageMetadata(@Nonnull Message message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable SymmetricKeyAlgorithm getEncryptionAlgorithm() {
|
||||||
|
Iterator<SymmetricKeyAlgorithm> algorithms = getEncryptionAlgorithms();
|
||||||
|
if (algorithms.hasNext()) {
|
||||||
|
return algorithms.next();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nonnull Iterator<SymmetricKeyAlgorithm> getEncryptionAlgorithms() {
|
||||||
|
return new LayerIterator<SymmetricKeyAlgorithm>(message) {
|
||||||
|
@Override
|
||||||
|
public boolean matches(Nested layer) {
|
||||||
|
return layer instanceof EncryptedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SymmetricKeyAlgorithm getProperty(Layer last) {
|
||||||
|
return ((EncryptedData) last).algorithm;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable CompressionAlgorithm getCompressionAlgorithm() {
|
||||||
|
Iterator<CompressionAlgorithm> algorithms = getCompressionAlgorithms();
|
||||||
|
if (algorithms.hasNext()) {
|
||||||
|
return algorithms.next();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nonnull Iterator<CompressionAlgorithm> getCompressionAlgorithms() {
|
||||||
|
return new LayerIterator<CompressionAlgorithm>(message) {
|
||||||
|
@Override
|
||||||
|
public boolean matches(Nested layer) {
|
||||||
|
return layer instanceof CompressedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompressionAlgorithm getProperty(Layer last) {
|
||||||
|
return ((CompressedData) last).algorithm;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFilename() {
|
||||||
|
return findLiteralData().getFileName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getModificationDate() {
|
||||||
|
return findLiteralData().getModificationDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StreamEncoding getFormat() {
|
||||||
|
return findLiteralData().getFormat();
|
||||||
|
}
|
||||||
|
|
||||||
|
private LiteralData findLiteralData() {
|
||||||
|
Nested nested = message.child;
|
||||||
|
while (nested.hasNestedChild()) {
|
||||||
|
Layer layer = (Layer) nested;
|
||||||
|
nested = layer.child;
|
||||||
|
}
|
||||||
|
return (LiteralData) nested;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static abstract class Layer {
|
||||||
|
protected final List<SignatureVerification> verifiedSignatures = new ArrayList<>();
|
||||||
|
protected final List<SignatureVerification.Failure> failedSignatures = new ArrayList<>();
|
||||||
|
protected Nested child;
|
||||||
|
|
||||||
|
public Nested getChild() {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChild(Nested child) {
|
||||||
|
this.child = child;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SignatureVerification> getVerifiedSignatures() {
|
||||||
|
return new ArrayList<>(verifiedSignatures);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SignatureVerification.Failure> getFailedSignatures() {
|
||||||
|
return new ArrayList<>(failedSignatures);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Nested {
|
||||||
|
boolean hasNestedChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Message extends Layer {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LiteralData implements Nested {
|
||||||
|
protected String fileName;
|
||||||
|
protected Date modificationDate;
|
||||||
|
protected StreamEncoding format;
|
||||||
|
|
||||||
|
public LiteralData() {
|
||||||
|
this("", new Date(0L), StreamEncoding.BINARY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LiteralData(String fileName, Date modificationDate, StreamEncoding format) {
|
||||||
|
this.fileName = fileName;
|
||||||
|
this.modificationDate = modificationDate;
|
||||||
|
this.format = format;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFileName() {
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getModificationDate() {
|
||||||
|
return modificationDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StreamEncoding getFormat() {
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNestedChild() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CompressedData extends Layer implements Nested {
|
||||||
|
protected final CompressionAlgorithm algorithm;
|
||||||
|
|
||||||
|
public CompressedData(CompressionAlgorithm zip) {
|
||||||
|
this.algorithm = zip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompressionAlgorithm getAlgorithm() {
|
||||||
|
return algorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNestedChild() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class EncryptedData extends Layer implements Nested {
|
||||||
|
protected final SymmetricKeyAlgorithm algorithm;
|
||||||
|
protected SessionKey sessionKey;
|
||||||
|
protected List<Long> recipients;
|
||||||
|
|
||||||
|
public EncryptedData(SymmetricKeyAlgorithm algorithm) {
|
||||||
|
this.algorithm = algorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SymmetricKeyAlgorithm getAlgorithm() {
|
||||||
|
return algorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SessionKey getSessionKey() {
|
||||||
|
return sessionKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Long> getRecipients() {
|
||||||
|
return new ArrayList<>(recipients);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNestedChild() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static abstract class LayerIterator<O> implements Iterator<O> {
|
||||||
|
private Nested current;
|
||||||
|
Layer last = null;
|
||||||
|
|
||||||
|
public LayerIterator(Message message) {
|
||||||
|
super();
|
||||||
|
this.current = message.child;
|
||||||
|
if (matches(current)) {
|
||||||
|
last = (Layer) current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
if (last == null) {
|
||||||
|
findNext();
|
||||||
|
}
|
||||||
|
return last != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public O next() {
|
||||||
|
if (last == null) {
|
||||||
|
findNext();
|
||||||
|
}
|
||||||
|
if (last != null) {
|
||||||
|
O property = getProperty(last);
|
||||||
|
last = null;
|
||||||
|
return property;
|
||||||
|
}
|
||||||
|
throw new NoSuchElementException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findNext() {
|
||||||
|
while (current instanceof Layer) {
|
||||||
|
current = ((Layer) current).child;
|
||||||
|
if (matches(current)) {
|
||||||
|
last = (Layer) current;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract boolean matches(Nested layer);
|
||||||
|
|
||||||
|
abstract O getProperty(Layer last);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -31,11 +31,11 @@ import org.bouncycastle.openpgp.operator.PBEDataDecryptorFactory;
|
||||||
import org.bouncycastle.openpgp.operator.PGPContentVerifierBuilderProvider;
|
import org.bouncycastle.openpgp.operator.PGPContentVerifierBuilderProvider;
|
||||||
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
|
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
|
||||||
import org.bouncycastle.openpgp.operator.SessionKeyDataDecryptorFactory;
|
import org.bouncycastle.openpgp.operator.SessionKeyDataDecryptorFactory;
|
||||||
import org.bouncycastle.pqc.crypto.rainbow.Layer;
|
|
||||||
import org.pgpainless.PGPainless;
|
import org.pgpainless.PGPainless;
|
||||||
import org.pgpainless.algorithm.CompressionAlgorithm;
|
import org.pgpainless.algorithm.CompressionAlgorithm;
|
||||||
import org.pgpainless.algorithm.EncryptionPurpose;
|
import org.pgpainless.algorithm.EncryptionPurpose;
|
||||||
import org.pgpainless.algorithm.OpenPgpPacket;
|
import org.pgpainless.algorithm.OpenPgpPacket;
|
||||||
|
import org.pgpainless.algorithm.StreamEncoding;
|
||||||
import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
|
import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
|
||||||
import org.pgpainless.decryption_verification.automaton.InputAlphabet;
|
import org.pgpainless.decryption_verification.automaton.InputAlphabet;
|
||||||
import org.pgpainless.decryption_verification.automaton.PDA;
|
import org.pgpainless.decryption_verification.automaton.PDA;
|
||||||
|
@ -69,14 +69,14 @@ public class OpenPgpMessageInputStream extends InputStream {
|
||||||
private boolean closed = false;
|
private boolean closed = false;
|
||||||
|
|
||||||
private Signatures signatures;
|
private Signatures signatures;
|
||||||
private LayerMetadata layerMetadata;
|
private MessageMetadata.Layer metadata;
|
||||||
|
|
||||||
public OpenPgpMessageInputStream(InputStream inputStream, ConsumerOptions options)
|
public OpenPgpMessageInputStream(InputStream inputStream, ConsumerOptions options)
|
||||||
throws IOException, PGPException {
|
throws IOException, PGPException {
|
||||||
this(inputStream, options, null);
|
this(inputStream, options, new MessageMetadata.Message());
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenPgpMessageInputStream(InputStream inputStream, ConsumerOptions options, LayerMetadata layerMetadata)
|
OpenPgpMessageInputStream(InputStream inputStream, ConsumerOptions options, MessageMetadata.Layer metadata)
|
||||||
throws PGPException, IOException {
|
throws PGPException, IOException {
|
||||||
// TODO: Use BCPGInputStream.wrap(inputStream);
|
// TODO: Use BCPGInputStream.wrap(inputStream);
|
||||||
if (inputStream instanceof BCPGInputStream) {
|
if (inputStream instanceof BCPGInputStream) {
|
||||||
|
@ -86,33 +86,12 @@ public class OpenPgpMessageInputStream extends InputStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.options = options;
|
this.options = options;
|
||||||
|
this.metadata = metadata;
|
||||||
this.resultBuilder = OpenPgpMetadata.getBuilder();
|
this.resultBuilder = OpenPgpMetadata.getBuilder();
|
||||||
this.signatures = new Signatures(options);
|
this.signatures = new Signatures(options);
|
||||||
this.signatures.addDetachedSignatures(options.getDetachedSignatures());
|
this.signatures.addDetachedSignatures(options.getDetachedSignatures());
|
||||||
|
|
||||||
consumePackets();
|
consumePackets(); // nom nom nom
|
||||||
}
|
|
||||||
|
|
||||||
static class LayerMetadata {
|
|
||||||
|
|
||||||
private CompressionAlgorithm compressionAlgorithm;
|
|
||||||
private SymmetricKeyAlgorithm symmetricKeyAlgorithm;
|
|
||||||
private LayerMetadata child;
|
|
||||||
|
|
||||||
public LayerMetadata setCompressionAlgorithm(CompressionAlgorithm algorithm) {
|
|
||||||
this.compressionAlgorithm = algorithm;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LayerMetadata setSymmetricEncryptionAlgorithm(SymmetricKeyAlgorithm algorithm) {
|
|
||||||
this.symmetricKeyAlgorithm = algorithm;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LayerMetadata setChild(LayerMetadata child) {
|
|
||||||
this.child = child;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -127,27 +106,21 @@ public class OpenPgpMessageInputStream extends InputStream {
|
||||||
*/
|
*/
|
||||||
private void consumePackets()
|
private void consumePackets()
|
||||||
throws IOException, PGPException {
|
throws IOException, PGPException {
|
||||||
System.out.println("Walk " + automaton);
|
|
||||||
int tag;
|
int tag;
|
||||||
loop: while ((tag = nextTag()) != -1) {
|
loop: while ((tag = nextTag()) != -1) {
|
||||||
OpenPgpPacket nextPacket = OpenPgpPacket.requireFromTag(tag);
|
OpenPgpPacket nextPacket = OpenPgpPacket.requireFromTag(tag);
|
||||||
System.out.println(nextPacket);
|
|
||||||
switch (nextPacket) {
|
switch (nextPacket) {
|
||||||
|
|
||||||
// Literal Data - the literal data content is the new input stream
|
// Literal Data - the literal data content is the new input stream
|
||||||
case LIT:
|
case LIT:
|
||||||
automaton.next(InputAlphabet.LiteralData);
|
automaton.next(InputAlphabet.LiteralData);
|
||||||
PGPLiteralData literalData = new PGPLiteralData(bcpgIn);
|
processLiteralData();
|
||||||
in = literalData.getDataStream();
|
|
||||||
break loop;
|
break loop;
|
||||||
|
|
||||||
// Compressed Data - the content contains another OpenPGP message
|
// Compressed Data - the content contains another OpenPGP message
|
||||||
case COMP:
|
case COMP:
|
||||||
automaton.next(InputAlphabet.CompressedData);
|
automaton.next(InputAlphabet.CompressedData);
|
||||||
PGPCompressedData compressedData = new PGPCompressedData(bcpgIn);
|
processCompressedData();
|
||||||
LayerMetadata compressionLayer = new LayerMetadata();
|
|
||||||
compressionLayer.setCompressionAlgorithm(CompressionAlgorithm.fromId(compressedData.getAlgorithm()));
|
|
||||||
in = new OpenPgpMessageInputStream(compressedData.getDataStream(), options, compressionLayer);
|
|
||||||
break loop;
|
break loop;
|
||||||
|
|
||||||
// One Pass Signatures
|
// One Pass Signatures
|
||||||
|
@ -160,12 +133,7 @@ public class OpenPgpMessageInputStream extends InputStream {
|
||||||
case SIG:
|
case SIG:
|
||||||
boolean isSigForOPS = automaton.peekStack() == StackAlphabet.ops;
|
boolean isSigForOPS = automaton.peekStack() == StackAlphabet.ops;
|
||||||
automaton.next(InputAlphabet.Signatures);
|
automaton.next(InputAlphabet.Signatures);
|
||||||
PGPSignatureList signatureList = readSignatures();
|
processSignature(isSigForOPS);
|
||||||
if (isSigForOPS) {
|
|
||||||
signatures.addOnePassCorrespondingSignatures(signatureList);
|
|
||||||
} else {
|
|
||||||
signatures.addPrependedSignatures(signatureList);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Encrypted Data (ESKs and SED/SEIPD are parsed the same by BC)
|
// Encrypted Data (ESKs and SED/SEIPD are parsed the same by BC)
|
||||||
|
@ -210,6 +178,29 @@ public class OpenPgpMessageInputStream extends InputStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void processSignature(boolean isSigForOPS) throws IOException {
|
||||||
|
PGPSignatureList signatureList = readSignatures();
|
||||||
|
if (isSigForOPS) {
|
||||||
|
signatures.addOnePassCorrespondingSignatures(signatureList);
|
||||||
|
} else {
|
||||||
|
signatures.addPrependedSignatures(signatureList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processCompressedData() throws IOException, PGPException {
|
||||||
|
PGPCompressedData compressedData = new PGPCompressedData(bcpgIn);
|
||||||
|
MessageMetadata.CompressedData compressionLayer = new MessageMetadata.CompressedData(
|
||||||
|
CompressionAlgorithm.fromId(compressedData.getAlgorithm()));
|
||||||
|
in = new OpenPgpMessageInputStream(compressedData.getDataStream(), options, compressionLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processLiteralData() throws IOException {
|
||||||
|
PGPLiteralData literalData = new PGPLiteralData(bcpgIn);
|
||||||
|
this.metadata.setChild(new MessageMetadata.LiteralData(literalData.getFileName(), literalData.getModificationTime(),
|
||||||
|
StreamEncoding.requireFromCode(literalData.getFormat())));
|
||||||
|
in = literalData.getDataStream();
|
||||||
|
}
|
||||||
|
|
||||||
private boolean processEncryptedData() throws IOException, PGPException {
|
private boolean processEncryptedData() throws IOException, PGPException {
|
||||||
PGPEncryptedDataList encDataList = new PGPEncryptedDataList(bcpgIn);
|
PGPEncryptedDataList encDataList = new PGPEncryptedDataList(bcpgIn);
|
||||||
|
|
||||||
|
@ -227,13 +218,14 @@ public class OpenPgpMessageInputStream extends InputStream {
|
||||||
// TODO: Replace with encDataList.addSessionKeyDecryptionMethod(sessionKey)
|
// TODO: Replace with encDataList.addSessionKeyDecryptionMethod(sessionKey)
|
||||||
PGPEncryptedData esk = esks.all().get(0);
|
PGPEncryptedData esk = esks.all().get(0);
|
||||||
try {
|
try {
|
||||||
|
MessageMetadata.EncryptedData encryptedData = new MessageMetadata.EncryptedData(options.getSessionKey().getAlgorithm());
|
||||||
if (esk instanceof PGPPBEEncryptedData) {
|
if (esk instanceof PGPPBEEncryptedData) {
|
||||||
PGPPBEEncryptedData skesk = (PGPPBEEncryptedData) esk;
|
PGPPBEEncryptedData skesk = (PGPPBEEncryptedData) esk;
|
||||||
in = skesk.getDataStream(decryptorFactory);
|
in = new OpenPgpMessageInputStream(skesk.getDataStream(decryptorFactory), options, encryptedData);
|
||||||
return true;
|
return true;
|
||||||
} else if (esk instanceof PGPPublicKeyEncryptedData) {
|
} else if (esk instanceof PGPPublicKeyEncryptedData) {
|
||||||
PGPPublicKeyEncryptedData pkesk = (PGPPublicKeyEncryptedData) esk;
|
PGPPublicKeyEncryptedData pkesk = (PGPPublicKeyEncryptedData) esk;
|
||||||
in = pkesk.getDataStream(decryptorFactory);
|
in = new OpenPgpMessageInputStream(pkesk.getDataStream(decryptorFactory), options, encryptedData);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("Unknown ESK class type: " + esk.getClass().getName());
|
throw new RuntimeException("Unknown ESK class type: " + esk.getClass().getName());
|
||||||
|
@ -250,7 +242,9 @@ public class OpenPgpMessageInputStream extends InputStream {
|
||||||
.getPBEDataDecryptorFactory(passphrase);
|
.getPBEDataDecryptorFactory(passphrase);
|
||||||
try {
|
try {
|
||||||
InputStream decrypted = skesk.getDataStream(decryptorFactory);
|
InputStream decrypted = skesk.getDataStream(decryptorFactory);
|
||||||
in = new OpenPgpMessageInputStream(decrypted, options);
|
MessageMetadata.EncryptedData encryptedData = new MessageMetadata.EncryptedData(
|
||||||
|
SymmetricKeyAlgorithm.requireFromId(skesk.getSymmetricAlgorithm(decryptorFactory)));
|
||||||
|
in = new OpenPgpMessageInputStream(decrypted, options, encryptedData);
|
||||||
return true;
|
return true;
|
||||||
} catch (PGPException e) {
|
} catch (PGPException e) {
|
||||||
// password mismatch? Try next password
|
// password mismatch? Try next password
|
||||||
|
@ -274,7 +268,9 @@ public class OpenPgpMessageInputStream extends InputStream {
|
||||||
.getPublicKeyDataDecryptorFactory(privateKey);
|
.getPublicKeyDataDecryptorFactory(privateKey);
|
||||||
try {
|
try {
|
||||||
InputStream decrypted = pkesk.getDataStream(decryptorFactory);
|
InputStream decrypted = pkesk.getDataStream(decryptorFactory);
|
||||||
in = new OpenPgpMessageInputStream(decrypted, options);
|
MessageMetadata.EncryptedData encryptedData = new MessageMetadata.EncryptedData(
|
||||||
|
SymmetricKeyAlgorithm.requireFromId(pkesk.getSymmetricAlgorithm(decryptorFactory)));
|
||||||
|
in = new OpenPgpMessageInputStream(decrypted, options, encryptedData);
|
||||||
return true;
|
return true;
|
||||||
} catch (PGPException e) {
|
} catch (PGPException e) {
|
||||||
// hm :/
|
// hm :/
|
||||||
|
@ -291,7 +287,9 @@ public class OpenPgpMessageInputStream extends InputStream {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
InputStream decrypted = pkesk.getDataStream(decryptorFactory);
|
InputStream decrypted = pkesk.getDataStream(decryptorFactory);
|
||||||
in = new OpenPgpMessageInputStream(decrypted, options);
|
MessageMetadata.EncryptedData encryptedData = new MessageMetadata.EncryptedData(
|
||||||
|
SymmetricKeyAlgorithm.requireFromId(pkesk.getSymmetricAlgorithm(decryptorFactory)));
|
||||||
|
in = new OpenPgpMessageInputStream(decrypted, options, encryptedData);
|
||||||
return true;
|
return true;
|
||||||
} catch (PGPException e) {
|
} catch (PGPException e) {
|
||||||
// hm :/
|
// hm :/
|
||||||
|
@ -402,6 +400,7 @@ public class OpenPgpMessageInputStream extends InputStream {
|
||||||
signatures.update(b);
|
signatures.update(b);
|
||||||
} else {
|
} else {
|
||||||
in.close();
|
in.close();
|
||||||
|
collectMetadata();
|
||||||
in = null;
|
in = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -426,6 +425,7 @@ public class OpenPgpMessageInputStream extends InputStream {
|
||||||
int r = in.read(b, off, len);
|
int r = in.read(b, off, len);
|
||||||
if (r == -1) {
|
if (r == -1) {
|
||||||
in.close();
|
in.close();
|
||||||
|
collectMetadata();
|
||||||
in = null;
|
in = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -447,6 +447,7 @@ public class OpenPgpMessageInputStream extends InputStream {
|
||||||
|
|
||||||
if (in != null) {
|
if (in != null) {
|
||||||
in.close();
|
in.close();
|
||||||
|
collectMetadata();
|
||||||
in = null;
|
in = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,6 +462,21 @@ public class OpenPgpMessageInputStream extends InputStream {
|
||||||
closed = true;
|
closed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void collectMetadata() {
|
||||||
|
if (in instanceof OpenPgpMessageInputStream) {
|
||||||
|
OpenPgpMessageInputStream child = (OpenPgpMessageInputStream) in;
|
||||||
|
MessageMetadata.Layer childLayer = child.metadata;
|
||||||
|
this.metadata.setChild((MessageMetadata.Nested) childLayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageMetadata getMetadata() {
|
||||||
|
if (!closed) {
|
||||||
|
throw new IllegalStateException("Stream must be closed before access to metadata can be granted.");
|
||||||
|
}
|
||||||
|
return new MessageMetadata((MessageMetadata.Message) metadata);
|
||||||
|
}
|
||||||
|
|
||||||
private static class SortedESKs {
|
private static class SortedESKs {
|
||||||
|
|
||||||
private List<PGPPBEEncryptedData> skesks = new ArrayList<>();
|
private List<PGPPBEEncryptedData> skesks = new ArrayList<>();
|
||||||
|
|
|
@ -187,10 +187,7 @@ public class PDA {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void next(InputAlphabet input) throws MalformedOpenPgpMessageException {
|
public void next(InputAlphabet input) throws MalformedOpenPgpMessageException {
|
||||||
State old = state;
|
|
||||||
StackAlphabet stackItem = stack.isEmpty() ? null : stack.peek();
|
|
||||||
state = state.transition(input, this);
|
state = state.transition(input, this);
|
||||||
System.out.println(id + ": Transition from " + old + " to " + state + " via " + input + " with stack " + stackItem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.decryption_verification;
|
||||||
|
|
||||||
|
import org.junit.JUtils;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.pgpainless.algorithm.CompressionAlgorithm;
|
||||||
|
import org.pgpainless.algorithm.StreamEncoding;
|
||||||
|
import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
|
||||||
|
import org.pgpainless.util.DateUtil;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
public class MessageMetadataTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void processTestMessage_COMP_ENC_ENC_LIT() {
|
||||||
|
// Note: COMP of ENC does not make sense, since ENC is indistinguishable from randomness
|
||||||
|
// and randomness cannot be encrypted.
|
||||||
|
// For the sake of testing though, this is okay.
|
||||||
|
MessageMetadata.Message message = new MessageMetadata.Message();
|
||||||
|
|
||||||
|
MessageMetadata.CompressedData compressedData = new MessageMetadata.CompressedData(CompressionAlgorithm.ZIP);
|
||||||
|
MessageMetadata.EncryptedData encryptedData = new MessageMetadata.EncryptedData(SymmetricKeyAlgorithm.AES_128);
|
||||||
|
MessageMetadata.EncryptedData encryptedData1 = new MessageMetadata.EncryptedData(SymmetricKeyAlgorithm.AES_256);
|
||||||
|
MessageMetadata.LiteralData literalData = new MessageMetadata.LiteralData();
|
||||||
|
|
||||||
|
message.setChild(compressedData);
|
||||||
|
compressedData.setChild(encryptedData);
|
||||||
|
encryptedData.setChild(encryptedData1);
|
||||||
|
encryptedData1.setChild(literalData);
|
||||||
|
|
||||||
|
MessageMetadata metadata = new MessageMetadata(message);
|
||||||
|
|
||||||
|
// Check encryption algs
|
||||||
|
assertEquals(SymmetricKeyAlgorithm.AES_128, metadata.getEncryptionAlgorithm(), "getEncryptionAlgorithm() returns alg of outermost EncryptedData");
|
||||||
|
Iterator<SymmetricKeyAlgorithm> encryptionAlgs = metadata.getEncryptionAlgorithms();
|
||||||
|
assertTrue(encryptionAlgs.hasNext(), "There is at least one EncryptedData child");
|
||||||
|
assertTrue(encryptionAlgs.hasNext(), "The child is still there");
|
||||||
|
assertEquals(SymmetricKeyAlgorithm.AES_128, encryptionAlgs.next(), "The first algo is AES128");
|
||||||
|
assertTrue(encryptionAlgs.hasNext(), "There is another EncryptedData");
|
||||||
|
assertTrue(encryptionAlgs.hasNext(), "There is *still* another EncryptedData");
|
||||||
|
assertEquals(SymmetricKeyAlgorithm.AES_256, encryptionAlgs.next(), "The second algo is AES256");
|
||||||
|
assertFalse(encryptionAlgs.hasNext(), "There is no more EncryptedData");
|
||||||
|
assertFalse(encryptionAlgs.hasNext(), "There *still* is no more EncryptedData");
|
||||||
|
|
||||||
|
assertEquals(CompressionAlgorithm.ZIP, metadata.getCompressionAlgorithm(), "getCompressionAlgorithm() returns alg of outermost CompressedData");
|
||||||
|
Iterator<CompressionAlgorithm> compAlgs = metadata.getCompressionAlgorithms();
|
||||||
|
assertTrue(compAlgs.hasNext());
|
||||||
|
assertTrue(compAlgs.hasNext());
|
||||||
|
assertEquals(CompressionAlgorithm.ZIP, compAlgs.next());
|
||||||
|
assertFalse(compAlgs.hasNext());
|
||||||
|
assertFalse(compAlgs.hasNext());
|
||||||
|
|
||||||
|
assertEquals("", metadata.getFilename());
|
||||||
|
JUtils.assertDateEquals(new Date(0L), metadata.getModificationDate());
|
||||||
|
assertEquals(StreamEncoding.BINARY, metadata.getFormat());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProcessLiteralDataMessage() {
|
||||||
|
MessageMetadata.LiteralData literalData = new MessageMetadata.LiteralData(
|
||||||
|
"collateral_murder.zip",
|
||||||
|
DateUtil.parseUTCDate("2010-04-05 10:12:03 UTC"),
|
||||||
|
StreamEncoding.BINARY);
|
||||||
|
MessageMetadata.Message message = new MessageMetadata.Message();
|
||||||
|
message.setChild(literalData);
|
||||||
|
|
||||||
|
MessageMetadata metadata = new MessageMetadata(message);
|
||||||
|
assertNull(metadata.getCompressionAlgorithm());
|
||||||
|
assertNull(metadata.getEncryptionAlgorithm());
|
||||||
|
assertEquals("collateral_murder.zip", metadata.getFilename());
|
||||||
|
assertEquals(DateUtil.parseUTCDate("2010-04-05 10:12:03 UTC"), metadata.getModificationDate());
|
||||||
|
assertEquals(StreamEncoding.BINARY, metadata.getFormat());
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,21 @@
|
||||||
package org.pgpainless.decryption_verification;
|
package org.pgpainless.decryption_verification;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.bouncycastle.bcpg.ArmoredInputStream;
|
import org.bouncycastle.bcpg.ArmoredInputStream;
|
||||||
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
||||||
import org.bouncycastle.bcpg.CompressionAlgorithmTags;
|
import org.bouncycastle.bcpg.CompressionAlgorithmTags;
|
||||||
|
@ -11,9 +27,14 @@ import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
import org.bouncycastle.openpgp.PGPSignature;
|
import org.bouncycastle.openpgp.PGPSignature;
|
||||||
import org.bouncycastle.util.io.Streams;
|
import org.bouncycastle.util.io.Streams;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.JUtils;
|
||||||
|
import org.junit.jupiter.api.Named;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
import org.pgpainless.PGPainless;
|
import org.pgpainless.PGPainless;
|
||||||
import org.pgpainless.algorithm.CompressionAlgorithm;
|
import org.pgpainless.algorithm.CompressionAlgorithm;
|
||||||
|
import org.pgpainless.algorithm.StreamEncoding;
|
||||||
import org.pgpainless.encryption_signing.EncryptionOptions;
|
import org.pgpainless.encryption_signing.EncryptionOptions;
|
||||||
import org.pgpainless.encryption_signing.EncryptionResult;
|
import org.pgpainless.encryption_signing.EncryptionResult;
|
||||||
import org.pgpainless.encryption_signing.EncryptionStream;
|
import org.pgpainless.encryption_signing.EncryptionStream;
|
||||||
|
@ -23,17 +44,7 @@ import org.pgpainless.exception.MalformedOpenPgpMessageException;
|
||||||
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||||
import org.pgpainless.util.ArmoredInputStreamFactory;
|
import org.pgpainless.util.ArmoredInputStreamFactory;
|
||||||
import org.pgpainless.util.Passphrase;
|
import org.pgpainless.util.Passphrase;
|
||||||
|
import org.pgpainless.util.Tuple;
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
|
|
||||||
public class OpenPgpMessageInputStreamTest {
|
public class OpenPgpMessageInputStreamTest {
|
||||||
|
|
||||||
|
@ -304,107 +315,119 @@ public class OpenPgpMessageInputStreamTest {
|
||||||
System.out.println(out);
|
System.out.println(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
interface Processor {
|
||||||
public void testProcessLIT() throws IOException, PGPException {
|
Tuple<String, MessageMetadata> process(String armoredMessage, ConsumerOptions options) throws PGPException, IOException;
|
||||||
String plain = processReadBuffered(LIT, ConsumerOptions.get());
|
|
||||||
assertEquals(PLAINTEXT, plain);
|
|
||||||
|
|
||||||
plain = processReadSequential(LIT, ConsumerOptions.get());
|
|
||||||
assertEquals(PLAINTEXT, plain);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
private static Stream<Arguments> provideMessageProcessors() {
|
||||||
public void testProcessLIT_LIT_fails() {
|
return Stream.of(
|
||||||
|
Arguments.of(Named.of("read(buf,off,len)", (Processor) OpenPgpMessageInputStreamTest::processReadBuffered)),
|
||||||
|
Arguments.of(Named.of("read()", (Processor) OpenPgpMessageInputStreamTest::processReadSequential)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest(name = "Process LIT using {0}")
|
||||||
|
@MethodSource("provideMessageProcessors")
|
||||||
|
public void testProcessLIT(Processor processor) throws IOException, PGPException {
|
||||||
|
Tuple<String, MessageMetadata> result = processor.process(LIT, ConsumerOptions.get());
|
||||||
|
String plain = result.getA();
|
||||||
|
assertEquals(PLAINTEXT, plain);
|
||||||
|
|
||||||
|
MessageMetadata metadata = result.getB();
|
||||||
|
assertNull(metadata.getCompressionAlgorithm());
|
||||||
|
assertNull(metadata.getEncryptionAlgorithm());
|
||||||
|
assertEquals("", metadata.getFilename());
|
||||||
|
JUtils.assertDateEquals(new Date(0L), metadata.getModificationDate());
|
||||||
|
assertEquals(StreamEncoding.BINARY, metadata.getFormat());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest(name = "Process LIT LIT using {0}")
|
||||||
|
@MethodSource("provideMessageProcessors")
|
||||||
|
public void testProcessLIT_LIT_fails(Processor processor) {
|
||||||
assertThrows(MalformedOpenPgpMessageException.class,
|
assertThrows(MalformedOpenPgpMessageException.class,
|
||||||
() -> processReadBuffered(LIT_LIT, ConsumerOptions.get()));
|
() -> processor.process(LIT_LIT, ConsumerOptions.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest(name = "Process COMP(LIT) using {0}")
|
||||||
|
@MethodSource("provideMessageProcessors")
|
||||||
|
public void testProcessCOMP_LIT(Processor processor) throws PGPException, IOException {
|
||||||
|
Tuple<String, MessageMetadata> result = processor.process(COMP_LIT, ConsumerOptions.get());
|
||||||
|
String plain = result.getA();
|
||||||
|
assertEquals(PLAINTEXT, plain);
|
||||||
|
MessageMetadata metadata = result.getB();
|
||||||
|
assertEquals(CompressionAlgorithm.ZIP, metadata.getCompressionAlgorithm());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest(name = "Process COMP using {0}")
|
||||||
|
@MethodSource("provideMessageProcessors")
|
||||||
|
public void testProcessCOMP_fails(Processor processor) {
|
||||||
assertThrows(MalformedOpenPgpMessageException.class,
|
assertThrows(MalformedOpenPgpMessageException.class,
|
||||||
() -> processReadSequential(LIT_LIT, ConsumerOptions.get()));
|
() -> processor.process(COMP, ConsumerOptions.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest(name = "Process COMP(COMP(LIT)) using {0}")
|
||||||
public void testProcessCOMP_LIT() throws PGPException, IOException {
|
@MethodSource("provideMessageProcessors")
|
||||||
String plain = processReadBuffered(COMP_LIT, ConsumerOptions.get());
|
public void testProcessCOMP_COMP_LIT(Processor processor) throws PGPException, IOException {
|
||||||
assertEquals(PLAINTEXT, plain);
|
Tuple<String, MessageMetadata> result = processor.process(COMP_COMP_LIT, ConsumerOptions.get());
|
||||||
|
String plain = result.getA();
|
||||||
plain = processReadSequential(COMP_LIT, ConsumerOptions.get());
|
|
||||||
assertEquals(PLAINTEXT, plain);
|
assertEquals(PLAINTEXT, plain);
|
||||||
|
MessageMetadata metadata = result.getB();
|
||||||
|
assertEquals(CompressionAlgorithm.ZIP, metadata.getCompressionAlgorithm());
|
||||||
|
Iterator<CompressionAlgorithm> compressionAlgorithms = metadata.getCompressionAlgorithms();
|
||||||
|
assertEquals(CompressionAlgorithm.ZIP, compressionAlgorithms.next());
|
||||||
|
assertEquals(CompressionAlgorithm.BZIP2, compressionAlgorithms.next());
|
||||||
|
assertFalse(compressionAlgorithms.hasNext());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest(name = "Process SIG LIT using {0}")
|
||||||
public void testProcessCOMP_fails() {
|
@MethodSource("provideMessageProcessors")
|
||||||
assertThrows(MalformedOpenPgpMessageException.class,
|
public void testProcessSIG_LIT(Processor processor) throws PGPException, IOException {
|
||||||
() -> processReadBuffered(COMP, ConsumerOptions.get()));
|
|
||||||
|
|
||||||
assertThrows(MalformedOpenPgpMessageException.class,
|
|
||||||
() -> processReadSequential(COMP, ConsumerOptions.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testProcessCOMP_COMP_LIT() throws PGPException, IOException {
|
|
||||||
String plain = processReadBuffered(COMP_COMP_LIT, ConsumerOptions.get());
|
|
||||||
assertEquals(PLAINTEXT, plain);
|
|
||||||
|
|
||||||
plain = processReadSequential(COMP_COMP_LIT, ConsumerOptions.get());
|
|
||||||
assertEquals(PLAINTEXT, plain);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testProcessSIG_LIT() throws PGPException, IOException {
|
|
||||||
PGPPublicKeyRing cert = PGPainless.extractCertificate(
|
PGPPublicKeyRing cert = PGPainless.extractCertificate(
|
||||||
PGPainless.readKeyRing().secretKeyRing(KEY));
|
PGPainless.readKeyRing().secretKeyRing(KEY));
|
||||||
|
|
||||||
String plain = processReadBuffered(SIG_LIT, ConsumerOptions.get()
|
Tuple<String, MessageMetadata> result = processor.process(SIG_LIT, ConsumerOptions.get()
|
||||||
.addVerificationCert(cert));
|
|
||||||
assertEquals(PLAINTEXT, plain);
|
|
||||||
|
|
||||||
plain = processReadSequential(SIG_LIT, ConsumerOptions.get()
|
|
||||||
.addVerificationCert(cert));
|
.addVerificationCert(cert));
|
||||||
|
String plain = result.getA();
|
||||||
assertEquals(PLAINTEXT, plain);
|
assertEquals(PLAINTEXT, plain);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest(name = "Process SENC(LIT) using {0}")
|
||||||
public void testProcessSENC_LIT() throws PGPException, IOException {
|
@MethodSource("provideMessageProcessors")
|
||||||
String plain = processReadBuffered(SENC_LIT, ConsumerOptions.get().addDecryptionPassphrase(Passphrase.fromPassword(PASSPHRASE)));
|
public void testProcessSENC_LIT(Processor processor) throws PGPException, IOException {
|
||||||
assertEquals(PLAINTEXT, plain);
|
Tuple<String, MessageMetadata> result = processor.process(SENC_LIT, ConsumerOptions.get().addDecryptionPassphrase(Passphrase.fromPassword(PASSPHRASE)));
|
||||||
|
String plain = result.getA();
|
||||||
plain = processReadSequential(SENC_LIT, ConsumerOptions.get().addDecryptionPassphrase(Passphrase.fromPassword(PASSPHRASE)));
|
|
||||||
assertEquals(PLAINTEXT, plain);
|
assertEquals(PLAINTEXT, plain);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest(name = "Process PENC(LIT) using {0}")
|
||||||
public void testProcessPENC_COMP_LIT() throws IOException, PGPException {
|
@MethodSource("provideMessageProcessors")
|
||||||
|
public void testProcessPENC_COMP_LIT(Processor processor) throws IOException, PGPException {
|
||||||
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(KEY);
|
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(KEY);
|
||||||
String plain = processReadBuffered(PENC_COMP_LIT, ConsumerOptions.get()
|
Tuple<String, MessageMetadata> result = processor.process(PENC_COMP_LIT, ConsumerOptions.get()
|
||||||
.addDecryptionKey(secretKeys));
|
|
||||||
assertEquals(PLAINTEXT, plain);
|
|
||||||
|
|
||||||
plain = processReadSequential(PENC_COMP_LIT, ConsumerOptions.get()
|
|
||||||
.addDecryptionKey(secretKeys));
|
.addDecryptionKey(secretKeys));
|
||||||
|
String plain = result.getA();
|
||||||
assertEquals(PLAINTEXT, plain);
|
assertEquals(PLAINTEXT, plain);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest(name = "Process OPS LIT SIG using {0}")
|
||||||
public void testProcessOPS_LIT_SIG() throws IOException, PGPException {
|
@MethodSource("provideMessageProcessors")
|
||||||
|
public void testProcessOPS_LIT_SIG(Processor processor) throws IOException, PGPException {
|
||||||
PGPPublicKeyRing cert = PGPainless.extractCertificate(PGPainless.readKeyRing().secretKeyRing(KEY));
|
PGPPublicKeyRing cert = PGPainless.extractCertificate(PGPainless.readKeyRing().secretKeyRing(KEY));
|
||||||
String plain = processReadBuffered(OPS_LIT_SIG, ConsumerOptions.get()
|
Tuple<String, MessageMetadata> result = processor.process(OPS_LIT_SIG, ConsumerOptions.get()
|
||||||
.addVerificationCert(cert));
|
|
||||||
assertEquals(PLAINTEXT, plain);
|
|
||||||
|
|
||||||
plain = processReadSequential(OPS_LIT_SIG, ConsumerOptions.get()
|
|
||||||
.addVerificationCert(cert));
|
.addVerificationCert(cert));
|
||||||
|
String plain = result.getA();
|
||||||
assertEquals(PLAINTEXT, plain);
|
assertEquals(PLAINTEXT, plain);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String processReadBuffered(String armoredMessage, ConsumerOptions options) throws PGPException, IOException {
|
private static Tuple<String, MessageMetadata> processReadBuffered(String armoredMessage, ConsumerOptions options) throws PGPException, IOException {
|
||||||
OpenPgpMessageInputStream in = get(armoredMessage, options);
|
OpenPgpMessageInputStream in = get(armoredMessage, options);
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
Streams.pipeAll(in, out);
|
Streams.pipeAll(in, out);
|
||||||
in.close();
|
in.close();
|
||||||
return out.toString();
|
MessageMetadata metadata = in.getMetadata();
|
||||||
|
return new Tuple<>(out.toString(), metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String processReadSequential(String armoredMessage, ConsumerOptions options) throws PGPException, IOException {
|
private static Tuple<String, MessageMetadata> processReadSequential(String armoredMessage, ConsumerOptions options) throws PGPException, IOException {
|
||||||
OpenPgpMessageInputStream in = get(armoredMessage, options);
|
OpenPgpMessageInputStream in = get(armoredMessage, options);
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
@ -414,10 +437,11 @@ public class OpenPgpMessageInputStreamTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
in.close();
|
in.close();
|
||||||
return out.toString();
|
MessageMetadata metadata = in.getMetadata();
|
||||||
|
return new Tuple<>(out.toString(), metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
private OpenPgpMessageInputStream get(String armored, ConsumerOptions options) throws IOException, PGPException {
|
private static OpenPgpMessageInputStream get(String armored, ConsumerOptions options) throws IOException, PGPException {
|
||||||
ByteArrayInputStream bytesIn = new ByteArrayInputStream(armored.getBytes(StandardCharsets.UTF_8));
|
ByteArrayInputStream bytesIn = new ByteArrayInputStream(armored.getBytes(StandardCharsets.UTF_8));
|
||||||
ArmoredInputStream armorIn = ArmoredInputStreamFactory.get(bytesIn);
|
ArmoredInputStream armorIn = ArmoredInputStreamFactory.get(bytesIn);
|
||||||
OpenPgpMessageInputStream pgpIn = new OpenPgpMessageInputStream(armorIn, options);
|
OpenPgpMessageInputStream pgpIn = new OpenPgpMessageInputStream(armorIn, options);
|
||||||
|
|
Loading…
Reference in a new issue