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

SOP: Inject API instance

This commit is contained in:
Paul Schaub 2025-03-20 15:03:24 +01:00
parent 57540d8028
commit 2200cb7372
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
18 changed files with 72 additions and 62 deletions

View file

@ -9,6 +9,7 @@ import java.io.InputStream
import java.io.OutputStream
import kotlin.jvm.Throws
import org.bouncycastle.util.io.Streams
import org.pgpainless.PGPainless
import org.pgpainless.decryption_verification.OpenPgpInputStream
import org.pgpainless.util.ArmoredOutputStreamFactory
import sop.Ready
@ -16,7 +17,7 @@ import sop.exception.SOPGPException
import sop.operation.Armor
/** Implementation of the `armor` operation using PGPainless. */
class ArmorImpl : Armor {
class ArmorImpl(private val api: PGPainless) : Armor {
@Throws(SOPGPException.BadData::class)
override fun data(data: InputStream): Ready {

View file

@ -9,6 +9,7 @@ import java.io.InputStream
import java.io.OutputStream
import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection
import org.pgpainless.PGPainless
import org.pgpainless.bouncycastle.extensions.openPgpFingerprint
import org.pgpainless.exception.MissingPassphraseException
import org.pgpainless.key.protection.SecretKeyRingProtector
@ -20,7 +21,7 @@ import sop.exception.SOPGPException
import sop.operation.ChangeKeyPassword
/** Implementation of the `change-key-password` operation using PGPainless. */
class ChangeKeyPasswordImpl : ChangeKeyPassword {
class ChangeKeyPasswordImpl(private val api: PGPainless) : ChangeKeyPassword {
private val oldProtector = MatchMakingSecretKeyRingProtector()
private var newPassphrase = Passphrase.emptyPassphrase()

View file

@ -10,12 +10,13 @@ import java.io.InputStream
import java.io.OutputStream
import org.bouncycastle.openpgp.PGPUtil
import org.bouncycastle.util.io.Streams
import org.pgpainless.PGPainless
import sop.Ready
import sop.exception.SOPGPException
import sop.operation.Dearmor
/** Implementation of the `dearmor` operation using PGPainless. */
class DearmorImpl : Dearmor {
class DearmorImpl(private val api: PGPainless) : Dearmor {
override fun data(data: InputStream): Ready {
val decoder =

View file

@ -25,9 +25,9 @@ import sop.operation.Decrypt
import sop.util.UTF8Util
/** Implementation of the `decrypt` operation using PGPainless. */
class DecryptImpl : Decrypt {
class DecryptImpl(private val api: PGPainless) : Decrypt {
private val consumerOptions = ConsumerOptions.get()
private val consumerOptions = ConsumerOptions.get(api)
private val protector = MatchMakingSecretKeyRingProtector()
override fun ciphertext(ciphertext: InputStream): ReadyWithResult<DecryptionResult> {

View file

@ -30,9 +30,9 @@ import sop.operation.DetachedSign
import sop.util.UTF8Util
/** Implementation of the `sign` operation using PGPainless. */
class DetachedSignImpl : DetachedSign {
class DetachedSignImpl(private val api: PGPainless) : DetachedSign {
private val signingOptions = SigningOptions.get()
private val signingOptions = SigningOptions.get(api)
private val protector = MatchMakingSecretKeyRingProtector()
private val signingKeys = mutableListOf<PGPSecretKeyRing>()
@ -56,10 +56,10 @@ class DetachedSignImpl : DetachedSign {
try {
val signingStream =
PGPainless.encryptAndOrSign()
api.generateMessage()
.discardOutput()
.withOptions(
ProducerOptions.sign(signingOptions)
ProducerOptions.sign(signingOptions, api)
.setAsciiArmor(armor)
.overrideCompressionAlgorithm(CompressionAlgorithm.UNCOMPRESSED))
@ -94,7 +94,7 @@ class DetachedSignImpl : DetachedSign {
override fun key(key: InputStream): DetachedSign = apply {
KeyReader.readSecretKeys(key, true).forEach {
val info = PGPainless.inspectKeyRing(it)
val info = api.inspect(api.toKey(it))
if (!info.isUsableForSigning) {
throw SOPGPException.KeyCannotSign(
"Key ${info.fingerprint} does not have valid, signing capable subkeys.")

View file

@ -18,9 +18,9 @@ import sop.operation.DetachedVerify
import sop.operation.VerifySignatures
/** Implementation of the `verify` operation using PGPainless. */
class DetachedVerifyImpl : DetachedVerify {
class DetachedVerifyImpl(private val api: PGPainless) : DetachedVerify {
private val options = ConsumerOptions.get().forceNonOpenPgpData()
private val options = ConsumerOptions.get(api).forceNonOpenPgpData()
override fun cert(cert: InputStream): DetachedVerify = apply {
options.addVerificationCerts(KeyReader.readPublicKeys(cert, true))

View file

@ -30,7 +30,7 @@ import sop.operation.Encrypt
import sop.util.UTF8Util
/** Implementation of the `encrypt` operation using PGPainless. */
class EncryptImpl : Encrypt {
class EncryptImpl(private val api: PGPainless) : Encrypt {
companion object {
@JvmField val RFC4880_PROFILE = Profile("rfc4880", "Follow the packet format of rfc4880")
@ -38,7 +38,7 @@ class EncryptImpl : Encrypt {
@JvmField val SUPPORTED_PROFILES = listOf(RFC4880_PROFILE)
}
private val encryptionOptions = EncryptionOptions.get()
private val encryptionOptions = EncryptionOptions.get(api)
private var signingOptions: SigningOptions? = null
private val signingKeys = mutableListOf<PGPSecretKeyRing>()
private val protector = MatchMakingSecretKeyRingProtector()
@ -58,9 +58,9 @@ class EncryptImpl : Encrypt {
val options =
if (signingOptions != null) {
ProducerOptions.signAndEncrypt(encryptionOptions, signingOptions!!)
ProducerOptions.signAndEncrypt(encryptionOptions, signingOptions!!, api)
} else {
ProducerOptions.encrypt(encryptionOptions)
ProducerOptions.encrypt(encryptionOptions, api)
}
.setAsciiArmor(armor)
.setEncoding(modeToStreamEncoding(mode))
@ -81,9 +81,7 @@ class EncryptImpl : Encrypt {
return object : ReadyWithResult<EncryptionResult>() {
override fun writeTo(outputStream: OutputStream): EncryptionResult {
val encryptionStream =
PGPainless.encryptAndOrSign()
.onOutputStream(outputStream)
.withOptions(options)
api.generateMessage().onOutputStream(outputStream).withOptions(options)
Streams.pipeAll(plaintext, encryptionStream)
encryptionStream.close()
// TODO: Extract and emit session key once BC supports that
@ -103,7 +101,7 @@ class EncryptImpl : Encrypt {
override fun signWith(key: InputStream): Encrypt = apply {
if (signingOptions == null) {
signingOptions = SigningOptions.get()
signingOptions = SigningOptions.get(api)
}
val signingKey =
@ -112,7 +110,7 @@ class EncryptImpl : Encrypt {
AssertionError(
"Exactly one secret key at a time expected. Got zero or multiple instead."))
val info = PGPainless.inspectKeyRing(signingKey)
val info = api.inspect(api.toKey(signingKey))
if (info.signingSubkeys.isEmpty()) {
throw SOPGPException.KeyCannotSign("Key ${info.fingerprint} cannot sign.")
}

View file

@ -13,7 +13,7 @@ import sop.Ready
import sop.operation.ExtractCert
/** Implementation of the `extract-cert` operation using PGPainless. */
class ExtractCertImpl : ExtractCert {
class ExtractCertImpl(private val api: PGPainless) : ExtractCert {
private var armor = true

View file

@ -26,7 +26,7 @@ import sop.exception.SOPGPException
import sop.operation.GenerateKey
/** Implementation of the `generate-key` operation using PGPainless. */
class GenerateKeyImpl : GenerateKey {
class GenerateKeyImpl(private val api: PGPainless) : GenerateKey {
companion object {
@JvmField

View file

@ -13,8 +13,8 @@ import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPLiteralData
import org.bouncycastle.openpgp.PGPOnePassSignatureList
import org.bouncycastle.openpgp.PGPSignatureList
import org.bouncycastle.openpgp.api.OpenPGPImplementation
import org.bouncycastle.util.io.Streams
import org.pgpainless.PGPainless
import org.pgpainless.decryption_verification.OpenPgpInputStream
import org.pgpainless.decryption_verification.cleartext_signatures.ClearsignedMessageUtil
import org.pgpainless.exception.WrongConsumingMethodException
@ -25,7 +25,7 @@ import sop.exception.SOPGPException
import sop.operation.InlineDetach
/** Implementation of the `inline-detach` operation using PGPainless. */
class InlineDetachImpl : InlineDetach {
class InlineDetachImpl(private val api: PGPainless) : InlineDetach {
private var armor = true
@ -72,7 +72,7 @@ class InlineDetachImpl : InlineDetach {
}
// handle binary OpenPGP data
var objectFactory = OpenPGPImplementation.getInstance().pgpObjectFactory(pgpIn)
var objectFactory = api.implementation.pgpObjectFactory(pgpIn)
var next: Any?
while (objectFactory.nextObject().also { next = it } != null) {
@ -94,8 +94,8 @@ class InlineDetachImpl : InlineDetach {
// Decompress compressed data
try {
objectFactory =
OpenPGPImplementation.getInstance()
.pgpObjectFactory((next as PGPCompressedData).dataStream)
api.implementation.pgpObjectFactory(
(next as PGPCompressedData).dataStream)
} catch (e: PGPException) {
throw SOPGPException.BadData(
"Cannot decompress PGPCompressedData", e)

View file

@ -27,9 +27,9 @@ import sop.operation.InlineSign
import sop.util.UTF8Util
/** Implementation of the `inline-sign` operation using PGPainless. */
class InlineSignImpl : InlineSign {
class InlineSignImpl(private val api: PGPainless) : InlineSign {
private val signingOptions = SigningOptions.get()
private val signingOptions = SigningOptions.get(api)
private val protector = MatchMakingSecretKeyRingProtector()
private val signingKeys = mutableListOf<PGPSecretKeyRing>()
@ -57,7 +57,7 @@ class InlineSignImpl : InlineSign {
}
val producerOptions =
ProducerOptions.sign(signingOptions).apply {
ProducerOptions.sign(signingOptions, api).apply {
when (mode) {
InlineSignAs.clearsigned -> {
setCleartextSigned()
@ -80,7 +80,7 @@ class InlineSignImpl : InlineSign {
override fun writeTo(outputStream: OutputStream) {
try {
val signingStream =
PGPainless.encryptAndOrSign()
api.generateMessage()
.onOutputStream(outputStream)
.withOptions(producerOptions)
@ -98,7 +98,7 @@ class InlineSignImpl : InlineSign {
override fun key(key: InputStream): InlineSign = apply {
KeyReader.readSecretKeys(key, true).forEach {
val info = PGPainless.inspectKeyRing(it)
val info = api.inspect(api.toKey(it))
if (!info.isUsableForSigning) {
throw SOPGPException.KeyCannotSign(
"Key ${info.fingerprint} does not have valid, signing capable subkeys.")

View file

@ -19,9 +19,9 @@ import sop.exception.SOPGPException
import sop.operation.InlineVerify
/** Implementation of the `inline-verify` operation using PGPainless. */
class InlineVerifyImpl : InlineVerify {
class InlineVerifyImpl(private val api: PGPainless) : InlineVerify {
private val options = ConsumerOptions.get()
private val options = ConsumerOptions.get(api)
override fun cert(cert: InputStream): InlineVerify = apply {
options.addVerificationCerts(KeyReader.readPublicKeys(cert, true))

View file

@ -4,12 +4,13 @@
package org.pgpainless.sop
import org.pgpainless.PGPainless
import sop.Profile
import sop.exception.SOPGPException
import sop.operation.ListProfiles
/** Implementation of the `list-profiles` operation using PGPainless. */
class ListProfilesImpl : ListProfiles {
class ListProfilesImpl(private val api: PGPainless) : ListProfiles {
override fun subcommand(command: String): List<Profile> =
when (command) {

View file

@ -86,8 +86,8 @@ class MatchMakingSecretKeyRingProtector : SecretKeyRingProtector {
override fun getEncryptor(key: PGPPublicKey): PBESecretKeyEncryptor? =
protector.getEncryptor(key)
override fun getKeyPassword(p0: OpenPGPKey.OpenPGPSecretKey): CharArray? =
protector.getKeyPassword(p0)
override fun getKeyPassword(key: OpenPGPKey.OpenPGPSecretKey): CharArray? =
protector.getKeyPassword(key)
/** Clear all known passphrases from the protector. */
fun clear() {

View file

@ -24,7 +24,7 @@ import sop.exception.SOPGPException
import sop.operation.RevokeKey
import sop.util.UTF8Util
class RevokeKeyImpl : RevokeKey {
class RevokeKeyImpl(private val api: PGPainless) : RevokeKey {
private val protector = MatchMakingSecretKeyRingProtector()
private var armor = true
@ -41,21 +41,23 @@ class RevokeKeyImpl : RevokeKey {
val revocationCertificates = mutableListOf<OpenPGPCertificate>()
secretKeyRings.forEach { secretKeys ->
val editor = PGPainless.modifyKeyRing(secretKeys)
val openPGPKey = api.toKey(secretKeys)
val editor = api.modify(openPGPKey)
try {
val attributes =
RevocationAttributes.createKeyRevocation()
.withReason(RevocationAttributes.Reason.NO_REASON)
.withoutDescription()
if (secretKeys.publicKey.version == 6) {
if (openPGPKey.primaryKey.version == 6) {
revocationCertificates.add(
editor.createMinimalRevocationCertificate(protector, attributes))
} else {
val certificate = PGPainless.extractCertificate(secretKeys)
val certificate = openPGPKey.toCertificate()
val revocation = editor.createRevocation(protector, attributes)
revocationCertificates.add(
KeyRingUtils.injectCertification(certificate, revocation.signature)
.toOpenPGPCertificate())
KeyRingUtils.injectCertification(
certificate.pgpKeyRing, revocation.signature)
.toOpenPGPCertificate(api.implementation))
}
} catch (e: WrongPassphraseException) {
throw SOPGPException.KeyIsProtected(

View file

@ -4,6 +4,7 @@
package org.pgpainless.sop
import org.pgpainless.PGPainless
import sop.SOP
import sop.SOPV
import sop.operation.Armor
@ -22,35 +23,38 @@ import sop.operation.ListProfiles
import sop.operation.RevokeKey
import sop.operation.Version
class SOPImpl(private val sopv: SOPV = SOPVImpl()) : SOP {
class SOPImpl(
private val api: PGPainless = PGPainless.getInstance(),
private val sopv: SOPV = SOPVImpl(api)
) : SOP {
override fun armor(): Armor = ArmorImpl()
override fun armor(): Armor = ArmorImpl(api)
override fun changeKeyPassword(): ChangeKeyPassword = ChangeKeyPasswordImpl()
override fun changeKeyPassword(): ChangeKeyPassword = ChangeKeyPasswordImpl(api)
override fun dearmor(): Dearmor = DearmorImpl()
override fun dearmor(): Dearmor = DearmorImpl(api)
override fun decrypt(): Decrypt = DecryptImpl()
override fun decrypt(): Decrypt = DecryptImpl(api)
override fun detachedSign(): DetachedSign = DetachedSignImpl()
override fun detachedSign(): DetachedSign = DetachedSignImpl(api)
override fun detachedVerify(): DetachedVerify = sopv.detachedVerify()
override fun encrypt(): Encrypt = EncryptImpl()
override fun encrypt(): Encrypt = EncryptImpl(api)
override fun extractCert(): ExtractCert = ExtractCertImpl()
override fun extractCert(): ExtractCert = ExtractCertImpl(api)
override fun generateKey(): GenerateKey = GenerateKeyImpl()
override fun generateKey(): GenerateKey = GenerateKeyImpl(api)
override fun inlineDetach(): InlineDetach = InlineDetachImpl()
override fun inlineDetach(): InlineDetach = InlineDetachImpl(api)
override fun inlineSign(): InlineSign = InlineSignImpl()
override fun inlineSign(): InlineSign = InlineSignImpl(api)
override fun inlineVerify(): InlineVerify = sopv.inlineVerify()
override fun listProfiles(): ListProfiles = ListProfilesImpl()
override fun listProfiles(): ListProfiles = ListProfilesImpl(api)
override fun revokeKey(): RevokeKey = RevokeKeyImpl()
override fun revokeKey(): RevokeKey = RevokeKeyImpl(api)
override fun version(): Version = sopv.version()
}

View file

@ -4,21 +4,22 @@
package org.pgpainless.sop
import org.pgpainless.PGPainless
import org.pgpainless.util.ArmoredOutputStreamFactory
import sop.SOPV
import sop.operation.DetachedVerify
import sop.operation.InlineVerify
import sop.operation.Version
class SOPVImpl : SOPV {
class SOPVImpl(private val api: PGPainless) : SOPV {
init {
ArmoredOutputStreamFactory.setVersionInfo(null)
}
override fun detachedVerify(): DetachedVerify = DetachedVerifyImpl()
override fun detachedVerify(): DetachedVerify = DetachedVerifyImpl(api)
override fun inlineVerify(): InlineVerify = InlineVerifyImpl()
override fun inlineVerify(): InlineVerify = InlineVerifyImpl(api)
override fun version(): Version = VersionImpl()
override fun version(): Version = VersionImpl(api)
}

View file

@ -8,11 +8,12 @@ import java.io.IOException
import java.io.InputStream
import java.util.*
import org.bouncycastle.jce.provider.BouncyCastleProvider
import org.pgpainless.PGPainless
import sop.SOP
import sop.operation.Version
/** Implementation of the `version` operation using PGPainless. */
class VersionImpl : Version {
class VersionImpl(private val api: PGPainless) : Version {
companion object {
const val SOP_VERSION = 10