diff --git a/src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/BuildEncryptionOutputStreamAPI.java b/src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/BuildEncryptionOutputStreamAPI.java index ff41e125..656127c4 100644 --- a/src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/BuildEncryptionOutputStreamAPI.java +++ b/src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/BuildEncryptionOutputStreamAPI.java @@ -51,6 +51,7 @@ public final class BuildEncryptionOutputStreamAPI { private String signWith; private Set recipients; private boolean armorOutput; + private boolean textMode; // Signature @@ -99,6 +100,16 @@ OutputStream andWriteTo(OutputStream sinkForEncryptedData) throws PGPException, SignatureException, NoSuchAlgorithmException, NoSuchProviderException, IOException; } + public interface BuildWithTextMode extends Build { + + /** + * Emulates GnuPG's {@code --textmode} flag, which encodes data as text literal + * packets rather than binary literal packets. + * @return next step + */ + Build textMode(); + } + public interface WithAlgorithmSuite { @@ -222,14 +233,14 @@ interface Armor { * * @return next step */ - Build binaryOutput(); + BuildWithTextMode binaryOutput(); /** * Ascii armor the output, e.g. for usage in text protocols. * * @return next step */ - Build armorAsciiOutput(); + BuildWithTextMode armorAsciiOutput(); } } } @@ -486,21 +497,21 @@ public Armor andDoNotSign() { public final class ArmorImpl implements Armor { @Override - public Build binaryOutput() { + public BuildWithTextMode binaryOutput() { BuildEncryptionOutputStreamAPI.this.armorOutput = false; LOGGER.trace("binary output"); - return new Builder(); + return new BuilderWithTextMode(); } @Override - public Build armorAsciiOutput() { + public BuildWithTextMode armorAsciiOutput() { BuildEncryptionOutputStreamAPI.this.armorOutput = true; LOGGER.trace("ascii armor output"); - return new Builder(); + return new BuilderWithTextMode(); } - public final class Builder implements Build { + public class Builder implements Build { @Override public OutputStream andWriteTo(OutputStream sinkForEncryptedData) @@ -513,10 +524,21 @@ public OutputStream andWriteTo(OutputStream sinkForEncryptedData) BuildEncryptionOutputStreamAPI.this.sinkForEncryptedData, getKeySelectionStrategy(), BuildEncryptionOutputStreamAPI.this.armorOutput, - BuildEncryptionOutputStreamAPI.this.recipients); + BuildEncryptionOutputStreamAPI.this.recipients, + BuildEncryptionOutputStreamAPI.this.textMode); } } + + public final class BuilderWithTextMode extends Builder implements BuildWithTextMode { + + @Override + public Build textMode() { + BuildEncryptionOutputStreamAPI.this.textMode = true; + LOGGER.trace("text mode"); + return this; + } + } } } } diff --git a/src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/encrypting/PGPEncryptingStream.java b/src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/encrypting/PGPEncryptingStream.java index 8ddc794e..87817def 100644 --- a/src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/encrypting/PGPEncryptingStream.java +++ b/src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/encrypting/PGPEncryptingStream.java @@ -78,6 +78,7 @@ private PGPEncryptingStream(final KeyringConfig config, final PGPAlgorithmSuite * @param keySelectionStrategy selection strategy * @param armor armor the file (true) or use binary. * @param encryptTo encrypt to + * @param textMode simulates GnuPG's {@code --textmode} flag * * @return stream where plaintext gets written into * @@ -93,7 +94,8 @@ public static OutputStream create(final KeyringConfig config, final OutputStream cipherTextSink, final KeySelectionStrategy keySelectionStrategy, final boolean armor, - final Set encryptTo) + final Set encryptTo, + final boolean textMode) throws IOException, PGPException, NoSuchAlgorithmException, NoSuchProviderException { requireNonNull(config, "callback must not be null"); @@ -109,7 +111,7 @@ public static OutputStream create(final KeyringConfig config, } final PGPEncryptingStream encryptingStream = new PGPEncryptingStream(config, algorithmSuite); - encryptingStream.setup(cipherTextSink, signingUid, encryptTo, keySelectionStrategy, armor); + encryptingStream.setup(cipherTextSink, signingUid, encryptTo, keySelectionStrategy, armor, textMode); return encryptingStream; } @@ -122,6 +124,7 @@ public static OutputStream create(final KeyringConfig config, * @param pubEncKeys the pub enc keys * @param keySelectionStrategy key selection strategy (for signatures) * @param armor if OutputStream should be "armored", that means base64 encoded + * @param textMode simulates GnuPG's {@code --textmode} flag * * @throws IOException Signals that an I/O exception has occurred. * @throws PGPException the pGP exception @@ -134,7 +137,8 @@ private void setup(final OutputStream cipherTextSink, @Nullable final String signingUid, final Set pubEncKeys, final KeySelectionStrategy keySelectionStrategy, - final boolean armor) throws + final boolean armor, + final boolean textMode) throws IOException, PGPException { isDoSign = signingUid != null; @@ -186,7 +190,7 @@ private void setup(final OutputStream cipherTextSink, new BcPGPContentSignerBuilder(pgpSec.getPublicKey().getAlgorithm(), algorithmSuite.getHashAlgorithmCode().getAlgorithmId())); - signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, pgpPrivKey); + signatureGenerator.init(textMode ? PGPSignature.CANONICAL_TEXT_DOCUMENT : PGPSignature.BINARY_DOCUMENT, pgpPrivKey); final Iterator userIDs = pgpSec.getPublicKey().getUserIDs(); if (userIDs.hasNext()) { @@ -208,7 +212,7 @@ private void setup(final OutputStream cipherTextSink, encryptionDataStreamGenerator = new PGPLiteralDataGenerator(); encryptionDataStream = encryptionDataStreamGenerator - .open(compressionStream, PGPLiteralData.BINARY, "", new Date(), new byte[1 << 16]); + .open(compressionStream, textMode ? PGPLiteralData.TEXT : PGPLiteralData.BINARY, "", new Date(), new byte[1 << 16]); } @Override @@ -268,4 +272,4 @@ public void close() throws IOException { isClosed = true; } } -} \ No newline at end of file +} diff --git a/src/test/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/encrypting/EncryptWithOpenPGPTestDriver.java b/src/test/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/encrypting/EncryptWithOpenPGPTestDriver.java index f49019e0..a2fa03f9 100644 --- a/src/test/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/encrypting/EncryptWithOpenPGPTestDriver.java +++ b/src/test/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/encrypting/EncryptWithOpenPGPTestDriver.java @@ -91,10 +91,10 @@ void encryptAndSign(final InputStream in, OutputStream out, final Set