mirror of
https://github.com/pgpainless/pgpainless.git
synced 2025-09-09 10:19:39 +02:00
WIP: Transform Options and OpenPgpMessageInputStream
This commit is contained in:
parent
53053cf3fc
commit
217a25bd62
13 changed files with 231 additions and 111 deletions
|
@ -10,6 +10,7 @@ import org.bouncycastle.bcpg.SecretKeyPacket;
|
|||
import org.bouncycastle.bcpg.SecretSubkeyPacket;
|
||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.pgpainless.key.SubkeyIdentifier;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
@ -60,6 +61,11 @@ public final class GnuPGDummyKeyUtil {
|
|||
return hardwareBackedKeys;
|
||||
}
|
||||
|
||||
public static Builder modify(@Nonnull OpenPGPKey key)
|
||||
{
|
||||
return modify(key.getPGPSecretKeyRing());
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the given {@link PGPSecretKeyRing}.
|
||||
*
|
||||
|
|
|
@ -11,7 +11,10 @@ import org.bouncycastle.openpgp.PGPPublicKeyRing
|
|||
import org.bouncycastle.openpgp.PGPSecretKeyRing
|
||||
import org.bouncycastle.openpgp.PGPSignature
|
||||
import org.bouncycastle.openpgp.api.OpenPGPApi
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate
|
||||
import org.bouncycastle.openpgp.api.OpenPGPImplementation
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKeyReader
|
||||
import org.bouncycastle.openpgp.api.bc.BcOpenPGPApi
|
||||
import org.pgpainless.algorithm.OpenPGPKeyVersion
|
||||
import org.pgpainless.bouncycastle.PolicyAdapter
|
||||
|
@ -43,6 +46,14 @@ class PGPainless(
|
|||
fun generateKey(version: OpenPGPKeyVersion = OpenPGPKeyVersion.v4): KeyRingTemplates =
|
||||
KeyRingTemplates(version)
|
||||
|
||||
fun readKey(): OpenPGPKeyReader = api.readKeyOrCertificate()
|
||||
|
||||
fun toKey(secretKeyRing: PGPSecretKeyRing): OpenPGPKey =
|
||||
OpenPGPKey(secretKeyRing, implementation)
|
||||
|
||||
fun toCertificate(publicKeyRing: PGPPublicKeyRing): OpenPGPCertificate =
|
||||
OpenPGPCertificate(publicKeyRing, implementation)
|
||||
|
||||
companion object {
|
||||
|
||||
@Volatile private var instance: PGPainless? = null
|
||||
|
@ -81,7 +92,9 @@ class PGPainless(
|
|||
*
|
||||
* @return builder
|
||||
*/
|
||||
@JvmStatic fun readKeyRing() = KeyRingReader()
|
||||
@Deprecated("Use readKey() instead.", replaceWith = ReplaceWith("readKey()"))
|
||||
@JvmStatic
|
||||
fun readKeyRing() = KeyRingReader()
|
||||
|
||||
/**
|
||||
* Extract a public key certificate from a secret key.
|
||||
|
@ -90,6 +103,7 @@ class PGPainless(
|
|||
* @return public key certificate
|
||||
*/
|
||||
@JvmStatic
|
||||
@Deprecated("Use toKey() and then .toCertificate() instead.")
|
||||
fun extractCertificate(secretKey: PGPSecretKeyRing) =
|
||||
KeyRingUtils.publicKeyRingFrom(secretKey)
|
||||
|
||||
|
@ -190,6 +204,9 @@ class PGPainless(
|
|||
fun inspectKeyRing(key: PGPKeyRing, referenceTime: Date = Date()) =
|
||||
KeyRingInfo(key, referenceTime)
|
||||
|
||||
fun inspectKeyRing(key: OpenPGPKey, referenceTime: Date = Date()) =
|
||||
KeyRingInfo(key, getPolicy(), referenceTime)
|
||||
|
||||
/**
|
||||
* Access, and make changes to PGPainless policy on acceptable/default algorithms etc.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package org.pgpainless.bouncycastle.extensions
|
||||
|
||||
import org.bouncycastle.openpgp.PGPOnePassSignature
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentKey
|
||||
|
||||
fun OpenPGPCertificate.getSigningKeyFor(ops: PGPOnePassSignature): OpenPGPComponentKey? =
|
||||
this.getKey(ops.keyIdentifier)
|
|
@ -0,0 +1,8 @@
|
|||
package org.pgpainless.bouncycastle.extensions
|
||||
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey.OpenPGPSecretKey
|
||||
|
||||
fun OpenPGPKey.getSecretKeyFor(pkesk: PGPPublicKeyEncryptedData): OpenPGPSecretKey? =
|
||||
this.getSecretKey(pkesk.keyIdentifier)
|
|
@ -73,7 +73,4 @@ fun PGPSecretKeyRing.getSecretKeyFor(onePassSignature: PGPOnePassSignature): PGP
|
|||
this.getSecretKey(onePassSignature.keyID)
|
||||
|
||||
fun PGPSecretKeyRing.getSecretKeyFor(pkesk: PGPPublicKeyEncryptedData): PGPSecretKey? =
|
||||
when (pkesk.version) {
|
||||
3 -> this.getSecretKey(pkesk.keyID)
|
||||
else -> throw NotImplementedError("Version 6 PKESKs are not yet supported.")
|
||||
}
|
||||
this.getSecretKey(pkesk.keyIdentifier)
|
||||
|
|
|
@ -4,11 +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.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
|
||||
|
@ -19,7 +24,9 @@ import org.pgpainless.util.Passphrase
|
|||
import org.pgpainless.util.SessionKey
|
||||
|
||||
/** Options for decryption and signature verification. */
|
||||
class ConsumerOptions {
|
||||
class ConsumerOptions(
|
||||
private val implementation: OpenPGPImplementation
|
||||
) {
|
||||
|
||||
private var ignoreMDCErrors = false
|
||||
var isDisableAsciiArmorCRC = false
|
||||
|
@ -34,7 +41,7 @@ class ConsumerOptions {
|
|||
private var sessionKey: SessionKey? = null
|
||||
private val customDecryptorFactories =
|
||||
mutableMapOf<SubkeyIdentifier, PublicKeyDataDecryptorFactory>()
|
||||
private val decryptionKeys = mutableMapOf<PGPSecretKeyRing, SecretKeyRingProtector>()
|
||||
private val decryptionKeys = mutableMapOf<OpenPGPKey, SecretKeyRingProtector>()
|
||||
private val decryptionPassphrases = mutableSetOf<Passphrase>()
|
||||
private var missingKeyPassphraseStrategy = MissingKeyPassphraseStrategy.INTERACTIVE
|
||||
private var multiPassStrategy: MultiPassStrategy = InMemoryMultiPassStrategy()
|
||||
|
@ -65,6 +72,10 @@ class ConsumerOptions {
|
|||
|
||||
fun getVerifyNotAfter() = verifyNotAfter
|
||||
|
||||
fun addVerificationCert(verificationCert: OpenPGPCertificate): ConsumerOptions = apply {
|
||||
this.certificates.addCertificate(verificationCert)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a certificate (public key ring) for signature verification.
|
||||
*
|
||||
|
@ -155,6 +166,12 @@ class ConsumerOptions {
|
|||
|
||||
fun getSessionKey() = sessionKey
|
||||
|
||||
@JvmOverloads
|
||||
fun addDecryptionKey(
|
||||
key: OpenPGPKey,
|
||||
protector: SecretKeyRingProtector = SecretKeyRingProtector.unprotectedKeys()
|
||||
) = apply { decryptionKeys[key] = protector }
|
||||
|
||||
/**
|
||||
* Add a key for message decryption. If the key is encrypted, the [SecretKeyRingProtector] is
|
||||
* used to decrypt it when needed.
|
||||
|
@ -167,7 +184,7 @@ class ConsumerOptions {
|
|||
fun addDecryptionKey(
|
||||
key: PGPSecretKeyRing,
|
||||
protector: SecretKeyRingProtector = SecretKeyRingProtector.unprotectedKeys()
|
||||
) = apply { decryptionKeys[key] = protector }
|
||||
) = addDecryptionKey(OpenPGPKey(key, implementation), protector)
|
||||
|
||||
/**
|
||||
* Add the keys in the provided key collection for message decryption.
|
||||
|
@ -270,7 +287,7 @@ class ConsumerOptions {
|
|||
* @param decryptionKeyRing secret key
|
||||
* @return protector for that particular secret key
|
||||
*/
|
||||
fun getSecretKeyProtector(decryptionKeyRing: PGPSecretKeyRing): SecretKeyRingProtector? {
|
||||
fun getSecretKeyProtector(decryptionKeyRing: OpenPGPKey): SecretKeyRingProtector? {
|
||||
return decryptionKeys[decryptionKeyRing]
|
||||
}
|
||||
|
||||
|
@ -378,14 +395,20 @@ class ConsumerOptions {
|
|||
* available signer certificates.
|
||||
*/
|
||||
class CertificateSource {
|
||||
private val explicitCertificates: MutableSet<PGPPublicKeyRing> = mutableSetOf()
|
||||
private val explicitCertificates: MutableSet<OpenPGPCertificate> = mutableSetOf()
|
||||
|
||||
/**
|
||||
* Add a certificate as verification cert explicitly.
|
||||
*
|
||||
* @param certificate certificate
|
||||
*/
|
||||
fun addCertificate(certificate: PGPPublicKeyRing) {
|
||||
fun addCertificate(certificate: PGPPublicKeyRing,
|
||||
implementation: OpenPGPImplementation = PGPainless.getInstance().implementation
|
||||
) {
|
||||
explicitCertificates.add(OpenPGPCertificate(certificate, implementation))
|
||||
}
|
||||
|
||||
fun addCertificate(certificate: OpenPGPCertificate) {
|
||||
explicitCertificates.add(certificate)
|
||||
}
|
||||
|
||||
|
@ -394,7 +417,7 @@ class ConsumerOptions {
|
|||
*
|
||||
* @return explicitly set verification certs
|
||||
*/
|
||||
fun getExplicitCertificates(): Set<PGPPublicKeyRing> {
|
||||
fun getExplicitCertificates(): Set<OpenPGPCertificate> {
|
||||
return explicitCertificates.toSet()
|
||||
}
|
||||
|
||||
|
@ -406,15 +429,23 @@ class ConsumerOptions {
|
|||
* @param keyId key id
|
||||
* @return certificate
|
||||
*/
|
||||
fun getCertificate(keyId: Long): PGPPublicKeyRing? {
|
||||
return explicitCertificates.firstOrNull { it.getPublicKey(keyId) != null }
|
||||
fun getCertificate(keyId: Long): OpenPGPCertificate? {
|
||||
return getCertificate(KeyIdentifier(keyId))
|
||||
}
|
||||
|
||||
fun getCertificate(signature: PGPSignature): PGPPublicKeyRing? =
|
||||
explicitCertificates.firstOrNull { it.getPublicKeyFor(signature) != null }
|
||||
fun getCertificate(identifier: KeyIdentifier): OpenPGPCertificate? {
|
||||
return explicitCertificates.firstOrNull { it.getKey(identifier) != null }
|
||||
}
|
||||
|
||||
fun getCertificate(signature: PGPSignature): OpenPGPCertificate? =
|
||||
explicitCertificates.firstOrNull { it.getSigningKeyFor(signature) != null }
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic fun get() = ConsumerOptions()
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun get(
|
||||
implementation: OpenPGPImplementation = PGPainless.getInstance().implementation
|
||||
) = ConsumerOptions(implementation)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,10 +4,12 @@
|
|||
|
||||
package org.pgpainless.decryption_verification
|
||||
|
||||
import org.bouncycastle.bcpg.KeyIdentifier
|
||||
import java.util.*
|
||||
import javax.annotation.Nonnull
|
||||
import org.bouncycastle.openpgp.PGPKeyRing
|
||||
import org.bouncycastle.openpgp.PGPLiteralData
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate
|
||||
import org.pgpainless.algorithm.CompressionAlgorithm
|
||||
import org.pgpainless.algorithm.StreamEncoding
|
||||
import org.pgpainless.algorithm.SymmetricKeyAlgorithm
|
||||
|
@ -47,9 +49,15 @@ class MessageMetadata(val message: Message) {
|
|||
if (encryptionAlgorithm == null) false
|
||||
else encryptionAlgorithm != SymmetricKeyAlgorithm.NULL
|
||||
|
||||
fun isEncryptedFor(keys: PGPKeyRing): Boolean {
|
||||
fun isEncryptedFor(cert: OpenPGPCertificate): Boolean {
|
||||
return encryptionLayers.asSequence().any {
|
||||
it.recipients.any { keyId -> keys.getPublicKey(keyId) != null }
|
||||
it.recipients.any { keyId -> cert.getKey(KeyIdentifier(keyId)) != null }
|
||||
}
|
||||
}
|
||||
|
||||
fun isEncryptedFor(cert: PGPKeyRing): Boolean {
|
||||
return encryptionLayers.asSequence().any {
|
||||
it.recipients.any { keyId -> cert.getPublicKey(keyId) != null }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,6 +278,9 @@ class MessageMetadata(val message: Message) {
|
|||
fun isVerifiedSignedBy(keys: PGPKeyRing) =
|
||||
verifiedSignatures.any { keys.matches(it.signingKey) }
|
||||
|
||||
fun isVerifiedSignedBy(cert: OpenPGPCertificate) =
|
||||
verifiedSignatures.any { cert.pgpKeyRing.matches(it.signingKey) }
|
||||
|
||||
fun isVerifiedDetachedSignedBy(fingerprint: OpenPgpFingerprint) =
|
||||
verifiedDetachedSignatures.any { it.signingKey.matches(fingerprint) }
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import org.bouncycastle.openpgp.PGPCompressedData
|
|||
import org.bouncycastle.openpgp.PGPEncryptedData
|
||||
import org.bouncycastle.openpgp.PGPEncryptedDataList
|
||||
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
|
||||
|
@ -27,6 +28,10 @@ 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
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey.OpenPGPSecretKey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPSignature.OpenPGPDocumentSignature
|
||||
import org.bouncycastle.openpgp.operator.PBEDataDecryptorFactory
|
||||
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory
|
||||
import org.bouncycastle.util.io.TeeInputStream
|
||||
|
@ -37,6 +42,7 @@ 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
|
||||
|
@ -66,6 +72,7 @@ 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,
|
||||
|
@ -400,30 +407,33 @@ class OpenPgpMessageInputStream(
|
|||
}
|
||||
|
||||
val postponedDueToMissingPassphrase =
|
||||
mutableListOf<Pair<PGPSecretKey, PGPPublicKeyEncryptedData>>()
|
||||
mutableListOf<Pair<OpenPGPSecretKey, PGPPublicKeyEncryptedData>>()
|
||||
|
||||
// try (known) secret keys
|
||||
esks.pkesks.forEach { pkesk ->
|
||||
LOGGER.debug("Encountered PKESK for recipient ${pkesk.keyID.openPgpKeyId()}")
|
||||
LOGGER.debug("Encountered PKESK for recipient ${pkesk.keyIdentifier}")
|
||||
val decryptionKeyCandidates = getDecryptionKeys(pkesk)
|
||||
for (decryptionKeys in decryptionKeyCandidates) {
|
||||
val secretKey = decryptionKeys.getSecretKeyFor(pkesk)!!
|
||||
val decryptionKeyId = SubkeyIdentifier(decryptionKeys, secretKey.keyID)
|
||||
if (hasUnsupportedS2KSpecifier(secretKey, decryptionKeyId)) {
|
||||
if (hasUnsupportedS2KSpecifier(secretKey)) {
|
||||
continue
|
||||
}
|
||||
|
||||
LOGGER.debug("Attempt decryption using secret key $decryptionKeyId")
|
||||
LOGGER.debug("Attempt decryption using secret key ${decryptionKeys.keyIdentifier}")
|
||||
val protector = options.getSecretKeyProtector(decryptionKeys) ?: continue
|
||||
if (!protector.hasPassphraseFor(secretKey.keyID)) {
|
||||
if (!protector.hasPassphraseFor(secretKey.keyIdentifier)) {
|
||||
LOGGER.debug(
|
||||
"Missing passphrase for key $decryptionKeyId. Postponing decryption until all other keys were tried.")
|
||||
"Missing passphrase for key ${decryptionKeys.keyIdentifier}. Postponing decryption until all other keys were tried.")
|
||||
postponedDueToMissingPassphrase.add(secretKey to pkesk)
|
||||
continue
|
||||
}
|
||||
|
||||
val privateKey = secretKey.unlock(protector)
|
||||
if (decryptWithPrivateKey(esks, privateKey, decryptionKeyId, pkesk)) {
|
||||
if (decryptWithPrivateKey(
|
||||
esks,
|
||||
privateKey,
|
||||
SubkeyIdentifier(secretKey.openPGPKey.pgpSecretKeyRing, secretKey.keyIdentifier),
|
||||
pkesk)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -431,24 +441,27 @@ class OpenPgpMessageInputStream(
|
|||
|
||||
// try anonymous secret keys
|
||||
for (pkesk in esks.anonPkesks) {
|
||||
for ((decryptionKeys, secretKey) in findPotentialDecryptionKeys(pkesk)) {
|
||||
val decryptionKeyId = SubkeyIdentifier(decryptionKeys, secretKey.keyID)
|
||||
if (hasUnsupportedS2KSpecifier(secretKey, decryptionKeyId)) {
|
||||
for (decryptionKeys in findPotentialDecryptionKeys(pkesk)) {
|
||||
if (hasUnsupportedS2KSpecifier(decryptionKeys)) {
|
||||
continue
|
||||
}
|
||||
|
||||
LOGGER.debug("Attempt decryption of anonymous PKESK with key $decryptionKeyId.")
|
||||
val protector = options.getSecretKeyProtector(decryptionKeys) ?: continue
|
||||
LOGGER.debug("Attempt decryption of anonymous PKESK with key $decryptionKeys.")
|
||||
val protector = options.getSecretKeyProtector(decryptionKeys.openPGPKey) ?: continue
|
||||
|
||||
if (!protector.hasPassphraseFor(secretKey.keyID)) {
|
||||
if (!protector.hasPassphraseFor(decryptionKeys.keyIdentifier)) {
|
||||
LOGGER.debug(
|
||||
"Missing passphrase for key $decryptionKeyId. Postponing decryption until all other keys were tried.")
|
||||
postponedDueToMissingPassphrase.add(secretKey to pkesk)
|
||||
"Missing passphrase for key ${decryptionKeys.keyIdentifier}. Postponing decryption until all other keys were tried.")
|
||||
postponedDueToMissingPassphrase.add(decryptionKeys to pkesk)
|
||||
continue
|
||||
}
|
||||
|
||||
val privateKey = secretKey.unlock(protector)
|
||||
if (decryptWithPrivateKey(esks, privateKey, decryptionKeyId, pkesk)) {
|
||||
val privateKey = decryptionKeys.unlock(protector)
|
||||
if (decryptWithPrivateKey(
|
||||
esks,
|
||||
privateKey,
|
||||
SubkeyIdentifier(decryptionKeys.openPGPKey.pgpSecretKeyRing, privateKey.keyIdentifier),
|
||||
pkesk)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -463,10 +476,10 @@ class OpenPgpMessageInputStream(
|
|||
} else if (options.getMissingKeyPassphraseStrategy() ==
|
||||
MissingKeyPassphraseStrategy.INTERACTIVE) {
|
||||
for ((secretKey, pkesk) in postponedDueToMissingPassphrase) {
|
||||
val keyId = secretKey.keyID
|
||||
val keyId = secretKey.keyIdentifier
|
||||
val decryptionKeys = getDecryptionKey(pkesk)!!
|
||||
val decryptionKeyId = SubkeyIdentifier(decryptionKeys, keyId)
|
||||
if (hasUnsupportedS2KSpecifier(secretKey, decryptionKeyId)) {
|
||||
val decryptionKeyId = SubkeyIdentifier(decryptionKeys.pgpSecretKeyRing, keyId)
|
||||
if (hasUnsupportedS2KSpecifier(secretKey)) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -489,24 +502,23 @@ class OpenPgpMessageInputStream(
|
|||
|
||||
private fun decryptWithPrivateKey(
|
||||
esks: SortedESKs,
|
||||
privateKey: PGPPrivateKey,
|
||||
privateKey: PGPKeyPair,
|
||||
decryptionKeyId: SubkeyIdentifier,
|
||||
pkesk: PGPPublicKeyEncryptedData
|
||||
): Boolean {
|
||||
val decryptorFactory =
|
||||
ImplementationFactory.getInstance().getPublicKeyDataDecryptorFactory(privateKey)
|
||||
ImplementationFactory.getInstance().getPublicKeyDataDecryptorFactory(privateKey.privateKey)
|
||||
return decryptPKESKAndStream(esks, decryptionKeyId, decryptorFactory, pkesk)
|
||||
}
|
||||
|
||||
private fun hasUnsupportedS2KSpecifier(
|
||||
secretKey: PGPSecretKey,
|
||||
decryptionKeyId: SubkeyIdentifier
|
||||
secretKey: OpenPGPSecretKey
|
||||
): Boolean {
|
||||
val s2k = secretKey.s2K
|
||||
val s2k = secretKey.pgpSecretKey.s2K
|
||||
if (s2k != null) {
|
||||
if (s2k.type in 100..110) {
|
||||
LOGGER.debug(
|
||||
"Skipping PKESK because key $decryptionKeyId has unsupported private S2K specifier ${s2k.type}")
|
||||
"Skipping PKESK because key ${secretKey.keyIdentifier} has unsupported private S2K specifier ${s2k.type}")
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -672,26 +684,26 @@ class OpenPgpMessageInputStream(
|
|||
return MessageMetadata((layerMetadata as Message))
|
||||
}
|
||||
|
||||
private fun getDecryptionKey(keyId: Long): PGPSecretKeyRing? =
|
||||
private fun getDecryptionKey(keyId: Long): OpenPGPKey? =
|
||||
options.getDecryptionKeys().firstOrNull {
|
||||
it.any { k -> k.keyID == keyId }
|
||||
it.pgpSecretKeyRing.any { k -> k.keyID == keyId }
|
||||
.and(
|
||||
PGPainless.inspectKeyRing(it).decryptionSubkeys.any { k ->
|
||||
k.keyIdentifier.keyId == keyId
|
||||
})
|
||||
}
|
||||
|
||||
private fun getDecryptionKey(pkesk: PGPPublicKeyEncryptedData): PGPSecretKeyRing? =
|
||||
private fun getDecryptionKey(pkesk: PGPPublicKeyEncryptedData): OpenPGPKey? =
|
||||
options.getDecryptionKeys().firstOrNull {
|
||||
it.getSecretKeyFor(pkesk) != null &&
|
||||
it.pgpSecretKeyRing.getSecretKeyFor(pkesk) != null &&
|
||||
PGPainless.inspectKeyRing(it).decryptionSubkeys.any { subkey ->
|
||||
pkesk.keyIdentifier.matches(subkey.keyIdentifier)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDecryptionKeys(pkesk: PGPPublicKeyEncryptedData): List<PGPSecretKeyRing> =
|
||||
private fun getDecryptionKeys(pkesk: PGPPublicKeyEncryptedData): List<OpenPGPKey> =
|
||||
options.getDecryptionKeys().filter {
|
||||
it.getSecretKeyFor(pkesk) != null &&
|
||||
it.pgpSecretKeyRing.getSecretKeyFor(pkesk) != null &&
|
||||
PGPainless.inspectKeyRing(it).decryptionSubkeys.any { subkey ->
|
||||
pkesk.keyIdentifier.matches(subkey.keyIdentifier)
|
||||
}
|
||||
|
@ -699,15 +711,15 @@ class OpenPgpMessageInputStream(
|
|||
|
||||
private fun findPotentialDecryptionKeys(
|
||||
pkesk: PGPPublicKeyEncryptedData
|
||||
): List<Pair<PGPSecretKeyRing, PGPSecretKey>> {
|
||||
): List<OpenPGPSecretKey> {
|
||||
val algorithm = pkesk.algorithm
|
||||
val candidates = mutableListOf<Pair<PGPSecretKeyRing, PGPSecretKey>>()
|
||||
val candidates = mutableListOf<OpenPGPSecretKey>()
|
||||
options.getDecryptionKeys().forEach {
|
||||
val info = PGPainless.inspectKeyRing(it)
|
||||
for (key in info.decryptionSubkeys) {
|
||||
if (key.pgpPublicKey.algorithm == algorithm &&
|
||||
info.isSecretKeyAvailable(key.keyIdentifier)) {
|
||||
candidates.add(it to it.getSecretKey(key.keyIdentifier))
|
||||
candidates.add(it.getSecretKey(key.keyIdentifier))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -753,8 +765,8 @@ class OpenPgpMessageInputStream(
|
|||
}
|
||||
|
||||
private class Signatures(val options: ConsumerOptions) : OutputStream() {
|
||||
val detachedSignatures = mutableListOf<SignatureCheck>()
|
||||
val prependedSignatures = mutableListOf<SignatureCheck>()
|
||||
val detachedSignatures = mutableListOf<OpenPGPDocumentSignature>()
|
||||
val prependedSignatures = mutableListOf<OpenPGPDocumentSignature>()
|
||||
val onePassSignatures = mutableListOf<OnePassSignatureCheck>()
|
||||
val opsUpdateStack = ArrayDeque<MutableList<OnePassSignatureCheck>>()
|
||||
var literalOPS = mutableListOf<OnePassSignatureCheck>()
|
||||
|
@ -798,22 +810,21 @@ class OpenPgpMessageInputStream(
|
|||
}
|
||||
}
|
||||
|
||||
fun initializeSignature(signature: PGPSignature): SignatureCheck? {
|
||||
fun initializeSignature(signature: PGPSignature): OpenPGPDocumentSignature? {
|
||||
val certificate = findCertificate(signature) ?: return null
|
||||
val publicKey = certificate.getPublicKeyFor(signature) ?: return null
|
||||
val verifierKey = SubkeyIdentifier(certificate, publicKey.keyID)
|
||||
initialize(signature, publicKey)
|
||||
return SignatureCheck(signature, certificate, verifierKey)
|
||||
val publicKey = certificate.getSigningKeyFor(signature) ?: return null
|
||||
initialize(signature, publicKey.pgpPublicKey)
|
||||
return OpenPGPDocumentSignature(signature, publicKey)
|
||||
}
|
||||
|
||||
fun addOnePassSignature(signature: PGPOnePassSignature) {
|
||||
val certificate = findCertificate(signature)
|
||||
|
||||
if (certificate != null) {
|
||||
val publicKey = certificate.getPublicKeyFor(signature)
|
||||
val publicKey = certificate.getSigningKeyFor(signature)
|
||||
if (publicKey != null) {
|
||||
val ops = OnePassSignatureCheck(signature, certificate)
|
||||
initialize(signature, publicKey)
|
||||
initialize(signature, publicKey.pgpPublicKey)
|
||||
onePassSignatures.add(ops)
|
||||
literalOPS.add(ops)
|
||||
}
|
||||
|
@ -844,7 +855,7 @@ class OpenPgpMessageInputStream(
|
|||
val verification =
|
||||
SignatureVerification(
|
||||
signature,
|
||||
SubkeyIdentifier(check.verificationKeys, check.onePassSignature.keyID))
|
||||
SubkeyIdentifier(check.verificationKeys.pgpPublicKeyRing, check.onePassSignature.keyIdentifier))
|
||||
|
||||
try {
|
||||
SignatureValidator.signatureWasCreatedInBounds(
|
||||
|
@ -882,7 +893,7 @@ class OpenPgpMessageInputStream(
|
|||
opsUpdateStack.removeFirst()
|
||||
}
|
||||
|
||||
private fun findCertificate(signature: PGPSignature): PGPPublicKeyRing? {
|
||||
private fun findCertificate(signature: PGPSignature): OpenPGPCertificate? {
|
||||
val cert = options.getCertificateSource().getCertificate(signature)
|
||||
if (cert != null) {
|
||||
return cert
|
||||
|
@ -896,7 +907,7 @@ class OpenPgpMessageInputStream(
|
|||
return null // TODO: Missing cert for sig
|
||||
}
|
||||
|
||||
private fun findCertificate(signature: PGPOnePassSignature): PGPPublicKeyRing? {
|
||||
private fun findCertificate(signature: PGPOnePassSignature): OpenPGPCertificate? {
|
||||
val cert = options.getCertificateSource().getCertificate(signature.keyID)
|
||||
if (cert != null) {
|
||||
return cert
|
||||
|
@ -977,7 +988,7 @@ class OpenPgpMessageInputStream(
|
|||
|
||||
for (prepended in prependedSignatures) {
|
||||
val verification =
|
||||
SignatureVerification(prepended.signature, prepended.signingKeyIdentifier)
|
||||
SignatureVerification(prepended.signature, prepended.keyIdentifier)
|
||||
try {
|
||||
SignatureValidator.signatureWasCreatedInBounds(
|
||||
options.getVerifyNotBefore(), options.getVerifyNotAfter())
|
||||
|
|
|
@ -4,15 +4,17 @@
|
|||
|
||||
package org.pgpainless.key.protection
|
||||
|
||||
import kotlin.jvm.Throws
|
||||
import org.bouncycastle.bcpg.KeyIdentifier
|
||||
import org.bouncycastle.openpgp.PGPException
|
||||
import org.bouncycastle.openpgp.PGPSecretKey
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing
|
||||
import org.bouncycastle.openpgp.api.KeyPassphraseProvider
|
||||
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor
|
||||
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.
|
||||
|
@ -22,7 +24,7 @@ import org.pgpainless.util.Passphrase
|
|||
* While it is easy to create an implementation of this interface that fits your needs, there are a
|
||||
* bunch of implementations ready for use.
|
||||
*/
|
||||
interface SecretKeyRingProtector {
|
||||
interface SecretKeyRingProtector : KeyPassphraseProvider {
|
||||
|
||||
/**
|
||||
* Returns true, if the protector has a passphrase for the key with the given key-id.
|
||||
|
@ -30,7 +32,9 @@ interface SecretKeyRingProtector {
|
|||
* @param keyId key id
|
||||
* @return true if it has a passphrase, false otherwise
|
||||
*/
|
||||
fun hasPassphraseFor(keyId: Long): Boolean
|
||||
fun hasPassphraseFor(keyId: Long): Boolean = hasPassphraseFor(KeyIdentifier(keyId))
|
||||
|
||||
fun hasPassphraseFor(keyIdentifier: KeyIdentifier): Boolean
|
||||
|
||||
/**
|
||||
* Return a decryptor for the key of id `keyId`. This method returns null if the key is
|
||||
|
@ -39,7 +43,10 @@ interface SecretKeyRingProtector {
|
|||
* @param keyId id of the key
|
||||
* @return decryptor for the key
|
||||
*/
|
||||
@Throws(PGPException::class) fun getDecryptor(keyId: Long): PBESecretKeyDecryptor?
|
||||
@Throws(PGPException::class) fun getDecryptor(keyId: Long): PBESecretKeyDecryptor? =
|
||||
getDecryptor(KeyIdentifier(keyId))
|
||||
|
||||
@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
|
||||
|
@ -48,7 +55,10 @@ interface SecretKeyRingProtector {
|
|||
* @param keyId id of the key
|
||||
* @return encryptor for the key
|
||||
*/
|
||||
@Throws(PGPException::class) fun getEncryptor(keyId: Long): PBESecretKeyEncryptor?
|
||||
@Throws(PGPException::class) fun getEncryptor(keyId: Long): PBESecretKeyEncryptor? =
|
||||
getEncryptor(KeyIdentifier(keyId))
|
||||
|
||||
@Throws(PGPException::class) fun getEncryptor(keyIdentifier: KeyIdentifier): PBESecretKeyEncryptor?
|
||||
|
||||
companion object {
|
||||
|
||||
|
|
|
@ -3,14 +3,21 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
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
|
||||
|
||||
/**
|
||||
* Implementation of the [SecretKeyRingProtector] which assumes that all handled keys are not
|
||||
* password protected.
|
||||
*/
|
||||
class UnprotectedKeysProtector : SecretKeyRingProtector {
|
||||
override fun hasPassphraseFor(keyId: Long) = true
|
||||
override fun hasPassphraseFor(keyIdentifier: KeyIdentifier): Boolean = true
|
||||
|
||||
override fun getDecryptor(keyId: Long) = null
|
||||
override fun getDecryptor(keyIdentifier: KeyIdentifier): PBESecretKeyDecryptor? = null
|
||||
|
||||
override fun getEncryptor(keyId: Long) = null
|
||||
override fun getEncryptor(keyIdentifier: KeyIdentifier): PBESecretKeyEncryptor? = null
|
||||
|
||||
override fun getKeyPassword(p0: OpenPGPKey.OpenPGPSecretKey?): CharArray? = null
|
||||
}
|
||||
|
|
|
@ -7,6 +7,9 @@ package org.pgpainless.signature.consumer
|
|||
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
|
||||
|
||||
/**
|
||||
|
@ -20,7 +23,7 @@ import org.pgpainless.key.SubkeyIdentifier
|
|||
*/
|
||||
data class OnePassSignatureCheck(
|
||||
val onePassSignature: PGPOnePassSignature,
|
||||
val verificationKeys: PGPPublicKeyRing,
|
||||
val verificationKeys: OpenPGPCertificate,
|
||||
var signature: PGPSignature? = null
|
||||
) {
|
||||
|
||||
|
@ -30,5 +33,5 @@ data class OnePassSignatureCheck(
|
|||
* @return signing key fingerprint
|
||||
*/
|
||||
val signingKey: SubkeyIdentifier
|
||||
get() = SubkeyIdentifier(verificationKeys, onePassSignature.keyID)
|
||||
get() = SubkeyIdentifier(verificationKeys.pgpPublicKeyRing, onePassSignature.keyID)
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ import org.bouncycastle.bcpg.S2K;
|
|||
import org.bouncycastle.bcpg.SecretKeyPacket;
|
||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKeyReader;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.key.SubkeyIdentifier;
|
||||
|
@ -178,8 +180,9 @@ public class GnuPGDummyKeyUtilTest {
|
|||
|
||||
@Test
|
||||
public void testMoveAllKeysToCard() throws IOException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(FULL_KEY);
|
||||
PGPSecretKeyRing expected = PGPainless.readKeyRing().secretKeyRing(ALL_KEYS_ON_CARD);
|
||||
OpenPGPKeyReader reader = PGPainless.getInstance().readKey();
|
||||
OpenPGPKey secretKeys = reader.parseKey(FULL_KEY);
|
||||
OpenPGPKey expected = reader.parseKey(ALL_KEYS_ON_CARD);
|
||||
|
||||
PGPSecretKeyRing onCard = GnuPGDummyKeyUtil.modify(secretKeys)
|
||||
.divertPrivateKeysToCard(GnuPGDummyKeyUtil.KeyFilter.any(), cardSerial);
|
||||
|
@ -190,46 +193,50 @@ public class GnuPGDummyKeyUtilTest {
|
|||
assertEquals(S2K.GNU_PROTECTION_MODE_DIVERT_TO_CARD, s2K.getProtectionMode());
|
||||
}
|
||||
|
||||
assertArrayEquals(expected.getEncoded(), onCard.getEncoded());
|
||||
assertArrayEquals(expected.getPGPSecretKeyRing().getEncoded(), onCard.getEncoded());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMovePrimaryKeyToCard() throws IOException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(FULL_KEY);
|
||||
PGPSecretKeyRing expected = PGPainless.readKeyRing().secretKeyRing(PRIMARY_KEY_ON_CARD);
|
||||
OpenPGPKeyReader reader = PGPainless.getInstance().readKey();
|
||||
OpenPGPKey secretKeys = reader.parseKey(FULL_KEY);
|
||||
OpenPGPKey expected = reader.parseKey(PRIMARY_KEY_ON_CARD);
|
||||
|
||||
PGPSecretKeyRing onCard = GnuPGDummyKeyUtil.modify(secretKeys)
|
||||
.divertPrivateKeysToCard(GnuPGDummyKeyUtil.KeyFilter.only(primaryKeyId), cardSerial);
|
||||
|
||||
assertArrayEquals(expected.getEncoded(), onCard.getEncoded());
|
||||
assertArrayEquals(expected.getPGPSecretKeyRing().getEncoded(), onCard.getEncoded());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveEncryptionKeyToCard() throws IOException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(FULL_KEY);
|
||||
PGPSecretKeyRing expected = PGPainless.readKeyRing().secretKeyRing(ENCRYPTION_KEY_ON_CARD);
|
||||
OpenPGPKeyReader reader = PGPainless.getInstance().readKey();
|
||||
OpenPGPKey secretKeys = reader.parseKey(FULL_KEY);
|
||||
OpenPGPKey expected = reader.parseKey(ENCRYPTION_KEY_ON_CARD);
|
||||
|
||||
PGPSecretKeyRing onCard = GnuPGDummyKeyUtil.modify(secretKeys)
|
||||
.divertPrivateKeysToCard(GnuPGDummyKeyUtil.KeyFilter.only(encryptionKeyId), cardSerial);
|
||||
|
||||
assertArrayEquals(expected.getEncoded(), onCard.getEncoded());
|
||||
assertArrayEquals(expected.getPGPSecretKeyRing().getEncoded(), onCard.getEncoded());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveSigningKeyToCard() throws IOException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(FULL_KEY);
|
||||
PGPSecretKeyRing expected = PGPainless.readKeyRing().secretKeyRing(SIGNATURE_KEY_ON_CARD);
|
||||
OpenPGPKeyReader reader = PGPainless.getInstance().readKey();
|
||||
OpenPGPKey secretKeys = reader.parseKey(FULL_KEY);
|
||||
OpenPGPKey expected = reader.parseKey(SIGNATURE_KEY_ON_CARD);
|
||||
|
||||
PGPSecretKeyRing onCard = GnuPGDummyKeyUtil.modify(secretKeys)
|
||||
.divertPrivateKeysToCard(GnuPGDummyKeyUtil.KeyFilter.only(signatureKeyId), cardSerial);
|
||||
|
||||
assertArrayEquals(expected.getEncoded(), onCard.getEncoded());
|
||||
assertArrayEquals(expected.getPGPSecretKeyRing().getEncoded(), onCard.getEncoded());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveAllKeys() throws IOException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(FULL_KEY);
|
||||
PGPSecretKeyRing expected = PGPainless.readKeyRing().secretKeyRing(ALL_KEYS_REMOVED);
|
||||
OpenPGPKeyReader reader = PGPainless.getInstance().readKey();
|
||||
OpenPGPKey secretKeys = reader.parseKey(FULL_KEY);
|
||||
OpenPGPKey expected = reader.parseKey(ALL_KEYS_REMOVED);
|
||||
|
||||
PGPSecretKeyRing removedSecretKeys = GnuPGDummyKeyUtil.modify(secretKeys)
|
||||
.removePrivateKeys(GnuPGDummyKeyUtil.KeyFilter.any());
|
||||
|
@ -240,33 +247,35 @@ public class GnuPGDummyKeyUtilTest {
|
|||
assertEquals(GnuPGDummyExtension.NO_PRIVATE_KEY.getId(), s2k.getProtectionMode());
|
||||
}
|
||||
|
||||
assertArrayEquals(expected.getEncoded(), removedSecretKeys.getEncoded());
|
||||
assertArrayEquals(expected.getPGPSecretKeyRing().getEncoded(), removedSecretKeys.getEncoded());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSingleIdOfHardwareBackedKey() throws IOException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(FULL_KEY);
|
||||
assertTrue(GnuPGDummyKeyUtil.getIdsOfKeysWithGnuPGS2KDivertedToCard(secretKeys).isEmpty());
|
||||
OpenPGPKeyReader reader = PGPainless.getInstance().readKey();
|
||||
OpenPGPKey secretKeys = reader.parseKey(FULL_KEY);
|
||||
assertTrue(GnuPGDummyKeyUtil.getIdsOfKeysWithGnuPGS2KDivertedToCard(secretKeys.getPGPSecretKeyRing()).isEmpty());
|
||||
|
||||
PGPSecretKeyRing withHardwareBackedEncryptionKey = GnuPGDummyKeyUtil.modify(secretKeys)
|
||||
.divertPrivateKeysToCard(GnuPGDummyKeyUtil.KeyFilter.only(encryptionKeyId));
|
||||
|
||||
Set<SubkeyIdentifier> hardwareBackedKeys = GnuPGDummyKeyUtil
|
||||
.getIdsOfKeysWithGnuPGS2KDivertedToCard(withHardwareBackedEncryptionKey);
|
||||
assertEquals(Collections.singleton(new SubkeyIdentifier(secretKeys, encryptionKeyId)), hardwareBackedKeys);
|
||||
assertEquals(Collections.singleton(new SubkeyIdentifier(secretKeys.getPGPSecretKeyRing(), encryptionKeyId)), hardwareBackedKeys);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testGetIdsOfFullyHardwareBackedKey() throws IOException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(FULL_KEY);
|
||||
assertTrue(GnuPGDummyKeyUtil.getIdsOfKeysWithGnuPGS2KDivertedToCard(secretKeys).isEmpty());
|
||||
OpenPGPKeyReader reader = PGPainless.getInstance().readKey();
|
||||
OpenPGPKey secretKeys = reader.parseKey(FULL_KEY);
|
||||
assertTrue(GnuPGDummyKeyUtil.getIdsOfKeysWithGnuPGS2KDivertedToCard(secretKeys.getPGPSecretKeyRing()).isEmpty());
|
||||
|
||||
PGPSecretKeyRing withHardwareBackedEncryptionKey = GnuPGDummyKeyUtil.modify(secretKeys)
|
||||
.divertPrivateKeysToCard(GnuPGDummyKeyUtil.KeyFilter.any());
|
||||
Set<SubkeyIdentifier> expected = new HashSet<>();
|
||||
for (PGPSecretKey key : secretKeys) {
|
||||
expected.add(new SubkeyIdentifier(secretKeys, key.getKeyID()));
|
||||
for (PGPSecretKey key : secretKeys.getPGPSecretKeyRing()) {
|
||||
expected.add(new SubkeyIdentifier(secretKeys.getPGPSecretKeyRing(), key.getKeyID()));
|
||||
}
|
||||
|
||||
Set<SubkeyIdentifier> hardwareBackedKeys = GnuPGDummyKeyUtil
|
||||
|
|
|
@ -15,8 +15,9 @@ import java.io.IOException;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKeyReader;
|
||||
import org.bouncycastle.util.io.Streams;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -134,15 +135,16 @@ public class DecryptOrVerify {
|
|||
"=9PiO\n" +
|
||||
"-----END PGP MESSAGE-----";
|
||||
|
||||
private static PGPSecretKeyRing secretKey;
|
||||
private static PGPPublicKeyRing certificate;
|
||||
private static OpenPGPKey secretKey;
|
||||
private static OpenPGPCertificate certificate;
|
||||
|
||||
@BeforeAll
|
||||
public static void prepare() throws IOException {
|
||||
OpenPGPKeyReader reader = PGPainless.getInstance().readKey();
|
||||
// read the secret key
|
||||
secretKey = PGPainless.readKeyRing().secretKeyRing(KEY);
|
||||
secretKey = reader.parseKey(KEY);
|
||||
// certificate is the public part of the key
|
||||
certificate = PGPainless.extractCertificate(secretKey);
|
||||
certificate = secretKey.toCertificate();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -153,7 +155,7 @@ public class DecryptOrVerify {
|
|||
*/
|
||||
@Test
|
||||
public void decryptMessage() throws PGPException, IOException {
|
||||
ConsumerOptions consumerOptions = new ConsumerOptions()
|
||||
ConsumerOptions consumerOptions = ConsumerOptions.get()
|
||||
.addDecryptionKey(secretKey, keyProtector); // add the decryption key ring
|
||||
|
||||
ByteArrayOutputStream plaintextOut = new ByteArrayOutputStream();
|
||||
|
@ -186,7 +188,7 @@ public class DecryptOrVerify {
|
|||
*/
|
||||
@Test
|
||||
public void decryptMessageAndVerifySignatures() throws PGPException, IOException {
|
||||
ConsumerOptions consumerOptions = new ConsumerOptions()
|
||||
ConsumerOptions consumerOptions = ConsumerOptions.get()
|
||||
.addDecryptionKey(secretKey, keyProtector) // provide the secret key of the recipient for decryption
|
||||
.addVerificationCert(certificate); // provide the signers public key for signature verification
|
||||
|
||||
|
@ -218,7 +220,7 @@ public class DecryptOrVerify {
|
|||
*/
|
||||
@Test
|
||||
public void verifySignatures() throws PGPException, IOException {
|
||||
ConsumerOptions options = new ConsumerOptions()
|
||||
ConsumerOptions options = ConsumerOptions.get()
|
||||
.addVerificationCert(certificate); // provide the signers certificate for verification of signatures
|
||||
|
||||
for (String signed : new String[] {INBAND_SIGNED, CLEARTEXT_SIGNED}) {
|
||||
|
@ -257,7 +259,7 @@ public class DecryptOrVerify {
|
|||
|
||||
SigningOptions signingOptions = SigningOptions.get();
|
||||
// for cleartext signed messages, we need to add a detached signature...
|
||||
signingOptions.addDetachedSignature(keyProtector, secretKey, DocumentSignatureType.CANONICAL_TEXT_DOCUMENT);
|
||||
signingOptions.addDetachedSignature(keyProtector, secretKey.getPGPSecretKeyRing(), DocumentSignatureType.CANONICAL_TEXT_DOCUMENT);
|
||||
ProducerOptions producerOptions = ProducerOptions.sign(signingOptions)
|
||||
.setCleartextSigned(); // and declare that the message will be cleartext signed
|
||||
|
||||
|
@ -279,7 +281,7 @@ public class DecryptOrVerify {
|
|||
// and pass it to the decryption stream
|
||||
DecryptionStream verificationStream = PGPainless.decryptAndOrVerify()
|
||||
.onInputStream(signedIn)
|
||||
.withOptions(new ConsumerOptions().addVerificationCert(certificate));
|
||||
.withOptions(ConsumerOptions.get().addVerificationCert(certificate));
|
||||
|
||||
// plain will receive the plaintext message
|
||||
ByteArrayOutputStream plain = new ByteArrayOutputStream();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue