Compare commits

...

21 Commits
main ... 1.6.5

Author SHA1 Message Date
Paul Schaub d92672bd85
PGPainless 1.6.5 2023-12-15 17:35:50 +01:00
Paul Schaub d0c38601c9
Update changelog 2023-12-07 17:39:55 +01:00
Paul Schaub e06f60f62c
Add method to change the expiration time of subkeys 2023-12-07 17:38:36 +01:00
Paul Schaub 2c271178cd
Allow null as keyExpirationTime (no expiry) 2023-12-07 17:38:01 +01:00
Paul Schaub 4d1d8083d3
PGPainless 1.6.5-SNAPSHOT 2023-11-30 20:53:28 +01:00
Paul Schaub 1981af77b2
PGPainless 1.6.4 2023-11-30 20:51:36 +01:00
Paul Schaub 8ec9f49b86
Update CHANGELOG 2023-11-30 20:46:02 +01:00
Paul Schaub 2f67df57df
Bump logback to 1.4.13 2023-11-30 20:45:07 +01:00
Paul Schaub 160e42c32b
Bump BC to 1.77 2023-11-30 20:43:24 +01:00
Paul Schaub 5a343a39d3
Backport 97455aa256
Add test for handling key with unknown signature subpacket
2023-11-30 20:13:22 +01:00
Paul Schaub 38db67df80
Backport 74c7b025a0
Do not choke on unknown signature subpackets
Fixes #418
2023-11-30 20:09:02 +01:00
Paul Schaub 4f85a29e0c
Backport f39d2c5566
Prevent subkey binding signature from predating subkey
Fixes #419
2023-11-30 20:04:22 +01:00
Paul Schaub b7e8b56e3d
Please the checkstyle checker 2023-11-30 19:55:42 +01:00
Daniel Gultsch c61a129e08
add unit test to read decryption stream beyond end 2023-11-30 19:55:29 +01:00
Paul Schaub 4b474b4683
Backport b0caa95378
Properly feed an EOS token to the push down automata in OpenPgpMessageInputStream.read()
2023-11-30 19:55:06 +01:00
Paul Schaub 0c5521f82a
Fix changelog version headers 2023-11-23 14:01:13 +01:00
Paul Schaub ab74e157d0
Update CHANGELOG 2023-11-23 13:58:40 +01:00
Paul Schaub d812a2a8b6
PGPainless 1.6.4-SNAPSHOT 2023-11-23 13:56:56 +01:00
Paul Schaub d09b646011
PGPainless 1.6.3 2023-11-23 13:55:04 +01:00
Paul Schaub e32d6ac34c
Bump sop-java to 7.0.1 2023-11-23 13:54:23 +01:00
Paul Schaub 93cf8cc8d9
Remove test with expired key material 2023-11-23 13:52:02 +01:00
15 changed files with 298 additions and 293 deletions

View File

@ -5,7 +5,22 @@ SPDX-License-Identifier: CC0-1.0
# PGPainless Changelog
# 1.6.2
## 1.6.5
- Add `SecretKeyRingEditor.setExpirationDateOfSubkey()`
## 1.6.4
- Bump `bcpg-jdk8on` to `1.77`
- Bump `bcprov-jdk18on` to `1.77`
- Bump `logback-core` and `logback-classic` to `1.4.13`
- Properly feed EOS tokens to the pushdown automaton when reaching the end of stream (thanks @iNPUTmice)
- Do not choke on unknown signature subpackets (thanks @Jerbell)
- Prevent timing issues resulting in subkey binding signatures predating the subkey (@thanks Jerbell)
## 1.6.3
- Bump `sop-java` to `7.0.1`
- `decrypt --verify-with`: Fix to not throw `NoSignature` exception (exit code 3) if `VERIFICATIONS` is empty
## 1.6.2
- Switch `bcpg` and `bcprov` artifacts from `-jdk15to18`variant to `-jdk18on`
- Bump `bcpg-jdk8on` to `1.76`
- Bump `bcprov-jdk18on` to `1.76`
@ -13,7 +28,7 @@ SPDX-License-Identifier: CC0-1.0
encrypting to legacy keys which do not carry any key flags.
- Allow overriding of reference time in `EncryptionOptions` and `SigningOptions`.
# 1.6.1
## 1.6.1
- `KeyRingBuilder`: Require UTF8 when adding user-ID via `addUserId(byte[])`
- `pgpainless-sop`: Remove dependency on jetbrains annotations
- Add `CertificateAuthority` interface to allow integration with [`pgpainless-wot`](https://github.com/pgpainless/pgpainless-wot)

View File

@ -191,7 +191,7 @@ repositories {
}
dependencies {
implementation 'org.pgpainless:pgpainless-core:1.6.2'
implementation 'org.pgpainless:pgpainless-core:1.6.5'
}
```

View File

@ -712,6 +712,7 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
public int read() throws IOException {
if (nestedInputStream == null) {
if (packetInputStream != null) {
syntaxVerifier.next(InputSymbol.EndOfSequence);
syntaxVerifier.assertValid();
}
return -1;

View File

@ -304,6 +304,16 @@ public class KeyRingBuilder implements KeyRingBuilderInterface<KeyRingBuilder> {
public static PGPKeyPair generateKeyPair(KeySpec spec)
throws NoSuchAlgorithmException, PGPException,
InvalidAlgorithmParameterException {
Date keyCreationDate = spec.getKeyCreationDate();
if (keyCreationDate == null) {
keyCreationDate = new Date();
}
return generateKeyPair(spec, keyCreationDate);
}
public static PGPKeyPair generateKeyPair(KeySpec spec, Date keyCreationDate)
throws NoSuchAlgorithmException, PGPException,
InvalidAlgorithmParameterException {
KeyType type = spec.getKeyType();
KeyPairGenerator certKeyGenerator = KeyPairGenerator.getInstance(type.getName(),
ProviderFactory.getProvider());
@ -312,8 +322,6 @@ public class KeyRingBuilder implements KeyRingBuilderInterface<KeyRingBuilder> {
// Create raw Key Pair
KeyPair keyPair = certKeyGenerator.generateKeyPair();
Date keyCreationDate = spec.getKeyCreationDate() != null ? spec.getKeyCreationDate() : new Date();
// Form PGP key pair
PGPKeyPair pgpKeyPair = ImplementationFactory.getInstance()
.getPGPKeyPair(type.getAlgorithm(), keyPair, keyCreationDate);

View File

@ -47,6 +47,7 @@ import org.pgpainless.key.protection.PasswordBasedSecretKeyRingProtector;
import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.key.protection.UnprotectedKeysProtector;
import org.pgpainless.key.protection.passphrase_provider.SolitaryPassphraseProvider;
import org.pgpainless.key.util.KeyIdUtil;
import org.pgpainless.key.util.KeyRingUtils;
import org.pgpainless.key.util.RevocationAttributes;
import org.pgpainless.signature.builder.DirectKeySelfSignatureBuilder;
@ -290,6 +291,7 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
@Override
public void modifyHashedSubpackets(SelfSignatureSubpackets hashedSubpackets) {
SignatureSubpacketsHelper.applyFrom(keySpec.getSubpackets(), (SignatureSubpackets) hashedSubpackets);
hashedSubpackets.setSignatureCreationTime(referenceTime);
}
};
@ -307,7 +309,7 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
@Nullable SelfSignatureSubpackets.Callback subpacketsCallback,
@Nonnull SecretKeyRingProtector secretKeyRingProtector)
throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException {
PGPKeyPair keyPair = KeyRingBuilder.generateKeyPair(keySpec);
PGPKeyPair keyPair = KeyRingBuilder.generateKeyPair(keySpec, referenceTime);
SecretKeyRingProtector subKeyProtector = PasswordBasedSecretKeyRingProtector
.forKeyId(keyPair.getKeyID(), subkeyPassphrase);
@ -608,6 +610,25 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
return this;
}
@Override
public SecretKeyRingEditorInterface setExpirationDateOfSubkey(@Nullable Date expiration, long keyId, @Nonnull SecretKeyRingProtector secretKeyRingProtector) throws PGPException {
// is primary key
if (keyId == secretKeyRing.getPublicKey().getKeyID()) {
return setExpirationDate(expiration, secretKeyRingProtector);
}
// is subkey
PGPPublicKey subkey = secretKeyRing.getPublicKey(keyId);
if (subkey != null) {
PGPSignature prevBinding = PGPainless.inspectKeyRing(secretKeyRing).getCurrentSubkeyBindingSignature(keyId);
PGPSignature bindingSig = reissueSubkeyBindingSignature(subkey, expiration, secretKeyRingProtector, prevBinding);
secretKeyRing = KeyRingUtils.injectCertification(secretKeyRing, subkey, bindingSig);
} else {
throw new NoSuchElementException("No subkey with ID " + KeyIdUtil.formatKeyId(keyId) + " found.");
}
return this;
}
@Override
public PGPPublicKeyRing createMinimalRevocationCertificate(
@Nonnull SecretKeyRingProtector secretKeyRingProtector,
@ -698,6 +719,57 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
return builder.build(publicKey);
}
private PGPSignature reissueSubkeyBindingSignature(
PGPPublicKey subkey,
Date expiration,
SecretKeyRingProtector secretKeyRingProtector,
PGPSignature prevSubkeyBindingSignature)
throws PGPException {
if (subkey == null) {
throw new IllegalArgumentException("Subkey MUST NOT be null.");
}
if (prevSubkeyBindingSignature == null) {
throw new IllegalArgumentException("Previous subkey binding signature for "
+ KeyIdUtil.formatKeyId(subkey.getKeyID()) + " MUST NOT be null.");
}
PGPPublicKey primaryKey = secretKeyRing.getPublicKey();
PGPSecretKey secretPrimaryKey = secretKeyRing.getSecretKey();
PGPSecretKey secretSubkey = secretKeyRing.getSecretKey(subkey.getKeyID());
if (secretPrimaryKey == null) {
throw new NoSuchElementException("Secret Key Ring does not contain secret-key component for the primary key.");
}
SubkeyBindingSignatureBuilder builder = new SubkeyBindingSignatureBuilder(
secretPrimaryKey, secretKeyRingProtector, prevSubkeyBindingSignature);
SelfSignatureSubpackets subpackets = builder.getHashedSubpackets();
if (referenceTime != null) {
subpackets.setSignatureCreationTime(referenceTime);
}
// Set expiration
subpackets.setKeyExpirationTime(subkey, expiration);
subpackets.setSignatureExpirationTime(null); // avoid copying sig exp time
List<KeyFlag> previousKeyFlags = SignatureSubpacketsUtil.parseKeyFlags(prevSubkeyBindingSignature);
if (previousKeyFlags != null && previousKeyFlags.contains(KeyFlag.SIGN_DATA)) {
if (secretSubkey == null) {
throw new NoSuchElementException("Secret keyring does not contain secret-key component for subkey " +
KeyIdUtil.formatKeyId(subkey.getKeyID()));
}
// Create new embedded back-sig
subpackets.clearEmbeddedSignatures();
try {
subpackets.addEmbeddedSignature(
new PrimaryKeyBindingSignatureBuilder(secretSubkey, secretKeyRingProtector)
.build(primaryKey));
} catch (IOException e) {
throw new PGPException("Cannot add embedded primary-key back signature.", e);
}
}
return builder.build(subkey);
}
private PGPSignature getPreviousDirectKeySignature() {
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeyRing, referenceTime);
return info.getLatestDirectKeySelfSignature();

View File

@ -469,6 +469,23 @@ public interface SecretKeyRingEditorInterface {
@Nonnull SecretKeyRingProtector secretKeyRingProtector)
throws PGPException;
/**
* Set the expiration date for the subkey identified by the given keyId to the given expiration date.
* If the key is supposed to never expire, then an expiration date of null is expected.
*
* @param expiration new expiration date of null
* @param keyId id of the subkey
* @param secretKeyRingProtector to unlock the secret key
* @return the builder
* @throws PGPException in case we cannot generate a new subkey-binding or self-signature with the
* changed expiration date
*/
SecretKeyRingEditorInterface setExpirationDateOfSubkey(
@Nullable Date expiration,
long keyId,
@Nonnull SecretKeyRingProtector secretKeyRingProtector)
throws PGPException;
/**
* Create a minimal, self-authorizing revocation certificate, containing only the primary key
* and a revocation signature.

View File

@ -46,11 +46,11 @@ public interface SelfSignatureSubpackets extends BaseSignatureSubpackets {
SelfSignatureSubpackets setPrimaryUserId(@Nullable PrimaryUserID primaryUserId);
SelfSignatureSubpackets setKeyExpirationTime(@Nonnull PGPPublicKey key, @Nonnull Date keyExpirationTime);
SelfSignatureSubpackets setKeyExpirationTime(@Nonnull PGPPublicKey key, @Nullable Date keyExpirationTime);
SelfSignatureSubpackets setKeyExpirationTime(@Nonnull Date keyCreationTime, @Nonnull Date keyExpirationTime);
SelfSignatureSubpackets setKeyExpirationTime(@Nonnull Date keyCreationTime, @Nullable Date keyExpirationTime);
SelfSignatureSubpackets setKeyExpirationTime(boolean isCritical, @Nonnull Date keyCreationTime, @Nonnull Date keyExpirationTime);
SelfSignatureSubpackets setKeyExpirationTime(boolean isCritical, @Nonnull Date keyCreationTime, @Nullable Date keyExpirationTime);
SelfSignatureSubpackets setKeyExpirationTime(boolean isCritical, long secondsFromCreationToExpiration);

View File

@ -271,18 +271,22 @@ public class SignatureSubpackets
}
@Override
public SignatureSubpackets setKeyExpirationTime(@Nonnull PGPPublicKey key, @Nonnull Date keyExpirationTime) {
public SignatureSubpackets setKeyExpirationTime(@Nonnull PGPPublicKey key, @Nullable Date keyExpirationTime) {
return setKeyExpirationTime(key.getCreationTime(), keyExpirationTime);
}
@Override
public SignatureSubpackets setKeyExpirationTime(@Nonnull Date keyCreationTime, @Nonnull Date keyExpirationTime) {
public SignatureSubpackets setKeyExpirationTime(@Nonnull Date keyCreationTime, @Nullable Date keyExpirationTime) {
return setKeyExpirationTime(true, keyCreationTime, keyExpirationTime);
}
@Override
public SignatureSubpackets setKeyExpirationTime(boolean isCritical, @Nonnull Date keyCreationTime, @Nonnull Date keyExpirationTime) {
return setKeyExpirationTime(isCritical, (keyExpirationTime.getTime() / 1000) - (keyCreationTime.getTime() / 1000));
public SignatureSubpackets setKeyExpirationTime(boolean isCritical, @Nonnull Date keyCreationTime, @Nullable Date keyExpirationTime) {
if (keyExpirationTime != null) {
return setKeyExpirationTime(isCritical, (keyExpirationTime.getTime() / 1000) - (keyCreationTime.getTime() / 1000));
} else {
return setKeyExpirationTime(isCritical, 0L);
}
}
@Override

View File

@ -35,7 +35,13 @@ public class SignatureSubpacketsHelper {
public static SignatureSubpackets applyFrom(PGPSignatureSubpacketVector vector, SignatureSubpackets subpackets) {
for (SignatureSubpacket subpacket : vector.toArray()) {
org.pgpainless.algorithm.SignatureSubpacket type = org.pgpainless.algorithm.SignatureSubpacket.requireFromCode(subpacket.getType());
org.pgpainless.algorithm.SignatureSubpacket type = org.pgpainless.algorithm.SignatureSubpacket.fromCode(subpacket.getType());
if (type == null) {
// Unknown subpacket, ignore and just add to the residuals
subpackets.addResidualSubpacket(subpacket);
continue;
}
switch (type) {
case signatureCreationTime:
case issuerKeyId:

View File

@ -1,272 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <info@pgpainless.org>
//
// SPDX-License-Identifier: Apache-2.0
package investigations;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.util.io.Streams;
import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.DocumentSignatureType;
import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
import org.pgpainless.decryption_verification.ConsumerOptions;
import org.pgpainless.decryption_verification.DecryptionStream;
import org.pgpainless.decryption_verification.MessageInspector;
import org.pgpainless.encryption_signing.EncryptionOptions;
import org.pgpainless.encryption_signing.EncryptionStream;
import org.pgpainless.encryption_signing.ProducerOptions;
import org.pgpainless.encryption_signing.SigningOptions;
import org.pgpainless.implementation.ImplementationFactory;
import org.pgpainless.implementation.JceImplementationFactory;
import org.pgpainless.key.protection.SecretKeyRingProtector;
public class KleopatraCompatibilityTest {
public static final String KLEOPATRA_PUBKEY = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" +
"\n" +
"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\n" +
"g94JEXpwhb9guKuzYzP/QeBp4qFu5FO87w==\n" +
"=Jz7i\n" +
"-----END PGP PUBLIC KEY BLOCK-----\n";
public static final String KLEOPATRA_SECKEY = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
"\n" +
"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\n" +
"=cgLL\n" +
"-----END PGP PRIVATE KEY BLOCK-----\n";
// signed and encrypted
public static final String KLEOPATRA_MESSAGE = "-----BEGIN PGP MESSAGE-----\n" +
"\n" +
"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\n" +
"=MgH4\n" +
"-----END PGP MESSAGE-----\n";
public static final String PGPAINLESS_MESSAGE = "-----BEGIN PGP MESSAGE-----\n" +
"Version: PGPainless\n" +
"\n" +
"hQGMA2gglaIyvWSdAQv/Y9Wx763qAM95+teCUPPNRc5Iwqbc5uFjxfbcwsHIWdiZ\n" +
"n2wHNUmd2dUqYgpqOcBwZ/fUJuoHj/uXKZ1pbz2QSVYaL9MulKpgWiVAo0K2w0Oc\n" +
"97KfZ0d66tcZIhslVpZW06+lXuwMyjjjExe32fAkPFnYyTNORljyYlb/RDSkh7Ke\n" +
"Q+48fLR2kitV0WyRZ+d9cMfx2+D2gWYiaFGek9SrhI8L+nNd4UKvM4K4sSq4JHYf\n" +
"DCxGPWYOaTculuX8dfDh3ftHbrmL2Ca7Iv4NB0kSduG8Gin2OWyeSIPIwpF2ci9g\n" +
"cIBssAYhmS88FQit5pW9z2RZ/e9XmYIP++kz3/EdI6DqkiPUv1fiHTrJBC93LvVg\n" +
"pq75h9RNFuUlqR09SVuB/uZB6tYgv77vy5lPFo+wmLjM41aS4+qI1hBI3Ym4XTc1\n" +
"spPA0sEHtQTQ/xRNYqGpwunJniMF3ukWpOB6UNvQld+p2lj8czexhEAcne1cjey/\n" +
"f0/WUnluSt0HIg8Mnd7s0ukBhb4YxjvARjuqi6PikGz4JPshRwB8dPtS9FQiRxL7\n" +
"obaPHXlmLwohEtT3akzoIj/9C3Y7qnfreSllDgRDxRVFPXy5QnQqpsTy2JuJ4cvo\n" +
"p55RE2kyJ3vBZlB6T53pSgC00hQnNxoqgy7aejRItlec7zx5DnEg8t4rA7LYEGLT\n" +
"MBLWbTRc/njH6GTyc/3x7j9k8V83exqpF6fXrE3GP1C3fBxHY2S9/5BFAlzimplz\n" +
"Mow4S15D04EllRRk6f9HKY598xS4QlDEW/f3utwkQ8+/lNqesVuV8n76WDldMv2O\n" +
"5gTqAZ/pKhDKRLY6km4B2+2IAt2zg+V141wryHJgE/4VyUbu7zZxDIcDouuATQvt\n" +
"wNMnntqy3NTbM7DefSiYe9IUsTUz/g0VQJikoJx+rdX6YzQnRk/cmwvELnskQjSk\n" +
"aGd92A4ousaM299IOkbpLvFaJdrs7cLH0rEQTG5S3tRJSLEnjr94BUVtpIhQDo3i\n" +
"455UahKcCx/KhyIzo+8OdH0TYZf5ZFGLdTrqgi0ybAHcLrXkM+g2JOsst99CeRUq\n" +
"f/T4oFvuDSlLU56iWlLVE7gvDBibXfWIJ65YBHY4ueEzBC/3xOVj+dmTM2JfUSX7\n" +
"mqD25NaDCOuN4WhJmZHC1wyipj3KYT2bLg4gasHr/LvEI+Df/DREdXtrYAqPqZYU\n" +
"0QuubMF4n3hMqmu2wA==\n" +
"=fMRM\n" +
"-----END PGP MESSAGE-----";
@Test
public void testMessageDecryptionAndVerification() throws PGPException, IOException {
ImplementationFactory.setFactoryImplementation(new JceImplementationFactory());
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(KLEOPATRA_SECKEY);
PGPPublicKeyRing publicKeys = PGPainless.readKeyRing().publicKeyRing(KLEOPATRA_PUBKEY);
ConsumerOptions options = new ConsumerOptions()
.addDecryptionKey(secretKeys)
.addVerificationCert(publicKeys);
ByteArrayOutputStream out = new ByteArrayOutputStream();
DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify()
.onInputStream(new ByteArrayInputStream(KLEOPATRA_MESSAGE.getBytes(StandardCharsets.UTF_8)))
.withOptions(options);
Streams.pipeAll(decryptionStream, out);
decryptionStream.close();
}
@Test
public void testEncryptAndSignMessage() throws PGPException, IOException {
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(KLEOPATRA_SECKEY);
PGPPublicKeyRing publicKeys = PGPainless.readKeyRing().publicKeyRing(KLEOPATRA_PUBKEY);
ProducerOptions options = ProducerOptions.signAndEncrypt(
EncryptionOptions.encryptCommunications()
.addRecipient(publicKeys)
.overrideEncryptionAlgorithm(SymmetricKeyAlgorithm.AES_128),
SigningOptions.get()
.addInlineSignature(SecretKeyRingProtector.unprotectedKeys(), secretKeys, DocumentSignatureType.BINARY_DOCUMENT)
);
ByteArrayOutputStream out = new ByteArrayOutputStream();
EncryptionStream encryptionStream = PGPainless.encryptAndOrSign()
.onOutputStream(out)
.withOptions(options);
ByteArrayInputStream in = new ByteArrayInputStream("Hallo, Welt!\n\n".getBytes(StandardCharsets.UTF_8));
Streams.pipeAll(in, encryptionStream);
encryptionStream.close();
}
@Test
public void testMessageInspection() throws PGPException, IOException {
MessageInspector.EncryptionInfo info = MessageInspector.determineEncryptionInfoForMessage(
new ByteArrayInputStream(KLEOPATRA_MESSAGE.getBytes(StandardCharsets.UTF_8)));
}
}

View File

@ -83,6 +83,24 @@ public class DecryptAndVerifyMessageTest {
assertEquals(new SubkeyIdentifier(TestKeys.JULIET_FINGERPRINT), metadata.getDecryptionKey());
}
@TestTemplate
@ExtendWith(TestAllImplementations.class)
public void decryptMessageAndReadBeyondEndTest() throws Exception {
final String encryptedMessage = TestKeys.MSG_SIGN_CRYPT_JULIET_JULIET;
final ConsumerOptions options = new ConsumerOptions()
.addDecryptionKey(juliet)
.addVerificationCert(KeyRingUtils.publicKeyRingFrom(juliet));
try (DecryptionStream decryptor = PGPainless.decryptAndOrVerify()
.onInputStream(new ByteArrayInputStream(encryptedMessage.getBytes()))
.withOptions(options);
ByteArrayOutputStream toPlain = new ByteArrayOutputStream()) {
Streams.pipeAll(decryptor, toPlain);
assertEquals(-1, decryptor.read());
}
}
@TestTemplate
@ExtendWith(TestAllImplementations.class)
public void decryptMessageAndVerifySignatureByteByByteTest() throws Exception {

View File

@ -0,0 +1,43 @@
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.key;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless;
import org.pgpainless.key.protection.SecretKeyRingProtector;
import java.io.IOException;
import java.util.Date;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class KeyWithUnsupportedSignatureSubpacketTest {
@Test
public void testCanSetExpirationDateOnKeyContainingUnknownSubpacket34() throws IOException, PGPException {
String KEY = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
"\n" +
"lFgEZWiyNhYJKwYBBAHaRw8BAQdA71QipJ0CAqOEqQWjuoQE4E7LarKSrNDwE/6K\n" +
"bQNrCLwAAQCtJ8kVG2AmbDfdVtr/7Ag+yBh0oCvjRvyUCOyIbruOeg+6tClTdWJw\n" +
"YWNrZXQzNCBUZXN0S2V5IDx0ZXN0QHBncGFpbmxlc3Mub3JnPoiTBBMWCgA7FiEE\n" +
"zhy5yrnZYU/iBza4G03SQVuWqx0FAmVosjYCGwMFCwkIBwICIgIGFQoJCAsCBBYC\n" +
"AwECHgcCF4AACgkQG03SQVuWqx1UGgD+IYLeh9t5eJCEnzueuOTYnTnrzyhnLgm9\n" +
"dw5qwMXU8VQA/28GCOb7610hyjiBbrrcshkWAKuMwp8bUSz5FOeS5cQEnF0EZWiy\n" +
"NhIKKwYBBAGXVQEFAQEHQK99ClLDYtn0I2b6Y26NhaL0RWcrNoI/ci0xgXEK2L0Y\n" +
"AwEIBwAA/06qciQHI0v7MP2LMWm/ZuTJwzlPqV8VsBhrDMyUPUD4D52IeAQYFgoA\n" +
"IBYhBM4cucq52WFP4gc2uBtN0kFblqsdBQJlaLI2AhsMAAoJEBtN0kFblqsdRQ0A\n" +
"/iUJ/Fp+D2RjZL+aiwByIxPCVvMJ7a28+GQGjg3hsU2BAP474dfOOVZiTDLWWxsB\n" +
"wxfzOAQxXDhgR9xd/Lk3MNJxDg==\n" +
"=YAt0\n" +
"-----END PGP PRIVATE KEY BLOCK-----";
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(KEY);
assertNotNull(secretKeys);
PGPainless.modifyKeyRing(secretKeys)
.setExpirationDate(new Date(), SecretKeyRingProtector.unprotectedKeys())
.done();
}
}

View File

@ -0,0 +1,93 @@
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.key.modification;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.junit.JUtils;
import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.EncryptionPurpose;
import org.pgpainless.key.OpenPgpFingerprint;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.util.DateUtil;
public class ChangeSubkeyExpirationTimeTest {
@Test
public void changeExpirationTimeOfSubkey() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("Alice");
Date now = secretKeys.getPublicKey().getCreationTime();
Date inAnHour = new Date(now.getTime() + 1000 * 60 * 60);
PGPPublicKey encryptionKey = PGPainless.inspectKeyRing(secretKeys)
.getEncryptionSubkeys(EncryptionPurpose.ANY).get(0);
secretKeys = PGPainless.modifyKeyRing(secretKeys)
.setExpirationDateOfSubkey(
inAnHour,
encryptionKey.getKeyID(),
SecretKeyRingProtector.unprotectedKeys())
.done();
JUtils.assertDateEquals(inAnHour, PGPainless.inspectKeyRing(secretKeys)
.getSubkeyExpirationDate(OpenPgpFingerprint.of(encryptionKey)));
}
@Test
public void changeExpirationTimeOfExpiredSubkey() throws PGPException, IOException {
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(
"-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
"Version: PGPainless\n" +
"Comment: CA52 4D5D E3D8 9CD9 105B BA45 3761 076B C6B5 3000\n" +
"Comment: Alice <alice@pgpainless.org>\n" +
"\n" +
"lFgEZXHykRYJKwYBBAHaRw8BAQdATArrVxPEpuA/wcayAxRl/v1tIYJSe4MCA/fO\n" +
"84CFgpcAAP9uZkLjoBIQAjUTEiS8Wk3sui3u4mJ4WVQEpNhQSpq37g8gtBxBbGlj\n" +
"ZSA8YWxpY2VAcGdwYWlubGVzcy5vcmc+iJUEExYKAEcFAmVx8pIJEDdhB2vGtTAA\n" +
"FiEEylJNXePYnNkQW7pFN2EHa8a1MAACngECmwEFFgIDAQAECwkIBwUVCgkICwWJ\n" +
"CWYBgAKZAQAAG3oA/0iJbwyjGOTa2RlgBKdmFjlBG5uwMGheKge/aZBbdUd8AQCB\n" +
"8NFWmyLlne4hDMM2g8RFf/W156wnyTH7jTQLx2sZDJxYBGVx8pIWCSsGAQQB2kcP\n" +
"AQEHQLQt6ns7yTxLvIWXqFCekh6QEvUumhHvCTjZPXa/UxCNAAEA+FHhZ1uik6PN\n" +
"Pwli9Tp9QGddf3pwQw+OL/K7gpZO3sgQHYjVBBgWCgB9BQJlcfKSAp4BApsCBRYC\n" +
"AwEABAsJCAcFFQoJCAtfIAQZFgoABgUCZXHykgAKCRCRKlHdDPaYKjyZAQD10Km4\n" +
"Qs37yF9bntS+z9Va7AMUuBlzYF5H/nXCRuqQTAEA60q++7Xwj94yLfoAfxH0V6Wd\n" +
"L2rDJCDZ3FFMlycToQMACgkQN2EHa8a1MADmDgD9EGzH6pPYRW5vWQGXNsr7PMWK\n" +
"LlBnevc0DaVWEHTu9tcA/iezQ9R+A90qcE1+HeNIJbSB89yIoJje2vePRV/JakAI\n" +
"nF0EZXHykhIKKwYBBAGXVQEFAQEHQOiLc02OQJD9qdpsyR6bJ52Cu8rUMlEJOELz\n" +
"1858OoQyAwEIBwAA/3YkHGmnVaQvUpSwlCInOvHvjLNLH9b9Lh/OxiuSoMgIEASI\n" +
"dQQYFgoAHQUCZXHykgKeAQKbDAUWAgMBAAQLCQgHBRUKCQgLAAoJEDdhB2vGtTAA\n" +
"1nkBAPAUcHxI1O+fE/QzuLANLHDeWc3Mc09KKnWoTkt/kk5VAQCIPlKQAcmmKdYE\n" +
"Tiz8woSKLQKswKr/jVMqnUiGPsU/DoiSBBgWCgBECRA3YQdrxrUwABYhBMpSTV3j\n" +
"2JzZEFu6RTdhB2vGtTAABYJlcfL6Ap4BApsMBRYCAwEABAsJCAcFFQoJCAsFiQAA\n" +
"AGgAAMNmAQDN/TML2zdgBNkfh7TIqbI4Flx54Yi7qEjSXg0Z+tszHgD/e1Bf+xEs\n" +
"BC9ewVsyQsnj3B0FliGYaPiQeoY/FGBmYQs=\n" +
"=5Ur6\n" +
"-----END PGP PRIVATE KEY BLOCK-----"
);
assertNotNull(secretKeys);
// subkey is expired at 2023-12-07 16:29:46 UTC
OpenPgpFingerprint encryptionSubkey = new OpenPgpV4Fingerprint("2E541354A23C9943375EC27A3EF133ED8720D636");
JUtils.assertDateEquals(
DateUtil.parseUTCDate("2023-12-07 16:29:46 UTC"),
PGPainless.inspectKeyRing(secretKeys).getSubkeyExpirationDate(encryptionSubkey));
// re-validate the subkey by setting its expiry to null (no expiry)
secretKeys = PGPainless.modifyKeyRing(secretKeys)
.setExpirationDateOfSubkey(null, encryptionSubkey.getKeyId(), SecretKeyRingProtector.unprotectedKeys())
.done();
assertNull(PGPainless.inspectKeyRing(secretKeys).getSubkeyExpirationDate(encryptionSubkey));
}
}

View File

@ -23,7 +23,7 @@ To start using pgpainless-sop in your code, include the following lines in your
...
dependencies {
...
implementation "org.pgpainless:pgpainless-sop:1.6.2"
implementation "org.pgpainless:pgpainless-sop:1.6.5"
...
}
@ -34,7 +34,7 @@ dependencies {
<dependency>
<groupId>org.pgpainless</groupId>
<artifactId>pgpainless-sop</artifactId>
<version>1.6.2</version>
<version>1.6.5</version>
</dependency>
...
</dependencies>

View File

@ -4,16 +4,16 @@
allprojects {
ext {
shortVersion = '1.6.3'
isSnapshot = true
shortVersion = '1.6.5'
isSnapshot = false
pgpainlessMinAndroidSdk = 10
javaSourceCompatibility = 1.8
bouncyCastleVersion = '1.76'
bouncyCastleVersion = '1.77'
bouncyPgVersion = bouncyCastleVersion
junitVersion = '5.8.2'
logbackVersion = '1.2.11'
logbackVersion = '1.4.13'
mockitoVersion = '4.5.1'
slf4jVersion = '1.7.36'
sopJavaVersion = '7.0.0'
sopJavaVersion = '7.0.1'
}
}