1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2025-12-08 21:31:08 +01:00

Even more migration and code compiles again

This commit is contained in:
Paul Schaub 2025-02-11 16:17:48 +01:00
parent aa3b78b374
commit 6798d2deda
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
50 changed files with 368 additions and 245 deletions

View file

@ -61,8 +61,7 @@ public final class GnuPGDummyKeyUtil {
return hardwareBackedKeys;
}
public static Builder modify(@Nonnull OpenPGPKey key)
{
public static Builder modify(@Nonnull OpenPGPKey key) {
return modify(key.getPGPSecretKeyRing());
}

View file

@ -4,6 +4,7 @@
package org.pgpainless.exception;
import org.bouncycastle.bcpg.KeyIdentifier;
import org.bouncycastle.openpgp.PGPException;
public class WrongPassphraseException extends PGPException {
@ -13,7 +14,11 @@ public class WrongPassphraseException extends PGPException {
}
public WrongPassphraseException(long keyId, PGPException cause) {
this("Wrong passphrase provided for key " + Long.toHexString(keyId), cause);
this(new KeyIdentifier(keyId), cause);
}
public WrongPassphraseException(KeyIdentifier keyIdentifier, PGPException cause) {
this("Wrong passphrase provided for key " + keyIdentifier, cause);
}
public WrongPassphraseException(String message, PGPException cause) {

View file

@ -9,6 +9,8 @@ import org.bouncycastle.openpgp.PGPKeyRing
import org.bouncycastle.openpgp.PGPOnePassSignature
import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSignature
import org.bouncycastle.openpgp.api.OpenPGPCertificate
import org.bouncycastle.openpgp.api.OpenPGPImplementation
import org.pgpainless.PGPainless
import org.pgpainless.key.OpenPgpFingerprint
import org.pgpainless.key.SubkeyIdentifier
@ -72,3 +74,10 @@ val PGPKeyRing.openPgpFingerprint: OpenPgpFingerprint
/** Return this OpenPGP key as an ASCII armored String. */
fun PGPKeyRing.toAsciiArmor(): String = PGPainless.asciiArmor(this)
@Deprecated("Use toOpenPGPCertificate(implementation) instead.")
fun PGPKeyRing.toOpenPGPCertificate(): OpenPGPCertificate =
toOpenPGPCertificate(PGPainless.getInstance().implementation)
fun PGPKeyRing.toOpenPGPCertificate(implementation: OpenPGPImplementation): OpenPGPCertificate =
OpenPGPCertificate(this, implementation)

View file

@ -6,6 +6,9 @@ package org.pgpainless.bouncycastle.extensions
import openpgp.openPgpKeyId
import org.bouncycastle.openpgp.*
import org.bouncycastle.openpgp.api.OpenPGPImplementation
import org.bouncycastle.openpgp.api.OpenPGPKey
import org.pgpainless.PGPainless
import org.pgpainless.key.OpenPgpFingerprint
/** OpenPGP certificate containing the public keys of this OpenPGP key. */
@ -74,3 +77,10 @@ fun PGPSecretKeyRing.getSecretKeyFor(onePassSignature: PGPOnePassSignature): PGP
fun PGPSecretKeyRing.getSecretKeyFor(pkesk: PGPPublicKeyEncryptedData): PGPSecretKey? =
this.getSecretKey(pkesk.keyIdentifier)
@Deprecated("Use toOpenPGPKey(implementation) instead.")
fun PGPSecretKeyRing.toOpenPGPKey(): OpenPGPKey =
toOpenPGPKey(PGPainless.getInstance().implementation)
fun PGPSecretKeyRing.toOpenPGPKey(implementation: OpenPGPImplementation): OpenPGPKey =
OpenPGPKey(this, implementation)

View file

@ -4,17 +4,16 @@
package org.pgpainless.decryption_verification
import org.bouncycastle.bcpg.KeyIdentifier
import java.io.IOException
import java.io.InputStream
import java.util.*
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.*
import org.bouncycastle.openpgp.api.OpenPGPCertificate
import org.bouncycastle.openpgp.api.OpenPGPImplementation
import org.bouncycastle.openpgp.api.OpenPGPKey
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory
import org.pgpainless.PGPainless
import org.pgpainless.bouncycastle.extensions.getPublicKeyFor
import org.pgpainless.decryption_verification.cleartext_signatures.InMemoryMultiPassStrategy
import org.pgpainless.decryption_verification.cleartext_signatures.MultiPassStrategy
import org.pgpainless.key.SubkeyIdentifier
@ -24,9 +23,7 @@ import org.pgpainless.util.Passphrase
import org.pgpainless.util.SessionKey
/** Options for decryption and signature verification. */
class ConsumerOptions(
private val implementation: OpenPGPImplementation
) {
class ConsumerOptions {
private var ignoreMDCErrors = false
var isDisableAsciiArmorCRC = false
@ -183,7 +180,8 @@ class ConsumerOptions(
@JvmOverloads
fun addDecryptionKey(
key: PGPSecretKeyRing,
protector: SecretKeyRingProtector = SecretKeyRingProtector.unprotectedKeys()
protector: SecretKeyRingProtector = SecretKeyRingProtector.unprotectedKeys(),
implementation: OpenPGPImplementation = PGPainless.getInstance().implementation
) = addDecryptionKey(OpenPGPKey(key, implementation), protector)
/**
@ -402,8 +400,10 @@ class ConsumerOptions(
*
* @param certificate certificate
*/
fun addCertificate(certificate: PGPPublicKeyRing,
implementation: OpenPGPImplementation = PGPainless.getInstance().implementation
@JvmOverloads
fun addCertificate(
certificate: PGPPublicKeyRing,
implementation: OpenPGPImplementation = PGPainless.getInstance().implementation
) {
explicitCertificates.add(OpenPGPCertificate(certificate, implementation))
}
@ -442,10 +442,6 @@ class ConsumerOptions(
}
companion object {
@JvmStatic
@JvmOverloads
fun get(
implementation: OpenPGPImplementation = PGPainless.getInstance().implementation
) = ConsumerOptions(implementation)
@JvmStatic fun get() = ConsumerOptions()
}
}

View file

@ -4,9 +4,9 @@
package org.pgpainless.decryption_verification
import org.bouncycastle.bcpg.KeyIdentifier
import java.util.*
import javax.annotation.Nonnull
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.PGPKeyRing
import org.bouncycastle.openpgp.PGPLiteralData
import org.bouncycastle.openpgp.api.OpenPGPCertificate

View file

@ -4,7 +4,8 @@
package org.pgpainless.decryption_verification
import org.bouncycastle.openpgp.PGPPublicKeyRing
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.api.OpenPGPCertificate
fun interface MissingPublicKeyCallback {
@ -14,14 +15,14 @@ fun interface MissingPublicKeyCallback {
* here. PGPainless will then continue verification with the next signature.
*
* Note: The key-id might belong to a subkey, so be aware that when looking up the
* [PGPPublicKeyRing], you may not only search for the key-id on the key rings primary key!
* [OpenPGPCertificate], you may not only search for the key-id on the key rings primary key!
*
* It would be super cool to provide the OpenPgp fingerprint here, but unfortunately
* one-pass-signatures only contain the key id.
*
* @param keyId ID of the missing signing (sub)key
* @param keyIdentifier ID of the missing signing (sub)key
* @return keyring containing the key or null
* @see <a href="https://datatracker.ietf.org/doc/html/rfc4880#section-5.4">RFC</a>
*/
fun onMissingPublicKeyEncountered(keyId: Long): PGPPublicKeyRing?
fun onMissingPublicKeyEncountered(keyIdentifier: KeyIdentifier): OpenPGPCertificate?
}

View file

@ -21,12 +21,8 @@ import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPKeyPair
import org.bouncycastle.openpgp.PGPOnePassSignature
import org.bouncycastle.openpgp.PGPPBEEncryptedData
import org.bouncycastle.openpgp.PGPPrivateKey
import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData
import org.bouncycastle.openpgp.PGPPublicKeyRing
import org.bouncycastle.openpgp.PGPSecretKey
import org.bouncycastle.openpgp.PGPSecretKeyRing
import org.bouncycastle.openpgp.PGPSignature
import org.bouncycastle.openpgp.api.OpenPGPCertificate
import org.bouncycastle.openpgp.api.OpenPGPKey
@ -40,11 +36,9 @@ import org.pgpainless.algorithm.CompressionAlgorithm
import org.pgpainless.algorithm.OpenPgpPacket
import org.pgpainless.algorithm.StreamEncoding
import org.pgpainless.algorithm.SymmetricKeyAlgorithm
import org.pgpainless.bouncycastle.extensions.getPublicKeyFor
import org.pgpainless.bouncycastle.extensions.getSecretKeyFor
import org.pgpainless.bouncycastle.extensions.getSigningKeyFor
import org.pgpainless.bouncycastle.extensions.issuerKeyId
import org.pgpainless.bouncycastle.extensions.unlock
import org.pgpainless.decryption_verification.MessageMetadata.CompressedData
import org.pgpainless.decryption_verification.MessageMetadata.EncryptedData
import org.pgpainless.decryption_verification.MessageMetadata.Layer
@ -61,18 +55,16 @@ import org.pgpainless.exception.MissingDecryptionMethodException
import org.pgpainless.exception.MissingPassphraseException
import org.pgpainless.exception.SignatureValidationException
import org.pgpainless.exception.UnacceptableAlgorithmException
import org.pgpainless.exception.WrongPassphraseException
import org.pgpainless.implementation.ImplementationFactory
import org.pgpainless.key.SubkeyIdentifier
import org.pgpainless.key.util.KeyRingUtils
import org.pgpainless.policy.Policy
import org.pgpainless.signature.consumer.CertificateValidator
import org.pgpainless.signature.consumer.OnePassSignatureCheck
import org.pgpainless.signature.consumer.SignatureCheck
import org.pgpainless.signature.consumer.SignatureValidator
import org.pgpainless.util.ArmoredInputStreamFactory
import org.pgpainless.util.SessionKey
import org.slf4j.LoggerFactory
import kotlin.math.sign
class OpenPgpMessageInputStream(
type: Type,
@ -430,10 +422,11 @@ class OpenPgpMessageInputStream(
val privateKey = secretKey.unlock(protector)
if (decryptWithPrivateKey(
esks,
privateKey,
SubkeyIdentifier(secretKey.openPGPKey.pgpSecretKeyRing, secretKey.keyIdentifier),
pkesk)) {
esks,
privateKey,
SubkeyIdentifier(
secretKey.openPGPKey.pgpSecretKeyRing, secretKey.keyIdentifier),
pkesk)) {
return true
}
}
@ -441,27 +434,24 @@ class OpenPgpMessageInputStream(
// try anonymous secret keys
for (pkesk in esks.anonPkesks) {
for (decryptionKeys in findPotentialDecryptionKeys(pkesk)) {
if (hasUnsupportedS2KSpecifier(decryptionKeys)) {
for (decryptionKey in findPotentialDecryptionKeys(pkesk)) {
if (hasUnsupportedS2KSpecifier(decryptionKey)) {
continue
}
LOGGER.debug("Attempt decryption of anonymous PKESK with key $decryptionKeys.")
val protector = options.getSecretKeyProtector(decryptionKeys.openPGPKey) ?: continue
LOGGER.debug("Attempt decryption of anonymous PKESK with key $decryptionKey.")
val protector = options.getSecretKeyProtector(decryptionKey.openPGPKey) ?: continue
if (!protector.hasPassphraseFor(decryptionKeys.keyIdentifier)) {
if (!protector.hasPassphraseFor(decryptionKey.keyIdentifier)) {
LOGGER.debug(
"Missing passphrase for key ${decryptionKeys.keyIdentifier}. Postponing decryption until all other keys were tried.")
postponedDueToMissingPassphrase.add(decryptionKeys to pkesk)
"Missing passphrase for key ${decryptionKey.keyIdentifier}. Postponing decryption until all other keys were tried.")
postponedDueToMissingPassphrase.add(decryptionKey to pkesk)
continue
}
val privateKey = decryptionKeys.unlock(protector)
val privateKey = decryptionKey.unlock(protector)
if (decryptWithPrivateKey(
esks,
privateKey,
SubkeyIdentifier(decryptionKeys.openPGPKey.pgpSecretKeyRing, privateKey.keyIdentifier),
pkesk)) {
esks, privateKey, SubkeyIdentifier(decryptionKey), pkesk)) {
return true
}
}
@ -471,7 +461,7 @@ class OpenPgpMessageInputStream(
MissingKeyPassphraseStrategy.THROW_EXCEPTION) {
// Non-interactive mode: Throw an exception with all locked decryption keys
postponedDueToMissingPassphrase
.map { SubkeyIdentifier(getDecryptionKey(it.first.keyID)!!, it.first.keyID) }
.map { SubkeyIdentifier(it.first) }
.also { if (it.isNotEmpty()) throw MissingPassphraseException(it.toSet()) }
} else if (options.getMissingKeyPassphraseStrategy() ==
MissingKeyPassphraseStrategy.INTERACTIVE) {
@ -486,7 +476,12 @@ class OpenPgpMessageInputStream(
LOGGER.debug(
"Attempt decryption with key $decryptionKeyId while interactively requesting its passphrase.")
val protector = options.getSecretKeyProtector(decryptionKeys) ?: continue
val privateKey = secretKey.unlock(protector)
val privateKey =
try {
secretKey.unlock(protector)
} catch (e: PGPException) {
throw WrongPassphraseException(secretKey.keyIdentifier, e)
}
if (decryptWithPrivateKey(esks, privateKey, decryptionKeyId, pkesk)) {
return true
}
@ -507,13 +502,12 @@ class OpenPgpMessageInputStream(
pkesk: PGPPublicKeyEncryptedData
): Boolean {
val decryptorFactory =
ImplementationFactory.getInstance().getPublicKeyDataDecryptorFactory(privateKey.privateKey)
ImplementationFactory.getInstance()
.getPublicKeyDataDecryptorFactory(privateKey.privateKey)
return decryptPKESKAndStream(esks, decryptionKeyId, decryptorFactory, pkesk)
}
private fun hasUnsupportedS2KSpecifier(
secretKey: OpenPGPSecretKey
): Boolean {
private fun hasUnsupportedS2KSpecifier(secretKey: OpenPGPSecretKey): Boolean {
val s2k = secretKey.pgpSecretKey.s2K
if (s2k != null) {
if (s2k.type in 100..110) {
@ -686,7 +680,8 @@ class OpenPgpMessageInputStream(
private fun getDecryptionKey(keyId: Long): OpenPGPKey? =
options.getDecryptionKeys().firstOrNull {
it.pgpSecretKeyRing.any { k -> k.keyID == keyId }
it.pgpSecretKeyRing
.any { k -> k.keyID == keyId }
.and(
PGPainless.inspectKeyRing(it).decryptionSubkeys.any { k ->
k.keyIdentifier.keyId == keyId
@ -855,7 +850,9 @@ class OpenPgpMessageInputStream(
val verification =
SignatureVerification(
signature,
SubkeyIdentifier(check.verificationKeys.pgpPublicKeyRing, check.onePassSignature.keyIdentifier))
SubkeyIdentifier(
check.verificationKeys.pgpPublicKeyRing,
check.onePassSignature.keyIdentifier))
try {
SignatureValidator.signatureWasCreatedInBounds(
@ -902,13 +899,13 @@ class OpenPgpMessageInputStream(
if (options.getMissingCertificateCallback() != null) {
return options
.getMissingCertificateCallback()!!
.onMissingPublicKeyEncountered(signature.keyID)
.onMissingPublicKeyEncountered(signature.keyIdentifiers.first())
}
return null // TODO: Missing cert for sig
}
private fun findCertificate(signature: PGPOnePassSignature): OpenPGPCertificate? {
val cert = options.getCertificateSource().getCertificate(signature.keyID)
val cert = options.getCertificateSource().getCertificate(signature.keyIdentifier)
if (cert != null) {
return cert
}
@ -916,7 +913,7 @@ class OpenPgpMessageInputStream(
if (options.getMissingCertificateCallback() != null) {
return options
.getMissingCertificateCallback()!!
.onMissingPublicKeyEncountered(signature.keyID)
.onMissingPublicKeyEncountered(signature.keyIdentifier)
}
return null // TODO: Missing cert for sig
}
@ -968,15 +965,13 @@ class OpenPgpMessageInputStream(
fun finish(layer: Layer, policy: Policy) {
for (detached in detachedSignatures) {
val verification =
SignatureVerification(detached.signature, detached.signingKeyIdentifier)
SignatureVerification(detached.signature, SubkeyIdentifier(detached.issuer))
try {
SignatureValidator.signatureWasCreatedInBounds(
options.getVerifyNotBefore(), options.getVerifyNotAfter())
.verify(detached.signature)
CertificateValidator.validateCertificateAndVerifyInitializedSignature(
detached.signature,
KeyRingUtils.publicKeys(detached.signingKeyRing),
policy)
detached.signature, detached.issuerCertificate.pgpPublicKeyRing, policy)
LOGGER.debug("Acceptable signature by key ${verification.signingKey}")
layer.addVerifiedDetachedSignature(verification)
} catch (e: SignatureValidationException) {
@ -988,15 +983,13 @@ class OpenPgpMessageInputStream(
for (prepended in prependedSignatures) {
val verification =
SignatureVerification(prepended.signature, prepended.keyIdentifier)
SignatureVerification(prepended.signature, SubkeyIdentifier(prepended.issuer))
try {
SignatureValidator.signatureWasCreatedInBounds(
options.getVerifyNotBefore(), options.getVerifyNotAfter())
.verify(prepended.signature)
CertificateValidator.validateCertificateAndVerifyInitializedSignature(
prepended.signature,
KeyRingUtils.publicKeys(prepended.signingKeyRing),
policy)
prepended.signature, prepended.issuerCertificate.pgpPublicKeyRing, policy)
LOGGER.debug("Acceptable signature by key ${verification.signingKey}")
layer.addVerifiedPrependedSignature(verification)
} catch (e: SignatureValidationException) {

View file

@ -5,6 +5,7 @@
package org.pgpainless.key
import java.nio.charset.Charset
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.PGPKeyRing
import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSecretKey
@ -55,6 +56,8 @@ abstract class OpenPgpFingerprint : CharSequence, Comparable<OpenPgpFingerprint>
constructor(keys: PGPKeyRing) : this(keys.publicKey)
abstract val keyIdentifier: KeyIdentifier
/**
* Check, whether the fingerprint consists of 40 valid hexadecimal characters.
*

View file

@ -8,6 +8,7 @@ import java.net.URI
import java.nio.Buffer
import java.nio.ByteBuffer
import java.nio.charset.Charset
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.PGPKeyRing
import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSecretKey
@ -39,6 +40,8 @@ class OpenPgpV4Fingerprint : OpenPgpFingerprint {
return buf.getLong()
}
override val keyIdentifier: KeyIdentifier = KeyIdentifier(bytes)
override fun isValid(fingerprint: String): Boolean {
return fingerprint.matches("^[0-9A-F]{40}$".toRegex())
}

View file

@ -4,6 +4,7 @@
package org.pgpainless.key
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.PGPKeyRing
import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSecretKey
@ -24,4 +25,6 @@ class OpenPgpV5Fingerprint : _64DigitFingerprint {
override fun getVersion(): Int {
return 5
}
override val keyIdentifier: KeyIdentifier = KeyIdentifier(bytes)
}

View file

@ -7,6 +7,7 @@ package org.pgpainless.key
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.PGPKeyRing
import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentKey
/**
* Tuple class used to identify a subkey by fingerprints of the primary key of the subkeys key ring,
@ -25,6 +26,12 @@ class SubkeyIdentifier(
constructor(keys: PGPKeyRing, keyId: Long) : this(keys, KeyIdentifier(keyId))
constructor(
key: OpenPGPComponentKey
) : this(
OpenPgpFingerprint.of(key.certificate.pgpPublicKeyRing),
OpenPgpFingerprint.of(key.pgpPublicKey))
constructor(
keys: PGPKeyRing,
subkeyFingerprint: OpenPgpFingerprint

View file

@ -7,6 +7,7 @@ package org.pgpainless.key
import java.nio.Buffer
import java.nio.ByteBuffer
import java.nio.charset.Charset
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.PGPKeyRing
import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSecretKey
@ -51,6 +52,8 @@ open class _64DigitFingerprint : OpenPgpFingerprint {
return -1 // might be v5 or v6
}
override val keyIdentifier: KeyIdentifier = KeyIdentifier(bytes)
override fun isValid(fingerprint: String): Boolean {
return fingerprint.matches(("^[0-9A-F]{64}$".toRegex()))
}

View file

@ -9,6 +9,7 @@ import java.util.function.Predicate
import javax.annotation.Nonnull
import kotlin.NoSuchElementException
import openpgp.openPgpKeyId
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.bcpg.sig.KeyExpirationTime
import org.bouncycastle.openpgp.*
import org.pgpainless.PGPainless
@ -248,7 +249,7 @@ class SecretKeyRingEditor(
val version = OpenPGPKeyVersion.from(secretKeyRing.getPublicKey().version)
val keyPair = KeyRingBuilder.generateKeyPair(keySpec, OpenPGPKeyVersion.v4, referenceTime)
val subkeyProtector =
PasswordBasedSecretKeyRingProtector.forKeyId(keyPair.keyID, subkeyPassphrase)
PasswordBasedSecretKeyRingProtector.forKeyId(keyPair.keyIdentifier, subkeyPassphrase)
val keyFlags = KeyFlag.fromBitmask(keySpec.subpackets.keyFlags).toMutableList()
return addSubKey(
keyPair,
@ -555,15 +556,15 @@ class SecretKeyRingEditor(
}
override fun changeSubKeyPassphraseFromOldPassphrase(
keyId: Long,
keyIdentifier: KeyIdentifier,
oldPassphrase: Passphrase,
oldProtectionSettings: KeyRingProtectionSettings
): SecretKeyRingEditorInterface.WithKeyRingEncryptionSettings {
return WithKeyRingEncryptionSettingsImpl(
this,
keyId,
keyIdentifier,
CachingSecretKeyRingProtector(
mapOf(keyId to oldPassphrase), oldProtectionSettings, null))
mapOf(keyIdentifier to oldPassphrase), oldProtectionSettings, null))
}
override fun done(): PGPSecretKeyRing {
@ -745,7 +746,7 @@ class SecretKeyRingEditor(
private class WithKeyRingEncryptionSettingsImpl(
private val editor: SecretKeyRingEditor,
private val keyId: Long?,
private val keyId: KeyIdentifier?,
private val oldProtector: SecretKeyRingProtector
) : SecretKeyRingEditorInterface.WithKeyRingEncryptionSettings {
@ -762,7 +763,7 @@ class SecretKeyRingEditor(
private class WithPassphraseImpl(
private val editor: SecretKeyRingEditor,
private val keyId: Long?,
private val keyId: KeyIdentifier?,
private val oldProtector: SecretKeyRingProtector,
private val newProtectionSettings: KeyRingProtectionSettings
) : SecretKeyRingEditorInterface.WithPassphrase {

View file

@ -8,6 +8,7 @@ import java.io.IOException
import java.security.InvalidAlgorithmParameterException
import java.security.NoSuchAlgorithmException
import java.util.*
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.*
import org.pgpainless.algorithm.KeyFlag
import org.pgpainless.key.OpenPgpFingerprint
@ -592,19 +593,9 @@ interface SecretKeyRingEditorInterface {
KeyRingProtectionSettings.secureDefaultSettings()
): WithKeyRingEncryptionSettings
/**
* Change the passphrase of a single subkey in the key ring.
*
* Note: While it is a valid use-case to have different passphrases per subKey, this is one of
* the reasons why OpenPGP sucks in practice.
*
* @param keyId id of the subkey
* @param oldPassphrase old passphrase (empty if the key was unprotected)
* @return next builder step
*/
@Deprecated("Pass KeyIdentifier instead.")
fun changeSubKeyPassphraseFromOldPassphrase(keyId: Long, oldPassphrase: Passphrase) =
changeSubKeyPassphraseFromOldPassphrase(
keyId, oldPassphrase, KeyRingProtectionSettings.secureDefaultSettings())
changeSubKeyPassphraseFromOldPassphrase(KeyIdentifier(keyId), oldPassphrase)
/**
* Change the passphrase of a single subkey in the key ring.
@ -612,13 +603,30 @@ interface SecretKeyRingEditorInterface {
* Note: While it is a valid use-case to have different passphrases per subKey, this is one of
* the reasons why OpenPGP sucks in practice.
*
* @param keyId id of the subkey
* @param keyIdentifier id of the subkey
* @param oldPassphrase old passphrase (empty if the key was unprotected)
* @return next builder step
*/
fun changeSubKeyPassphraseFromOldPassphrase(
keyIdentifier: KeyIdentifier,
oldPassphrase: Passphrase
) =
changeSubKeyPassphraseFromOldPassphrase(
keyIdentifier, oldPassphrase, KeyRingProtectionSettings.secureDefaultSettings())
/**
* Change the passphrase of a single subkey in the key ring.
*
* Note: While it is a valid use-case to have different passphrases per subKey, this is one of
* the reasons why OpenPGP sucks in practice.
*
* @param keyIdentifier id of the subkey
* @param oldPassphrase old passphrase (empty if the key was unprotected)
* @param oldProtectionSettings custom settings for the old passphrase
* @return next builder step
*/
fun changeSubKeyPassphraseFromOldPassphrase(
keyId: Long,
keyIdentifier: KeyIdentifier,
oldPassphrase: Passphrase,
oldProtectionSettings: KeyRingProtectionSettings
): WithKeyRingEncryptionSettings

View file

@ -4,6 +4,8 @@
package org.pgpainless.key.protection
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.api.OpenPGPKey
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor
import org.pgpainless.implementation.ImplementationFactory
@ -22,16 +24,21 @@ open class BaseSecretKeyRingProtector(
passphraseProvider: SecretKeyPassphraseProvider
) : this(passphraseProvider, KeyRingProtectionSettings.secureDefaultSettings())
override fun hasPassphraseFor(keyId: Long): Boolean = passphraseProvider.hasPassphrase(keyId)
override fun hasPassphraseFor(keyIdentifier: KeyIdentifier): Boolean {
return passphraseProvider.hasPassphrase(keyIdentifier)
}
override fun getDecryptor(keyId: Long): PBESecretKeyDecryptor? =
passphraseProvider.getPassphraseFor(keyId)?.let {
getDecryptor(KeyIdentifier(keyId))
override fun getDecryptor(keyIdentifier: KeyIdentifier): PBESecretKeyDecryptor? =
passphraseProvider.getPassphraseFor(keyIdentifier)?.let {
if (it.isEmpty) null
else ImplementationFactory.getInstance().getPBESecretKeyDecryptor(it)
}
override fun getEncryptor(keyId: Long): PBESecretKeyEncryptor? =
passphraseProvider.getPassphraseFor(keyId)?.let {
override fun getEncryptor(keyIdentifier: KeyIdentifier): PBESecretKeyEncryptor? {
return passphraseProvider.getPassphraseFor(keyIdentifier)?.let {
if (it.isEmpty) null
else
ImplementationFactory.getInstance()
@ -41,4 +48,9 @@ open class BaseSecretKeyRingProtector(
protectionSettings.s2kCount,
it)
}
}
override fun getKeyPassword(p0: OpenPGPKey.OpenPGPSecretKey): CharArray? {
return passphraseProvider.getPassphraseFor(p0.keyIdentifier)?.getChars()
}
}

View file

@ -4,9 +4,12 @@
package org.pgpainless.key.protection
import openpgp.openPgpKeyId
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.PGPKeyRing
import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.api.OpenPGPKey
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor
import org.pgpainless.key.OpenPgpFingerprint
import org.pgpainless.key.protection.passphrase_provider.SecretKeyPassphraseProvider
import org.pgpainless.util.Passphrase
@ -21,7 +24,7 @@ import org.pgpainless.util.Passphrase
*/
class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphraseProvider {
private val cache: MutableMap<Long?, Passphrase>
private val cache: MutableMap<KeyIdentifier?, Passphrase>
private val protector: SecretKeyRingProtector
private val provider: SecretKeyPassphraseProvider?
@ -30,12 +33,12 @@ class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphras
constructor(
missingPassphraseCallback: SecretKeyPassphraseProvider?
) : this(
mapOf<Long, Passphrase>(),
mapOf<KeyIdentifier, Passphrase>(),
KeyRingProtectionSettings.secureDefaultSettings(),
missingPassphraseCallback)
constructor(
passphrases: Map<Long, Passphrase>,
passphrases: Map<KeyIdentifier, Passphrase>,
protectionSettings: KeyRingProtectionSettings,
missingPassphraseCallback: SecretKeyPassphraseProvider?
) {
@ -44,6 +47,10 @@ class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphras
this.provider = missingPassphraseCallback
}
@Deprecated("Pass KeyIdentifier instead.")
fun addPassphrase(keyId: Long, passphrase: Passphrase) =
addPassphrase(KeyIdentifier(keyId), passphrase)
/**
* Add a passphrase to the cache. If the cache already contains a passphrase for the given
* key-id, a [IllegalArgumentException] is thrown. The reason for this is to prevent accidental
@ -53,24 +60,30 @@ class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphras
* If you can ensure that there will be no key-id clash, and you want to replace the passphrase,
* you can use [replacePassphrase] to replace the passphrase.
*
* @param keyId id of the key
* @param keyIdentifier id of the key
* @param passphrase passphrase
*/
fun addPassphrase(keyId: Long, passphrase: Passphrase) = apply {
require(!cache.containsKey(keyId)) {
"The cache already holds a passphrase for ID ${keyId.openPgpKeyId()}.\n" +
fun addPassphrase(keyIdentifier: KeyIdentifier, passphrase: Passphrase) = apply {
require(!cache.containsKey(keyIdentifier)) {
"The cache already holds a passphrase for ID ${keyIdentifier}.\n" +
"If you want to replace this passphrase, use replacePassphrase(Long, Passphrase) instead."
}
cache[keyId] = passphrase
cache[keyIdentifier] = passphrase
}
@Deprecated("Pass KeyIdentifier instead.")
fun replacePassphrase(keyId: Long, passphrase: Passphrase) =
replacePassphrase(KeyIdentifier(keyId), passphrase)
/**
* Replace the passphrase for the given key-id in the cache.
*
* @param keyId keyId
* @param passphrase passphrase
*/
fun replacePassphrase(keyId: Long, passphrase: Passphrase) = apply { cache[keyId] = passphrase }
fun replacePassphrase(keyId: KeyIdentifier, passphrase: Passphrase) = apply {
cache[keyId] = passphrase
}
/**
* Remember the given passphrase for all keys in the given key ring. If for the key-id of any
@ -91,14 +104,14 @@ class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphras
fun addPassphrase(keyRing: PGPKeyRing, passphrase: Passphrase) = apply {
// check for existing passphrases before doing anything
keyRing.publicKeys.forEach {
require(!cache.containsKey(it.keyID)) {
"The cache already holds a passphrase for the key with ID ${it.keyID.openPgpKeyId()}.\n" +
require(!cache.containsKey(it.keyIdentifier)) {
"The cache already holds a passphrase for the key with ID ${it.keyIdentifier}.\n" +
"If you want to replace the passphrase, use replacePassphrase(PGPKeyRing, Passphrase) instead."
}
}
// only then instert
keyRing.publicKeys.forEach { cache[it.keyID] = passphrase }
keyRing.publicKeys.forEach { cache[it.keyIdentifier] = passphrase }
}
/**
@ -108,7 +121,7 @@ class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphras
* @param passphrase passphrase
*/
fun replacePassphrase(keyRing: PGPKeyRing, passphrase: Passphrase) = apply {
keyRing.publicKeys.forEach { cache[it.keyID] = passphrase }
keyRing.publicKeys.forEach { cache[it.keyIdentifier] = passphrase }
}
/**
@ -118,7 +131,7 @@ class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphras
* @param passphrase passphrase
*/
fun addPassphrase(key: PGPPublicKey, passphrase: Passphrase) =
addPassphrase(key.keyID, passphrase)
addPassphrase(key.keyIdentifier, passphrase)
/**
* Remember the given passphrase for the key with the given fingerprint.
@ -127,14 +140,17 @@ class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphras
* @param passphrase passphrase
*/
fun addPassphrase(fingerprint: OpenPgpFingerprint, passphrase: Passphrase) =
addPassphrase(fingerprint.keyId, passphrase)
addPassphrase(fingerprint.keyIdentifier, passphrase)
@Deprecated("Pass KeyIdentifier instead.")
fun forgetPassphrase(keyId: Long) = forgetPassphrase(KeyIdentifier(keyId))
/**
* Remove a passphrase from the cache. The passphrase will be cleared and then removed.
*
* @param keyId id of the key
*/
fun forgetPassphrase(keyId: Long) = apply { cache.remove(keyId)?.clear() }
fun forgetPassphrase(keyId: KeyIdentifier) = apply { cache.remove(keyId)?.clear() }
/**
* Forget the passphrase to all keys in the provided key ring.
@ -150,18 +166,27 @@ class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphras
*
* @param key key
*/
fun forgetPassphrase(key: PGPPublicKey) = apply { forgetPassphrase(key.keyID) }
fun forgetPassphrase(key: PGPPublicKey) = apply { forgetPassphrase(key.keyIdentifier) }
override fun getPassphraseFor(keyId: Long?): Passphrase? {
return if (hasPassphrase(keyId)) cache[keyId]
else provider?.getPassphraseFor(keyId)?.also { cache[keyId] = it }
override fun getPassphraseFor(keyIdentifier: KeyIdentifier): Passphrase? {
return if (hasPassphrase(keyIdentifier)) cache[keyIdentifier]
else provider?.getPassphraseFor(keyIdentifier)?.also { cache[keyIdentifier] = it }
}
override fun hasPassphrase(keyId: Long?) = cache[keyId]?.isValid ?: false
override fun hasPassphraseFor(keyIdentifier: KeyIdentifier): Boolean {
return hasPassphrase(keyIdentifier)
}
override fun hasPassphraseFor(keyId: Long) = hasPassphrase(keyId)
override fun hasPassphrase(keyIdentifier: KeyIdentifier): Boolean {
return cache[keyIdentifier]?.isValid ?: false
}
override fun getDecryptor(keyId: Long) = protector.getDecryptor(keyId)
override fun getDecryptor(keyIdentifier: KeyIdentifier): PBESecretKeyDecryptor? =
protector.getDecryptor(keyIdentifier)
override fun getEncryptor(keyId: Long) = protector.getEncryptor(keyId)
override fun getEncryptor(keyIdentifier: KeyIdentifier): PBESecretKeyEncryptor? =
protector.getEncryptor(keyIdentifier)
override fun getKeyPassword(p0: OpenPGPKey.OpenPGPSecretKey): CharArray? =
getPassphraseFor(p0.keyIdentifier)?.getChars()
}

View file

@ -4,6 +4,7 @@
package org.pgpainless.key.protection
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.PGPKeyRing
import org.bouncycastle.openpgp.PGPSecretKey
import org.pgpainless.key.protection.passphrase_provider.SecretKeyPassphraseProvider
@ -38,12 +39,12 @@ class PasswordBasedSecretKeyRingProtector : BaseSecretKeyRingProtector {
): PasswordBasedSecretKeyRingProtector {
return object : SecretKeyPassphraseProvider {
override fun getPassphraseFor(keyId: Long?): Passphrase? {
return if (hasPassphrase(keyId)) passphrase else null
override fun getPassphraseFor(keyIdentifier: KeyIdentifier): Passphrase? {
return if (hasPassphrase(keyIdentifier)) passphrase else null
}
override fun hasPassphrase(keyId: Long?): Boolean {
return keyId != null && keyRing.getPublicKey(keyId) != null
override fun hasPassphrase(keyIdentifier: KeyIdentifier): Boolean {
return keyRing.getPublicKey(keyIdentifier) != null
}
}
.let { PasswordBasedSecretKeyRingProtector(it) }
@ -51,20 +52,20 @@ class PasswordBasedSecretKeyRingProtector : BaseSecretKeyRingProtector {
@JvmStatic
fun forKey(key: PGPSecretKey, passphrase: Passphrase): PasswordBasedSecretKeyRingProtector =
forKeyId(key.publicKey.keyID, passphrase)
forKeyId(key.publicKey.keyIdentifier, passphrase)
@JvmStatic
fun forKeyId(
singleKeyId: Long,
singleKeyIdentifier: KeyIdentifier,
passphrase: Passphrase
): PasswordBasedSecretKeyRingProtector {
return object : SecretKeyPassphraseProvider {
override fun getPassphraseFor(keyId: Long?): Passphrase? {
return if (hasPassphrase(keyId)) passphrase else null
override fun getPassphraseFor(keyIdentifier: KeyIdentifier): Passphrase? {
return if (hasPassphrase(keyIdentifier)) passphrase else null
}
override fun hasPassphrase(keyId: Long?): Boolean {
return keyId == singleKeyId
override fun hasPassphrase(keyIdentifier: KeyIdentifier): Boolean {
return keyIdentifier.matches(singleKeyIdentifier)
}
}
.let { PasswordBasedSecretKeyRingProtector(it) }

View file

@ -4,6 +4,7 @@
package org.pgpainless.key.protection
import kotlin.Throws
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPSecretKey
@ -14,7 +15,6 @@ import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor
import org.pgpainless.key.protection.passphrase_provider.SecretKeyPassphraseProvider
import org.pgpainless.key.protection.passphrase_provider.SolitaryPassphraseProvider
import org.pgpainless.util.Passphrase
import kotlin.Throws
/**
* Task of the [SecretKeyRingProtector] is to map encryptor/decryptor objects to key-ids.
@ -43,10 +43,11 @@ interface SecretKeyRingProtector : KeyPassphraseProvider {
* @param keyId id of the key
* @return decryptor for the key
*/
@Throws(PGPException::class) fun getDecryptor(keyId: Long): PBESecretKeyDecryptor? =
getDecryptor(KeyIdentifier(keyId))
@Throws(PGPException::class)
fun getDecryptor(keyId: Long): PBESecretKeyDecryptor? = getDecryptor(KeyIdentifier(keyId))
@Throws(PGPException::class) fun getDecryptor(keyIdentifier: KeyIdentifier): PBESecretKeyDecryptor?
@Throws(PGPException::class)
fun getDecryptor(keyIdentifier: KeyIdentifier): PBESecretKeyDecryptor?
/**
* Return an encryptor for the key of id `keyId`. This method returns null if the key is
@ -55,10 +56,11 @@ interface SecretKeyRingProtector : KeyPassphraseProvider {
* @param keyId id of the key
* @return encryptor for the key
*/
@Throws(PGPException::class) fun getEncryptor(keyId: Long): PBESecretKeyEncryptor? =
getEncryptor(KeyIdentifier(keyId))
@Throws(PGPException::class)
fun getEncryptor(keyId: Long): PBESecretKeyEncryptor? = getEncryptor(KeyIdentifier(keyId))
@Throws(PGPException::class) fun getEncryptor(keyIdentifier: KeyIdentifier): PBESecretKeyEncryptor?
@Throws(PGPException::class)
fun getEncryptor(keyIdentifier: KeyIdentifier): PBESecretKeyEncryptor?
companion object {
@ -97,7 +99,7 @@ interface SecretKeyRingProtector : KeyPassphraseProvider {
passphrase: Passphrase,
keys: PGPSecretKeyRing
): SecretKeyRingProtector =
fromPassphraseMap(keys.map { it.keyID }.associateWith { passphrase })
fromPassphraseMap(keys.map { it.keyIdentifier }.associateWith { passphrase })
/**
* Use the provided passphrase to unlock any key.
@ -132,12 +134,15 @@ interface SecretKeyRingProtector : KeyPassphraseProvider {
* Otherwise, this protector will always return null.
*
* @param passphrase passphrase
* @param keyId id of the key to lock/unlock
* @param keyIdentifier id of the key to lock/unlock
* @return protector
*/
@JvmStatic
fun unlockSingleKeyWith(passphrase: Passphrase, keyId: Long): SecretKeyRingProtector =
PasswordBasedSecretKeyRingProtector.forKeyId(keyId, passphrase)
fun unlockSingleKeyWith(
passphrase: Passphrase,
keyIdentifier: KeyIdentifier
): SecretKeyRingProtector =
PasswordBasedSecretKeyRingProtector.forKeyId(keyIdentifier, passphrase)
/**
* Protector for unprotected keys. This protector returns null for all
@ -159,7 +164,9 @@ interface SecretKeyRingProtector : KeyPassphraseProvider {
* @return protector
*/
@JvmStatic
fun fromPassphraseMap(passphraseMap: Map<Long, Passphrase>): SecretKeyRingProtector =
fun fromPassphraseMap(
passphraseMap: Map<KeyIdentifier, Passphrase>
): SecretKeyRingProtector =
CachingSecretKeyRingProtector(
passphraseMap, KeyRingProtectionSettings.secureDefaultSettings(), null)
}

View file

@ -4,6 +4,7 @@
package org.pgpainless.key.protection.passphrase_provider
import org.bouncycastle.bcpg.KeyIdentifier
import org.pgpainless.util.Passphrase
/**
@ -14,9 +15,11 @@ import org.pgpainless.util.Passphrase
*
* TODO: Make this null-safe and throw an exception instead?
*/
class MapBasedPassphraseProvider(val map: Map<Long?, Passphrase>) : SecretKeyPassphraseProvider {
class MapBasedPassphraseProvider(val map: Map<KeyIdentifier?, Passphrase>) :
SecretKeyPassphraseProvider {
override fun getPassphraseFor(keyId: Long?): Passphrase? = map[keyId]
override fun getPassphraseFor(keyIdentifier: KeyIdentifier): Passphrase? = map[keyIdentifier]
override fun hasPassphrase(keyId: Long?): Boolean = map.containsKey(keyId)
override fun hasPassphrase(keyIdentifier: KeyIdentifier): Boolean =
map.containsKey(keyIdentifier)
}

View file

@ -4,6 +4,7 @@
package org.pgpainless.key.protection.passphrase_provider
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.PGPSecretKey
import org.pgpainless.util.Passphrase
@ -19,7 +20,7 @@ interface SecretKeyPassphraseProvider {
* @return passphrase or null, if no passphrase record is found.
*/
fun getPassphraseFor(secretKey: PGPSecretKey): Passphrase? {
return getPassphraseFor(secretKey.keyID)
return getPassphraseFor(secretKey.keyIdentifier)
}
/**
@ -30,7 +31,11 @@ interface SecretKeyPassphraseProvider {
* @param keyId if of the secret key
* @return passphrase or null, if no passphrase record has been found.
*/
fun getPassphraseFor(keyId: Long?): Passphrase?
fun getPassphraseFor(keyId: Long): Passphrase? = getPassphraseFor(KeyIdentifier(keyId))
fun hasPassphrase(keyId: Long?): Boolean
fun getPassphraseFor(keyIdentifier: KeyIdentifier): Passphrase?
fun hasPassphrase(keyId: Long): Boolean = hasPassphrase(KeyIdentifier(keyId))
fun hasPassphrase(keyIdentifier: KeyIdentifier): Boolean
}

View file

@ -4,12 +4,13 @@
package org.pgpainless.key.protection.passphrase_provider
import org.bouncycastle.bcpg.KeyIdentifier
import org.pgpainless.util.Passphrase
/** Implementation of the [SecretKeyPassphraseProvider] that holds a single [Passphrase]. */
class SolitaryPassphraseProvider(val passphrase: Passphrase?) : SecretKeyPassphraseProvider {
override fun getPassphraseFor(keyId: Long?): Passphrase? = passphrase
override fun getPassphraseFor(keyIdentifier: KeyIdentifier): Passphrase? = passphrase
override fun hasPassphrase(keyId: Long?): Boolean = true
override fun hasPassphrase(keyIdentifier: KeyIdentifier): Boolean = true
}

View file

@ -7,6 +7,7 @@ package org.pgpainless.key.util
import java.io.ByteArrayOutputStream
import kotlin.jvm.Throws
import openpgp.openPgpKeyId
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.bcpg.S2K
import org.bouncycastle.bcpg.SecretKeyPacket
import org.bouncycastle.openpgp.*
@ -468,7 +469,7 @@ class KeyRingUtils {
@JvmStatic
@Throws(MissingPassphraseException::class, PGPException::class)
fun changePassphrase(
keyId: Long?,
keyId: KeyIdentifier?,
secretKeys: PGPSecretKeyRing,
oldProtector: SecretKeyRingProtector,
newProtector: SecretKeyRingProtector
@ -484,7 +485,7 @@ class KeyRingUtils {
secretKeys.secretKeys
.asSequence()
.map {
if (it.keyID == keyId) {
if (it.keyIdentifier.matches(keyId)) {
reencryptPrivateKey(it, oldProtector, newProtector)
} else {
it

View file

@ -13,6 +13,7 @@ import org.bouncycastle.openpgp.PGPSignature
import org.pgpainless.PGPainless
import org.pgpainless.algorithm.KeyFlag
import org.pgpainless.algorithm.SignatureType
import org.pgpainless.bouncycastle.extensions.getPublicKey
import org.pgpainless.bouncycastle.extensions.issuerKeyId
import org.pgpainless.exception.SignatureValidationException
import org.pgpainless.key.util.KeyRingUtils
@ -303,10 +304,12 @@ class CertificateValidator {
policy: Policy
): Boolean {
return validateCertificate(
onePassSignature.signature!!, onePassSignature.verificationKeys, policy) &&
onePassSignature.signature!!,
onePassSignature.verificationKeys.pgpPublicKeyRing,
policy) &&
SignatureVerifier.verifyOnePassSignature(
onePassSignature.signature!!,
onePassSignature.verificationKeys.getPublicKey(
onePassSignature.verificationKeys.pgpKeyRing.getPublicKey(
onePassSignature.signature!!.issuerKeyId),
onePassSignature,
policy)

View file

@ -8,8 +8,6 @@ import org.bouncycastle.openpgp.PGPOnePassSignature
import org.bouncycastle.openpgp.PGPPublicKeyRing
import org.bouncycastle.openpgp.PGPSignature
import org.bouncycastle.openpgp.api.OpenPGPCertificate
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentKey
import org.pgpainless.bouncycastle.extensions.getSigningKeyFor
import org.pgpainless.key.SubkeyIdentifier
/**