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:
parent
f74932c4d0
commit
7e345a0e33
6 changed files with 62 additions and 80 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,11 +1032,8 @@ class OpenPgpMessageInputStream(
|
|||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
private fun initialize(signature: PGPSignature, publicKey: PGPPublicKey) {
|
||||
val verifierProvider =
|
||||
OpenPGPImplementation.getInstance().pgpContentVerifierBuilderProvider()
|
||||
val verifierProvider = api.implementation.pgpContentVerifierBuilderProvider()
|
||||
try {
|
||||
signature.init(verifierProvider, publicKey)
|
||||
} catch (e: PGPException) {
|
||||
|
@ -1056,10 +1041,8 @@ class OpenPgpMessageInputStream(
|
|||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
private fun initialize(ops: PGPOnePassSignature, publicKey: PGPPublicKey) {
|
||||
val verifierProvider =
|
||||
OpenPGPImplementation.getInstance().pgpContentVerifierBuilderProvider()
|
||||
val verifierProvider = api.implementation.pgpContentVerifierBuilderProvider()
|
||||
try {
|
||||
ops.init(verifierProvider, publicKey)
|
||||
} catch (e: PGPException) {
|
||||
|
@ -1067,39 +1050,33 @@ class OpenPgpMessageInputStream(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
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.")
|
||||
|
|
|
@ -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()))
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue