mirror of
https://github.com/pgpainless/pgpainless.git
synced 2025-09-09 10:19:39 +02:00
Bump BC to 1.80, apply required code changes
We had to rework the HardwareSecurity decryptor factory classes, which now take a PKESK version as additional argument Further, we had to remove support for generating secp256k1 EC keys. Lastly, parsing One-Pass-Signatures of unsupported versions in BC now throws, so we had to introduce a respective catch block.
This commit is contained in:
parent
739070681f
commit
001acb55ee
8 changed files with 46 additions and 21 deletions
|
@ -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"))
|
||||
|
||||
|
|
|
@ -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<String, byte[]> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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'
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue