From 344ad1c982bce928c07493471d24e98f115da1ba Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 20 Oct 2022 16:07:31 +0200 Subject: [PATCH] Identify custom decryptor factories by subkey id --- .../ConsumerOptions.java | 7 ++++--- .../CustomPublicKeyDataDecryptorFactory.java | 3 ++- .../DecryptionStreamFactory.java | 2 +- .../HardwareSecurity.java | 19 +++++++++++++------ ...stomPublicKeyDataDecryptorFactoryTest.java | 3 ++- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/ConsumerOptions.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/ConsumerOptions.java index 0f02aba0..f8f59d36 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/ConsumerOptions.java +++ b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/ConsumerOptions.java @@ -25,6 +25,7 @@ import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory; import org.pgpainless.decryption_verification.cleartext_signatures.InMemoryMultiPassStrategy; import org.pgpainless.decryption_verification.cleartext_signatures.MultiPassStrategy; +import org.pgpainless.key.SubkeyIdentifier; import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.signature.SignatureUtils; import org.pgpainless.util.Passphrase; @@ -49,7 +50,7 @@ public class ConsumerOptions { // Session key for decryption without passphrase/key private SessionKey sessionKey = null; - private final Map customPublicKeyDataDecryptorFactories = new HashMap<>(); + private final Map customPublicKeyDataDecryptorFactories = new HashMap<>(); private final Map decryptionKeys = new HashMap<>(); private final Set decryptionPassphrases = new HashSet<>(); @@ -249,11 +250,11 @@ public class ConsumerOptions { * @return options */ public ConsumerOptions addCustomDecryptorFactory(@Nonnull CustomPublicKeyDataDecryptorFactory factory) { - this.customPublicKeyDataDecryptorFactories.put(factory.getKeyId(), factory); + this.customPublicKeyDataDecryptorFactories.put(factory.getSubkeyIdentifier(), factory); return this; } - Map getCustomDecryptorFactories() { + Map getCustomDecryptorFactories() { return new HashMap<>(customPublicKeyDataDecryptorFactories); } 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 43e8e723..37dc10a9 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 @@ -5,9 +5,10 @@ package org.pgpainless.decryption_verification; import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory; +import org.pgpainless.key.SubkeyIdentifier; public interface CustomPublicKeyDataDecryptorFactory extends PublicKeyDataDecryptorFactory { - long getKeyId(); + SubkeyIdentifier getSubkeyIdentifier(); } diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStreamFactory.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStreamFactory.java index 23e3e47d..451750ee 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStreamFactory.java +++ b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStreamFactory.java @@ -409,7 +409,7 @@ public final class DecryptionStreamFactory { } // Try custom PublicKeyDataDecryptorFactories (e.g. hardware-backed). - Map customFactories = options.getCustomDecryptorFactories(); + Map customFactories = options.getCustomDecryptorFactories(); for (PGPPublicKeyEncryptedData publicKeyEncryptedData : publicKeyProtected) { Long keyId = publicKeyEncryptedData.getKeyID(); if (!customFactories.containsKey(keyId)) { 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 d5bf60db..f234ff00 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 @@ -11,6 +11,7 @@ import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.operator.PGPDataDecryptor; import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory; import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory; +import org.pgpainless.key.SubkeyIdentifier; import java.util.HashSet; import java.util.Set; @@ -74,16 +75,16 @@ public class HardwareSecurity { // luckily we can instantiate the BcPublicKeyDataDecryptorFactory with null as argument. private final PublicKeyDataDecryptorFactory factory = new BcPublicKeyDataDecryptorFactory(null); - private long keyId; + private SubkeyIdentifier subkey; /** * Create a new {@link HardwareDataDecryptorFactory}. * * @param callback decryption callback */ - public HardwareDataDecryptorFactory(long keyId, DecryptionCallback callback) { + public HardwareDataDecryptorFactory(SubkeyIdentifier subkeyIdentifier, DecryptionCallback callback) { this.callback = callback; - this.keyId = keyId; + this.subkey = subkeyIdentifier; } @Override @@ -91,7 +92,7 @@ public class HardwareSecurity { throws PGPException { try { // delegate decryption to the callback - return callback.decryptSessionKey(keyId, keyAlgorithm, secKeyData[0]); + return callback.decryptSessionKey(subkey.getSubkeyId(), keyAlgorithm, secKeyData[0]); } catch (HardwareSecurityException e) { throw new PGPException("Hardware-backed decryption failed.", e); } @@ -104,8 +105,14 @@ public class HardwareSecurity { } @Override - public long getKeyId() { - return keyId; + public PGPDataDecryptor createDataDecryptor(int aeadAlgorithm, byte[] iv, int chunkSize, int encAlgorithm, byte[] key) + throws PGPException { + return factory.createDataDecryptor(aeadAlgorithm, iv, chunkSize, encAlgorithm, key); + } + + @Override + public SubkeyIdentifier getSubkeyIdentifier() { + return subkey; } } 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 4ea894e5..73c3bf56 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 @@ -19,6 +19,7 @@ import org.pgpainless.algorithm.EncryptionPurpose; import org.pgpainless.encryption_signing.EncryptionOptions; import org.pgpainless.encryption_signing.EncryptionStream; import org.pgpainless.encryption_signing.ProducerOptions; +import org.pgpainless.key.SubkeyIdentifier; import org.pgpainless.key.info.KeyRingInfo; import org.pgpainless.key.protection.UnlockSecretKey; import org.pgpainless.util.Passphrase; @@ -74,7 +75,7 @@ public class CustomPublicKeyDataDecryptorFactoryTest { .withOptions(ConsumerOptions.get() .addCustomDecryptorFactory( new HardwareSecurity.HardwareDataDecryptorFactory( - encryptionKey.getKeyID(), + new SubkeyIdentifier(cert, encryptionKey.getKeyID()), hardwareDecryptionCallback))); ByteArrayOutputStream decryptedOut = new ByteArrayOutputStream();