1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-12-26 04:47:59 +01:00

2/3 the way to working sig verification

This commit is contained in:
Paul Schaub 2022-10-06 21:52:23 +02:00
parent 37dc362cc3
commit c65e484bb4
5 changed files with 353 additions and 279 deletions

View file

@ -0,0 +1,38 @@
package org.pgpainless.decryption_verification;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class DelayedTeeInputStreamInputStream extends InputStream {
private int last = -1;
private final InputStream inputStream;
private final OutputStream outputStream;
public DelayedTeeInputStreamInputStream(InputStream inputStream, OutputStream outputStream) {
this.inputStream = inputStream;
this.outputStream = outputStream;
}
@Override
public int read() throws IOException {
if (last != -1) {
outputStream.write(last);
}
last = inputStream.read();
return last;
}
/**
* Squeeze the last byte out and update the output stream.
*
* @throws IOException in case of an IO error
*/
public void squeeze() throws IOException {
if (last != -1) {
outputStream.write(last);
}
last = -1;
}
}

View file

@ -20,7 +20,6 @@ import org.bouncycastle.openpgp.PGPEncryptedData;
import org.bouncycastle.openpgp.PGPEncryptedDataList; import org.bouncycastle.openpgp.PGPEncryptedDataList;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPLiteralData; import org.bouncycastle.openpgp.PGPLiteralData;
import org.bouncycastle.openpgp.PGPObjectFactory;
import org.bouncycastle.openpgp.PGPOnePassSignature; import org.bouncycastle.openpgp.PGPOnePassSignature;
import org.bouncycastle.openpgp.PGPPBEEncryptedData; import org.bouncycastle.openpgp.PGPPBEEncryptedData;
import org.bouncycastle.openpgp.PGPPrivateKey; import org.bouncycastle.openpgp.PGPPrivateKey;
@ -53,7 +52,6 @@ import org.pgpainless.key.info.KeyRingInfo;
import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.key.protection.UnlockSecretKey; import org.pgpainless.key.protection.UnlockSecretKey;
import org.pgpainless.signature.SignatureUtils; import org.pgpainless.signature.SignatureUtils;
import org.pgpainless.util.ArmorUtils;
import org.pgpainless.util.Passphrase; import org.pgpainless.util.Passphrase;
import org.pgpainless.util.Tuple; import org.pgpainless.util.Tuple;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -68,6 +66,7 @@ public class OpenPgpMessageInputStream extends InputStream {
protected final OpenPgpMetadata.Builder resultBuilder; protected final OpenPgpMetadata.Builder resultBuilder;
// Pushdown Automaton to verify validity of OpenPGP packet sequence in an OpenPGP message // Pushdown Automaton to verify validity of OpenPGP packet sequence in an OpenPGP message
protected final PDA automaton = new PDA(); protected final PDA automaton = new PDA();
protected final DelayedTeeInputStreamInputStream delayedTee;
// InputStream of OpenPGP packets of the current layer // InputStream of OpenPGP packets of the current layer
protected final BCPGInputStream packetInputStream; protected final BCPGInputStream packetInputStream;
// InputStream of a nested data packet // InputStream of a nested data packet
@ -96,8 +95,9 @@ public class OpenPgpMessageInputStream extends InputStream {
this.signatures.addDetachedSignatures(options.getDetachedSignatures()); this.signatures.addDetachedSignatures(options.getDetachedSignatures());
} }
BCPGInputStream bcpg = BCPGInputStream.wrap(inputStream); delayedTee = new DelayedTeeInputStreamInputStream(inputStream, signatures);
this.packetInputStream = new TeeBCPGInputStream(bcpg, signatures); BCPGInputStream bcpg = BCPGInputStream.wrap(delayedTee);
this.packetInputStream = bcpg;
// *omnomnom* // *omnomnom*
consumePackets(); consumePackets();
@ -121,22 +121,15 @@ public class OpenPgpMessageInputStream extends InputStream {
*/ */
private void consumePackets() private void consumePackets()
throws IOException, PGPException { throws IOException, PGPException {
int tag;
loop: while ((tag = nextTag()) != -1) {
OpenPgpPacket nextPacket; OpenPgpPacket nextPacket;
try { loop: while ((nextPacket = nextPacketTag()) != null) {
nextPacket = OpenPgpPacket.requireFromTag(tag);
} catch (NoSuchElementException e) {
log("Invalid tag: " + tag);
throw e;
}
log(nextPacket.toString());
signatures.nextPacket(nextPacket); signatures.nextPacket(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);
delayedTee.squeeze();
processLiteralData(); processLiteralData();
break loop; break loop;
@ -145,12 +138,14 @@ public class OpenPgpMessageInputStream extends InputStream {
automaton.next(InputAlphabet.CompressedData); automaton.next(InputAlphabet.CompressedData);
signatures.commitNested(); signatures.commitNested();
processCompressedData(); processCompressedData();
delayedTee.squeeze();
break loop; break loop;
// One Pass Signature // One Pass Signature
case OPS: case OPS:
automaton.next(InputAlphabet.OnePassSignatures); automaton.next(InputAlphabet.OnePassSignatures);
PGPOnePassSignature onePassSignature = readOnePassSignature(); PGPOnePassSignature onePassSignature = readOnePassSignature();
delayedTee.squeeze();
signatures.addOnePassSignature(onePassSignature); signatures.addOnePassSignature(onePassSignature);
break; break;
@ -160,6 +155,7 @@ public class OpenPgpMessageInputStream extends InputStream {
automaton.next(InputAlphabet.Signatures); automaton.next(InputAlphabet.Signatures);
PGPSignature signature = readSignature(); PGPSignature signature = readSignature();
delayedTee.squeeze();
processSignature(signature, isSigForOPS); processSignature(signature, isSigForOPS);
break; break;
@ -170,6 +166,7 @@ public class OpenPgpMessageInputStream extends InputStream {
case SED: case SED:
case SEIPD: case SEIPD:
automaton.next(InputAlphabet.EncryptedData); automaton.next(InputAlphabet.EncryptedData);
delayedTee.squeeze();
if (processEncryptedData()) { if (processEncryptedData()) {
break loop; break loop;
} }
@ -179,6 +176,7 @@ public class OpenPgpMessageInputStream extends InputStream {
// Marker Packets need to be skipped and ignored // Marker Packets need to be skipped and ignored
case MARKER: case MARKER:
packetInputStream.readPacket(); // skip packetInputStream.readPacket(); // skip
delayedTee.squeeze();
break; break;
// Key Packets are illegal in this context // Key Packets are illegal in this context
@ -206,6 +204,23 @@ public class OpenPgpMessageInputStream extends InputStream {
} }
} }
private OpenPgpPacket nextPacketTag() throws IOException {
int tag = nextTag();
if (tag == -1) {
log("EOF");
return null;
}
OpenPgpPacket packet;
try {
packet = OpenPgpPacket.requireFromTag(tag);
} catch (NoSuchElementException e) {
log("Invalid tag: " + tag);
throw e;
}
log(packet.toString());
return packet;
}
private void processSignature(PGPSignature signature, boolean isSigForOPS) { private void processSignature(PGPSignature signature, boolean isSigForOPS) {
if (isSigForOPS) { if (isSigForOPS) {
signatures.popNested(); signatures.popNested();
@ -229,41 +244,6 @@ public class OpenPgpMessageInputStream extends InputStream {
nestedInputStream = literalData.getDataStream(); nestedInputStream = literalData.getDataStream();
} }
private void debugEncryptedData() throws PGPException, IOException {
PGPEncryptedDataList encDataList = new PGPEncryptedDataList(packetInputStream);
// TODO: Replace with !encDataList.isIntegrityProtected()
if (!encDataList.get(0).isIntegrityProtected()) {
throw new MessageNotIntegrityProtectedException();
}
SortedESKs esks = new SortedESKs(encDataList);
for (PGPPublicKeyEncryptedData pkesk : esks.pkesks) {
long keyId = pkesk.getKeyID();
PGPSecretKeyRing decryptionKeys = getDecryptionKey(keyId);
if (decryptionKeys == null) {
continue;
}
SecretKeyRingProtector protector = options.getSecretKeyProtector(decryptionKeys);
PGPSecretKey decryptionKey = decryptionKeys.getSecretKey(keyId);
PGPPrivateKey privateKey = UnlockSecretKey.unlockSecretKey(decryptionKey, protector);
PublicKeyDataDecryptorFactory decryptorFactory = ImplementationFactory.getInstance()
.getPublicKeyDataDecryptorFactory(privateKey);
try {
InputStream decrypted = pkesk.getDataStream(decryptorFactory);
InputStream decoder = PGPUtil.getDecoderStream(decrypted);
PGPObjectFactory objectFactory = ImplementationFactory.getInstance()
.getPGPObjectFactory(decoder);
objectFactory.nextObject();
objectFactory.nextObject();
objectFactory.nextObject();
} catch (PGPException e) {
// hm :/
}
}
}
private boolean processEncryptedData() throws IOException, PGPException { private boolean processEncryptedData() throws IOException, PGPException {
PGPEncryptedDataList encDataList = new PGPEncryptedDataList(packetInputStream); PGPEncryptedDataList encDataList = new PGPEncryptedDataList(packetInputStream);
@ -553,12 +533,13 @@ public class OpenPgpMessageInputStream extends InputStream {
// for literal data. UUUUUGLY!!!! // for literal data. UUUUUGLY!!!!
private static final class Signatures extends OutputStream { private static final class Signatures extends OutputStream {
final ConsumerOptions options; final ConsumerOptions options;
final List<PGPSignature> detachedSignatures; final List<SIG> detachedSignatures;
final List<PGPSignature> prependedSignatures; final List<SIG> prependedSignatures;
final List<OPS> onePassSignatures; final List<OPS> onePassSignatures;
final Stack<List<OPS>> opsUpdateStack; final Stack<List<OPS>> opsUpdateStack;
List<OPS> literalOPS = new ArrayList<>(); List<OPS> literalOPS = new ArrayList<>();
final List<PGPSignature> correspondingSignatures; final List<PGPSignature> correspondingSignatures;
boolean isLiteral = true;
private Signatures(ConsumerOptions options) { private Signatures(ConsumerOptions options) {
this.options = options; this.options = options;
@ -579,14 +560,14 @@ public class OpenPgpMessageInputStream extends InputStream {
long keyId = SignatureUtils.determineIssuerKeyId(signature); long keyId = SignatureUtils.determineIssuerKeyId(signature);
PGPPublicKeyRing certificate = findCertificate(keyId); PGPPublicKeyRing certificate = findCertificate(keyId);
initialize(signature, certificate, keyId); initialize(signature, certificate, keyId);
this.detachedSignatures.add(signature); this.detachedSignatures.add(new SIG(signature));
} }
void addPrependedSignature(PGPSignature signature) { void addPrependedSignature(PGPSignature signature) {
long keyId = SignatureUtils.determineIssuerKeyId(signature); long keyId = SignatureUtils.determineIssuerKeyId(signature);
PGPPublicKeyRing certificate = findCertificate(keyId); PGPPublicKeyRing certificate = findCertificate(keyId);
initialize(signature, certificate, keyId); initialize(signature, certificate, keyId);
this.prependedSignatures.add(signature); this.prependedSignatures.add(new SIG(signature));
} }
void addOnePassSignature(PGPOnePassSignature signature) { void addOnePassSignature(PGPOnePassSignature signature) {
@ -630,7 +611,7 @@ public class OpenPgpMessageInputStream extends InputStream {
opsUpdateStack.pop(); opsUpdateStack.pop();
} }
private void initialize(PGPSignature signature, PGPPublicKeyRing certificate, long keyId) { private static void initialize(PGPSignature signature, PGPPublicKeyRing certificate, long keyId) {
if (certificate == null) { if (certificate == null) {
// SHIT // SHIT
return; return;
@ -672,7 +653,7 @@ public class OpenPgpMessageInputStream extends InputStream {
ops.update(b); ops.update(b);
} }
for (PGPSignature detached : detachedSignatures) { for (SIG detached : detachedSignatures) {
detached.update(b); detached.update(b);
} }
} }
@ -682,13 +663,22 @@ public class OpenPgpMessageInputStream extends InputStream {
ops.update(b, off, len); ops.update(b, off, len);
} }
for (PGPSignature detached : detachedSignatures) { for (SIG detached : detachedSignatures) {
detached.update(b, off, len); detached.update(b, off, len);
} }
} }
public void updatePacket(byte b) { public void updatePacket(byte b) {
for (List<OPS> nestedOPSs : opsUpdateStack) { for (SIG detached : detachedSignatures) {
detached.update(b);
}
for (SIG prepended : prependedSignatures) {
prepended.update(b);
}
for (int i = opsUpdateStack.size() - 1; i >= 0; i--) {
List<OPS> nestedOPSs = opsUpdateStack.get(i);
for (OPS ops : nestedOPSs) { for (OPS ops : nestedOPSs) {
ops.update(b); ops.update(b);
} }
@ -696,6 +686,14 @@ public class OpenPgpMessageInputStream extends InputStream {
} }
public void updatePacket(byte[] buf, int off, int len) { public void updatePacket(byte[] buf, int off, int len) {
for (SIG detached : detachedSignatures) {
detached.update(buf, off, len);
}
for (SIG prepended : prependedSignatures) {
prepended.update(buf, off, len);
}
for (int i = opsUpdateStack.size() - 1; i >= 0; i--) { for (int i = opsUpdateStack.size() - 1; i >= 0; i--) {
List<OPS> nestedOPSs = opsUpdateStack.get(i); List<OPS> nestedOPSs = opsUpdateStack.get(i);
for (OPS ops : nestedOPSs) { for (OPS ops : nestedOPSs) {
@ -705,24 +703,16 @@ public class OpenPgpMessageInputStream extends InputStream {
} }
public void finish() { public void finish() {
for (PGPSignature detached : detachedSignatures) { for (SIG detached : detachedSignatures) {
boolean verified = false; boolean verified = detached.verify();
try { log("Detached Signature by " + Long.toHexString(detached.signature.getKeyID()) + " is " + (verified ? "verified" : "unverified"));
verified = detached.verify(); System.out.println(detached);
} catch (PGPException e) {
log("Cannot verify detached signature.", e);
}
log("Detached Signature by " + Long.toHexString(detached.getKeyID()) + " is " + (verified ? "verified" : "unverified"));
} }
for (PGPSignature prepended : prependedSignatures) { for (SIG prepended : prependedSignatures) {
boolean verified = false; boolean verified = prepended.verify();
try { log("Prepended Signature by " + Long.toHexString(prepended.signature.getKeyID()) + " is " + (verified ? "verified" : "unverified"));
verified = prepended.verify(); System.out.println(prepended);
} catch (PGPException e) {
log("Cannot verify prepended signature.", e);
}
log("Prepended Signature by " + Long.toHexString(prepended.getKeyID()) + " is " + (verified ? "verified" : "unverified"));
} }
} }
@ -738,9 +728,92 @@ public class OpenPgpMessageInputStream extends InputStream {
public void nextPacket(OpenPgpPacket nextPacket) { public void nextPacket(OpenPgpPacket nextPacket) {
if (nextPacket == OpenPgpPacket.LIT) { if (nextPacket == OpenPgpPacket.LIT) {
isLiteral = true;
if (literalOPS.isEmpty() && !opsUpdateStack.isEmpty()) { if (literalOPS.isEmpty() && !opsUpdateStack.isEmpty()) {
literalOPS = opsUpdateStack.pop(); literalOPS = opsUpdateStack.pop();
} }
} else {
isLiteral = false;
}
}
static class SIG {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
PGPSignature signature;
boolean finished;
boolean valid;
public SIG(PGPSignature signature) {
this.signature = signature;
}
public void init(PGPPublicKeyRing certificate) {
initialize(signature, certificate, signature.getKeyID());
}
public boolean verify() {
finished = true;
try {
valid = this.signature.verify();
} catch (PGPException e) {
log("Cannot verify SIG " + signature.getKeyID());
}
return valid;
}
public void update(byte b) {
if (finished) {
log("Updating finished sig!");
return;
}
signature.update(b);
bytes.write(b);
}
public void update(byte[] bytes, int off, int len) {
if (finished) {
log("Updating finished sig!");
return;
}
signature.update(bytes, off, len);
this.bytes.write(bytes, off, len);
}
@Override
public String toString() {
String OPS = "c40d03000a01fbfcc82a015e733001";
String LIT_H = "cb28620000000000";
String LIT = "656e637279707420e28898207369676e20e28898207369676e20e28898207369676e";
String SIG1 = "c2c10400010a006f058262c806350910fbfcc82a015e7330471400000000001e002073616c74406e6f746174696f6e732e736571756f69612d7067702e6f7267b0409ed8ea96dac66447bdff5b7b60c9f80a0ab91d257029153dc3b6d8c27b98162104d1a66e1a23b182c9980f788cfbfcc82a015e7330000029640c00846b5096d92474fd446cc7edaf9f14572cab93a80e12384c1e829f95debc6e8373c2ce5402be53dc1a18cf92a0ed909e0fb38855713ef8ffb13502ffac7c830fa254cc1aa6c666a97b0cc3bc176538f6913d3b8e8981a65cc42df10e0f39e4d0a06dfe961437b59a71892f4fca1116aed15123ea0d86a7b2ce47dd9d3ef22d920631bc011e82babe03ad5d72b3ba7f95bf646f20ccf6f7a4d95de37397c76c7d53741458e51ab6074007f61181c7b88b7c98f5b7510c8dfa3be01f4841501679478b15c5249d928e2a10d15ec63efa1500b994d5bfb32ffb174a976116930eb97a111e6dfd4c5e43e04a5d76ba74806a62fda63a8c3f53f6eebaf852892340e81dd08bbf348454a2cf525aeb512cf33aeeee78465ee4c442e41cc45ac4e3bb0c3333677aa60332ee7f464d9020f8554b82d619872477cca18d8431888f4ae8abe5894e9720f759c410cd7991db12703dc147040dd0d3758223e0b75de6ceae49c1a0c2c45efedeb7114ae785cc886afdc45c82172e4476e1ab5b86dc4314dd76";
String SIG1f = "c2c13b0400010a006f058262c806350910fbfcc82a015e7330471400000000001e002073616c74406e6f746174696f6e732e736571756f69612d7067702e6f7267b0409ed8ea96dac66447bdff5b7b60c9f80a0ab91d257029153dc3b6d8c27b98162104d1a66e1a23b182c9980f788cfbfcc82a015e7330000029640c00846b5096d92474fd446cc7edaf9f14572cab93a80e12384c1e829f95debc6e8373c2ce5402be53dc1a18cf92a0ed909e0fb38855713ef8ffb13502ffac7c830fa254cc1aa6c666a97b0cc3bc176538f6913d3b8e8981a65cc42df10e0f39e4d0a06dfe961437b59a71892f4fca1116aed15123ea0d86a7b2ce47dd9d3ef22d920631bc011e82babe03ad5d72b3ba7f95bf646f20ccf6f7a4d95de37397c76c7d53741458e51ab6074007f61181c7b88b7c98f5b7510c8dfa3be01f4841501679478b15c5249d928e2a10d15ec63efa1500b994d5bfb32ffb174a976116930eb97a111e6dfd4c5e43e04a5d76ba74806a62fda63a8c3f53f6eebaf852892340e81dd08bbf348454a2cf525aeb512cf33aeeee78465ee4c442e41cc45ac4e3bb0c3333677aa60332ee7f464d9020f8554b82d619872477cca18d8431888f4ae8abe5894e9720f759c410cd7991db12703dc147040dd0d3758223e0b75de6ceae49c1a0c2c45efedeb7114ae785cc886afdc45c82172e4476e1ab5b86dc4314dd76";
String SIG2 = "c2c10400010a006f058262c806350910fbfcc82a015e7330471400000000001e002073616c74406e6f746174696f6e732e736571756f69612d7067702e6f7267a4d9c117dc7ba3a7e9270856f128d2ab271743eac3cb5750b22a89bd5fd60753162104d1a66e1a23b182c9980f788cfbfcc82a015e73300000b8400bff796c20fa8b25ff7a42686338e06417a2966e85a0fc2723c928bef6cd19d34cf5e7d55ada33080613012dadb79e0278e59d9e7ed7d2d6102912a5f768c2e75b60099225c3d8bfe0c123240188b80dbee89b9b3bd5b13ccc662abc37e2129b6968adac9aba43aa778c0fe4fe337591ee87a96a29a013debc83555293c877144fc676aa1b03782c501949521a320adf6ad96c4f2e036b52a18369c637fdc49033696a84d03a69580b953187fce5aca6fb26fc8815da9f3b513bfe8e304f33ecb4b521aeb7d09c4a284ea66123bd0d6a358b2526d762ca110e1f7f20b3038d774b64d5cfd34e2213765828359d7afc5bf24d5270e99d80c3c1568fa01624b6ea1e9ce4e6890ce9bacf6611a45d41e2671f68f5b096446bf08d27ce75608425b2e3ab92146229ad1fcd8224aca5b5f73960506e7df07bfbf3664348e8ecbfb2eb467b9cfe412cb377a6ee2eb5fd11be9cf9208fe9a74c296f52cfa02a1eb0519ad9a8349bf6ccd6495feb7e391451bf96e08a0798883dee5974e47cbf3b51f111b6d3";
String SIG2f = "c2c13b0400010a006f058262c806350910fbfcc82a015e7330471400000000001e002073616c74406e6f746174696f6e732e736571756f69612d7067702e6f7267a4d9c117dc7ba3a7e9270856f128d2ab271743eac3cb5750b22a89bd5fd60753162104d1a66e1a23b182c9980f788cfbfcc82a015e73300000b8400bff796c20fa8b25ff7a42686338e06417a2966e85a0fc2723c928bef6cd19d34cf5e7d55ada33080613012dadb79e0278e59d9e7ed7d2d6102912a5f768c2e75b60099225c3d8bfe0c123240188b80dbee89b9b3bd5b13ccc662abc37e2129b6968adac9aba43aa778c0fe4fe337591ee87a96a29a013debc83555293c877144fc676aa1b03782c501949521a320adf6ad96c4f2e036b52a18369c637fdc49033696a84d03a69580b953187fce5aca6fb26fc8815da9f3b513bfe8e304f33ecb4b521aeb7d09c4a284ea66123bd0d6a358b2526d762ca110e1f7f20b3038d774b64d5cfd34e2213765828359d7afc5bf24d5270e99d80c3c1568fa01624b6ea1e9ce4e6890ce9bacf6611a45d41e2671f68f5b096446bf08d27ce75608425b2e3ab92146229ad1fcd8224aca5b5f73960506e7df07bfbf3664348e8ecbfb2eb467b9cfe412cb377a6ee2eb5fd11be9cf9208fe9a74c296f52cfa02a1eb0519ad9a8349bf6ccd6495feb7e391451bf96e08a0798883dee5974e47cbf3b51f111b6d3";
String out = "";
String hex = Hex.toHexString(bytes.toByteArray());
while (hex.contains(OPS)) {
hex = hex.replace(OPS, "[OPS]");
}
while (hex.contains(LIT_H)) {
hex = hex.replace(LIT_H, "[LIT]");
}
while (hex.contains(LIT)) {
hex = hex.replace(LIT, "<content>");
}
while (hex.contains(SIG1)) {
hex = hex.replace(SIG1, "[SIG1]");
}
while (hex.contains(SIG1f)) {
hex = hex.replace(SIG1f, "[SIG1f]");
}
while (hex.contains(SIG2)) {
hex = hex.replace(SIG2, "[SIG2]");
}
while (hex.contains(SIG2f)) {
hex = hex.replace(SIG2f, "[SIG2f]");
}
return out + hex;
} }
} }
@ -796,8 +869,10 @@ public class OpenPgpMessageInputStream extends InputStream {
String LIT_H = "cb28620000000000"; String LIT_H = "cb28620000000000";
String LIT = "656e637279707420e28898207369676e20e28898207369676e20e28898207369676e"; String LIT = "656e637279707420e28898207369676e20e28898207369676e20e28898207369676e";
String SIG1 = "c2c10400010a006f058262c806350910fbfcc82a015e7330471400000000001e002073616c74406e6f746174696f6e732e736571756f69612d7067702e6f7267b0409ed8ea96dac66447bdff5b7b60c9f80a0ab91d257029153dc3b6d8c27b98162104d1a66e1a23b182c9980f788cfbfcc82a015e7330000029640c00846b5096d92474fd446cc7edaf9f14572cab93a80e12384c1e829f95debc6e8373c2ce5402be53dc1a18cf92a0ed909e0fb38855713ef8ffb13502ffac7c830fa254cc1aa6c666a97b0cc3bc176538f6913d3b8e8981a65cc42df10e0f39e4d0a06dfe961437b59a71892f4fca1116aed15123ea0d86a7b2ce47dd9d3ef22d920631bc011e82babe03ad5d72b3ba7f95bf646f20ccf6f7a4d95de37397c76c7d53741458e51ab6074007f61181c7b88b7c98f5b7510c8dfa3be01f4841501679478b15c5249d928e2a10d15ec63efa1500b994d5bfb32ffb174a976116930eb97a111e6dfd4c5e43e04a5d76ba74806a62fda63a8c3f53f6eebaf852892340e81dd08bbf348454a2cf525aeb512cf33aeeee78465ee4c442e41cc45ac4e3bb0c3333677aa60332ee7f464d9020f8554b82d619872477cca18d8431888f4ae8abe5894e9720f759c410cd7991db12703dc147040dd0d3758223e0b75de6ceae49c1a0c2c45efedeb7114ae785cc886afdc45c82172e4476e1ab5b86dc4314dd76"; String SIG1 = "c2c10400010a006f058262c806350910fbfcc82a015e7330471400000000001e002073616c74406e6f746174696f6e732e736571756f69612d7067702e6f7267b0409ed8ea96dac66447bdff5b7b60c9f80a0ab91d257029153dc3b6d8c27b98162104d1a66e1a23b182c9980f788cfbfcc82a015e7330000029640c00846b5096d92474fd446cc7edaf9f14572cab93a80e12384c1e829f95debc6e8373c2ce5402be53dc1a18cf92a0ed909e0fb38855713ef8ffb13502ffac7c830fa254cc1aa6c666a97b0cc3bc176538f6913d3b8e8981a65cc42df10e0f39e4d0a06dfe961437b59a71892f4fca1116aed15123ea0d86a7b2ce47dd9d3ef22d920631bc011e82babe03ad5d72b3ba7f95bf646f20ccf6f7a4d95de37397c76c7d53741458e51ab6074007f61181c7b88b7c98f5b7510c8dfa3be01f4841501679478b15c5249d928e2a10d15ec63efa1500b994d5bfb32ffb174a976116930eb97a111e6dfd4c5e43e04a5d76ba74806a62fda63a8c3f53f6eebaf852892340e81dd08bbf348454a2cf525aeb512cf33aeeee78465ee4c442e41cc45ac4e3bb0c3333677aa60332ee7f464d9020f8554b82d619872477cca18d8431888f4ae8abe5894e9720f759c410cd7991db12703dc147040dd0d3758223e0b75de6ceae49c1a0c2c45efedeb7114ae785cc886afdc45c82172e4476e1ab5b86dc4314dd76";
String SIG1f = "c2c13b0400010a006f058262c806350910fbfcc82a015e7330471400000000001e002073616c74406e6f746174696f6e732e736571756f69612d7067702e6f7267b0409ed8ea96dac66447bdff5b7b60c9f80a0ab91d257029153dc3b6d8c27b98162104d1a66e1a23b182c9980f788cfbfcc82a015e7330000029640c00846b5096d92474fd446cc7edaf9f14572cab93a80e12384c1e829f95debc6e8373c2ce5402be53dc1a18cf92a0ed909e0fb38855713ef8ffb13502ffac7c830fa254cc1aa6c666a97b0cc3bc176538f6913d3b8e8981a65cc42df10e0f39e4d0a06dfe961437b59a71892f4fca1116aed15123ea0d86a7b2ce47dd9d3ef22d920631bc011e82babe03ad5d72b3ba7f95bf646f20ccf6f7a4d95de37397c76c7d53741458e51ab6074007f61181c7b88b7c98f5b7510c8dfa3be01f4841501679478b15c5249d928e2a10d15ec63efa1500b994d5bfb32ffb174a976116930eb97a111e6dfd4c5e43e04a5d76ba74806a62fda63a8c3f53f6eebaf852892340e81dd08bbf348454a2cf525aeb512cf33aeeee78465ee4c442e41cc45ac4e3bb0c3333677aa60332ee7f464d9020f8554b82d619872477cca18d8431888f4ae8abe5894e9720f759c410cd7991db12703dc147040dd0d3758223e0b75de6ceae49c1a0c2c45efedeb7114ae785cc886afdc45c82172e4476e1ab5b86dc4314dd76";
String SIG2 = "c2c10400010a006f058262c806350910fbfcc82a015e7330471400000000001e002073616c74406e6f746174696f6e732e736571756f69612d7067702e6f7267a4d9c117dc7ba3a7e9270856f128d2ab271743eac3cb5750b22a89bd5fd60753162104d1a66e1a23b182c9980f788cfbfcc82a015e73300000b8400bff796c20fa8b25ff7a42686338e06417a2966e85a0fc2723c928bef6cd19d34cf5e7d55ada33080613012dadb79e0278e59d9e7ed7d2d6102912a5f768c2e75b60099225c3d8bfe0c123240188b80dbee89b9b3bd5b13ccc662abc37e2129b6968adac9aba43aa778c0fe4fe337591ee87a96a29a013debc83555293c877144fc676aa1b03782c501949521a320adf6ad96c4f2e036b52a18369c637fdc49033696a84d03a69580b953187fce5aca6fb26fc8815da9f3b513bfe8e304f33ecb4b521aeb7d09c4a284ea66123bd0d6a358b2526d762ca110e1f7f20b3038d774b64d5cfd34e2213765828359d7afc5bf24d5270e99d80c3c1568fa01624b6ea1e9ce4e6890ce9bacf6611a45d41e2671f68f5b096446bf08d27ce75608425b2e3ab92146229ad1fcd8224aca5b5f73960506e7df07bfbf3664348e8ecbfb2eb467b9cfe412cb377a6ee2eb5fd11be9cf9208fe9a74c296f52cfa02a1eb0519ad9a8349bf6ccd6495feb7e391451bf96e08a0798883dee5974e47cbf3b51f111b6d3"; String SIG2 = "c2c10400010a006f058262c806350910fbfcc82a015e7330471400000000001e002073616c74406e6f746174696f6e732e736571756f69612d7067702e6f7267a4d9c117dc7ba3a7e9270856f128d2ab271743eac3cb5750b22a89bd5fd60753162104d1a66e1a23b182c9980f788cfbfcc82a015e73300000b8400bff796c20fa8b25ff7a42686338e06417a2966e85a0fc2723c928bef6cd19d34cf5e7d55ada33080613012dadb79e0278e59d9e7ed7d2d6102912a5f768c2e75b60099225c3d8bfe0c123240188b80dbee89b9b3bd5b13ccc662abc37e2129b6968adac9aba43aa778c0fe4fe337591ee87a96a29a013debc83555293c877144fc676aa1b03782c501949521a320adf6ad96c4f2e036b52a18369c637fdc49033696a84d03a69580b953187fce5aca6fb26fc8815da9f3b513bfe8e304f33ecb4b521aeb7d09c4a284ea66123bd0d6a358b2526d762ca110e1f7f20b3038d774b64d5cfd34e2213765828359d7afc5bf24d5270e99d80c3c1568fa01624b6ea1e9ce4e6890ce9bacf6611a45d41e2671f68f5b096446bf08d27ce75608425b2e3ab92146229ad1fcd8224aca5b5f73960506e7df07bfbf3664348e8ecbfb2eb467b9cfe412cb377a6ee2eb5fd11be9cf9208fe9a74c296f52cfa02a1eb0519ad9a8349bf6ccd6495feb7e391451bf96e08a0798883dee5974e47cbf3b51f111b6d3";
String out = signature.getKeyID() + " last=" + signature.isContaining() + "\n"; String SIG2f = "c2c13b0400010a006f058262c806350910fbfcc82a015e7330471400000000001e002073616c74406e6f746174696f6e732e736571756f69612d7067702e6f7267a4d9c117dc7ba3a7e9270856f128d2ab271743eac3cb5750b22a89bd5fd60753162104d1a66e1a23b182c9980f788cfbfcc82a015e73300000b8400bff796c20fa8b25ff7a42686338e06417a2966e85a0fc2723c928bef6cd19d34cf5e7d55ada33080613012dadb79e0278e59d9e7ed7d2d6102912a5f768c2e75b60099225c3d8bfe0c123240188b80dbee89b9b3bd5b13ccc662abc37e2129b6968adac9aba43aa778c0fe4fe337591ee87a96a29a013debc83555293c877144fc676aa1b03782c501949521a320adf6ad96c4f2e036b52a18369c637fdc49033696a84d03a69580b953187fce5aca6fb26fc8815da9f3b513bfe8e304f33ecb4b521aeb7d09c4a284ea66123bd0d6a358b2526d762ca110e1f7f20b3038d774b64d5cfd34e2213765828359d7afc5bf24d5270e99d80c3c1568fa01624b6ea1e9ce4e6890ce9bacf6611a45d41e2671f68f5b096446bf08d27ce75608425b2e3ab92146229ad1fcd8224aca5b5f73960506e7df07bfbf3664348e8ecbfb2eb467b9cfe412cb377a6ee2eb5fd11be9cf9208fe9a74c296f52cfa02a1eb0519ad9a8349bf6ccd6495feb7e391451bf96e08a0798883dee5974e47cbf3b51f111b6d3";
String out = "last=" + signature.isContaining() + "\n";
String hex = Hex.toHexString(bytes.toByteArray()); String hex = Hex.toHexString(bytes.toByteArray());
while (hex.contains(OPS)) { while (hex.contains(OPS)) {
@ -812,9 +887,15 @@ public class OpenPgpMessageInputStream extends InputStream {
while (hex.contains(SIG1)) { while (hex.contains(SIG1)) {
hex = hex.replace(SIG1, "[SIG1]"); hex = hex.replace(SIG1, "[SIG1]");
} }
while (hex.contains(SIG1f)) {
hex = hex.replace(SIG1f, "[SIG1f]");
}
while (hex.contains(SIG2)) { while (hex.contains(SIG2)) {
hex = hex.replace(SIG2, "[SIG2]"); hex = hex.replace(SIG2, "[SIG2]");
} }
while (hex.contains(SIG2f)) {
hex = hex.replace(SIG2f, "[SIG2f]");
}
return out + hex; return out + hex;
} }

View file

@ -1,36 +0,0 @@
package org.pgpainless.decryption_verification;
import org.bouncycastle.bcpg.BCPGInputStream;
import org.pgpainless.util.ArmorUtils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class TeeBCPGInputStream extends BCPGInputStream {
private final OutputStream out;
public TeeBCPGInputStream(InputStream in, OutputStream outputStream) {
super(in);
this.out = outputStream;
}
@Override
public int read() throws IOException {
int r = super.read();
if (r != -1) {
out.write(r);
}
return r;
}
@Override
public int read(byte[] buf, int off, int len) throws IOException {
int r = super.read(buf, off, len);
if (r > 0) {
out.write(buf, off, r);
}
return r;
}
}

View file

@ -4,7 +4,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -143,11 +142,11 @@ public class OpenPgpMessageInputStreamTest {
"-----BEGIN PGP MESSAGE-----\n" + "-----BEGIN PGP MESSAGE-----\n" +
"Version: PGPainless\n" + "Version: PGPainless\n" +
"\n" + "\n" +
"hF4Dyqa/GWUy6WsSAQdAQ62BwmUt8Iby0+jvrLhMgST79KR/as+dyl0nf1uki2sw\n" + "hF4Dyqa/GWUy6WsSAQdAuGt49sQwdAHH3jPx11V3wSh7Amur3TbnONiQYJmMo3Qw\n" +
"Thg1Ojtf0hOyJgcpQ4nP2Q0wYFR0F1sCydaIlTGreYZHlGtybP7/Ml6KNZILTRWP\n" + "87yBnZCsaB7evxLBgi6PpF3tiytHM60xlrPeKKPpJhu60vNafRM2OOwqk7AdcZw4\n" +
"0kYBkGBgK7oQWRIVyoF2POvEP6EX1X8nvQk7O3NysVdRVbnia7gE3AzRYuha4kxs\n" + "0kYBEhiioO2btSuafNrQEjYzAgC7K6l7aPCcQObNp4ofryXu1P5vN+vUZp357hyS\n" +
"pI6xJkntLMS3K6him1Y9FHINIASFSB+C\n" + "6zZqP+0wJQ9yJZMvFTtFeSaSi0oMP2sb\n" +
"=5p00\n" + "=LvRL\n" +
"-----END PGP MESSAGE-----"; "-----END PGP MESSAGE-----";
public static final String OPS_LIT_SIG = "" + public static final String OPS_LIT_SIG = "" +
@ -170,8 +169,8 @@ public class OpenPgpMessageInputStreamTest {
// genKey(); // genKey();
// genSIG_LIT(); // genSIG_LIT();
// genSENC_LIT(); // genSENC_LIT();
// genPENC_COMP_LIT(); genPENC_COMP_LIT();
genOPS_LIT_SIG(); // genOPS_LIT_SIG();
} }
public static void genLIT() throws IOException { public static void genLIT() throws IOException {
@ -433,10 +432,7 @@ public class OpenPgpMessageInputStreamTest {
assertNull(metadata.getCompressionAlgorithm()); assertNull(metadata.getCompressionAlgorithm());
} }
@ParameterizedTest(name = "Process PENC(OPS OPS OPS LIT SIG SIG SIG) using {0}") String BOB_KEY = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
@MethodSource("provideMessageProcessors")
public void testProcessOPS_OPS_OPS_LIT_SIG_SIG_SIG(Processor processor) throws IOException, PGPException {
String KEY = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
"Comment: Bob's OpenPGP Transferable Secret Key\n" + "Comment: Bob's OpenPGP Transferable Secret Key\n" +
"\n" + "\n" +
"lQVYBF2lnPIBDAC5cL9PQoQLTMuhjbYvb4Ncuuo0bfmgPRFywX53jPhoFf4Zg6mv\n" + "lQVYBF2lnPIBDAC5cL9PQoQLTMuhjbYvb4Ncuuo0bfmgPRFywX53jPhoFf4Zg6mv\n" +
@ -518,6 +514,62 @@ public class OpenPgpMessageInputStreamTest {
"xqAY9Bwizt4FWgXuLm1a4+So4V9j1TRCXd12Uc2l2RNmgDE=\n" + "xqAY9Bwizt4FWgXuLm1a4+So4V9j1TRCXd12Uc2l2RNmgDE=\n" +
"=miES\n" + "=miES\n" +
"-----END PGP PRIVATE KEY BLOCK-----"; "-----END PGP PRIVATE KEY BLOCK-----";
@ParameterizedTest(name = "Process PENC(OPS OPS LIT SIG SIG) using {0}")
@MethodSource("provideMessageProcessors")
public void testProcessPENC_OPS_OPS_LIT_SIG_SIG(Processor processor) throws IOException, PGPException {
String MSG = "-----BEGIN PGP MESSAGE-----\n" +
"\n" +
"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\n" +
"=mdYs\n" +
"-----END PGP MESSAGE-----\n";
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(BOB_KEY);
PGPPublicKeyRing certificate = PGPainless.extractCertificate(secretKeys);
Tuple<String, MessageMetadata> result = processor.process(MSG, ConsumerOptions.get()
.addVerificationCert(certificate)
.addDecryptionKey(secretKeys));
String plain = result.getA();
assertEquals("encrypt ∘ sign ∘ sign", plain);
MessageMetadata metadata = result.getB();
assertEquals(SymmetricKeyAlgorithm.AES_256, metadata.getEncryptionAlgorithm());
assertNull(metadata.getCompressionAlgorithm());
}
@ParameterizedTest(name = "Process PENC(OPS OPS OPS LIT SIG SIG SIG) using {0}")
@MethodSource("provideMessageProcessors")
public void testProcessOPS_OPS_OPS_LIT_SIG_SIG_SIG(Processor processor) throws IOException, PGPException {
String MSG = "-----BEGIN PGP MESSAGE-----\n" + String MSG = "-----BEGIN PGP MESSAGE-----\n" +
"\n" + "\n" +
"wcDMA3wvqk35PDeyAQwA0yaEgydkAMEfl7rDTYVGanLKiFiWIs34mkF+LB8qR5eY\n" + "wcDMA3wvqk35PDeyAQwA0yaEgydkAMEfl7rDTYVGanLKiFiWIs34mkF+LB8qR5eY\n" +
@ -565,7 +617,7 @@ public class OpenPgpMessageInputStreamTest {
"x12WVuyITVU3fCfHp6/0A6wPtJezCvoodqPlw/3fd5eSVYzb5C3v564uhz4=\n" + "x12WVuyITVU3fCfHp6/0A6wPtJezCvoodqPlw/3fd5eSVYzb5C3v564uhz4=\n" +
"=JP9T\n" + "=JP9T\n" +
"-----END PGP MESSAGE-----"; "-----END PGP MESSAGE-----";
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(KEY); PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(BOB_KEY);
PGPPublicKeyRing certificate = PGPainless.extractCertificate(secretKeys); PGPPublicKeyRing certificate = PGPainless.extractCertificate(secretKeys);
Tuple<String, MessageMetadata> result = processor.process(MSG, ConsumerOptions.get() Tuple<String, MessageMetadata> result = processor.process(MSG, ConsumerOptions.get()

View file

@ -1,61 +0,0 @@
package org.pgpainless.decryption_verification;
import org.bouncycastle.bcpg.ArmoredInputStream;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.BCPGInputStream;
import org.bouncycastle.bcpg.Packet;
import org.bouncycastle.openpgp.PGPCompressedData;
import org.bouncycastle.openpgp.PGPException;
import org.junit.jupiter.api.Test;
import org.pgpainless.algorithm.OpenPgpPacket;
import org.pgpainless.util.ArmoredInputStreamFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
public class TeeBCPGInputStreamTest {
private static final Logger LOGGER = LoggerFactory.getLogger(TeeBCPGInputStreamTest.class);
private static final String INBAND_SIGNED = "-----BEGIN PGP MESSAGE-----\n" +
"Version: PGPainless\n" +
"\n" +
"owGbwMvMyCUWdXSHvVTUtXbG0yJJDCDgkZqTk6+jEJ5flJOiyNVRysIoxsXAxsqU\n" +
"GDiVjUGRUwCmQUyRRWnOn9Z/PIseF3Yz6cCEL05nZDj1OClo75WVTjNmJPemW6qV\n" +
"6ki//1K1++2s0qTP+0N11O4z/BVLDDdxnmQryS+5VXjBX7/0Hxnm/eqeX6Zum35r\n" +
"M8e7ufwA\n" +
"=RDiy\n" +
"-----END PGP MESSAGE-----";
@Test
public void test() throws IOException, PGPException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ArmoredOutputStream armorOut = new ArmoredOutputStream(out);
ByteArrayInputStream bytesIn = new ByteArrayInputStream(INBAND_SIGNED.getBytes(StandardCharsets.UTF_8));
ArmoredInputStream armorIn = ArmoredInputStreamFactory.get(bytesIn);
BCPGInputStream bcpgIn = new BCPGInputStream(armorIn);
TeeBCPGInputStream teeIn = new TeeBCPGInputStream(bcpgIn, armorOut);
ByteArrayOutputStream nestedOut = new ByteArrayOutputStream();
ArmoredOutputStream nestedArmorOut = new ArmoredOutputStream(nestedOut);
PGPCompressedData compressedData = new PGPCompressedData(teeIn);
InputStream nestedStream = compressedData.getDataStream();
BCPGInputStream nestedBcpgIn = new BCPGInputStream(nestedStream);
TeeBCPGInputStream nestedTeeIn = new TeeBCPGInputStream(nestedBcpgIn, nestedArmorOut);
int tag;
while ((tag = nestedTeeIn.nextPacketTag()) != -1) {
LOGGER.debug(OpenPgpPacket.requireFromTag(tag).toString());
Packet packet = nestedTeeIn.readPacket();
}
nestedArmorOut.close();
LOGGER.debug(nestedOut.toString());
}
}