1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2025-12-09 05:41:07 +01:00

Transparent decryption

This commit is contained in:
Paul Schaub 2025-12-02 13:10:47 +01:00
parent de47a683d9
commit a1af39a4f7
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
18 changed files with 461 additions and 357 deletions

View file

@ -57,11 +57,10 @@ class GnuPGDummyKeyUtil private constructor() {
*/
@JvmStatic fun modify(secretKeys: PGPSecretKeyRing) = Builder(secretKeys)
@JvmStatic fun serialToBytes(sn: Int) = byteArrayOf(
(sn shr 24).toByte(),
(sn shr(16)).toByte(),
(sn shr(8)).toByte(),
sn.toByte())
@JvmStatic
fun serialToBytes(sn: Int) =
byteArrayOf(
(sn shr 24).toByte(), (sn shr (16)).toByte(), (sn shr (8)).toByte(), sn.toByte())
}
class Builder(private val keys: PGPSecretKeyRing) {

View file

@ -38,7 +38,6 @@ import org.bouncycastle.openpgp.api.OpenPGPKey.OpenPGPSecretKey
import org.bouncycastle.openpgp.api.OpenPGPSignature.OpenPGPDocumentSignature
import org.bouncycastle.openpgp.api.exception.MalformedOpenPGPSignatureException
import org.bouncycastle.openpgp.operator.PBEDataDecryptorFactory
import org.bouncycastle.openpgp.operator.PGPDataDecryptorFactory
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory
import org.bouncycastle.util.io.TeeInputStream
import org.pgpainless.PGPainless
@ -448,16 +447,19 @@ class OpenPgpMessageInputStream(
}
if (secretKey.hasExternalSecretKey()) {
LOGGER.debug("Decryption key ${secretKey.keyIdentifier} is located on an external device, e.g. a smartcard.")
LOGGER.debug(
"Decryption key ${secretKey.keyIdentifier} is located on an external device, e.g. a smartcard.")
for (hardwareTokenBackend in options.hardwareTokenBackends) {
LOGGER.debug("Attempt decryption with ${hardwareTokenBackend.getBackendName()} backend.")
LOGGER.debug(
"Attempt decryption with ${hardwareTokenBackend.getBackendName()} backend.")
if (decryptWithHardwareKey(
hardwareTokenBackend,
esks,
secretKey,
protector,
SubkeyIdentifier(secretKey.openPGPKey.pgpSecretKeyRing, secretKey.keyIdentifier),
pkesk)) {
hardwareTokenBackend,
esks,
secretKey,
protector,
SubkeyIdentifier(
secretKey.openPGPKey.pgpSecretKeyRing, secretKey.keyIdentifier),
pkesk)) {
return true
}
}
@ -624,16 +626,22 @@ class OpenPgpMessageInputStream(
pkesk: PGPPublicKeyEncryptedData
): Boolean {
try {
val decrypted = pkesk.getDataStream(decryptorFactory)
val sessionKey = SessionKey(pkesk.getSessionKey(decryptorFactory))
throwIfUnacceptable(sessionKey.algorithm)
val pgpSessionKey = PGPSessionKey(sessionKey.algorithm.algorithmId, sessionKey.key)
val sessionKeyEncData = esks.esks.extractSessionKeyEncryptedData()
val decrypted =
sessionKeyEncData.getDataStream(
api.implementation.sessionKeyDataDecryptorFactory(pgpSessionKey))
val encryptedData = esks.toEncryptedData(sessionKey, layerMetadata.depth)
encryptedData.decryptionKey = decryptionKeyId
encryptedData.sessionKey = sessionKey
encryptedData.addRecipients(esks.pkesks.plus(esks.anonPkesks).map { it.keyIdentifier })
LOGGER.debug("Successfully decrypted data with key $decryptionKeyId")
val integrityProtected = IntegrityProtectedInputStream(decrypted, pkesk, options)
val integrityProtected =
IntegrityProtectedInputStream(decrypted, sessionKeyEncData, options)
nestedInputStream =
OpenPgpMessageInputStream(integrityProtected, options, encryptedData, api)
return true
@ -790,7 +798,7 @@ class OpenPgpMessageInputStream(
}
}
private class ESKsAndData(private val esks: PGPEncryptedDataList) {
private class ESKsAndData(val esks: PGPEncryptedDataList) {
fun toEncryptedData(sk: SessionKey, depth: Int): EncryptedData {
return when (EncryptedDataPacketType.of(esks)!!) {
EncryptedDataPacketType.SED ->

View file

@ -313,18 +313,20 @@ class SigningOptions(private val api: PGPainless) {
subpacketsCallback)
}
fun addInlineSignature(hardwareBackedKey: OpenPGPComponentKey,
hardwareContentSignerBuilderProviderFactory: PGPContentSignerBuilderProviderFactory,
hashAlgorithm: HashAlgorithm,
signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT,
subpacketsCallback: Callback? = null
) = addHardwareSigningMethod(
hardwareBackedKey,
hardwareContentSignerBuilderProviderFactory,
hashAlgorithm,
signatureType,
false,
subpacketsCallback)
fun addInlineSignature(
hardwareBackedKey: OpenPGPComponentKey,
hardwareContentSignerBuilderProviderFactory: PGPContentSignerBuilderProviderFactory,
hashAlgorithm: HashAlgorithm,
signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT,
subpacketsCallback: Callback? = null
) =
addHardwareSigningMethod(
hardwareBackedKey,
hardwareContentSignerBuilderProviderFactory,
hashAlgorithm,
signatureType,
false,
subpacketsCallback)
/**
* Add detached signatures with all key rings from the provided secret key ring collection.
@ -532,7 +534,14 @@ class SigningOptions(private val api: PGPainless) {
hashAlgorithm: HashAlgorithm,
signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT,
subpacketsCallback: Callback? = null
) = addHardwareSigningMethod(hardwareBackedKey, hardwareContentSignerBuilderProviderFactory, hashAlgorithm, signatureType, true, subpacketsCallback)
) =
addHardwareSigningMethod(
hardwareBackedKey,
hardwareContentSignerBuilderProviderFactory,
hashAlgorithm,
signatureType,
true,
subpacketsCallback)
private fun addHardwareSigningMethod(
hardwareBackedKey: OpenPGPComponentKey,
@ -540,15 +549,15 @@ class SigningOptions(private val api: PGPainless) {
hashAlgorithm: HashAlgorithm,
signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT,
detached: Boolean,
subpacketsCallback: Callback? = null) = apply {
subpacketsCallback: Callback? = null
) = apply {
rejectWeakKeys(hardwareBackedKey)
val pubkey = hardwareBackedKey.pgpPublicKey
val pgpContentSignerBuilder = hardwareContentSignerBuilderProviderFactory.create(hashAlgorithm)
.get(pubkey)
val pgpContentSignerBuilder =
hardwareContentSignerBuilderProviderFactory.create(hashAlgorithm).get(pubkey)
val generator = PGPSignatureGenerator(
pgpContentSignerBuilder, pubkey)
.apply {
val generator =
PGPSignatureGenerator(pgpContentSignerBuilder, pubkey).apply {
init(signatureType.signatureType.code, pubkey)
}
@ -582,17 +591,19 @@ class SigningOptions(private val api: PGPainless) {
val publicKeyAlgorithm = requireFromId(signingKey.pgpPublicKey.algorithm)
val bitStrength = signingKey.pgpPublicKey.bitStrength
if (!api.algorithmPolicy.publicKeyAlgorithmPolicy.isAcceptable(
publicKeyAlgorithm, bitStrength)) {
publicKeyAlgorithm, bitStrength)) {
throw UnacceptableSigningKeyException(
PublicKeyAlgorithmPolicyException(
signingKey, publicKeyAlgorithm, bitStrength))
PublicKeyAlgorithmPolicyException(signingKey, publicKeyAlgorithm, bitStrength))
}
}
private fun prepareSignatureGenerator(generator: PGPSignatureGenerator, signingKey: PGPPublicKey, subpacketCallback: Callback?) {
private fun prepareSignatureGenerator(
generator: PGPSignatureGenerator,
signingKey: PGPPublicKey,
subpacketCallback: Callback?
) {
// Subpackets
val hashedSubpackets =
SignatureSubpackets.createHashedSubpackets(signingKey)
val hashedSubpackets = SignatureSubpackets.createHashedSubpackets(signingKey)
val unhashedSubpackets = SignatureSubpackets.createEmptySubpackets()
if (subpacketCallback != null) {
subpacketCallback.modifyHashedSubpackets(hashedSubpackets)

View file

@ -210,7 +210,6 @@ $algorithm of size $bitSize is not acceptable.""",
}
}
class GeneralKeyException(message: String,
fingerprint: OpenPgpFingerprint
) : KeyException(message, fingerprint)
class GeneralKeyException(message: String, fingerprint: OpenPgpFingerprint) :
KeyException(message, fingerprint)
}

View file

@ -1,3 +1,7 @@
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.hardware
import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData

View file

@ -1,3 +1,7 @@
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.signature
import org.bouncycastle.openpgp.operator.PGPContentSignerBuilderProvider