diff --git a/pgpainless-core/build.gradle b/pgpainless-core/build.gradle index bab6ecf1..5d251feb 100644 --- a/pgpainless-core/build.gradle +++ b/pgpainless-core/build.gradle @@ -21,6 +21,7 @@ dependencies { // Bouncy Castle api "org.bouncycastle:bcprov-jdk18on:$bouncyCastleVersion" + api "org.bouncycastle:bcutil-jdk18on:$bouncyPgVersion" api "org.bouncycastle:bcpg-jdk18on:$bouncyPgVersion" // api(files("../libs/bcpg-jdk18on-1.70.jar")) diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/CachingBcPublicKeyDataDecryptorFactory.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/CachingBcPublicKeyDataDecryptorFactory.java index 9196cc37..162d1fbb 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/CachingBcPublicKeyDataDecryptorFactory.java +++ b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/CachingBcPublicKeyDataDecryptorFactory.java @@ -4,8 +4,12 @@ package org.pgpainless.decryption_verification; +import org.bouncycastle.bcpg.AEADEncDataPacket; +import org.bouncycastle.bcpg.SymmetricEncIntegrityPacket; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPrivateKey; +import org.bouncycastle.openpgp.PGPSessionKey; +import org.bouncycastle.openpgp.operator.PGPDataDecryptor; import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory; import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory; import org.bouncycastle.util.encoders.Base64; @@ -27,25 +31,25 @@ import java.util.Map; * The result of that is then placed in the cache and returned. */ public class CachingBcPublicKeyDataDecryptorFactory - extends BcPublicKeyDataDecryptorFactory - implements CustomPublicKeyDataDecryptorFactory { + extends CustomPublicKeyDataDecryptorFactory { private static final Logger LOGGER = LoggerFactory.getLogger(CachingBcPublicKeyDataDecryptorFactory.class); + private final BcPublicKeyDataDecryptorFactory decryptorFactory; private final Map cachedSessionKeys = new HashMap<>(); private final SubkeyIdentifier decryptionKey; public CachingBcPublicKeyDataDecryptorFactory(PGPPrivateKey privateKey, SubkeyIdentifier decryptionKey) { - super(privateKey); + this.decryptorFactory = new BcPublicKeyDataDecryptorFactory(privateKey); this.decryptionKey = decryptionKey; } @Override - public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData) throws PGPException { + public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData, int pkeskVersion) throws PGPException { byte[] sessionKey = lookupSessionKeyData(secKeyData); if (sessionKey == null) { LOGGER.debug("Cache miss for encrypted session key " + Hex.toHexString(secKeyData[0])); - sessionKey = costlyRecoverSessionData(keyAlgorithm, secKeyData); + sessionKey = costlyRecoverSessionData(keyAlgorithm, secKeyData, pkeskVersion); cacheSessionKeyData(secKeyData, sessionKey); } else { LOGGER.debug("Cache hit for encrypted session key " + Hex.toHexString(secKeyData[0])); @@ -53,8 +57,8 @@ public class CachingBcPublicKeyDataDecryptorFactory return sessionKey; } - public byte[] costlyRecoverSessionData(int keyAlgorithm, byte[][] secKeyData) throws PGPException { - return super.recoverSessionData(keyAlgorithm, secKeyData); + public byte[] costlyRecoverSessionData(int keyAlgorithm, byte[][] secKeyData, int pkeskVersion) throws PGPException { + return decryptorFactory.recoverSessionData(keyAlgorithm, secKeyData, pkeskVersion); } private byte[] lookupSessionKeyData(byte[][] secKeyData) { @@ -91,4 +95,19 @@ public class CachingBcPublicKeyDataDecryptorFactory public SubkeyIdentifier getSubkeyIdentifier() { return decryptionKey; } + + @Override + public PGPDataDecryptor createDataDecryptor(boolean b, int i, byte[] bytes) throws PGPException { + return decryptorFactory.createDataDecryptor(b, i, bytes); + } + + @Override + public PGPDataDecryptor createDataDecryptor(AEADEncDataPacket aeadEncDataPacket, PGPSessionKey pgpSessionKey) throws PGPException { + return decryptorFactory.createDataDecryptor(aeadEncDataPacket, pgpSessionKey); + } + + @Override + public PGPDataDecryptor createDataDecryptor(SymmetricEncIntegrityPacket symmetricEncIntegrityPacket, PGPSessionKey pgpSessionKey) throws PGPException { + return decryptorFactory.createDataDecryptor(symmetricEncIntegrityPacket, pgpSessionKey); + } } diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactory.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactory.java index 91902cc7..2b07a059 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactory.java +++ b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactory.java @@ -4,6 +4,7 @@ package org.pgpainless.decryption_verification; +import org.bouncycastle.openpgp.operator.AbstractPublicKeyDataDecryptorFactory; import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory; import org.pgpainless.key.SubkeyIdentifier; @@ -14,7 +15,7 @@ import org.pgpainless.key.SubkeyIdentifier; * TPMs. * @see ConsumerOptions#addCustomDecryptorFactory(CustomPublicKeyDataDecryptorFactory) */ -public interface CustomPublicKeyDataDecryptorFactory extends PublicKeyDataDecryptorFactory { +public abstract class CustomPublicKeyDataDecryptorFactory extends AbstractPublicKeyDataDecryptorFactory { /** * Return the {@link SubkeyIdentifier} for which this particular {@link CustomPublicKeyDataDecryptorFactory} @@ -22,6 +23,6 @@ public interface CustomPublicKeyDataDecryptorFactory extends PublicKeyDataDecryp * * @return subkey identifier */ - SubkeyIdentifier getSubkeyIdentifier(); + abstract SubkeyIdentifier getSubkeyIdentifier(); } diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/HardwareSecurity.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/HardwareSecurity.java index fc88ef33..a8662557 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/HardwareSecurity.java +++ b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/HardwareSecurity.java @@ -29,11 +29,12 @@ public class HardwareSecurity { * @param keyId id of the key * @param keyAlgorithm algorithm * @param sessionKeyData encrypted session key + * @param pkeskVersion Public-Key Encrypted Session-Key Packet version * * @return decrypted session key * @throws HardwareSecurityException exception */ - byte[] decryptSessionKey(long keyId, int keyAlgorithm, byte[] sessionKeyData) + byte[] decryptSessionKey(long keyId, int keyAlgorithm, byte[] sessionKeyData, int pkeskVersion) throws HardwareSecurityException; } @@ -43,7 +44,7 @@ public class HardwareSecurity { * to a {@link DecryptionCallback}. * Users can provide such a callback to delegate decryption of messages to hardware security SDKs. */ - public static class HardwareDataDecryptorFactory implements CustomPublicKeyDataDecryptorFactory { + public static class HardwareDataDecryptorFactory extends CustomPublicKeyDataDecryptorFactory { private final DecryptionCallback callback; // luckily we can instantiate the BcPublicKeyDataDecryptorFactory with null as argument. @@ -63,11 +64,11 @@ public class HardwareSecurity { } @Override - public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData) + public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData, int pkeskVersion) throws PGPException { try { // delegate decryption to the callback - return callback.decryptSessionKey(subkey.getSubkeyId(), keyAlgorithm, secKeyData[0]); + return callback.decryptSessionKey(subkey.getSubkeyId(), keyAlgorithm, secKeyData[0], pkeskVersion); } catch (HardwareSecurityException e) { throw new PGPException("Hardware-backed decryption failed.", e); } diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.java index dd8cf0e2..81465a81 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.java +++ b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.java @@ -369,10 +369,14 @@ public class OpenPgpMessageInputStream extends DecryptionStream { private void processOnePassSignature() throws PGPException, IOException { syntaxVerifier.next(InputSymbol.OnePassSignature); - PGPOnePassSignature onePassSignature = packetInputStream.readOnePassSignature(); - LOGGER.debug("One-Pass-Signature Packet by key " + KeyIdUtil.formatKeyId(onePassSignature.getKeyID()) + - " at depth " + metadata.depth + " encountered"); - signatures.addOnePassSignature(onePassSignature); + try { + PGPOnePassSignature onePassSignature = packetInputStream.readOnePassSignature(); + LOGGER.debug("One-Pass-Signature Packet by key " + KeyIdUtil.formatKeyId(onePassSignature.getKeyID()) + + " at depth " + metadata.depth + " encountered"); + signatures.addOnePassSignature(onePassSignature); + } catch (UnsupportedPacketVersionException e) { + LOGGER.debug("Ignoring One-Pass-Signature Packet of unsupported version.", e); + } } private void processSignature() throws PGPException, IOException { diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/EllipticCurve.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/EllipticCurve.java index 2372896e..1ad0e2c6 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/EllipticCurve.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/EllipticCurve.java @@ -18,7 +18,6 @@ public enum EllipticCurve { _P256("prime256v1", 256), // prime256v1 is equivalent to P-256, see https://tools.ietf.org/search/rfc4492#page-32 _P384("secp384r1", 384), // secp384r1 is equivalent to P-384, see https://tools.ietf.org/search/rfc4492#page-32 _P521("secp521r1", 521), // secp521r1 is equivalent to P-521, see https://tools.ietf.org/search/rfc4492#page-32 - _SECP256K1("secp256k1", 256), _BRAINPOOLP256R1("brainpoolP256r1", 256), _BRAINPOOLP384R1("brainpoolP384r1", 384), _BRAINPOOLP512R1("brainpoolP512r1", 512) diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactoryTest.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactoryTest.java index 73c3bf56..71fbf9be 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactoryTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactoryTest.java @@ -55,14 +55,14 @@ public class CustomPublicKeyDataDecryptorFactoryTest { HardwareSecurity.DecryptionCallback hardwareDecryptionCallback = new HardwareSecurity.DecryptionCallback() { @Override - public byte[] decryptSessionKey(long keyId, int keyAlgorithm, byte[] sessionKeyData) + public byte[] decryptSessionKey(long keyId, int keyAlgorithm, byte[] sessionKeyData, int pkeskVersion) throws HardwareSecurity.HardwareSecurityException { // Emulate hardware decryption. try { PGPSecretKey decryptionKey = secretKey.getSecretKey(encryptionKey.getKeyID()); PGPPrivateKey privateKey = UnlockSecretKey.unlockSecretKey(decryptionKey, Passphrase.emptyPassphrase()); PublicKeyDataDecryptorFactory internal = new BcPublicKeyDataDecryptorFactory(privateKey); - return internal.recoverSessionData(keyAlgorithm, new byte[][] {sessionKeyData}); + return internal.recoverSessionData(keyAlgorithm, new byte[][] {sessionKeyData}, pkeskVersion); } catch (PGPException e) { throw new HardwareSecurity.HardwareSecurityException(); } diff --git a/version.gradle b/version.gradle index 8c2e3f0c..2bc838a2 100644 --- a/version.gradle +++ b/version.gradle @@ -8,7 +8,7 @@ allprojects { isSnapshot = true pgpainlessMinAndroidSdk = 10 javaSourceCompatibility = 1.8 - bouncyCastleVersion = '1.77' + bouncyCastleVersion = '1.80' bouncyPgVersion = bouncyCastleVersion junitVersion = '5.8.2' logbackVersion = '1.2.13'