1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2025-04-16 03:28:37 +02:00

Bump bcpg, bcprov to 1.80, add bcutil dependency

Adding bcutil as a dependency is apparently required now.
See https://github.com/bcgit/bc-java/issues/1977
This commit is contained in:
Paul Schaub 2025-03-11 22:04:03 +01:00
parent 9a1a01fe05
commit 883eb80a63
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
6 changed files with 47 additions and 14 deletions
pgpainless-core
version.gradle

View file

@ -22,6 +22,7 @@ dependencies {
// Bouncy Castle
api "org.bouncycastle:bcprov-jdk18on:$bouncyCastleVersion"
api "org.bouncycastle:bcpg-jdk18on:$bouncyPgVersion"
api "org.bouncycastle:bcutil-jdk18on:$bouncyCastleVersion"
// api(files("../libs/bcpg-jdk18on-1.70.jar"))
// @Nullable, @Nonnull annotations

View file

@ -4,7 +4,11 @@
package org.pgpainless.decryption_verification
import org.bouncycastle.bcpg.AEADEncDataPacket
import org.bouncycastle.bcpg.SymmetricEncIntegrityPacket
import org.bouncycastle.openpgp.PGPPrivateKey
import org.bouncycastle.openpgp.PGPSessionKey
import org.bouncycastle.openpgp.operator.PGPDataDecryptor
import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory
import org.bouncycastle.util.encoders.Base64
import org.pgpainless.key.SubkeyIdentifier
@ -21,16 +25,34 @@ import org.pgpainless.key.SubkeyIdentifier
class CachingBcPublicKeyDataDecryptorFactory(
privateKey: PGPPrivateKey,
override val subkeyIdentifier: SubkeyIdentifier
) : BcPublicKeyDataDecryptorFactory(privateKey), CustomPublicKeyDataDecryptorFactory {
) : CustomPublicKeyDataDecryptorFactory() {
private val decryptorFactory: BcPublicKeyDataDecryptorFactory =
BcPublicKeyDataDecryptorFactory(privateKey)
private val cachedSessions: MutableMap<String, ByteArray> = mutableMapOf()
override fun createDataDecryptor(p0: Boolean, p1: Int, p2: ByteArray?): PGPDataDecryptor {
return decryptorFactory.createDataDecryptor(p0, p1, p2)
}
override fun createDataDecryptor(p0: AEADEncDataPacket?, p1: PGPSessionKey?): PGPDataDecryptor {
return decryptorFactory.createDataDecryptor(p0, p1)
}
override fun createDataDecryptor(
p0: SymmetricEncIntegrityPacket?,
p1: PGPSessionKey?
): PGPDataDecryptor {
return decryptorFactory.createDataDecryptor(p0, p1)
}
override fun recoverSessionData(
keyAlgorithm: Int,
secKeyData: Array<out ByteArray>
secKeyData: Array<out ByteArray>,
pkeskVersion: Int
): ByteArray =
lookupSessionKeyData(secKeyData)
?: costlyRecoverSessionData(keyAlgorithm, secKeyData).also {
?: costlyRecoverSessionData(keyAlgorithm, secKeyData, pkeskVersion).also {
cacheSessionKeyData(secKeyData, it)
}
@ -39,8 +61,9 @@ class CachingBcPublicKeyDataDecryptorFactory(
private fun costlyRecoverSessionData(
keyAlgorithm: Int,
secKeyData: Array<out ByteArray>
): ByteArray = super.recoverSessionData(keyAlgorithm, secKeyData)
secKeyData: Array<out ByteArray>,
pkeskVersion: Int
): ByteArray = decryptorFactory.recoverSessionData(keyAlgorithm, secKeyData, pkeskVersion)
private fun cacheSessionKeyData(secKeyData: Array<out ByteArray>, sessionKey: ByteArray) {
cachedSessions[toKey(secKeyData)] = sessionKey.clone()

View file

@ -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
*
* @see [ConsumerOptions.addCustomDecryptorFactory]
*/
interface CustomPublicKeyDataDecryptorFactory : PublicKeyDataDecryptorFactory {
abstract class CustomPublicKeyDataDecryptorFactory : AbstractPublicKeyDataDecryptorFactory() {
/**
* Identifier for the subkey for which this particular [CustomPublicKeyDataDecryptorFactory] is
@ -22,5 +23,5 @@ interface CustomPublicKeyDataDecryptorFactory : PublicKeyDataDecryptorFactory {
*
* @return subkey identifier
*/
val subkeyIdentifier: SubkeyIdentifier
abstract val subkeyIdentifier: SubkeyIdentifier
}

View file

@ -29,11 +29,17 @@ class HardwareSecurity {
* @param keyId id of the key
* @param keyAlgorithm algorithm
* @param sessionKeyData encrypted session key
* @param pkeskVersion version of the Public-Key-Encrypted-Session-Key packet (3 or 6)
* @return decrypted session key
* @throws HardwareSecurityException exception
*/
@Throws(HardwareSecurityException::class)
fun decryptSessionKey(keyId: Long, keyAlgorithm: Int, sessionKeyData: ByteArray): ByteArray
fun decryptSessionKey(
keyId: Long,
keyAlgorithm: Int,
sessionKeyData: ByteArray,
pkeskVersion: Int
): ByteArray
}
/**
@ -44,7 +50,7 @@ class HardwareSecurity {
class HardwareDataDecryptorFactory(
override val subkeyIdentifier: SubkeyIdentifier,
private val callback: DecryptionCallback,
) : CustomPublicKeyDataDecryptorFactory {
) : CustomPublicKeyDataDecryptorFactory() {
// luckily we can instantiate the BcPublicKeyDataDecryptorFactory with null as argument.
private val factory: PublicKeyDataDecryptorFactory = BcPublicKeyDataDecryptorFactory(null)
@ -73,10 +79,12 @@ class HardwareSecurity {
override fun recoverSessionData(
keyAlgorithm: Int,
secKeyData: Array<out ByteArray>
secKeyData: Array<out ByteArray>,
pkeskVersion: Int
): ByteArray {
return try {
callback.decryptSessionKey(subkeyIdentifier.subkeyId, keyAlgorithm, secKeyData[0])
callback.decryptSessionKey(
subkeyIdentifier.subkeyId, keyAlgorithm, secKeyData[0], pkeskVersion)
} catch (e: HardwareSecurityException) {
throw PGPException("Hardware-backed decryption failed.", e)
}

View file

@ -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();
}

View file

@ -8,7 +8,7 @@ allprojects {
isSnapshot = true
pgpainlessMinAndroidSdk = 10
javaSourceCompatibility = 1.8
bouncyCastleVersion = '1.78.1'
bouncyCastleVersion = '1.80'
bouncyPgVersion = bouncyCastleVersion
junitVersion = '5.8.2'
logbackVersion = '1.5.13'