From 5c25b0c730724341bdedc14bdf7912be0114a951 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Wed, 8 Dec 2021 03:00:53 +0100 Subject: [PATCH] Implement stream dump --- .../org/pgpainless/util/StreamDumper.java | 424 ++++++++++++++++++ .../org/pgpainless/util/StreamDumpTest.java | 57 +++ 2 files changed, 481 insertions(+) create mode 100644 pgpainless-core/src/main/java/org/pgpainless/util/StreamDumper.java create mode 100644 pgpainless-core/src/test/java/org/pgpainless/util/StreamDumpTest.java diff --git a/pgpainless-core/src/main/java/org/pgpainless/util/StreamDumper.java b/pgpainless-core/src/main/java/org/pgpainless/util/StreamDumper.java new file mode 100644 index 00000000..4c05be0f --- /dev/null +++ b/pgpainless-core/src/main/java/org/pgpainless/util/StreamDumper.java @@ -0,0 +1,424 @@ +package org.pgpainless.util; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.Date; +import java.util.Iterator; + +import org.bouncycastle.bcpg.SignatureSubpacket; +import org.bouncycastle.bcpg.sig.EmbeddedSignature; +import org.bouncycastle.bcpg.sig.Exportable; +import org.bouncycastle.bcpg.sig.Features; +import org.bouncycastle.bcpg.sig.IntendedRecipientFingerprint; +import org.bouncycastle.bcpg.sig.IssuerFingerprint; +import org.bouncycastle.bcpg.sig.IssuerKeyID; +import org.bouncycastle.bcpg.sig.KeyExpirationTime; +import org.bouncycastle.bcpg.sig.KeyFlags; +import org.bouncycastle.bcpg.sig.NotationData; +import org.bouncycastle.bcpg.sig.PreferredAlgorithms; +import org.bouncycastle.bcpg.sig.PrimaryUserID; +import org.bouncycastle.bcpg.sig.Revocable; +import org.bouncycastle.bcpg.sig.RevocationKey; +import org.bouncycastle.bcpg.sig.RevocationReason; +import org.bouncycastle.bcpg.sig.SignatureCreationTime; +import org.bouncycastle.bcpg.sig.SignatureExpirationTime; +import org.bouncycastle.bcpg.sig.SignatureTarget; +import org.bouncycastle.bcpg.sig.SignerUserID; +import org.bouncycastle.bcpg.sig.TrustSignature; +import org.bouncycastle.openpgp.PGPCompressedData; +import org.bouncycastle.openpgp.PGPEncryptedData; +import org.bouncycastle.openpgp.PGPEncryptedDataList; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPLiteralData; +import org.bouncycastle.openpgp.PGPObjectFactory; +import org.bouncycastle.openpgp.PGPOnePassSignature; +import org.bouncycastle.openpgp.PGPOnePassSignatureList; +import org.bouncycastle.openpgp.PGPPBEEncryptedData; +import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData; +import org.bouncycastle.openpgp.PGPSessionKey; +import org.bouncycastle.openpgp.PGPSignature; +import org.bouncycastle.openpgp.PGPSignatureList; +import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; +import org.bouncycastle.openpgp.bc.BcPGPObjectFactory; +import org.bouncycastle.openpgp.operator.SessionKeyDataDecryptorFactory; +import org.bouncycastle.openpgp.operator.bc.BcSessionKeyDataDecryptorFactory; +import org.bouncycastle.util.encoders.Hex; +import org.bouncycastle.util.io.Streams; +import org.pgpainless.algorithm.CompressionAlgorithm; +import org.pgpainless.algorithm.Feature; +import org.pgpainless.algorithm.HashAlgorithm; +import org.pgpainless.algorithm.KeyFlag; +import org.pgpainless.algorithm.PublicKeyAlgorithm; +import org.pgpainless.algorithm.SignatureType; +import org.pgpainless.algorithm.StreamEncoding; +import org.pgpainless.algorithm.SymmetricKeyAlgorithm; +import org.pgpainless.key.util.RevocationAttributes; + +public class StreamDumper { + + public static void dump(InputStream inputStream, PGPSessionKey sessionKey) throws IOException, PGPException { + + StringBuilder stringBuilder = new StringBuilder(); + StringBuilderWrapper sbw = new StringBuilderWrapper(stringBuilder); + + PGPObjectFactory objectFactory = new BcPGPObjectFactory(inputStream); + walkObjects(sbw, objectFactory, sessionKey); + + System.out.println(sbw); + } + + private static void walkObjects(StringBuilderWrapper sbw, PGPObjectFactory objectFactory, PGPSessionKey sessionKey) throws IOException, PGPException { + Object next; + + while ((next = objectFactory.nextObject()) != null) { + + if (next instanceof PGPOnePassSignatureList) { + PGPOnePassSignatureList onePassSignatures = (PGPOnePassSignatureList) next; + Iterator iterator = onePassSignatures.iterator(); + while (iterator.hasNext()) { + PGPOnePassSignature pgpOnePassSignature = iterator.next(); + sbw.appendLine("One-Pass Signature Packet").iind() + .appendLine("Type: " + SignatureType.valueOf(pgpOnePassSignature.getSignatureType())) + .appendLine("Public Key Algorithm: " + PublicKeyAlgorithm.fromId(pgpOnePassSignature.getKeyAlgorithm())) + .appendLine("Hash Algorithm: " + HashAlgorithm.fromId(pgpOnePassSignature.getHashAlgorithm())) + .appendLine("Issuer Key ID: " + Long.toHexString(pgpOnePassSignature.getKeyID())) + .dind() + .emptyLine(); + } + } + else if (next instanceof PGPSignatureList) { + PGPSignatureList signatures = (PGPSignatureList) next; + for (PGPSignature signature : signatures) { + appendSignature(sbw, signature); + sbw.emptyLine(); + } + } + else if (next instanceof PGPEncryptedDataList) { + PGPEncryptedDataList encryptedDataList = (PGPEncryptedDataList) next; + SessionKeyDataDecryptorFactory sessionKeyDataDecryptorFactory = null; + if (sessionKey != null) { + sessionKeyDataDecryptorFactory = new BcSessionKeyDataDecryptorFactory(sessionKey); + } + for (PGPEncryptedData encryptedData : encryptedDataList) { + if (encryptedData instanceof PGPPublicKeyEncryptedData) { + PGPPublicKeyEncryptedData pkesk = (PGPPublicKeyEncryptedData) encryptedData; + sbw.appendLine("Public-Key Encrypted Session Key Packet").iind() + .appendLine("Recipient: " + Long.toHexString(pkesk.getKeyID())); + + if (sessionKeyDataDecryptorFactory != null) { + try { + InputStream inputStream = pkesk.getDataStream(sessionKeyDataDecryptorFactory); + sbw.appendLine("Session Key: " + Hex.toHexString(sessionKey.getKey())); + sbw.appendLine("Symmetric Algorithm: " + SymmetricKeyAlgorithm.fromId(sessionKey.getAlgorithm())); + sbw.appendLine("Decryption Successful"); + sbw.emptyLine(); + + PGPObjectFactory decryptedFactory = new BcPGPObjectFactory(inputStream); + walkObjects(sbw, decryptedFactory, sessionKey); + } catch (PGPException e) { + sbw.appendLine("Decryption Failed"); + } + } + + if (pkesk.isIntegrityProtected()) { + sbw.appendLine("Modification Detection Code Packet").iind() + .appendLine("Valid: " + pkesk.verify()) + .dind(); + } + } else if (encryptedData instanceof PGPPBEEncryptedData) { + PGPPBEEncryptedData skesk = (PGPPBEEncryptedData) encryptedData; + sbw.appendLine("Symmetric-Key Encrypted Session Key Packet").iind() + .appendLine("Integrity Protected: " + skesk.isIntegrityProtected()) + .dind().emptyLine(); + } + } + sbw.emptyLine(); + } + else if (next instanceof PGPLiteralData) { + PGPLiteralData literalData = (PGPLiteralData) next; + StreamEncoding encoding = StreamEncoding.fromCode(literalData.getFormat()); + String fileName = literalData.getFileName(); + Date modificationDate = literalData.getModificationTime(); + + sbw.appendLine("Literal Data Packet").iind() + .appendLine("Format: " + encoding); + if (fileName != null && !fileName.isEmpty()) { + sbw.appendLine("File Name: " + fileName); + } + if (modificationDate != null && modificationDate.getTime() != 0) { + sbw.appendLine("Modification Date: " + DateUtil.formatUTCDate(modificationDate)); + } + + byte[] peek = new byte[512]; + InputStream literalIn = literalData.getDataStream(); + int read = literalIn.read(peek); + Streams.drain(literalIn); + literalIn.close(); + + String content = ""; + if (read != -1) { + content = new String(peek, 0, read).replace("\r", "\\r").replace("\n", "\\n"); + } + sbw.appendLine("Content: \"" + content + "\"") + .dind() + .emptyLine(); + } + else if (next instanceof PGPCompressedData) { + PGPCompressedData compressedData = (PGPCompressedData) next; + sbw.appendLine("Compressed Data Packet").iind() + .appendLine("Algorithm: " + CompressionAlgorithm.fromId(compressedData.getAlgorithm())) + .emptyLine(); + + PGPObjectFactory compressedFactory = new BcPGPObjectFactory(compressedData.getDataStream()); + walkObjects(sbw, compressedFactory, sessionKey); + sbw.dind(); + } + /* + + case PacketTags.SYMMETRIC_KEY_ENC_SESSION: + case PacketTags.ONE_PASS_SIGNATURE: + case PacketTags.SECRET_KEY: + case PacketTags.PUBLIC_KEY: + case PacketTags.SECRET_SUBKEY: + case PacketTags.COMPRESSED_DATA: + case PacketTags.SYMMETRIC_KEY_ENC: + case PacketTags.MARKER: + case PacketTags.LITERAL_DATA: + case PacketTags.TRUST: + case PacketTags.USER_ID: + case PacketTags.PUBLIC_SUBKEY: + case PacketTags.USER_ATTRIBUTE: + case PacketTags.SYM_ENC_INTEGRITY_PRO: + case PacketTags.MOD_DETECTION_CODE: + + case PacketTags.EXPERIMENTAL_1: + case PacketTags.EXPERIMENTAL_2: + case PacketTags.EXPERIMENTAL_3: + case PacketTags.EXPERIMENTAL_4: + */ + } + } + + private static void appendSignature(StringBuilderWrapper sbw, PGPSignature signature) throws PGPException { + sbw.appendLine("Signature Packet").iind() + .appendLine("Version: " + signature.getVersion()) + .appendLine("Type: " + SignatureType.valueOf(signature.getSignatureType())) + .appendLine("Public Key Algorithm: " + PublicKeyAlgorithm.fromId(signature.getKeyAlgorithm())) + .appendLine("Hash Algorithm: " + HashAlgorithm.fromId(signature.getHashAlgorithm())); + + if (signature.getHashedSubPackets().toArray().length != 0) { + sbw.appendLine("Hashed Area:").iind(); + appendSubpacketVector(sbw, signature.getHashedSubPackets()); + sbw.dind(); + } + + if (signature.getUnhashedSubPackets().toArray().length != 0) { + sbw.appendLine("Unhashed Area:").iind(); + appendSubpacketVector(sbw, signature.getUnhashedSubPackets()); + sbw.dind(); + } + + sbw.appendLine("Digest Prefix: " + Hex.toHexString(signature.getDigestPrefix())) + .appendLine("Signature: ").iind() + .appendLine(Hex.toHexString(signature.getSignature())).dind() + .dind(); + } + + private static void appendSubpacketVector(StringBuilderWrapper sbw, PGPSignatureSubpacketVector vector) throws PGPException { + PGPSignatureList embeddedSignatures = vector.getEmbeddedSignatures(); + int embeddedSigCount = 0; + + for (SignatureSubpacket subpacket : vector.toArray()) { + switch (org.pgpainless.algorithm.SignatureSubpacket.fromCode(subpacket.getType())) { + case signatureCreationTime: + SignatureCreationTime signatureCreationTime = (SignatureCreationTime) subpacket; + sbw.appendLine("Signature Creation Time: " + DateUtil.formatUTCDate(signatureCreationTime.getTime()) + (signatureCreationTime.isCritical() ? " (critical)" : "")); + break; + case signatureExpirationTime: + SignatureExpirationTime signatureExpirationTime = (SignatureExpirationTime) subpacket; + sbw.appendLine("Signature Expiration Time: " + signatureExpirationTime.getTime() + (signatureExpirationTime.isCritical() ? " (critical)" : "")); + break; + case exportableCertification: + Exportable exportable = (Exportable) subpacket; + sbw.appendLine("Exportable: " + exportable.isExportable() + (exportable.isCritical() ? " (critical)" : "")); + break; + case trustSignature: + TrustSignature trustSignature = (TrustSignature) subpacket; + sbw.appendLine("Trust Signature" + (trustSignature.isCritical() ? " (critical)" : "") + ":").iind() + .appendLine("Depth: " + trustSignature.getDepth()) + .appendLine("Amount: " + trustSignature.getTrustAmount()) + .dind(); + break; + case regularExpression: + sbw.appendLine("Regular Expression: " + new String(subpacket.getData())); + break; + case revocable: + Revocable revocable = (Revocable) subpacket; + sbw.appendLine("Revocable: " + revocable.isRevocable() + (revocable.isCritical() ? " (critical)" : "")); + break; + case keyExpirationTime: + KeyExpirationTime keyExpirationTime = (KeyExpirationTime) subpacket; + sbw.appendLine("Key Expiration Time: " + keyExpirationTime.getTime() + (keyExpirationTime.isCritical() ? " (critical)" : "")); + break; + case placeholder: + sbw.appendLine("Placeholder: " + new String(subpacket.getData())); + break; + case preferredSymmetricAlgorithms: + PreferredAlgorithms preferredSymmetricAlgorithms = (PreferredAlgorithms) subpacket; + int[] symAlgIds = preferredSymmetricAlgorithms.getPreferences(); + SymmetricKeyAlgorithm[] symAlgs = new SymmetricKeyAlgorithm[symAlgIds.length]; + for (int i = 0; i < symAlgs.length; i++) { + symAlgs[i] = SymmetricKeyAlgorithm.fromId(symAlgIds[i]); + } + sbw.appendLine("Preferred Symmetric Algorithms: " + Arrays.toString(symAlgs) + (preferredSymmetricAlgorithms.isCritical() ? " (critical)" : "")); + break; + case revocationKey: + RevocationKey revocationKey = (RevocationKey) subpacket; + sbw.appendLine("Revocation Key" + (revocationKey.isCritical() ? " (critical)" : "") + ":").iind() + .appendLine("Key Algorithm: " + PublicKeyAlgorithm.fromId(revocationKey.getAlgorithm())) + .appendLine("Signature Class: " + revocationKey.getSignatureClass()) + .appendLine("Fingerprint: " + new String(revocationKey.getFingerprint())) + .dind(); + break; + case issuerKeyId: + IssuerKeyID issuerKeyID = (IssuerKeyID) subpacket; + sbw.appendLine("Issuer Key ID: " + Long.toHexString(issuerKeyID.getKeyID()) + (issuerKeyID.isCritical() ? " (critical)" : "")); + break; + case notationData: + NotationData notationData = (NotationData) subpacket; + sbw.appendLine("Notation Data" + (notationData.isCritical() ? " (critical)" : "") + ":").iind() + .appendLine("Notation Name: " + notationData.getNotationName()) + .appendLine("Notation Value: " + notationData.getNotationValue()) + .dind(); + break; + case preferredHashAlgorithms: + PreferredAlgorithms preferredHashAlgorithms = (PreferredAlgorithms) subpacket; + int[] hashAlgIds = preferredHashAlgorithms.getPreferences(); + HashAlgorithm[] hashAlgs = new HashAlgorithm[hashAlgIds.length]; + for (int i = 0; i < hashAlgs.length; i++) { + hashAlgs[i] = HashAlgorithm.fromId(hashAlgIds[i]); + } + sbw.appendLine("Preferred Hash Algorithms: " + Arrays.toString(hashAlgs) + (preferredHashAlgorithms.isCritical() ? " (critical)" : "")); + break; + case preferredCompressionAlgorithms: + PreferredAlgorithms preferredCompressionAlgorithms = (PreferredAlgorithms) subpacket; + int[] compAlgIds = preferredCompressionAlgorithms.getPreferences(); + CompressionAlgorithm[] compAlgs = new CompressionAlgorithm[compAlgIds.length]; + for (int i = 0; i < compAlgs.length; i++) { + compAlgs[i] = CompressionAlgorithm.fromId(compAlgIds[i]); + } + sbw.appendLine("Preferred Compression Algorithms: " + Arrays.toString(compAlgs) + (preferredCompressionAlgorithms.isCritical() ? " (critical)" : "")); + break; + case keyServerPreferences: + sbw.appendLine("Key Server Preferences: " + new String(subpacket.getData())); + break; + case preferredKeyServers: + sbw.appendLine("Preferred Key Servers: " + new String(subpacket.getData())); + break; + case primaryUserId: + PrimaryUserID primaryUserID = (PrimaryUserID) subpacket; + sbw.appendLine("Primary User-ID: " + primaryUserID.isPrimaryUserID() + (primaryUserID.isCritical() ? " (critical)" : "")); + break; + case policyUrl: + sbw.appendLine("Policy-URL: " + new String(subpacket.getData())); + break; + case keyFlags: + KeyFlags keyFlags = (KeyFlags) subpacket; + KeyFlag[] flags = KeyFlag.fromBitmask(keyFlags.getFlags()).toArray(new KeyFlag[0]); + sbw.appendLine("Key Flags: " + Arrays.toString(flags) + (keyFlags.isCritical() ? " (critical)" : "")); + break; + case signerUserId: + SignerUserID signerUserID = (SignerUserID) subpacket; + sbw.appendLine("Signer User-ID: " + signerUserID.getID() + (signerUserID.isCritical() ? " (critical)" : "")); + break; + case revocationReason: + RevocationReason revocationReason = (RevocationReason) subpacket; + sbw.appendLine("Revocation Reason: " + RevocationAttributes.Reason.fromCode(revocationReason.getRevocationReason()) + (revocationReason.isCritical() ? " (critical)" : "")).iind() + .appendLine("Description: " + revocationReason.getRevocationDescription()).dind(); + break; + case features: + Features features = (Features) subpacket; + Feature[] featurez = Feature.fromBitmask(features.getFeatures()).toArray(new Feature[0]); + sbw.appendLine("Features: " + Arrays.toString(featurez) + (features.isCritical() ? " (critical)" : "")); + break; + case signatureTarget: + SignatureTarget signatureTarget = (SignatureTarget) subpacket; + sbw.appendLine("Signature Target" + (signatureTarget.isCritical() ? " (critical)" : "" + ":")).iind() + .appendLine("Public Key Algorithm: " + PublicKeyAlgorithm.fromId(signatureTarget.getPublicKeyAlgorithm())) + .appendLine("Hash Algorithm: " + HashAlgorithm.fromId(signatureTarget.getHashAlgorithm())) + .appendLine("Hash Data: " + Hex.toHexString(signatureTarget.getHashData())) + .dind(); + break; + case embeddedSignature: + EmbeddedSignature embeddedSignature = (EmbeddedSignature) subpacket; + sbw.appendLine("Embedded Signature" + (embeddedSignature.isCritical() ? " (critical)" : "") + ":").iind(); + appendSignature(sbw, embeddedSignatures.get(embeddedSigCount++)); + break; + case issuerFingerprint: + IssuerFingerprint issuerFingerprint = (IssuerFingerprint) subpacket; + sbw.appendLine("Issuer Fingerprint: " + Hex.toHexString(issuerFingerprint.getFingerprint()) + (issuerFingerprint.isCritical() ? " (critical)" : "")); + break; + case preferredAEADAlgorithms: + PreferredAlgorithms preferredAEADAlgorithms = (PreferredAlgorithms) subpacket; + int[] aeadAlgIds = preferredAEADAlgorithms.getPreferences(); + sbw.appendLine("Preferred AEAD Algorithms: " + Arrays.toString(aeadAlgIds) + (preferredAEADAlgorithms.isCritical() ? " (critical)" : "")); + break; + case intendedRecipientFingerprint: + IntendedRecipientFingerprint intendedRecipientFingerprint = (IntendedRecipientFingerprint) subpacket; + sbw.appendLine("Intended Recipient Fingerprint" + (intendedRecipientFingerprint.isCritical() ? " critical" : "") + ":").iind() + .appendLine("Key Version: " + intendedRecipientFingerprint.getKeyVersion()) + .appendLine("Fingerprint: " + Hex.toHexString(intendedRecipientFingerprint.getFingerprint())) + .dind(); + break; + case attestedCertification: + sbw.appendLine("Attested Certification: " + new String(subpacket.getData())); + break; + default: + sbw.appendLine("Experimental Subpacket (Tag " + subpacket.getType() + ")" + (subpacket.isCritical() ? " (critical)" : "") + ":" + new String(subpacket.getData())); + } + } + } + + public static class StringBuilderWrapper { + private final StringBuilder sb; + private int indentationLevel = 0; + private final int spacesPerLevel = 2; + + public StringBuilderWrapper(StringBuilder sb) { + this.sb = sb; + } + + public StringBuilderWrapper appendLine(String line) { + spaces(); + sb.append(line).append('\n'); + return this; + } + + public StringBuilderWrapper iind() { + indentationLevel++; + return this; + } + + public StringBuilderWrapper dind() { + indentationLevel--; + return this; + } + + public StringBuilderWrapper emptyLine() { + sb.append('\n'); + return this; + } + + private StringBuilderWrapper spaces() { + for (int i = 0; i < indentationLevel * spacesPerLevel; i++) { + sb.append(' '); + } + return this; + } + + public String toString() { + return sb.toString(); + } + } +} \ No newline at end of file diff --git a/pgpainless-core/src/test/java/org/pgpainless/util/StreamDumpTest.java b/pgpainless-core/src/test/java/org/pgpainless/util/StreamDumpTest.java new file mode 100644 index 00000000..e4d35188 --- /dev/null +++ b/pgpainless-core/src/test/java/org/pgpainless/util/StreamDumpTest.java @@ -0,0 +1,57 @@ +package org.pgpainless.util; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import org.bouncycastle.bcpg.ArmoredInputStream; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPSessionKey; +import org.bouncycastle.util.encoders.Hex; +import org.junit.jupiter.api.Test; +import org.pgpainless.algorithm.SymmetricKeyAlgorithm; + +public class StreamDumpTest { + + @Test + public void test() throws IOException, PGPException { + String encryptedMessage = "-----BEGIN PGP MESSAGE-----\n" + + "\n" + + "wV4Di9iOlMDSAzMSAQdAu/2VmD0uZASFHqAD0IVNq7C8rdsJ+ZQd2nQsuBilygUw\n" + + "9bK+bOzU6ksTZgKgdAjO8zpvM+N0B3L0TtiwLr5rj0rPkCyVLdACnBpWOCZCMpsK\n" + + "0j4B4um24+oCDHtxRu1e1IvsboBtGN9ElxidGAiUdPJ3L0QrNVgzdmVTwuywtIHW\n" + + "r66Eaq8vCTmJpcsy0BYTiQ==\n" + + "=FY/Q\n" + + "-----END PGP MESSAGE-----\n"; + PGPSessionKey sessionKey = new PGPSessionKey(SymmetricKeyAlgorithm.AES_256.getAlgorithmId(), Hex.decode("920B1779565C8DF4DD9DB46966CDF2B51BC882C241DE8EF437CADEC711E7EB04")); + + String signedMessage = "-----BEGIN PGP MESSAGE-----\n" + + "\n" + + "xA0DAAgB0D9vhlIm/osBxA0DAAoWCTXiD9yZ2YYByxRiAAAAAABIZWxsbywgd29y\n" + + "bGQhCsJ1BAAWCgAnBYJcdpUyFiEEjeZMrRdY/BlFYM9ZCTXiD9yZ2YYJEAk14g/c\n" + + "mdmGAAC5AgD/U/FD8PPqqABrkdg9bV4aToP6YENgXGq8M7SIvTaznl0BAM1KdOKs\n" + + "UWPQgh5AJp3kOUzSO7v+brfw03O1wQaOmgsHwsBzBAABCAAnBYJdkKU/FiEEPoh3\n" + + "yHcnRpKXUYn10D9vhlIm/osJENA/b4ZSJv6LAAAQ1Qf/bC4uL61DQrR0s+3n7By8\n" + + "Rp0cfppfR94NK9GUtCcL03Ci78qimpjcZja+r03xTj4r3TGASRngaYD0cOU+erF9\n" + + "DO3PPGZKxajOqtFXoQKdQnUhaRnU2CMfL+voRzH7kFssvcHzy7JoeFDLxadt8yym\n" + + "Hm3vN+oDB3b8uWVEzaVMn71cbjJzlsLBaLclSlE/Nj36x9TeunnHhZJ7BFmkTaBd\n" + + "W5kdBtqIV6Mii+xiYjrtrkFzYkEDNz6hK2so8SjpaGck2tSiBSrybf0/CLWwb/+e\n" + + "i6yLPi6Afbxz+5Yp4jjxNkUdjeQFNFExix0DUPVowhZQN9hwZvJXmfUzi71+BB6N\n" + + "uA==\n" + + "=BDwS\n" + + "-----END PGP MESSAGE-----\n"; + + String compressedSignedMessage = "-----BEGIN PGP MESSAGE-----\n" + + "\n" + + "owGbwMvMwCH2sPOSUOzzWymMp0WSGGK6InU9UnNy8nUUyvOLclIUuTpKWRjEOBhk\n" + + "xRRZ8jZHv1c9Zfp0SurkSJguViaQFgYuTgGYSJ09w/8M9xn6J9em8Bvs3rHgYd+G\n" + + "z519Zy++FFuYsPHwz8KmXNliRoaNP2zq+A5kp7MJWjc2JrdXW8y+GTd9So2lDcMq\n" + + "h3UsTFwA\n" + + "=56Gw\n" + + "-----END PGP MESSAGE-----"; + + ArmoredInputStream inputStream = new ArmoredInputStream(new ByteArrayInputStream(encryptedMessage.getBytes(StandardCharsets.UTF_8))); + + StreamDumper.dump(inputStream, sessionKey); + } +}