diff --git a/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionBuilder.java b/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionBuilder.java index b41111fa..a1ea9536 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionBuilder.java +++ b/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionBuilder.java @@ -35,6 +35,7 @@ import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; import org.pgpainless.algorithm.CompressionAlgorithm; import org.pgpainless.algorithm.HashAlgorithm; +import org.pgpainless.algorithm.SignatureType; import org.pgpainless.algorithm.SymmetricKeyAlgorithm; import org.pgpainless.exception.SecretKeyNotFoundException; import org.pgpainless.key.OpenPgpV4Fingerprint; @@ -54,6 +55,7 @@ public class EncryptionBuilder implements EncryptionBuilderInterface { private OutputStream outputStream; private final Set encryptionKeys = new HashSet<>(); private boolean detachedSignature = false; + private SignatureType signatureType = SignatureType.BINARY_DOCUMENT; private final Set signingKeys = new HashSet<>(); private SecretKeyRingProtector signingKeysDecryptor; private SymmetricKeyAlgorithm symmetricKeyAlgorithm = SymmetricKeyAlgorithm.AES_128; @@ -257,17 +259,17 @@ public class EncryptionBuilder implements EncryptionBuilderInterface { } @Override - public Armor signWith(@Nonnull SecretKeyRingProtector decryptor, @Nonnull PGPSecretKey... keys) { + public DocumentType signWith(@Nonnull SecretKeyRingProtector decryptor, @Nonnull PGPSecretKey... keys) { return new SignWithImpl().signWith(decryptor, keys); } @Override - public Armor signWith(@Nonnull SecretKeyRingProtector decryptor, @Nonnull PGPSecretKeyRing... keyRings) { + public DocumentType signWith(@Nonnull SecretKeyRingProtector decryptor, @Nonnull PGPSecretKeyRing... keyRings) { return new SignWithImpl().signWith(decryptor, keyRings); } @Override - public Armor signWith(@Nonnull SecretKeyRingSelectionStrategy selectionStrategy, + public DocumentType signWith(@Nonnull SecretKeyRingSelectionStrategy selectionStrategy, @Nonnull SecretKeyRingProtector decryptor, @Nonnull MultiMap keys) throws SecretKeyNotFoundException { @@ -278,7 +280,7 @@ public class EncryptionBuilder implements EncryptionBuilderInterface { class SignWithImpl implements SignWith { @Override - public Armor signWith(@Nonnull SecretKeyRingProtector decryptor, + public DocumentType signWith(@Nonnull SecretKeyRingProtector decryptor, @Nonnull PGPSecretKey... keys) { if (keys.length == 0) { throw new IllegalArgumentException("Recipient list MUST NOT be empty."); @@ -291,11 +293,11 @@ public class EncryptionBuilder implements EncryptionBuilderInterface { } } EncryptionBuilder.this.signingKeysDecryptor = decryptor; - return new ArmorImpl(); + return new DocumentTypeImpl(); } @Override - public Armor signWith(@Nonnull SecretKeyRingProtector decryptor, + public DocumentType signWith(@Nonnull SecretKeyRingProtector decryptor, @Nonnull PGPSecretKeyRing... keys) { if (keys.length == 0) { throw new IllegalArgumentException("Recipient list MUST NOT be empty."); @@ -309,11 +311,11 @@ public class EncryptionBuilder implements EncryptionBuilderInterface { } } EncryptionBuilder.this.signingKeysDecryptor = decryptor; - return new ArmorImpl(); + return new DocumentTypeImpl(); } @Override - public Armor signWith(@Nonnull SecretKeyRingSelectionStrategy ringSelectionStrategy, + public DocumentType signWith(@Nonnull SecretKeyRingSelectionStrategy ringSelectionStrategy, @Nonnull SecretKeyRingProtector decryptor, @Nonnull MultiMap keys) { if (keys.isEmpty()) { @@ -332,6 +334,21 @@ public class EncryptionBuilder implements EncryptionBuilderInterface { } } } + return new DocumentTypeImpl(); + } + } + + class DocumentTypeImpl implements DocumentType { + + @Override + public Armor signBinaryDocument() { + EncryptionBuilder.this.signatureType = SignatureType.BINARY_DOCUMENT; + return new ArmorImpl(); + } + + @Override + public Armor signCanonicalText() { + EncryptionBuilder.this.signatureType = SignatureType.CANONICAL_TEXT_DOCUMENT; return new ArmorImpl(); } } @@ -363,6 +380,7 @@ public class EncryptionBuilder implements EncryptionBuilderInterface { EncryptionBuilder.this.outputStream, EncryptionBuilder.this.encryptionKeys, EncryptionBuilder.this.detachedSignature, + signatureType, privateKeys, EncryptionBuilder.this.symmetricKeyAlgorithm, EncryptionBuilder.this.hashAlgorithm, diff --git a/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionBuilderInterface.java b/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionBuilderInterface.java index fcec8046..22645d1d 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionBuilderInterface.java +++ b/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionBuilderInterface.java @@ -181,7 +181,7 @@ public interface EncryptionBuilderInterface { * @param keys secret keys * @return api handle */ - default Armor signWith(@Nonnull PGPSecretKey... keys) { + default DocumentType signWith(@Nonnull PGPSecretKey... keys) { return signWith(new UnprotectedKeysProtector(), keys); } @@ -193,7 +193,7 @@ public interface EncryptionBuilderInterface { * @param keys secret keys used for signing * @return api handle */ - Armor signWith(@Nonnull SecretKeyRingProtector decryptor, @Nonnull PGPSecretKey... keys); + DocumentType signWith(@Nonnull SecretKeyRingProtector decryptor, @Nonnull PGPSecretKey... keys); /** * Pass in a list of secret keys used for signing, along with a {@link SecretKeyRingProtector} used to unlock @@ -203,7 +203,7 @@ public interface EncryptionBuilderInterface { * @param keyRings secret keys used for signing * @return api handle */ - Armor signWith(@Nonnull SecretKeyRingProtector decryptor, @Nonnull PGPSecretKeyRing... keyRings); + DocumentType signWith(@Nonnull SecretKeyRingProtector decryptor, @Nonnull PGPSecretKeyRing... keyRings); /** * Pass in a map of secret keys for signing, as well as a {@link org.pgpainless.key.selection.key.SecretKeySelectionStrategy} @@ -218,13 +218,20 @@ public interface EncryptionBuilderInterface { * * @throws SecretKeyNotFoundException in case no suitable secret key can be found */ - Armor signWith(@Nonnull SecretKeyRingSelectionStrategy selectionStrategy, + DocumentType signWith(@Nonnull SecretKeyRingSelectionStrategy selectionStrategy, @Nonnull SecretKeyRingProtector decryptor, @Nonnull MultiMap keys) throws SecretKeyNotFoundException; } + interface DocumentType { + + Armor signBinaryDocument(); + + Armor signCanonicalText(); + } + interface Armor { /** diff --git a/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionStream.java b/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionStream.java index 23821b94..08f35959 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionStream.java +++ b/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionStream.java @@ -42,6 +42,7 @@ import org.bouncycastle.openpgp.operator.bc.BcPGPDataEncryptorBuilder; import org.bouncycastle.openpgp.operator.bc.BcPublicKeyKeyEncryptionMethodGenerator; import org.pgpainless.algorithm.CompressionAlgorithm; import org.pgpainless.algorithm.HashAlgorithm; +import org.pgpainless.algorithm.SignatureType; import org.pgpainless.algorithm.SymmetricKeyAlgorithm; import org.pgpainless.decryption_verification.DetachedSignature; import org.pgpainless.decryption_verification.OpenPgpMetadata; @@ -63,6 +64,7 @@ public final class EncryptionStream extends OutputStream { private final CompressionAlgorithm compressionAlgorithm; private final Set encryptionKeys; private final boolean detachedSignature; + private final SignatureType signatureType; private final Map signingKeys; private final boolean asciiArmor; @@ -85,6 +87,7 @@ public final class EncryptionStream extends OutputStream { EncryptionStream(@Nonnull OutputStream targetOutputStream, @Nonnull Set encryptionKeys, boolean detachedSignature, + SignatureType signatureType, @Nonnull Map signingKeys, @Nonnull SymmetricKeyAlgorithm symmetricKeyAlgorithm, @Nonnull HashAlgorithm hashAlgorithm, @@ -97,6 +100,7 @@ public final class EncryptionStream extends OutputStream { this.compressionAlgorithm = compressionAlgorithm; this.encryptionKeys = Collections.unmodifiableSet(encryptionKeys); this.detachedSignature = detachedSignature; + this.signatureType = signatureType; this.signingKeys = Collections.unmodifiableMap(signingKeys); this.asciiArmor = asciiArmor; @@ -156,7 +160,7 @@ public final class EncryptionStream extends OutputStream { privateKey.getPublicKeyPacket().getAlgorithm(), hashAlgorithm.getAlgorithmId()); PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder); - signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, privateKey); + signatureGenerator.init(signatureType.getCode(), privateKey); signatureGenerators.put(fingerprint, signatureGenerator); } } diff --git a/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/EncryptDecryptTest.java b/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/EncryptDecryptTest.java index 7a167882..7b5bf5f7 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/EncryptDecryptTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/EncryptDecryptTest.java @@ -142,6 +142,7 @@ public class EncryptDecryptTest { .toRecipients(recipientPub) .usingSecureAlgorithms() .signWith(keyDecryptor, senderSec) + .signBinaryDocument() .noArmor(); Streams.pipeAll(new ByteArrayInputStream(secretMessage), encryptor); @@ -197,6 +198,7 @@ public class EncryptDecryptTest { .doNotEncrypt() .createDetachedSignature() .signWith(keyRingProtector, signingKeys) + .signBinaryDocument() .noArmor(); Streams.pipeAll(inputStream, signer); signer.close(); @@ -238,6 +240,7 @@ public class EncryptDecryptTest { EncryptionStream signer = PGPainless.encryptAndOrSign().onOutputStream(signOut) .doNotEncrypt() .signWith(keyRingProtector, signingKeys) + .signBinaryDocument() .asciiArmor(); Streams.pipeAll(inputStream, signer); signer.close(); diff --git a/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/LengthTest.java b/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/LengthTest.java index 26654673..ccb9afda 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/LengthTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/LengthTest.java @@ -26,7 +26,6 @@ import java.util.Random; import java.util.logging.Level; import java.util.logging.Logger; -import jdk.nashorn.internal.ir.annotations.Ignore; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing; @@ -96,7 +95,6 @@ public class LengthTest { encryptDecryptForSecretKeyRings(sender, recipient); } - @Ignore private void encryptDecryptForSecretKeyRings(PGPSecretKeyRing senderSec, PGPSecretKeyRing recipientSec) throws PGPException, IOException { @@ -117,6 +115,7 @@ public class LengthTest { // .doNotEncrypt() .usingSecureAlgorithms() .signWith(keyDecryptor, senderSec) + .signBinaryDocument() .noArmor(); Streams.pipeAll(new ByteArrayInputStream(secretMessage), encryptor); diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/modification/ChangeSecretKeyRingPassphraseTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/modification/ChangeSecretKeyRingPassphraseTest.java index bc84e858..7cc3fd80 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/key/modification/ChangeSecretKeyRingPassphraseTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/key/modification/ChangeSecretKeyRingPassphraseTest.java @@ -182,6 +182,7 @@ public class ChangeSecretKeyRingPassphraseTest { EncryptionStream stream = PGPainless.encryptAndOrSign().onOutputStream(dummy) .doNotEncrypt() .signWith(PasswordBasedSecretKeyRingProtector.forKey(keyRing, passphrase), keyRing) + .signBinaryDocument() .noArmor(); Streams.pipeAll(new ByteArrayInputStream(dummyMessage.getBytes()), stream);