1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-12-25 04:17:59 +01:00

Identify custom decryptor factories by subkey id

This commit is contained in:
Paul Schaub 2022-10-20 16:07:31 +02:00
parent 2fdfdfa63e
commit 344ad1c982
5 changed files with 22 additions and 12 deletions

View file

@ -25,6 +25,7 @@ import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory; import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
import org.pgpainless.decryption_verification.cleartext_signatures.InMemoryMultiPassStrategy; import org.pgpainless.decryption_verification.cleartext_signatures.InMemoryMultiPassStrategy;
import org.pgpainless.decryption_verification.cleartext_signatures.MultiPassStrategy; import org.pgpainless.decryption_verification.cleartext_signatures.MultiPassStrategy;
import org.pgpainless.key.SubkeyIdentifier;
import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.signature.SignatureUtils; import org.pgpainless.signature.SignatureUtils;
import org.pgpainless.util.Passphrase; import org.pgpainless.util.Passphrase;
@ -49,7 +50,7 @@ public class ConsumerOptions {
// Session key for decryption without passphrase/key // Session key for decryption without passphrase/key
private SessionKey sessionKey = null; private SessionKey sessionKey = null;
private final Map<Long, PublicKeyDataDecryptorFactory> customPublicKeyDataDecryptorFactories = new HashMap<>(); private final Map<SubkeyIdentifier, PublicKeyDataDecryptorFactory> customPublicKeyDataDecryptorFactories = new HashMap<>();
private final Map<PGPSecretKeyRing, SecretKeyRingProtector> decryptionKeys = new HashMap<>(); private final Map<PGPSecretKeyRing, SecretKeyRingProtector> decryptionKeys = new HashMap<>();
private final Set<Passphrase> decryptionPassphrases = new HashSet<>(); private final Set<Passphrase> decryptionPassphrases = new HashSet<>();
@ -249,11 +250,11 @@ public class ConsumerOptions {
* @return options * @return options
*/ */
public ConsumerOptions addCustomDecryptorFactory(@Nonnull CustomPublicKeyDataDecryptorFactory factory) { public ConsumerOptions addCustomDecryptorFactory(@Nonnull CustomPublicKeyDataDecryptorFactory factory) {
this.customPublicKeyDataDecryptorFactories.put(factory.getKeyId(), factory); this.customPublicKeyDataDecryptorFactories.put(factory.getSubkeyIdentifier(), factory);
return this; return this;
} }
Map<Long, PublicKeyDataDecryptorFactory> getCustomDecryptorFactories() { Map<SubkeyIdentifier, PublicKeyDataDecryptorFactory> getCustomDecryptorFactories() {
return new HashMap<>(customPublicKeyDataDecryptorFactories); return new HashMap<>(customPublicKeyDataDecryptorFactories);
} }

View file

@ -5,9 +5,10 @@
package org.pgpainless.decryption_verification; package org.pgpainless.decryption_verification;
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory; import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
import org.pgpainless.key.SubkeyIdentifier;
public interface CustomPublicKeyDataDecryptorFactory extends PublicKeyDataDecryptorFactory { public interface CustomPublicKeyDataDecryptorFactory extends PublicKeyDataDecryptorFactory {
long getKeyId(); SubkeyIdentifier getSubkeyIdentifier();
} }

View file

@ -409,7 +409,7 @@ public final class DecryptionStreamFactory {
} }
// Try custom PublicKeyDataDecryptorFactories (e.g. hardware-backed). // Try custom PublicKeyDataDecryptorFactories (e.g. hardware-backed).
Map<Long, PublicKeyDataDecryptorFactory> customFactories = options.getCustomDecryptorFactories(); Map<SubkeyIdentifier, PublicKeyDataDecryptorFactory> customFactories = options.getCustomDecryptorFactories();
for (PGPPublicKeyEncryptedData publicKeyEncryptedData : publicKeyProtected) { for (PGPPublicKeyEncryptedData publicKeyEncryptedData : publicKeyProtected) {
Long keyId = publicKeyEncryptedData.getKeyID(); Long keyId = publicKeyEncryptedData.getKeyID();
if (!customFactories.containsKey(keyId)) { if (!customFactories.containsKey(keyId)) {

View file

@ -11,6 +11,7 @@ import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.operator.PGPDataDecryptor; import org.bouncycastle.openpgp.operator.PGPDataDecryptor;
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory; import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory; import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory;
import org.pgpainless.key.SubkeyIdentifier;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@ -74,16 +75,16 @@ public class HardwareSecurity {
// luckily we can instantiate the BcPublicKeyDataDecryptorFactory with null as argument. // luckily we can instantiate the BcPublicKeyDataDecryptorFactory with null as argument.
private final PublicKeyDataDecryptorFactory factory = private final PublicKeyDataDecryptorFactory factory =
new BcPublicKeyDataDecryptorFactory(null); new BcPublicKeyDataDecryptorFactory(null);
private long keyId; private SubkeyIdentifier subkey;
/** /**
* Create a new {@link HardwareDataDecryptorFactory}. * Create a new {@link HardwareDataDecryptorFactory}.
* *
* @param callback decryption callback * @param callback decryption callback
*/ */
public HardwareDataDecryptorFactory(long keyId, DecryptionCallback callback) { public HardwareDataDecryptorFactory(SubkeyIdentifier subkeyIdentifier, DecryptionCallback callback) {
this.callback = callback; this.callback = callback;
this.keyId = keyId; this.subkey = subkeyIdentifier;
} }
@Override @Override
@ -91,7 +92,7 @@ public class HardwareSecurity {
throws PGPException { throws PGPException {
try { try {
// delegate decryption to the callback // delegate decryption to the callback
return callback.decryptSessionKey(keyId, keyAlgorithm, secKeyData[0]); return callback.decryptSessionKey(subkey.getSubkeyId(), keyAlgorithm, secKeyData[0]);
} catch (HardwareSecurityException e) { } catch (HardwareSecurityException e) {
throw new PGPException("Hardware-backed decryption failed.", e); throw new PGPException("Hardware-backed decryption failed.", e);
} }
@ -104,8 +105,14 @@ public class HardwareSecurity {
} }
@Override @Override
public long getKeyId() { public PGPDataDecryptor createDataDecryptor(int aeadAlgorithm, byte[] iv, int chunkSize, int encAlgorithm, byte[] key)
return keyId; throws PGPException {
return factory.createDataDecryptor(aeadAlgorithm, iv, chunkSize, encAlgorithm, key);
}
@Override
public SubkeyIdentifier getSubkeyIdentifier() {
return subkey;
} }
} }

View file

@ -19,6 +19,7 @@ import org.pgpainless.algorithm.EncryptionPurpose;
import org.pgpainless.encryption_signing.EncryptionOptions; import org.pgpainless.encryption_signing.EncryptionOptions;
import org.pgpainless.encryption_signing.EncryptionStream; import org.pgpainless.encryption_signing.EncryptionStream;
import org.pgpainless.encryption_signing.ProducerOptions; import org.pgpainless.encryption_signing.ProducerOptions;
import org.pgpainless.key.SubkeyIdentifier;
import org.pgpainless.key.info.KeyRingInfo; import org.pgpainless.key.info.KeyRingInfo;
import org.pgpainless.key.protection.UnlockSecretKey; import org.pgpainless.key.protection.UnlockSecretKey;
import org.pgpainless.util.Passphrase; import org.pgpainless.util.Passphrase;
@ -74,7 +75,7 @@ public class CustomPublicKeyDataDecryptorFactoryTest {
.withOptions(ConsumerOptions.get() .withOptions(ConsumerOptions.get()
.addCustomDecryptorFactory( .addCustomDecryptorFactory(
new HardwareSecurity.HardwareDataDecryptorFactory( new HardwareSecurity.HardwareDataDecryptorFactory(
encryptionKey.getKeyID(), new SubkeyIdentifier(cert, encryptionKey.getKeyID()),
hardwareDecryptionCallback))); hardwareDecryptionCallback)));
ByteArrayOutputStream decryptedOut = new ByteArrayOutputStream(); ByteArrayOutputStream decryptedOut = new ByteArrayOutputStream();