Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added a builder method to sign/encrypt as a text document #61

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public final class BuildEncryptionOutputStreamAPI {
private String signWith;
private Set<PGPPublicKey> recipients;
private boolean armorOutput;
private boolean textMode;

// Signature

Expand Down Expand Up @@ -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 {

Expand Down Expand Up @@ -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();
}
}
}
Expand Down Expand Up @@ -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)
Expand All @@ -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;
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand All @@ -93,7 +94,8 @@ public static OutputStream create(final KeyringConfig config,
final OutputStream cipherTextSink,
final KeySelectionStrategy keySelectionStrategy,
final boolean armor,
final Set<PGPPublicKey> encryptTo)
final Set<PGPPublicKey> encryptTo,
final boolean textMode)
throws IOException, PGPException, NoSuchAlgorithmException, NoSuchProviderException {

requireNonNull(config, "callback must not be null");
Expand All @@ -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;
}

Expand All @@ -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
Expand All @@ -134,7 +137,8 @@ private void setup(final OutputStream cipherTextSink,
@Nullable final String signingUid,
final Set<PGPPublicKey> pubEncKeys,
final KeySelectionStrategy keySelectionStrategy,
final boolean armor) throws
final boolean armor,
final boolean textMode) throws
IOException, PGPException {
isDoSign = signingUid != null;

Expand Down Expand Up @@ -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()) {
Expand All @@ -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
Expand Down Expand Up @@ -268,4 +272,4 @@ public void close() throws IOException {
isClosed = true;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,10 @@ void encryptAndSign(final InputStream in, OutputStream out, final Set<PGPPublicK

try (final OutputStream encryptionStream = PGPEncryptingStream
.create(config, algorithmSuite, signatureUid, out, keySelectionStrategy, armor,
pubEncKeys)) {
pubEncKeys, false)) {
Streams.pipeAll(in, encryptionStream);
encryptionStream.flush();
}
out.flush();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SignatureException;
Expand Down Expand Up @@ -127,6 +126,41 @@ public void encryptAndSignBinary_thenDecryptAndVerify_yieldsOriginalPlaintext()
assertArrayEquals(expectedPlaintext, decryptedPlaintext);
}

@Test
public void encryptAndSignTextModeBinary_thenDecryptAndVerify_yieldsOriginalPlaintext()
throws IOException, PGPException, NoSuchAlgorithmException, NoSuchProviderException, SignatureException {
final byte[] expectedPlaintext = ExampleMessages.IMPORTANT_QUOTE_TEXT.getBytes("US-ASCII");

ByteArrayOutputStream cipherText = new ByteArrayOutputStream();

final OutputStream encryptionStream = BouncyGPG
.encryptToStream()
.withConfig(Configs.keyringConfigFromFilesForSender())
.withAlgorithms(algorithmSuite)
.toRecipient("recipient@example.com")
.andSignWith("sender@example.com")
.binaryOutput()
.textMode()
.andWriteTo(cipherText);

encryptionStream.write(expectedPlaintext);
encryptionStream.close();
cipherText.close();

ByteArrayInputStream cipherTextAsSource = new ByteArrayInputStream(cipherText.toByteArray());

// Decrypt
final InputStream decryptedPlaintextStream = BouncyGPG
.decryptAndVerifyStream()
.withConfig(Configs.keyringConfigFromResourceForRecipient())
.andRequireSignatureFromAllKeys("sender@example.com")
.fromEncryptedInputStream(cipherTextAsSource);

final byte[] decryptedPlaintext = Streams.readAll(decryptedPlaintextStream);

assertArrayEquals(expectedPlaintext, decryptedPlaintext);
}


@Test
public void encryptAndSignBinaryWithSHA256_AES256_thenDecryptAndVerify_yieldsOriginalPlaintext()
Expand Down