1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2025-09-09 18:29:39 +02:00

More API down-handing

This commit is contained in:
Paul Schaub 2025-03-18 13:52:19 +01:00
parent f74932c4d0
commit 7e345a0e33
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
6 changed files with 62 additions and 80 deletions

View file

@ -217,7 +217,7 @@ class PGPainless(
*
* @return builder
*/
@JvmStatic fun decryptAndOrVerify(): DecryptionBuilder = DecryptionBuilder()
@JvmStatic fun decryptAndOrVerify(): DecryptionBuilder = DecryptionBuilder(getInstance())
/**
* Make changes to a secret key at the given reference time. This method can be used to

View file

@ -5,22 +5,24 @@
package org.pgpainless.decryption_verification
import java.io.InputStream
import org.pgpainless.PGPainless
/**
* Builder class that takes an [InputStream] of ciphertext (or plaintext signed data) and combines
* it with a configured [ConsumerOptions] object to form a [DecryptionStream] which can be used to
* decrypt an OpenPGP message or verify signatures.
*/
class DecryptionBuilder : DecryptionBuilderInterface {
class DecryptionBuilder(private val api: PGPainless) : DecryptionBuilderInterface {
override fun onInputStream(inputStream: InputStream): DecryptionBuilderInterface.DecryptWith {
return DecryptWithImpl(inputStream)
return DecryptWithImpl(inputStream, api)
}
class DecryptWithImpl(val inputStream: InputStream) : DecryptionBuilderInterface.DecryptWith {
class DecryptWithImpl(val inputStream: InputStream, val api: PGPainless) :
DecryptionBuilderInterface.DecryptWith {
override fun withOptions(consumerOptions: ConsumerOptions): DecryptionStream {
return OpenPgpMessageInputStream.create(inputStream, consumerOptions)
return OpenPgpMessageInputStream.create(inputStream, consumerOptions, api)
}
}
}

View file

@ -51,7 +51,7 @@ class MessageMetadata(val message: Message) {
fun isEncryptedFor(cert: OpenPGPCertificate): Boolean {
return encryptionLayers.asSequence().any {
it.recipients.any { keyId -> cert.getKey(KeyIdentifier(keyId)) != null }
it.recipients.any { identifier -> cert.getKey(identifier) != null }
}
}
@ -87,12 +87,15 @@ class MessageMetadata(val message: Message) {
/** List containing all recipient keyIDs. */
val recipientKeyIds: List<Long>
get() = recipientKeyIdentifiers.map { it.keyId }.toList()
val recipientKeyIdentifiers: List<KeyIdentifier>
get() =
encryptionLayers
.asSequence()
.map { it.recipients.toMutableList() }
.reduce { all, keyIds ->
all.addAll(keyIds)
.reduce { all, keyIdentifiers ->
all.addAll(keyIdentifiers)
all
}
.toList()
@ -475,9 +478,11 @@ class MessageMetadata(val message: Message) {
var sessionKey: SessionKey? = null
/** List of all recipient key ids to which the packet was encrypted for. */
val recipients: List<Long> = mutableListOf()
val recipients: List<KeyIdentifier> = mutableListOf()
fun addRecipients(keyIds: List<Long>) = apply { (recipients as MutableList).addAll(keyIds) }
fun addRecipients(keyIds: List<KeyIdentifier>) = apply {
(recipients as MutableList).addAll(keyIds)
}
/**
* Identifier of the subkey that was used to decrypt the packet (in case of a public key

View file

@ -26,7 +26,6 @@ import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData
import org.bouncycastle.openpgp.PGPSessionKey
import org.bouncycastle.openpgp.PGPSignature
import org.bouncycastle.openpgp.api.OpenPGPCertificate
import org.bouncycastle.openpgp.api.OpenPGPImplementation
import org.bouncycastle.openpgp.api.OpenPGPKey
import org.bouncycastle.openpgp.api.OpenPGPKey.OpenPGPPrivateKey
import org.bouncycastle.openpgp.api.OpenPGPKey.OpenPGPSecretKey
@ -74,10 +73,10 @@ class OpenPgpMessageInputStream(
inputStream: InputStream,
private val options: ConsumerOptions,
private val layerMetadata: Layer,
private val policy: Policy
private val api: PGPainless
) : DecryptionStream() {
private val signatures: Signatures = Signatures(options)
private val signatures: Signatures = Signatures(options, api)
private var packetInputStream: TeeBCPGInputStream? = null
private var nestedInputStream: InputStream? = null
private val syntaxVerifier = PDA()
@ -131,8 +130,8 @@ class OpenPgpMessageInputStream(
inputStream: InputStream,
options: ConsumerOptions,
metadata: Layer,
policy: Policy
) : this(Type.standard, inputStream, options, metadata, policy)
api: PGPainless
) : this(Type.standard, inputStream, options, metadata, api)
private fun consumePackets() {
val pIn = packetInputStream ?: return
@ -232,7 +231,7 @@ class OpenPgpMessageInputStream(
LOGGER.debug(
"Compressed Data Packet (${compressionLayer.algorithm}) at depth ${layerMetadata.depth} encountered.")
nestedInputStream =
OpenPgpMessageInputStream(decompress(compressedData), options, compressionLayer, policy)
OpenPgpMessageInputStream(decompress(compressedData), options, compressionLayer, api)
}
private fun decompress(compressedData: PGPCompressedData): InputStream {
@ -313,7 +312,8 @@ class OpenPgpMessageInputStream(
signatures
.leaveNesting() // TODO: Only leave nesting if all OPSs of the nesting layer are
// dealt with
signatures.addCorrespondingOnePassSignature(signature, layerMetadata, policy)
signatures.addCorrespondingOnePassSignature(
signature, layerMetadata, api.algorithmPolicy)
} else {
LOGGER.debug(
"Prepended Signature Packet by key ${keyId.openPgpKeyId()} at depth ${layerMetadata.depth} encountered.")
@ -345,7 +345,7 @@ class OpenPgpMessageInputStream(
esks.pkesks
.filter {
// find matching PKESK
it.keyID == key.subkeyId
it.keyIdentifier == key.keyIdentifier
}
.forEach {
// attempt decryption
@ -362,8 +362,7 @@ class OpenPgpMessageInputStream(
throwIfUnacceptable(sk.algorithm)
val pgpSk = PGPSessionKey(sk.algorithm.algorithmId, sk.key)
val decryptorFactory =
OpenPGPImplementation.getInstance().sessionKeyDataDecryptorFactory(pgpSk)
val decryptorFactory = api.implementation.sessionKeyDataDecryptorFactory(pgpSk)
val layer = EncryptedData(sk.algorithm, layerMetadata.depth + 1)
val skEncData = encDataList.extractSessionKeyEncryptedData()
try {
@ -372,7 +371,7 @@ class OpenPgpMessageInputStream(
val integrityProtected =
IntegrityProtectedInputStream(decrypted, skEncData, options)
nestedInputStream =
OpenPgpMessageInputStream(integrityProtected, options, layer, policy)
OpenPgpMessageInputStream(integrityProtected, options, layer, api)
LOGGER.debug("Successfully decrypted data using provided session key")
return true
} catch (e: PGPException) {
@ -395,8 +394,7 @@ class OpenPgpMessageInputStream(
}
val decryptorFactory =
OpenPGPImplementation.getInstance()
.pbeDataDecryptorFactory(passphrase.getChars())
api.implementation.pbeDataDecryptorFactory(passphrase.getChars())
if (decryptSKESKAndStream(esks, skesk, decryptorFactory)) {
return true
}
@ -518,7 +516,7 @@ class OpenPgpMessageInputStream(
pkesk: PGPPublicKeyEncryptedData
): Boolean {
val decryptorFactory =
OpenPGPImplementation.getInstance().publicKeyDataDecryptorFactory(privateKey.privateKey)
api.implementation.publicKeyDataDecryptorFactory(privateKey.privateKey)
return decryptPKESKAndStream(esks, decryptionKeyId, decryptorFactory, pkesk)
}
@ -545,11 +543,11 @@ class OpenPgpMessageInputStream(
throwIfUnacceptable(sessionKey.algorithm)
val encryptedData = EncryptedData(sessionKey.algorithm, layerMetadata.depth + 1)
encryptedData.sessionKey = sessionKey
encryptedData.addRecipients(esks.pkesks.map { it.keyID })
encryptedData.addRecipients(esks.pkesks.map { it.keyIdentifier })
LOGGER.debug("Successfully decrypted data with passphrase")
val integrityProtected = IntegrityProtectedInputStream(decrypted, skesk, options)
nestedInputStream =
OpenPgpMessageInputStream(integrityProtected, options, encryptedData, policy)
OpenPgpMessageInputStream(integrityProtected, options, encryptedData, api)
return true
} catch (e: UnacceptableAlgorithmException) {
throw e
@ -578,11 +576,11 @@ class OpenPgpMessageInputStream(
layerMetadata.depth + 1)
encryptedData.decryptionKey = decryptionKeyId
encryptedData.sessionKey = sessionKey
encryptedData.addRecipients(esks.pkesks.plus(esks.anonPkesks).map { it.keyID })
encryptedData.addRecipients(esks.pkesks.plus(esks.anonPkesks).map { it.keyIdentifier })
LOGGER.debug("Successfully decrypted data with key $decryptionKeyId")
val integrityProtected = IntegrityProtectedInputStream(decrypted, pkesk, options)
nestedInputStream =
OpenPgpMessageInputStream(integrityProtected, options, encryptedData, policy)
OpenPgpMessageInputStream(integrityProtected, options, encryptedData, api)
return true
} catch (e: UnacceptableAlgorithmException) {
throw e
@ -620,7 +618,7 @@ class OpenPgpMessageInputStream(
throw RuntimeException(e)
}
}
signatures.finish(layerMetadata, policy)
signatures.finish(layerMetadata, api.algorithmPolicy)
}
return r
}
@ -647,7 +645,7 @@ class OpenPgpMessageInputStream(
throw RuntimeException(e)
}
}
signatures.finish(layerMetadata, policy)
signatures.finish(layerMetadata, api.algorithmPolicy)
}
return r
}
@ -693,16 +691,6 @@ class OpenPgpMessageInputStream(
return MessageMetadata((layerMetadata as Message))
}
private fun getDecryptionKey(keyId: Long): OpenPGPKey? =
options.getDecryptionKeys().firstOrNull {
it.pgpSecretKeyRing
.any { k -> k.keyID == keyId }
.and(
PGPainless.inspectKeyRing(it).decryptionSubkeys.any { k ->
k.keyIdentifier.keyId == keyId
})
}
private fun getDecryptionKey(pkesk: PGPPublicKeyEncryptedData): OpenPGPKey? =
options.getDecryptionKeys().firstOrNull {
it.pgpSecretKeyRing.getSecretKeyFor(pkesk) != null &&
@ -737,7 +725,7 @@ class OpenPgpMessageInputStream(
}
private fun isAcceptable(algorithm: SymmetricKeyAlgorithm): Boolean =
policy.symmetricKeyDecryptionAlgorithmPolicy.isAcceptable(algorithm)
api.algorithmPolicy.symmetricKeyDecryptionAlgorithmPolicy.isAcceptable(algorithm)
private fun throwIfUnacceptable(algorithm: SymmetricKeyAlgorithm) {
if (!isAcceptable(algorithm)) {
@ -774,7 +762,7 @@ class OpenPgpMessageInputStream(
get() = skesks.plus(pkesks).plus(anonPkesks)
}
private class Signatures(val options: ConsumerOptions) : OutputStream() {
private class Signatures(val options: ConsumerOptions, val api: PGPainless) : OutputStream() {
val detachedSignatures = mutableListOf<OpenPGPDocumentSignature>()
val prependedSignatures = mutableListOf<OpenPGPDocumentSignature>()
val onePassSignatures = mutableListOf<OnePassSignatureCheck>()
@ -1044,27 +1032,21 @@ class OpenPgpMessageInputStream(
}
}
companion object {
@JvmStatic
private fun initialize(signature: PGPSignature, publicKey: PGPPublicKey) {
val verifierProvider =
OpenPGPImplementation.getInstance().pgpContentVerifierBuilderProvider()
try {
signature.init(verifierProvider, publicKey)
} catch (e: PGPException) {
throw RuntimeException(e)
}
private fun initialize(signature: PGPSignature, publicKey: PGPPublicKey) {
val verifierProvider = api.implementation.pgpContentVerifierBuilderProvider()
try {
signature.init(verifierProvider, publicKey)
} catch (e: PGPException) {
throw RuntimeException(e)
}
}
@JvmStatic
private fun initialize(ops: PGPOnePassSignature, publicKey: PGPPublicKey) {
val verifierProvider =
OpenPGPImplementation.getInstance().pgpContentVerifierBuilderProvider()
try {
ops.init(verifierProvider, publicKey)
} catch (e: PGPException) {
throw RuntimeException(e)
}
private fun initialize(ops: PGPOnePassSignature, publicKey: PGPPublicKey) {
val verifierProvider = api.implementation.pgpContentVerifierBuilderProvider()
try {
ops.init(verifierProvider, publicKey)
} catch (e: PGPException) {
throw RuntimeException(e)
}
}
}
@ -1074,32 +1056,27 @@ class OpenPgpMessageInputStream(
private val LOGGER = LoggerFactory.getLogger(OpenPgpMessageInputStream::class.java)
@JvmStatic
fun create(inputStream: InputStream, options: ConsumerOptions) =
create(inputStream, options, PGPainless.getInstance().algorithmPolicy)
@JvmStatic
fun create(inputStream: InputStream, options: ConsumerOptions, policy: Policy) =
create(inputStream, options, Message(), policy)
fun create(inputStream: InputStream, options: ConsumerOptions, api: PGPainless) =
create(inputStream, options, Message(), api)
@JvmStatic
internal fun create(
inputStream: InputStream,
options: ConsumerOptions,
metadata: Layer,
policy: Policy
api: PGPainless
): OpenPgpMessageInputStream {
val openPgpIn = OpenPgpInputStream(inputStream)
openPgpIn.reset()
if (openPgpIn.isNonOpenPgp || options.isForceNonOpenPgpData()) {
return OpenPgpMessageInputStream(
Type.non_openpgp, openPgpIn, options, metadata, policy)
Type.non_openpgp, openPgpIn, options, metadata, api)
}
if (openPgpIn.isBinaryOpenPgp) {
// Simply consume OpenPGP message
return OpenPgpMessageInputStream(
Type.standard, openPgpIn, options, metadata, policy)
return OpenPgpMessageInputStream(Type.standard, openPgpIn, options, metadata, api)
}
return if (openPgpIn.isAsciiArmored) {
@ -1107,10 +1084,10 @@ class OpenPgpMessageInputStream(
if (armorIn.isClearText) {
(metadata as Message).setCleartextSigned()
OpenPgpMessageInputStream(
Type.cleartext_signed, armorIn, options, metadata, policy)
Type.cleartext_signed, armorIn, options, metadata, api)
} else {
// Simply consume dearmored OpenPGP message
OpenPgpMessageInputStream(Type.standard, armorIn, options, metadata, policy)
OpenPgpMessageInputStream(Type.standard, armorIn, options, metadata, api)
}
} else {
throw AssertionError("Cannot deduce type of data.")

View file

@ -8,7 +8,6 @@ import java.util.*
import org.bouncycastle.openpgp.PGPPublicKeyRing
import org.bouncycastle.openpgp.api.OpenPGPCertificate
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentKey
import org.bouncycastle.openpgp.api.OpenPGPImplementation
import org.bouncycastle.openpgp.operator.PGPKeyEncryptionMethodGenerator
import org.pgpainless.PGPainless
import org.pgpainless.PGPainless.Companion.inspectKeyRing
@ -334,9 +333,9 @@ class EncryptionOptions(
_encryptionKeys.add(key)
_encryptionKeyIdentifiers.add(SubkeyIdentifier(key))
addEncryptionMethod(
OpenPGPImplementation.getInstance()
.publicKeyKeyEncryptionMethodGenerator(key.pgpPublicKey)
.also { it.setUseWildcardRecipient(wildcardRecipient) })
api.implementation.publicKeyKeyEncryptionMethodGenerator(key.pgpPublicKey).also {
it.setUseWildcardRecipient(wildcardRecipient)
})
}
/**
@ -359,8 +358,7 @@ class EncryptionOptions(
fun addMessagePassphrase(passphrase: Passphrase) = apply {
require(!passphrase.isEmpty) { "Passphrase MUST NOT be empty." }
addEncryptionMethod(
OpenPGPImplementation.getInstance()
.pbeKeyEncryptionMethodGenerator(passphrase.getChars()))
api.implementation.pbeKeyEncryptionMethodGenerator(passphrase.getChars()))
}
/**

View file

@ -697,7 +697,7 @@ public class OpenPgpMessageInputStreamTest {
throws IOException {
ByteArrayInputStream bytesIn = new ByteArrayInputStream(armored.getBytes(StandardCharsets.UTF_8));
ArmoredInputStream armorIn = ArmoredInputStreamFactory.get(bytesIn);
OpenPgpMessageInputStream pgpIn = OpenPgpMessageInputStream.create(armorIn, options);
OpenPgpMessageInputStream pgpIn = OpenPgpMessageInputStream.create(armorIn, options, PGPainless.getInstance());
return pgpIn;
}
}