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

Even more migration and code compiles again

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

View file

@ -14,7 +14,6 @@ import java.io.IOException;
import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.KeyFlag; import org.pgpainless.algorithm.KeyFlag;
@ -135,7 +134,7 @@ public class RoundTripEncryptDecryptCmdTest extends CLITest {
} }
@Test @Test
@Disabled("Disabled, since we now read certificates from secret keys") // @Disabled("Disabled, since we now read certificates from secret keys")
public void testEncryptingForKeyFails() throws IOException { public void testEncryptingForKeyFails() throws IOException {
File notACert = writeFile("key.asc", KEY); File notACert = writeFile("key.asc", KEY);

View file

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

View file

@ -4,6 +4,7 @@
package org.pgpainless.exception; package org.pgpainless.exception;
import org.bouncycastle.bcpg.KeyIdentifier;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
public class WrongPassphraseException extends PGPException { public class WrongPassphraseException extends PGPException {
@ -13,7 +14,11 @@ public class WrongPassphraseException extends PGPException {
} }
public WrongPassphraseException(long keyId, PGPException cause) { 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) { 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.PGPOnePassSignature
import org.bouncycastle.openpgp.PGPPublicKey import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSignature import org.bouncycastle.openpgp.PGPSignature
import org.bouncycastle.openpgp.api.OpenPGPCertificate
import org.bouncycastle.openpgp.api.OpenPGPImplementation
import org.pgpainless.PGPainless import org.pgpainless.PGPainless
import org.pgpainless.key.OpenPgpFingerprint import org.pgpainless.key.OpenPgpFingerprint
import org.pgpainless.key.SubkeyIdentifier import org.pgpainless.key.SubkeyIdentifier
@ -72,3 +74,10 @@ val PGPKeyRing.openPgpFingerprint: OpenPgpFingerprint
/** Return this OpenPGP key as an ASCII armored String. */ /** Return this OpenPGP key as an ASCII armored String. */
fun PGPKeyRing.toAsciiArmor(): String = PGPainless.asciiArmor(this) 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 openpgp.openPgpKeyId
import org.bouncycastle.openpgp.* 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 import org.pgpainless.key.OpenPgpFingerprint
/** OpenPGP certificate containing the public keys of this OpenPGP key. */ /** 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? = fun PGPSecretKeyRing.getSecretKeyFor(pkesk: PGPPublicKeyEncryptedData): PGPSecretKey? =
this.getSecretKey(pkesk.keyIdentifier) 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 package org.pgpainless.decryption_verification
import org.bouncycastle.bcpg.KeyIdentifier
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.util.* import java.util.*
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.* import org.bouncycastle.openpgp.*
import org.bouncycastle.openpgp.api.OpenPGPCertificate import org.bouncycastle.openpgp.api.OpenPGPCertificate
import org.bouncycastle.openpgp.api.OpenPGPImplementation import org.bouncycastle.openpgp.api.OpenPGPImplementation
import org.bouncycastle.openpgp.api.OpenPGPKey import org.bouncycastle.openpgp.api.OpenPGPKey
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory
import org.pgpainless.PGPainless 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.InMemoryMultiPassStrategy
import org.pgpainless.decryption_verification.cleartext_signatures.MultiPassStrategy import org.pgpainless.decryption_verification.cleartext_signatures.MultiPassStrategy
import org.pgpainless.key.SubkeyIdentifier import org.pgpainless.key.SubkeyIdentifier
@ -24,9 +23,7 @@ import org.pgpainless.util.Passphrase
import org.pgpainless.util.SessionKey import org.pgpainless.util.SessionKey
/** Options for decryption and signature verification. */ /** Options for decryption and signature verification. */
class ConsumerOptions( class ConsumerOptions {
private val implementation: OpenPGPImplementation
) {
private var ignoreMDCErrors = false private var ignoreMDCErrors = false
var isDisableAsciiArmorCRC = false var isDisableAsciiArmorCRC = false
@ -183,7 +180,8 @@ class ConsumerOptions(
@JvmOverloads @JvmOverloads
fun addDecryptionKey( fun addDecryptionKey(
key: PGPSecretKeyRing, key: PGPSecretKeyRing,
protector: SecretKeyRingProtector = SecretKeyRingProtector.unprotectedKeys() protector: SecretKeyRingProtector = SecretKeyRingProtector.unprotectedKeys(),
implementation: OpenPGPImplementation = PGPainless.getInstance().implementation
) = addDecryptionKey(OpenPGPKey(key, implementation), protector) ) = addDecryptionKey(OpenPGPKey(key, implementation), protector)
/** /**
@ -402,7 +400,9 @@ class ConsumerOptions(
* *
* @param certificate certificate * @param certificate certificate
*/ */
fun addCertificate(certificate: PGPPublicKeyRing, @JvmOverloads
fun addCertificate(
certificate: PGPPublicKeyRing,
implementation: OpenPGPImplementation = PGPainless.getInstance().implementation implementation: OpenPGPImplementation = PGPainless.getInstance().implementation
) { ) {
explicitCertificates.add(OpenPGPCertificate(certificate, implementation)) explicitCertificates.add(OpenPGPCertificate(certificate, implementation))
@ -442,10 +442,6 @@ class ConsumerOptions(
} }
companion object { companion object {
@JvmStatic @JvmStatic fun get() = ConsumerOptions()
@JvmOverloads
fun get(
implementation: OpenPGPImplementation = PGPainless.getInstance().implementation
) = ConsumerOptions(implementation)
} }
} }

View file

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

View file

@ -4,7 +4,8 @@
package org.pgpainless.decryption_verification package org.pgpainless.decryption_verification
import org.bouncycastle.openpgp.PGPPublicKeyRing import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.api.OpenPGPCertificate
fun interface MissingPublicKeyCallback { fun interface MissingPublicKeyCallback {
@ -14,14 +15,14 @@ fun interface MissingPublicKeyCallback {
* here. PGPainless will then continue verification with the next signature. * 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 * 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 * It would be super cool to provide the OpenPgp fingerprint here, but unfortunately
* one-pass-signatures only contain the key id. * 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 * @return keyring containing the key or null
* @see <a href="https://datatracker.ietf.org/doc/html/rfc4880#section-5.4">RFC</a> * @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.PGPKeyPair
import org.bouncycastle.openpgp.PGPOnePassSignature import org.bouncycastle.openpgp.PGPOnePassSignature
import org.bouncycastle.openpgp.PGPPBEEncryptedData import org.bouncycastle.openpgp.PGPPBEEncryptedData
import org.bouncycastle.openpgp.PGPPrivateKey
import org.bouncycastle.openpgp.PGPPublicKey import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData 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.PGPSignature
import org.bouncycastle.openpgp.api.OpenPGPCertificate import org.bouncycastle.openpgp.api.OpenPGPCertificate
import org.bouncycastle.openpgp.api.OpenPGPKey import org.bouncycastle.openpgp.api.OpenPGPKey
@ -40,11 +36,9 @@ import org.pgpainless.algorithm.CompressionAlgorithm
import org.pgpainless.algorithm.OpenPgpPacket import org.pgpainless.algorithm.OpenPgpPacket
import org.pgpainless.algorithm.StreamEncoding import org.pgpainless.algorithm.StreamEncoding
import org.pgpainless.algorithm.SymmetricKeyAlgorithm import org.pgpainless.algorithm.SymmetricKeyAlgorithm
import org.pgpainless.bouncycastle.extensions.getPublicKeyFor
import org.pgpainless.bouncycastle.extensions.getSecretKeyFor import org.pgpainless.bouncycastle.extensions.getSecretKeyFor
import org.pgpainless.bouncycastle.extensions.getSigningKeyFor import org.pgpainless.bouncycastle.extensions.getSigningKeyFor
import org.pgpainless.bouncycastle.extensions.issuerKeyId 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.CompressedData
import org.pgpainless.decryption_verification.MessageMetadata.EncryptedData import org.pgpainless.decryption_verification.MessageMetadata.EncryptedData
import org.pgpainless.decryption_verification.MessageMetadata.Layer 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.MissingPassphraseException
import org.pgpainless.exception.SignatureValidationException import org.pgpainless.exception.SignatureValidationException
import org.pgpainless.exception.UnacceptableAlgorithmException import org.pgpainless.exception.UnacceptableAlgorithmException
import org.pgpainless.exception.WrongPassphraseException
import org.pgpainless.implementation.ImplementationFactory import org.pgpainless.implementation.ImplementationFactory
import org.pgpainless.key.SubkeyIdentifier import org.pgpainless.key.SubkeyIdentifier
import org.pgpainless.key.util.KeyRingUtils
import org.pgpainless.policy.Policy import org.pgpainless.policy.Policy
import org.pgpainless.signature.consumer.CertificateValidator import org.pgpainless.signature.consumer.CertificateValidator
import org.pgpainless.signature.consumer.OnePassSignatureCheck import org.pgpainless.signature.consumer.OnePassSignatureCheck
import org.pgpainless.signature.consumer.SignatureCheck
import org.pgpainless.signature.consumer.SignatureValidator import org.pgpainless.signature.consumer.SignatureValidator
import org.pgpainless.util.ArmoredInputStreamFactory import org.pgpainless.util.ArmoredInputStreamFactory
import org.pgpainless.util.SessionKey import org.pgpainless.util.SessionKey
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import kotlin.math.sign
class OpenPgpMessageInputStream( class OpenPgpMessageInputStream(
type: Type, type: Type,
@ -432,7 +424,8 @@ class OpenPgpMessageInputStream(
if (decryptWithPrivateKey( if (decryptWithPrivateKey(
esks, esks,
privateKey, privateKey,
SubkeyIdentifier(secretKey.openPGPKey.pgpSecretKeyRing, secretKey.keyIdentifier), SubkeyIdentifier(
secretKey.openPGPKey.pgpSecretKeyRing, secretKey.keyIdentifier),
pkesk)) { pkesk)) {
return true return true
} }
@ -441,27 +434,24 @@ class OpenPgpMessageInputStream(
// try anonymous secret keys // try anonymous secret keys
for (pkesk in esks.anonPkesks) { for (pkesk in esks.anonPkesks) {
for (decryptionKeys in findPotentialDecryptionKeys(pkesk)) { for (decryptionKey in findPotentialDecryptionKeys(pkesk)) {
if (hasUnsupportedS2KSpecifier(decryptionKeys)) { if (hasUnsupportedS2KSpecifier(decryptionKey)) {
continue continue
} }
LOGGER.debug("Attempt decryption of anonymous PKESK with key $decryptionKeys.") LOGGER.debug("Attempt decryption of anonymous PKESK with key $decryptionKey.")
val protector = options.getSecretKeyProtector(decryptionKeys.openPGPKey) ?: continue val protector = options.getSecretKeyProtector(decryptionKey.openPGPKey) ?: continue
if (!protector.hasPassphraseFor(decryptionKeys.keyIdentifier)) { if (!protector.hasPassphraseFor(decryptionKey.keyIdentifier)) {
LOGGER.debug( LOGGER.debug(
"Missing passphrase for key ${decryptionKeys.keyIdentifier}. Postponing decryption until all other keys were tried.") "Missing passphrase for key ${decryptionKey.keyIdentifier}. Postponing decryption until all other keys were tried.")
postponedDueToMissingPassphrase.add(decryptionKeys to pkesk) postponedDueToMissingPassphrase.add(decryptionKey to pkesk)
continue continue
} }
val privateKey = decryptionKeys.unlock(protector) val privateKey = decryptionKey.unlock(protector)
if (decryptWithPrivateKey( if (decryptWithPrivateKey(
esks, esks, privateKey, SubkeyIdentifier(decryptionKey), pkesk)) {
privateKey,
SubkeyIdentifier(decryptionKeys.openPGPKey.pgpSecretKeyRing, privateKey.keyIdentifier),
pkesk)) {
return true return true
} }
} }
@ -471,7 +461,7 @@ class OpenPgpMessageInputStream(
MissingKeyPassphraseStrategy.THROW_EXCEPTION) { MissingKeyPassphraseStrategy.THROW_EXCEPTION) {
// Non-interactive mode: Throw an exception with all locked decryption keys // Non-interactive mode: Throw an exception with all locked decryption keys
postponedDueToMissingPassphrase postponedDueToMissingPassphrase
.map { SubkeyIdentifier(getDecryptionKey(it.first.keyID)!!, it.first.keyID) } .map { SubkeyIdentifier(it.first) }
.also { if (it.isNotEmpty()) throw MissingPassphraseException(it.toSet()) } .also { if (it.isNotEmpty()) throw MissingPassphraseException(it.toSet()) }
} else if (options.getMissingKeyPassphraseStrategy() == } else if (options.getMissingKeyPassphraseStrategy() ==
MissingKeyPassphraseStrategy.INTERACTIVE) { MissingKeyPassphraseStrategy.INTERACTIVE) {
@ -486,7 +476,12 @@ class OpenPgpMessageInputStream(
LOGGER.debug( LOGGER.debug(
"Attempt decryption with key $decryptionKeyId while interactively requesting its passphrase.") "Attempt decryption with key $decryptionKeyId while interactively requesting its passphrase.")
val protector = options.getSecretKeyProtector(decryptionKeys) ?: continue 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)) { if (decryptWithPrivateKey(esks, privateKey, decryptionKeyId, pkesk)) {
return true return true
} }
@ -507,13 +502,12 @@ class OpenPgpMessageInputStream(
pkesk: PGPPublicKeyEncryptedData pkesk: PGPPublicKeyEncryptedData
): Boolean { ): Boolean {
val decryptorFactory = val decryptorFactory =
ImplementationFactory.getInstance().getPublicKeyDataDecryptorFactory(privateKey.privateKey) ImplementationFactory.getInstance()
.getPublicKeyDataDecryptorFactory(privateKey.privateKey)
return decryptPKESKAndStream(esks, decryptionKeyId, decryptorFactory, pkesk) return decryptPKESKAndStream(esks, decryptionKeyId, decryptorFactory, pkesk)
} }
private fun hasUnsupportedS2KSpecifier( private fun hasUnsupportedS2KSpecifier(secretKey: OpenPGPSecretKey): Boolean {
secretKey: OpenPGPSecretKey
): Boolean {
val s2k = secretKey.pgpSecretKey.s2K val s2k = secretKey.pgpSecretKey.s2K
if (s2k != null) { if (s2k != null) {
if (s2k.type in 100..110) { if (s2k.type in 100..110) {
@ -686,7 +680,8 @@ class OpenPgpMessageInputStream(
private fun getDecryptionKey(keyId: Long): OpenPGPKey? = private fun getDecryptionKey(keyId: Long): OpenPGPKey? =
options.getDecryptionKeys().firstOrNull { options.getDecryptionKeys().firstOrNull {
it.pgpSecretKeyRing.any { k -> k.keyID == keyId } it.pgpSecretKeyRing
.any { k -> k.keyID == keyId }
.and( .and(
PGPainless.inspectKeyRing(it).decryptionSubkeys.any { k -> PGPainless.inspectKeyRing(it).decryptionSubkeys.any { k ->
k.keyIdentifier.keyId == keyId k.keyIdentifier.keyId == keyId
@ -855,7 +850,9 @@ class OpenPgpMessageInputStream(
val verification = val verification =
SignatureVerification( SignatureVerification(
signature, signature,
SubkeyIdentifier(check.verificationKeys.pgpPublicKeyRing, check.onePassSignature.keyIdentifier)) SubkeyIdentifier(
check.verificationKeys.pgpPublicKeyRing,
check.onePassSignature.keyIdentifier))
try { try {
SignatureValidator.signatureWasCreatedInBounds( SignatureValidator.signatureWasCreatedInBounds(
@ -902,13 +899,13 @@ class OpenPgpMessageInputStream(
if (options.getMissingCertificateCallback() != null) { if (options.getMissingCertificateCallback() != null) {
return options return options
.getMissingCertificateCallback()!! .getMissingCertificateCallback()!!
.onMissingPublicKeyEncountered(signature.keyID) .onMissingPublicKeyEncountered(signature.keyIdentifiers.first())
} }
return null // TODO: Missing cert for sig return null // TODO: Missing cert for sig
} }
private fun findCertificate(signature: PGPOnePassSignature): OpenPGPCertificate? { private fun findCertificate(signature: PGPOnePassSignature): OpenPGPCertificate? {
val cert = options.getCertificateSource().getCertificate(signature.keyID) val cert = options.getCertificateSource().getCertificate(signature.keyIdentifier)
if (cert != null) { if (cert != null) {
return cert return cert
} }
@ -916,7 +913,7 @@ class OpenPgpMessageInputStream(
if (options.getMissingCertificateCallback() != null) { if (options.getMissingCertificateCallback() != null) {
return options return options
.getMissingCertificateCallback()!! .getMissingCertificateCallback()!!
.onMissingPublicKeyEncountered(signature.keyID) .onMissingPublicKeyEncountered(signature.keyIdentifier)
} }
return null // TODO: Missing cert for sig return null // TODO: Missing cert for sig
} }
@ -968,15 +965,13 @@ class OpenPgpMessageInputStream(
fun finish(layer: Layer, policy: Policy) { fun finish(layer: Layer, policy: Policy) {
for (detached in detachedSignatures) { for (detached in detachedSignatures) {
val verification = val verification =
SignatureVerification(detached.signature, detached.signingKeyIdentifier) SignatureVerification(detached.signature, SubkeyIdentifier(detached.issuer))
try { try {
SignatureValidator.signatureWasCreatedInBounds( SignatureValidator.signatureWasCreatedInBounds(
options.getVerifyNotBefore(), options.getVerifyNotAfter()) options.getVerifyNotBefore(), options.getVerifyNotAfter())
.verify(detached.signature) .verify(detached.signature)
CertificateValidator.validateCertificateAndVerifyInitializedSignature( CertificateValidator.validateCertificateAndVerifyInitializedSignature(
detached.signature, detached.signature, detached.issuerCertificate.pgpPublicKeyRing, policy)
KeyRingUtils.publicKeys(detached.signingKeyRing),
policy)
LOGGER.debug("Acceptable signature by key ${verification.signingKey}") LOGGER.debug("Acceptable signature by key ${verification.signingKey}")
layer.addVerifiedDetachedSignature(verification) layer.addVerifiedDetachedSignature(verification)
} catch (e: SignatureValidationException) { } catch (e: SignatureValidationException) {
@ -988,15 +983,13 @@ class OpenPgpMessageInputStream(
for (prepended in prependedSignatures) { for (prepended in prependedSignatures) {
val verification = val verification =
SignatureVerification(prepended.signature, prepended.keyIdentifier) SignatureVerification(prepended.signature, SubkeyIdentifier(prepended.issuer))
try { try {
SignatureValidator.signatureWasCreatedInBounds( SignatureValidator.signatureWasCreatedInBounds(
options.getVerifyNotBefore(), options.getVerifyNotAfter()) options.getVerifyNotBefore(), options.getVerifyNotAfter())
.verify(prepended.signature) .verify(prepended.signature)
CertificateValidator.validateCertificateAndVerifyInitializedSignature( CertificateValidator.validateCertificateAndVerifyInitializedSignature(
prepended.signature, prepended.signature, prepended.issuerCertificate.pgpPublicKeyRing, policy)
KeyRingUtils.publicKeys(prepended.signingKeyRing),
policy)
LOGGER.debug("Acceptable signature by key ${verification.signingKey}") LOGGER.debug("Acceptable signature by key ${verification.signingKey}")
layer.addVerifiedPrependedSignature(verification) layer.addVerifiedPrependedSignature(verification)
} catch (e: SignatureValidationException) { } catch (e: SignatureValidationException) {

View file

@ -5,6 +5,7 @@
package org.pgpainless.key package org.pgpainless.key
import java.nio.charset.Charset import java.nio.charset.Charset
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.PGPKeyRing import org.bouncycastle.openpgp.PGPKeyRing
import org.bouncycastle.openpgp.PGPPublicKey import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSecretKey import org.bouncycastle.openpgp.PGPSecretKey
@ -55,6 +56,8 @@ abstract class OpenPgpFingerprint : CharSequence, Comparable<OpenPgpFingerprint>
constructor(keys: PGPKeyRing) : this(keys.publicKey) constructor(keys: PGPKeyRing) : this(keys.publicKey)
abstract val keyIdentifier: KeyIdentifier
/** /**
* Check, whether the fingerprint consists of 40 valid hexadecimal characters. * 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.Buffer
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.nio.charset.Charset import java.nio.charset.Charset
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.PGPKeyRing import org.bouncycastle.openpgp.PGPKeyRing
import org.bouncycastle.openpgp.PGPPublicKey import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSecretKey import org.bouncycastle.openpgp.PGPSecretKey
@ -39,6 +40,8 @@ class OpenPgpV4Fingerprint : OpenPgpFingerprint {
return buf.getLong() return buf.getLong()
} }
override val keyIdentifier: KeyIdentifier = KeyIdentifier(bytes)
override fun isValid(fingerprint: String): Boolean { override fun isValid(fingerprint: String): Boolean {
return fingerprint.matches("^[0-9A-F]{40}$".toRegex()) return fingerprint.matches("^[0-9A-F]{40}$".toRegex())
} }

View file

@ -4,6 +4,7 @@
package org.pgpainless.key package org.pgpainless.key
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.PGPKeyRing import org.bouncycastle.openpgp.PGPKeyRing
import org.bouncycastle.openpgp.PGPPublicKey import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSecretKey import org.bouncycastle.openpgp.PGPSecretKey
@ -24,4 +25,6 @@ class OpenPgpV5Fingerprint : _64DigitFingerprint {
override fun getVersion(): Int { override fun getVersion(): Int {
return 5 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.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.PGPKeyRing import org.bouncycastle.openpgp.PGPKeyRing
import org.bouncycastle.openpgp.PGPPublicKey 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, * 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(keys: PGPKeyRing, keyId: Long) : this(keys, KeyIdentifier(keyId))
constructor(
key: OpenPGPComponentKey
) : this(
OpenPgpFingerprint.of(key.certificate.pgpPublicKeyRing),
OpenPgpFingerprint.of(key.pgpPublicKey))
constructor( constructor(
keys: PGPKeyRing, keys: PGPKeyRing,
subkeyFingerprint: OpenPgpFingerprint subkeyFingerprint: OpenPgpFingerprint

View file

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

View file

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

View file

@ -8,6 +8,7 @@ import java.io.IOException
import java.security.InvalidAlgorithmParameterException import java.security.InvalidAlgorithmParameterException
import java.security.NoSuchAlgorithmException import java.security.NoSuchAlgorithmException
import java.util.* import java.util.*
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.* import org.bouncycastle.openpgp.*
import org.pgpainless.algorithm.KeyFlag import org.pgpainless.algorithm.KeyFlag
import org.pgpainless.key.OpenPgpFingerprint import org.pgpainless.key.OpenPgpFingerprint
@ -592,19 +593,9 @@ interface SecretKeyRingEditorInterface {
KeyRingProtectionSettings.secureDefaultSettings() KeyRingProtectionSettings.secureDefaultSettings()
): WithKeyRingEncryptionSettings ): WithKeyRingEncryptionSettings
/** @Deprecated("Pass KeyIdentifier instead.")
* 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
*/
fun changeSubKeyPassphraseFromOldPassphrase(keyId: Long, oldPassphrase: Passphrase) = fun changeSubKeyPassphraseFromOldPassphrase(keyId: Long, oldPassphrase: Passphrase) =
changeSubKeyPassphraseFromOldPassphrase( changeSubKeyPassphraseFromOldPassphrase(KeyIdentifier(keyId), oldPassphrase)
keyId, oldPassphrase, KeyRingProtectionSettings.secureDefaultSettings())
/** /**
* Change the passphrase of a single subkey in the key ring. * 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 * 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. * 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 oldPassphrase old passphrase (empty if the key was unprotected)
* @param oldProtectionSettings custom settings for the old passphrase * @param oldProtectionSettings custom settings for the old passphrase
* @return next builder step * @return next builder step
*/ */
fun changeSubKeyPassphraseFromOldPassphrase( fun changeSubKeyPassphraseFromOldPassphrase(
keyId: Long, keyIdentifier: KeyIdentifier,
oldPassphrase: Passphrase, oldPassphrase: Passphrase,
oldProtectionSettings: KeyRingProtectionSettings oldProtectionSettings: KeyRingProtectionSettings
): WithKeyRingEncryptionSettings ): WithKeyRingEncryptionSettings

View file

@ -4,6 +4,8 @@
package org.pgpainless.key.protection 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.PBESecretKeyDecryptor
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor
import org.pgpainless.implementation.ImplementationFactory import org.pgpainless.implementation.ImplementationFactory
@ -22,16 +24,21 @@ open class BaseSecretKeyRingProtector(
passphraseProvider: SecretKeyPassphraseProvider passphraseProvider: SecretKeyPassphraseProvider
) : this(passphraseProvider, KeyRingProtectionSettings.secureDefaultSettings()) ) : 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? = 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 if (it.isEmpty) null
else ImplementationFactory.getInstance().getPBESecretKeyDecryptor(it) else ImplementationFactory.getInstance().getPBESecretKeyDecryptor(it)
} }
override fun getEncryptor(keyId: Long): PBESecretKeyEncryptor? = override fun getEncryptor(keyIdentifier: KeyIdentifier): PBESecretKeyEncryptor? {
passphraseProvider.getPassphraseFor(keyId)?.let { return passphraseProvider.getPassphraseFor(keyIdentifier)?.let {
if (it.isEmpty) null if (it.isEmpty) null
else else
ImplementationFactory.getInstance() ImplementationFactory.getInstance()
@ -41,4 +48,9 @@ open class BaseSecretKeyRingProtector(
protectionSettings.s2kCount, protectionSettings.s2kCount,
it) 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 package org.pgpainless.key.protection
import openpgp.openPgpKeyId import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.PGPKeyRing import org.bouncycastle.openpgp.PGPKeyRing
import org.bouncycastle.openpgp.PGPPublicKey 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.OpenPgpFingerprint
import org.pgpainless.key.protection.passphrase_provider.SecretKeyPassphraseProvider import org.pgpainless.key.protection.passphrase_provider.SecretKeyPassphraseProvider
import org.pgpainless.util.Passphrase import org.pgpainless.util.Passphrase
@ -21,7 +24,7 @@ import org.pgpainless.util.Passphrase
*/ */
class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphraseProvider { class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphraseProvider {
private val cache: MutableMap<Long?, Passphrase> private val cache: MutableMap<KeyIdentifier?, Passphrase>
private val protector: SecretKeyRingProtector private val protector: SecretKeyRingProtector
private val provider: SecretKeyPassphraseProvider? private val provider: SecretKeyPassphraseProvider?
@ -30,12 +33,12 @@ class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphras
constructor( constructor(
missingPassphraseCallback: SecretKeyPassphraseProvider? missingPassphraseCallback: SecretKeyPassphraseProvider?
) : this( ) : this(
mapOf<Long, Passphrase>(), mapOf<KeyIdentifier, Passphrase>(),
KeyRingProtectionSettings.secureDefaultSettings(), KeyRingProtectionSettings.secureDefaultSettings(),
missingPassphraseCallback) missingPassphraseCallback)
constructor( constructor(
passphrases: Map<Long, Passphrase>, passphrases: Map<KeyIdentifier, Passphrase>,
protectionSettings: KeyRingProtectionSettings, protectionSettings: KeyRingProtectionSettings,
missingPassphraseCallback: SecretKeyPassphraseProvider? missingPassphraseCallback: SecretKeyPassphraseProvider?
) { ) {
@ -44,6 +47,10 @@ class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphras
this.provider = missingPassphraseCallback 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 * 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 * 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, * 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. * you can use [replacePassphrase] to replace the passphrase.
* *
* @param keyId id of the key * @param keyIdentifier id of the key
* @param passphrase passphrase * @param passphrase passphrase
*/ */
fun addPassphrase(keyId: Long, passphrase: Passphrase) = apply { fun addPassphrase(keyIdentifier: KeyIdentifier, passphrase: Passphrase) = apply {
require(!cache.containsKey(keyId)) { require(!cache.containsKey(keyIdentifier)) {
"The cache already holds a passphrase for ID ${keyId.openPgpKeyId()}.\n" + "The cache already holds a passphrase for ID ${keyIdentifier}.\n" +
"If you want to replace this passphrase, use replacePassphrase(Long, Passphrase) instead." "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. * Replace the passphrase for the given key-id in the cache.
* *
* @param keyId keyId * @param keyId keyId
* @param passphrase passphrase * @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 * 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 { fun addPassphrase(keyRing: PGPKeyRing, passphrase: Passphrase) = apply {
// check for existing passphrases before doing anything // check for existing passphrases before doing anything
keyRing.publicKeys.forEach { keyRing.publicKeys.forEach {
require(!cache.containsKey(it.keyID)) { require(!cache.containsKey(it.keyIdentifier)) {
"The cache already holds a passphrase for the key with ID ${it.keyID.openPgpKeyId()}.\n" + "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." "If you want to replace the passphrase, use replacePassphrase(PGPKeyRing, Passphrase) instead."
} }
} }
// only then instert // 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 * @param passphrase passphrase
*/ */
fun replacePassphrase(keyRing: PGPKeyRing, passphrase: Passphrase) = apply { 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 * @param passphrase passphrase
*/ */
fun addPassphrase(key: PGPPublicKey, 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. * Remember the given passphrase for the key with the given fingerprint.
@ -127,14 +140,17 @@ class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphras
* @param passphrase passphrase * @param passphrase passphrase
*/ */
fun addPassphrase(fingerprint: OpenPgpFingerprint, 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. * Remove a passphrase from the cache. The passphrase will be cleared and then removed.
* *
* @param keyId id of the key * @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. * Forget the passphrase to all keys in the provided key ring.
@ -150,18 +166,27 @@ class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphras
* *
* @param key key * @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? { override fun getPassphraseFor(keyIdentifier: KeyIdentifier): Passphrase? {
return if (hasPassphrase(keyId)) cache[keyId] return if (hasPassphrase(keyIdentifier)) cache[keyIdentifier]
else provider?.getPassphraseFor(keyId)?.also { cache[keyId] = it } 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 package org.pgpainless.key.protection
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.PGPKeyRing import org.bouncycastle.openpgp.PGPKeyRing
import org.bouncycastle.openpgp.PGPSecretKey import org.bouncycastle.openpgp.PGPSecretKey
import org.pgpainless.key.protection.passphrase_provider.SecretKeyPassphraseProvider import org.pgpainless.key.protection.passphrase_provider.SecretKeyPassphraseProvider
@ -38,12 +39,12 @@ class PasswordBasedSecretKeyRingProtector : BaseSecretKeyRingProtector {
): PasswordBasedSecretKeyRingProtector { ): PasswordBasedSecretKeyRingProtector {
return object : SecretKeyPassphraseProvider { return object : SecretKeyPassphraseProvider {
override fun getPassphraseFor(keyId: Long?): Passphrase? { override fun getPassphraseFor(keyIdentifier: KeyIdentifier): Passphrase? {
return if (hasPassphrase(keyId)) passphrase else null return if (hasPassphrase(keyIdentifier)) passphrase else null
} }
override fun hasPassphrase(keyId: Long?): Boolean { override fun hasPassphrase(keyIdentifier: KeyIdentifier): Boolean {
return keyId != null && keyRing.getPublicKey(keyId) != null return keyRing.getPublicKey(keyIdentifier) != null
} }
} }
.let { PasswordBasedSecretKeyRingProtector(it) } .let { PasswordBasedSecretKeyRingProtector(it) }
@ -51,20 +52,20 @@ class PasswordBasedSecretKeyRingProtector : BaseSecretKeyRingProtector {
@JvmStatic @JvmStatic
fun forKey(key: PGPSecretKey, passphrase: Passphrase): PasswordBasedSecretKeyRingProtector = fun forKey(key: PGPSecretKey, passphrase: Passphrase): PasswordBasedSecretKeyRingProtector =
forKeyId(key.publicKey.keyID, passphrase) forKeyId(key.publicKey.keyIdentifier, passphrase)
@JvmStatic @JvmStatic
fun forKeyId( fun forKeyId(
singleKeyId: Long, singleKeyIdentifier: KeyIdentifier,
passphrase: Passphrase passphrase: Passphrase
): PasswordBasedSecretKeyRingProtector { ): PasswordBasedSecretKeyRingProtector {
return object : SecretKeyPassphraseProvider { return object : SecretKeyPassphraseProvider {
override fun getPassphraseFor(keyId: Long?): Passphrase? { override fun getPassphraseFor(keyIdentifier: KeyIdentifier): Passphrase? {
return if (hasPassphrase(keyId)) passphrase else null return if (hasPassphrase(keyIdentifier)) passphrase else null
} }
override fun hasPassphrase(keyId: Long?): Boolean { override fun hasPassphrase(keyIdentifier: KeyIdentifier): Boolean {
return keyId == singleKeyId return keyIdentifier.matches(singleKeyIdentifier)
} }
} }
.let { PasswordBasedSecretKeyRingProtector(it) } .let { PasswordBasedSecretKeyRingProtector(it) }

View file

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

View file

@ -4,6 +4,7 @@
package org.pgpainless.key.protection.passphrase_provider package org.pgpainless.key.protection.passphrase_provider
import org.bouncycastle.bcpg.KeyIdentifier
import org.pgpainless.util.Passphrase import org.pgpainless.util.Passphrase
/** /**
@ -14,9 +15,11 @@ import org.pgpainless.util.Passphrase
* *
* TODO: Make this null-safe and throw an exception instead? * 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 package org.pgpainless.key.protection.passphrase_provider
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.PGPSecretKey import org.bouncycastle.openpgp.PGPSecretKey
import org.pgpainless.util.Passphrase import org.pgpainless.util.Passphrase
@ -19,7 +20,7 @@ interface SecretKeyPassphraseProvider {
* @return passphrase or null, if no passphrase record is found. * @return passphrase or null, if no passphrase record is found.
*/ */
fun getPassphraseFor(secretKey: PGPSecretKey): Passphrase? { 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 * @param keyId if of the secret key
* @return passphrase or null, if no passphrase record has been found. * @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 package org.pgpainless.key.protection.passphrase_provider
import org.bouncycastle.bcpg.KeyIdentifier
import org.pgpainless.util.Passphrase import org.pgpainless.util.Passphrase
/** Implementation of the [SecretKeyPassphraseProvider] that holds a single [Passphrase]. */ /** Implementation of the [SecretKeyPassphraseProvider] that holds a single [Passphrase]. */
class SolitaryPassphraseProvider(val passphrase: Passphrase?) : SecretKeyPassphraseProvider { 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 java.io.ByteArrayOutputStream
import kotlin.jvm.Throws import kotlin.jvm.Throws
import openpgp.openPgpKeyId import openpgp.openPgpKeyId
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.bcpg.S2K import org.bouncycastle.bcpg.S2K
import org.bouncycastle.bcpg.SecretKeyPacket import org.bouncycastle.bcpg.SecretKeyPacket
import org.bouncycastle.openpgp.* import org.bouncycastle.openpgp.*
@ -468,7 +469,7 @@ class KeyRingUtils {
@JvmStatic @JvmStatic
@Throws(MissingPassphraseException::class, PGPException::class) @Throws(MissingPassphraseException::class, PGPException::class)
fun changePassphrase( fun changePassphrase(
keyId: Long?, keyId: KeyIdentifier?,
secretKeys: PGPSecretKeyRing, secretKeys: PGPSecretKeyRing,
oldProtector: SecretKeyRingProtector, oldProtector: SecretKeyRingProtector,
newProtector: SecretKeyRingProtector newProtector: SecretKeyRingProtector
@ -484,7 +485,7 @@ class KeyRingUtils {
secretKeys.secretKeys secretKeys.secretKeys
.asSequence() .asSequence()
.map { .map {
if (it.keyID == keyId) { if (it.keyIdentifier.matches(keyId)) {
reencryptPrivateKey(it, oldProtector, newProtector) reencryptPrivateKey(it, oldProtector, newProtector)
} else { } else {
it it

View file

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

View file

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

View file

@ -21,6 +21,7 @@ import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignatureGenerator; import org.bouncycastle.openpgp.PGPSignatureGenerator;
import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.bouncycastle.openpgp.operator.PGPDataEncryptorBuilder; import org.bouncycastle.openpgp.operator.PGPDataEncryptorBuilder;
import org.bouncycastle.util.io.Streams; import org.bouncycastle.util.io.Streams;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -176,12 +177,13 @@ public class InvestigateMultiSEIPMessageHandlingTest {
@Test @Test
public void testDecryptAndVerifyDetectsAppendedSEIPData() throws IOException, PGPException { public void testDecryptAndVerifyDetectsAppendedSEIPData() throws IOException, PGPException {
PGPSecretKeyRing ring1 = PGPainless.readKeyRing().secretKeyRing(KEY1); PGPainless api = PGPainless.getInstance();
PGPSecretKeyRing ring2 = PGPainless.readKeyRing().secretKeyRing(KEY2); OpenPGPKey ring1 = api.readKey().parseKey(KEY1);
OpenPGPKey ring2 = api.readKey().parseKey(KEY2);
ConsumerOptions options = new ConsumerOptions() ConsumerOptions options = ConsumerOptions.get()
.addVerificationCert(PGPainless.extractCertificate(ring1)) .addVerificationCert(ring2)
.addVerificationCert(PGPainless.extractCertificate(ring2)) .addVerificationCert(ring2)
.addDecryptionKey(ring1); .addDecryptionKey(ring1);
DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify()

View file

@ -124,7 +124,7 @@ public class OnePassSignatureVerificationWithPartialLengthLiteralDataRegressionT
DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify()
.onInputStream(in) .onInputStream(in)
.withOptions(new ConsumerOptions() .withOptions(ConsumerOptions.get()
.addVerificationCert(cert) .addVerificationCert(cert)
.addDecryptionKey(secretKeys)); .addDecryptionKey(secretKeys));

View file

@ -544,7 +544,7 @@ public class AsciiArmorCRCTests {
assertThrows(IOException.class, () -> { assertThrows(IOException.class, () -> {
DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify()
.onInputStream(new ByteArrayInputStream(message.getBytes(StandardCharsets.UTF_8))) .onInputStream(new ByteArrayInputStream(message.getBytes(StandardCharsets.UTF_8)))
.withOptions(new ConsumerOptions().addDecryptionKey( .withOptions(ConsumerOptions.get().addDecryptionKey(
key, SecretKeyRingProtector.unlockAnyKeyWith(passphrase) key, SecretKeyRingProtector.unlockAnyKeyWith(passphrase)
)); ));

View file

@ -52,7 +52,7 @@ public class DecryptAndVerifyMessageTest {
public void decryptMessageAndVerifySignatureTest() throws Exception { public void decryptMessageAndVerifySignatureTest() throws Exception {
String encryptedMessage = TestKeys.MSG_SIGN_CRYPT_JULIET_JULIET; String encryptedMessage = TestKeys.MSG_SIGN_CRYPT_JULIET_JULIET;
ConsumerOptions options = new ConsumerOptions() ConsumerOptions options = ConsumerOptions.get()
.addDecryptionKey(juliet) .addDecryptionKey(juliet)
.addVerificationCert(KeyRingUtils.publicKeyRingFrom(juliet)); .addVerificationCert(KeyRingUtils.publicKeyRingFrom(juliet));
@ -87,7 +87,7 @@ public class DecryptAndVerifyMessageTest {
public void decryptMessageAndReadBeyondEndTest() throws Exception { public void decryptMessageAndReadBeyondEndTest() throws Exception {
final String encryptedMessage = TestKeys.MSG_SIGN_CRYPT_JULIET_JULIET; final String encryptedMessage = TestKeys.MSG_SIGN_CRYPT_JULIET_JULIET;
final ConsumerOptions options = new ConsumerOptions() final ConsumerOptions options = ConsumerOptions.get()
.addDecryptionKey(juliet) .addDecryptionKey(juliet)
.addVerificationCert(KeyRingUtils.publicKeyRingFrom(juliet)); .addVerificationCert(KeyRingUtils.publicKeyRingFrom(juliet));
@ -105,7 +105,7 @@ public class DecryptAndVerifyMessageTest {
public void decryptMessageAndVerifySignatureByteByByteTest() throws Exception { public void decryptMessageAndVerifySignatureByteByByteTest() throws Exception {
String encryptedMessage = TestKeys.MSG_SIGN_CRYPT_JULIET_JULIET; String encryptedMessage = TestKeys.MSG_SIGN_CRYPT_JULIET_JULIET;
ConsumerOptions options = new ConsumerOptions() ConsumerOptions options = ConsumerOptions.get()
.addDecryptionKey(juliet) .addDecryptionKey(juliet)
.addVerificationCert(KeyRingUtils.publicKeyRingFrom(juliet)); .addVerificationCert(KeyRingUtils.publicKeyRingFrom(juliet));

View file

@ -128,7 +128,7 @@ public class DecryptHiddenRecipientMessageTest {
"=1knQ\n" + "=1knQ\n" +
"-----END PGP MESSAGE-----\n"; "-----END PGP MESSAGE-----\n";
ByteArrayInputStream messageIn = new ByteArrayInputStream(message.getBytes(StandardCharsets.UTF_8)); ByteArrayInputStream messageIn = new ByteArrayInputStream(message.getBytes(StandardCharsets.UTF_8));
ConsumerOptions options = new ConsumerOptions() ConsumerOptions options = ConsumerOptions.get()
.addDecryptionKey(secretKeys); .addDecryptionKey(secretKeys);
DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify()

View file

@ -177,7 +177,7 @@ public class IgnoreUnknownSignatureVersionsTest {
private MessageMetadata verifySignature(PGPPublicKeyRing cert, String BASE_CASE) throws PGPException, IOException { private MessageMetadata verifySignature(PGPPublicKeyRing cert, String BASE_CASE) throws PGPException, IOException {
DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify().onInputStream(new ByteArrayInputStream(message.getBytes(StandardCharsets.UTF_8))) DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify().onInputStream(new ByteArrayInputStream(message.getBytes(StandardCharsets.UTF_8)))
.withOptions(new ConsumerOptions() .withOptions(ConsumerOptions.get()
.addVerificationCert(cert) .addVerificationCert(cert)
.addVerificationOfDetachedSignatures(new ByteArrayInputStream(BASE_CASE.getBytes(StandardCharsets.UTF_8)))); .addVerificationOfDetachedSignatures(new ByteArrayInputStream(BASE_CASE.getBytes(StandardCharsets.UTF_8))));

View file

@ -16,11 +16,13 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
import org.bouncycastle.bcpg.KeyIdentifier;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.api.OpenPGPCertificate; import org.bouncycastle.openpgp.api.OpenPGPCertificate;
import org.bouncycastle.util.io.Streams; import org.bouncycastle.util.io.Streams;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
@ -62,13 +64,13 @@ public class MissingPassphraseForDecryptionTest {
// interactive callback // interactive callback
SecretKeyPassphraseProvider callback = new SecretKeyPassphraseProvider() { SecretKeyPassphraseProvider callback = new SecretKeyPassphraseProvider() {
@Override @Override
public Passphrase getPassphraseFor(Long keyId) { public Passphrase getPassphraseFor(@NotNull KeyIdentifier keyIdentifier) {
// is called in interactive mode // is called in interactive mode
return Passphrase.fromPassword(passphrase); return Passphrase.fromPassword(passphrase);
} }
@Override @Override
public boolean hasPassphrase(Long keyId) { public boolean hasPassphrase(@NotNull KeyIdentifier keyIdentifier) {
return true; return true;
} }
}; };
@ -95,13 +97,13 @@ public class MissingPassphraseForDecryptionTest {
SecretKeyPassphraseProvider callback = new SecretKeyPassphraseProvider() { SecretKeyPassphraseProvider callback = new SecretKeyPassphraseProvider() {
@Override @Override
public Passphrase getPassphraseFor(Long keyId) { public Passphrase getPassphraseFor(@NotNull KeyIdentifier keyIdentifier) {
fail("MUST NOT get called in non-interactive mode."); fail("MUST NOT get called in non-interactive mode.");
return null; return null;
} }
@Override @Override
public boolean hasPassphrase(Long keyId) { public boolean hasPassphrase(@NotNull KeyIdentifier keyIdentifier) {
return true; return true;
} }
}; };

View file

@ -12,6 +12,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import org.bouncycastle.bcpg.KeyIdentifier;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.util.io.Streams; import org.bouncycastle.util.io.Streams;
@ -23,6 +24,8 @@ import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.key.protection.passphrase_provider.SecretKeyPassphraseProvider; import org.pgpainless.key.protection.passphrase_provider.SecretKeyPassphraseProvider;
import org.pgpainless.util.Passphrase; import org.pgpainless.util.Passphrase;
import javax.annotation.Nonnull;
public class PostponeDecryptionUsingKeyWithMissingPassphraseTest { public class PostponeDecryptionUsingKeyWithMissingPassphraseTest {
private static PGPSecretKeyRing k1; private static PGPSecretKeyRing k1;
@ -120,13 +123,13 @@ public class PostponeDecryptionUsingKeyWithMissingPassphraseTest {
public void missingPassphraseFirst() throws PGPException, IOException { public void missingPassphraseFirst() throws PGPException, IOException {
SecretKeyRingProtector protector1 = new CachingSecretKeyRingProtector(new SecretKeyPassphraseProvider() { SecretKeyRingProtector protector1 = new CachingSecretKeyRingProtector(new SecretKeyPassphraseProvider() {
@Override @Override
public Passphrase getPassphraseFor(Long keyId) { public Passphrase getPassphraseFor(@Nonnull KeyIdentifier keyIdentifier) {
fail("Although the first PKESK is for k1, we should have skipped it and tried k2 first, which has passphrase available."); fail("Although the first PKESK is for k1, we should have skipped it and tried k2 first, which has passphrase available.");
return null; return null;
} }
@Override @Override
public boolean hasPassphrase(Long keyId) { public boolean hasPassphrase(@Nonnull KeyIdentifier keyIdentifier) {
return false; return false;
} }
}); });
@ -134,7 +137,7 @@ public class PostponeDecryptionUsingKeyWithMissingPassphraseTest {
DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify()
.onInputStream(new ByteArrayInputStream(ENCRYPTED_FOR_K1_K2.getBytes(StandardCharsets.UTF_8))) .onInputStream(new ByteArrayInputStream(ENCRYPTED_FOR_K1_K2.getBytes(StandardCharsets.UTF_8)))
.withOptions(new ConsumerOptions() .withOptions(ConsumerOptions.get()
.addDecryptionKey(k1, protector1) .addDecryptionKey(k1, protector1)
.addDecryptionKey(k2, protector2)); .addDecryptionKey(k2, protector2));
@ -150,20 +153,20 @@ public class PostponeDecryptionUsingKeyWithMissingPassphraseTest {
SecretKeyRingProtector protector1 = SecretKeyRingProtector.unlockEachKeyWith(p1, k1); SecretKeyRingProtector protector1 = SecretKeyRingProtector.unlockEachKeyWith(p1, k1);
SecretKeyRingProtector protector2 = new CachingSecretKeyRingProtector(new SecretKeyPassphraseProvider() { SecretKeyRingProtector protector2 = new CachingSecretKeyRingProtector(new SecretKeyPassphraseProvider() {
@Override @Override
public Passphrase getPassphraseFor(Long keyId) { public Passphrase getPassphraseFor(@Nonnull KeyIdentifier keyIdentifier) {
fail("This callback should not get called, since the first PKESK is for k1, which has a passphrase available."); fail("This callback should not get called, since the first PKESK is for k1, which has a passphrase available.");
return null; return null;
} }
@Override @Override
public boolean hasPassphrase(Long keyId) { public boolean hasPassphrase(@Nonnull KeyIdentifier keyIdentifier) {
return false; return false;
} }
}); });
DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify()
.onInputStream(new ByteArrayInputStream(ENCRYPTED_FOR_K1_K2.getBytes(StandardCharsets.UTF_8))) .onInputStream(new ByteArrayInputStream(ENCRYPTED_FOR_K1_K2.getBytes(StandardCharsets.UTF_8)))
.withOptions(new ConsumerOptions() .withOptions(ConsumerOptions.get()
.addDecryptionKey(k1, protector1) .addDecryptionKey(k1, protector1)
.addDecryptionKey(k2, protector2)); .addDecryptionKey(k2, protector2));
@ -178,13 +181,13 @@ public class PostponeDecryptionUsingKeyWithMissingPassphraseTest {
public void messagePassphraseFirst() throws PGPException, IOException { public void messagePassphraseFirst() throws PGPException, IOException {
SecretKeyPassphraseProvider provider = new SecretKeyPassphraseProvider() { SecretKeyPassphraseProvider provider = new SecretKeyPassphraseProvider() {
@Override @Override
public Passphrase getPassphraseFor(Long keyId) { public Passphrase getPassphraseFor(@Nonnull KeyIdentifier keyIdentifier) {
fail("Since we provide a decryption passphrase, we should not try to decrypt any key."); fail("Since we provide a decryption passphrase, we should not try to decrypt any key.");
return null; return null;
} }
@Override @Override
public boolean hasPassphrase(Long keyId) { public boolean hasPassphrase(@Nonnull KeyIdentifier keyIdentifier) {
return false; return false;
} }
}; };
@ -192,7 +195,7 @@ public class PostponeDecryptionUsingKeyWithMissingPassphraseTest {
DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify()
.onInputStream(new ByteArrayInputStream(ENCRYPTED_FOR_K2_PASS_K1.getBytes(StandardCharsets.UTF_8))) .onInputStream(new ByteArrayInputStream(ENCRYPTED_FOR_K2_PASS_K1.getBytes(StandardCharsets.UTF_8)))
.withOptions(new ConsumerOptions() .withOptions(ConsumerOptions.get()
.addMessagePassphrase(PASSPHRASE) .addMessagePassphrase(PASSPHRASE)
.addDecryptionKey(k1, protector) .addDecryptionKey(k1, protector)
.addDecryptionKey(k2, protector)); .addDecryptionKey(k2, protector));

View file

@ -180,7 +180,7 @@ public class PreventDecryptionUsingNonEncryptionKeyTest {
ByteArrayInputStream msgIn = new ByteArrayInputStream(MSG.getBytes(StandardCharsets.UTF_8)); ByteArrayInputStream msgIn = new ByteArrayInputStream(MSG.getBytes(StandardCharsets.UTF_8));
DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify()
.onInputStream(msgIn) .onInputStream(msgIn)
.withOptions(new ConsumerOptions().addDecryptionKey(secretKeys)); .withOptions(ConsumerOptions.get().addDecryptionKey(secretKeys));
Streams.drain(decryptionStream); Streams.drain(decryptionStream);
decryptionStream.close(); decryptionStream.close();
@ -196,7 +196,7 @@ public class PreventDecryptionUsingNonEncryptionKeyTest {
ByteArrayInputStream msgIn = new ByteArrayInputStream(MSG.getBytes(StandardCharsets.UTF_8)); ByteArrayInputStream msgIn = new ByteArrayInputStream(MSG.getBytes(StandardCharsets.UTF_8));
DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify()
.onInputStream(msgIn) .onInputStream(msgIn)
.withOptions(new ConsumerOptions().addDecryptionKey(secretKeys)); .withOptions(ConsumerOptions.get().addDecryptionKey(secretKeys));
Streams.drain(decryptionStream); Streams.drain(decryptionStream);
decryptionStream.close(); decryptionStream.close();
@ -215,6 +215,6 @@ public class PreventDecryptionUsingNonEncryptionKeyTest {
assertThrows(MissingDecryptionMethodException.class, () -> assertThrows(MissingDecryptionMethodException.class, () ->
PGPainless.decryptAndOrVerify() PGPainless.decryptAndOrVerify()
.onInputStream(msgIn) .onInputStream(msgIn)
.withOptions(new ConsumerOptions().addDecryptionKey(secretKeys))); .withOptions(ConsumerOptions.get().addDecryptionKey(secretKeys)));
} }
} }

View file

@ -30,7 +30,7 @@ public class SignedMessageVerificationWithoutCertIsStillSignedTest {
@Test @Test
public void verifyMissingVerificationCertOptionStillResultsInMessageIsSigned() throws IOException, PGPException { public void verifyMissingVerificationCertOptionStillResultsInMessageIsSigned() throws IOException, PGPException {
ConsumerOptions withoutVerificationCert = new ConsumerOptions(); ConsumerOptions withoutVerificationCert = ConsumerOptions.get();
DecryptionStream verificationStream = PGPainless.decryptAndOrVerify() DecryptionStream verificationStream = PGPainless.decryptAndOrVerify()
.onInputStream(new ByteArrayInputStream(message.getBytes(StandardCharsets.UTF_8))) .onInputStream(new ByteArrayInputStream(message.getBytes(StandardCharsets.UTF_8)))
.withOptions(withoutVerificationCert); .withOptions(withoutVerificationCert);

View file

@ -57,7 +57,7 @@ public class VerifyDetachedSignatureTest {
DecryptionStream verifier = PGPainless.decryptAndOrVerify() DecryptionStream verifier = PGPainless.decryptAndOrVerify()
.onInputStream(new ByteArrayInputStream(signedContent.getBytes(StandardCharsets.UTF_8))) .onInputStream(new ByteArrayInputStream(signedContent.getBytes(StandardCharsets.UTF_8)))
.withOptions( .withOptions(
new ConsumerOptions() ConsumerOptions.get()
.addVerificationOfDetachedSignatures(new ByteArrayInputStream(signature.getBytes(StandardCharsets.UTF_8))) .addVerificationOfDetachedSignatures(new ByteArrayInputStream(signature.getBytes(StandardCharsets.UTF_8)))
.addVerificationCerts(PGPainless.readKeyRing().keyRingCollection(pubkey, true).getPgpPublicKeyRingCollection()) .addVerificationCerts(PGPainless.readKeyRing().keyRingCollection(pubkey, true).getPgpPublicKeyRingCollection())
.setMultiPassStrategy(new InMemoryMultiPassStrategy()) .setMultiPassStrategy(new InMemoryMultiPassStrategy())
@ -132,7 +132,7 @@ public class VerifyDetachedSignatureTest {
DecryptionStream verifier = PGPainless.decryptAndOrVerify() DecryptionStream verifier = PGPainless.decryptAndOrVerify()
.onInputStream(new ByteArrayInputStream(signedContent.getBytes(StandardCharsets.UTF_8))) .onInputStream(new ByteArrayInputStream(signedContent.getBytes(StandardCharsets.UTF_8)))
.withOptions( .withOptions(
new ConsumerOptions() ConsumerOptions.get()
.addVerificationOfDetachedSignatures(new ByteArrayInputStream(signature.getBytes(StandardCharsets.UTF_8))) .addVerificationOfDetachedSignatures(new ByteArrayInputStream(signature.getBytes(StandardCharsets.UTF_8)))
.addVerificationCerts(PGPainless.readKeyRing().keyRingCollection(pubkey, true).getPgpPublicKeyRingCollection()) .addVerificationCerts(PGPainless.readKeyRing().keyRingCollection(pubkey, true).getPgpPublicKeyRingCollection())
.setMultiPassStrategy(new InMemoryMultiPassStrategy()) .setMultiPassStrategy(new InMemoryMultiPassStrategy())

View file

@ -62,7 +62,7 @@ public class VerifyNotBeforeNotAfterTest {
@Test @Test
public void noConstraintsVerifyInlineSig() throws PGPException, IOException { public void noConstraintsVerifyInlineSig() throws PGPException, IOException {
ConsumerOptions options = new ConsumerOptions() ConsumerOptions options = ConsumerOptions.get()
.addVerificationCert(certificate); .addVerificationCert(certificate);
DecryptionStream verifier = PGPainless.decryptAndOrVerify() DecryptionStream verifier = PGPainless.decryptAndOrVerify()
.onInputStream(new ByteArrayInputStream(inlineSigned)) .onInputStream(new ByteArrayInputStream(inlineSigned))
@ -74,7 +74,7 @@ public class VerifyNotBeforeNotAfterTest {
@Test @Test
public void noConstraintsVerifyDetachedSig() throws PGPException, IOException { public void noConstraintsVerifyDetachedSig() throws PGPException, IOException {
ConsumerOptions options = new ConsumerOptions() ConsumerOptions options = ConsumerOptions.get()
.addVerificationCert(certificate) .addVerificationCert(certificate)
.addVerificationOfDetachedSignatures(new ByteArrayInputStream(detachedSignature)); .addVerificationOfDetachedSignatures(new ByteArrayInputStream(detachedSignature));
DecryptionStream verifier = PGPainless.decryptAndOrVerify() DecryptionStream verifier = PGPainless.decryptAndOrVerify()
@ -87,7 +87,7 @@ public class VerifyNotBeforeNotAfterTest {
@Test @Test
public void notBeforeT1DoesNotRejectInlineSigMadeAtT1() throws PGPException, IOException { public void notBeforeT1DoesNotRejectInlineSigMadeAtT1() throws PGPException, IOException {
ConsumerOptions options = new ConsumerOptions() ConsumerOptions options = ConsumerOptions.get()
.verifyNotBefore(T1) .verifyNotBefore(T1)
.addVerificationCert(certificate); .addVerificationCert(certificate);
DecryptionStream verifier = PGPainless.decryptAndOrVerify() DecryptionStream verifier = PGPainless.decryptAndOrVerify()
@ -99,7 +99,7 @@ public class VerifyNotBeforeNotAfterTest {
@Test @Test
public void notBeforeT1DoesNotRejectDetachedSigMadeAtT1() throws PGPException, IOException { public void notBeforeT1DoesNotRejectDetachedSigMadeAtT1() throws PGPException, IOException {
ConsumerOptions options = new ConsumerOptions() ConsumerOptions options = ConsumerOptions.get()
.verifyNotBefore(T1) .verifyNotBefore(T1)
.addVerificationCert(certificate) .addVerificationCert(certificate)
.addVerificationOfDetachedSignatures(new ByteArrayInputStream(detachedSignature)); .addVerificationOfDetachedSignatures(new ByteArrayInputStream(detachedSignature));
@ -112,7 +112,7 @@ public class VerifyNotBeforeNotAfterTest {
@Test @Test
public void verifyNotBeforeT2DoesRejectInlineSignatureMadeAtT1() throws PGPException, IOException { public void verifyNotBeforeT2DoesRejectInlineSignatureMadeAtT1() throws PGPException, IOException {
ConsumerOptions options = new ConsumerOptions() ConsumerOptions options = ConsumerOptions.get()
.verifyNotBefore(T2) .verifyNotBefore(T2)
.addVerificationCert(certificate); .addVerificationCert(certificate);
DecryptionStream verifier = PGPainless.decryptAndOrVerify() DecryptionStream verifier = PGPainless.decryptAndOrVerify()
@ -124,7 +124,7 @@ public class VerifyNotBeforeNotAfterTest {
@Test @Test
public void verifyNotBeforeT2DoesRejectDetachedSigMadeAtT1() throws PGPException, IOException { public void verifyNotBeforeT2DoesRejectDetachedSigMadeAtT1() throws PGPException, IOException {
ConsumerOptions options = new ConsumerOptions() ConsumerOptions options = ConsumerOptions.get()
.verifyNotBefore(T2) .verifyNotBefore(T2)
.addVerificationCert(certificate) .addVerificationCert(certificate)
.addVerificationOfDetachedSignatures(new ByteArrayInputStream(detachedSignature)); .addVerificationOfDetachedSignatures(new ByteArrayInputStream(detachedSignature));
@ -137,7 +137,7 @@ public class VerifyNotBeforeNotAfterTest {
@Test @Test
public void verifyNotAfterT1DoesNotRejectInlineSigMadeAtT1() throws PGPException, IOException { public void verifyNotAfterT1DoesNotRejectInlineSigMadeAtT1() throws PGPException, IOException {
ConsumerOptions options = new ConsumerOptions() ConsumerOptions options = ConsumerOptions.get()
.verifyNotAfter(T1) .verifyNotAfter(T1)
.addVerificationCert(certificate); .addVerificationCert(certificate);
DecryptionStream verifier = PGPainless.decryptAndOrVerify() DecryptionStream verifier = PGPainless.decryptAndOrVerify()
@ -149,7 +149,7 @@ public class VerifyNotBeforeNotAfterTest {
@Test @Test
public void verifyNotAfterT1DoesRejectDetachedSigMadeAtT1() throws PGPException, IOException { public void verifyNotAfterT1DoesRejectDetachedSigMadeAtT1() throws PGPException, IOException {
ConsumerOptions options = new ConsumerOptions() ConsumerOptions options = ConsumerOptions.get()
.verifyNotAfter(T1) .verifyNotAfter(T1)
.addVerificationCert(certificate) .addVerificationCert(certificate)
.addVerificationOfDetachedSignatures(new ByteArrayInputStream(detachedSignature)); .addVerificationOfDetachedSignatures(new ByteArrayInputStream(detachedSignature));
@ -162,7 +162,7 @@ public class VerifyNotBeforeNotAfterTest {
@Test @Test
public void verifyNotAfterT0DoesRejectInlineSigMadeAtT1() throws PGPException, IOException { public void verifyNotAfterT0DoesRejectInlineSigMadeAtT1() throws PGPException, IOException {
ConsumerOptions options = new ConsumerOptions() ConsumerOptions options = ConsumerOptions.get()
.verifyNotAfter(T0) .verifyNotAfter(T0)
.addVerificationCert(certificate); .addVerificationCert(certificate);
DecryptionStream verifier = PGPainless.decryptAndOrVerify() DecryptionStream verifier = PGPainless.decryptAndOrVerify()
@ -174,7 +174,7 @@ public class VerifyNotBeforeNotAfterTest {
@Test @Test
public void verifyNotAfterT0DoesRejectDetachedSigMadeAtT1() throws PGPException, IOException { public void verifyNotAfterT0DoesRejectDetachedSigMadeAtT1() throws PGPException, IOException {
ConsumerOptions options = new ConsumerOptions() ConsumerOptions options = ConsumerOptions.get()
.verifyNotAfter(T0) .verifyNotAfter(T0)
.addVerificationCert(certificate) .addVerificationCert(certificate)
.addVerificationOfDetachedSignatures(new ByteArrayInputStream(detachedSignature)); .addVerificationOfDetachedSignatures(new ByteArrayInputStream(detachedSignature));

View file

@ -35,7 +35,7 @@ class VerifyVersion3SignaturePacketTest {
void verifyDetachedVersion3Signature() throws PGPException, IOException { void verifyDetachedVersion3Signature() throws PGPException, IOException {
PGPSignature version3Signature = generateV3Signature(); PGPSignature version3Signature = generateV3Signature();
ConsumerOptions options = new ConsumerOptions() ConsumerOptions options = ConsumerOptions.get()
.addVerificationCert(TestKeys.getEmilPublicKeyRing()) .addVerificationCert(TestKeys.getEmilPublicKeyRing())
.addVerificationOfDetachedSignatures(new ByteArrayInputStream(version3Signature.getEncoded())); .addVerificationOfDetachedSignatures(new ByteArrayInputStream(version3Signature.getEncoded()));

View file

@ -13,21 +13,23 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import org.bouncycastle.bcpg.KeyIdentifier;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.api.OpenPGPCertificate; import org.bouncycastle.openpgp.api.OpenPGPCertificate;
import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.bouncycastle.util.io.Streams; import org.bouncycastle.util.io.Streams;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.DocumentSignatureType; import org.pgpainless.algorithm.DocumentSignatureType;
import org.pgpainless.algorithm.OpenPGPKeyVersion;
import org.pgpainless.encryption_signing.EncryptionStream; import org.pgpainless.encryption_signing.EncryptionStream;
import org.pgpainless.encryption_signing.ProducerOptions; import org.pgpainless.encryption_signing.ProducerOptions;
import org.pgpainless.encryption_signing.SigningOptions; import org.pgpainless.encryption_signing.SigningOptions;
import org.pgpainless.key.TestKeys; import org.pgpainless.key.TestKeys;
import org.pgpainless.key.info.KeyRingInfo;
import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.key.util.KeyRingUtils;
import javax.annotation.Nonnull;
/** /**
* Test functionality of the {@link MissingPublicKeyCallback} which is called when during signature verification, * Test functionality of the {@link MissingPublicKeyCallback} which is called when during signature verification,
@ -38,11 +40,12 @@ public class VerifyWithMissingPublicKeyCallbackTest {
@Test @Test
public void testMissingPublicKeyCallback() throws PGPException, IOException { public void testMissingPublicKeyCallback() throws PGPException, IOException {
PGPSecretKeyRing signingSecKeys = PGPainless.generateKeyRing().modernKeyRing("alice") PGPainless api = PGPainless.getInstance();
.getPGPSecretKeyRing();
OpenPGPKey signingSecKeys = api.generateKey(OpenPGPKeyVersion.v4).modernKeyRing("alice");
OpenPGPCertificate.OpenPGPComponentKey signingKey = OpenPGPCertificate.OpenPGPComponentKey signingKey =
new KeyRingInfo(signingSecKeys).getSigningSubkeys().get(0); signingSecKeys.getSigningKeys().get(0);
PGPPublicKeyRing signingPubKeys = KeyRingUtils.publicKeyRingFrom(signingSecKeys); OpenPGPCertificate signingPubKeys = signingSecKeys.toCertificate();
PGPPublicKeyRing unrelatedKeys = TestKeys.getJulietPublicKeyRing(); PGPPublicKeyRing unrelatedKeys = TestKeys.getJulietPublicKeyRing();
String msg = "Arguing that you don't care about the right to privacy because you have nothing to hide" + String msg = "Arguing that you don't care about the right to privacy because you have nothing to hide" +
@ -51,7 +54,7 @@ public class VerifyWithMissingPublicKeyCallbackTest {
EncryptionStream signingStream = PGPainless.encryptAndOrSign().onOutputStream(signOut) EncryptionStream signingStream = PGPainless.encryptAndOrSign().onOutputStream(signOut)
.withOptions(ProducerOptions.sign(new SigningOptions().addInlineSignature( .withOptions(ProducerOptions.sign(new SigningOptions().addInlineSignature(
SecretKeyRingProtector.unprotectedKeys(), SecretKeyRingProtector.unprotectedKeys(),
signingSecKeys, DocumentSignatureType.CANONICAL_TEXT_DOCUMENT signingSecKeys.getPGPSecretKeyRing(), DocumentSignatureType.CANONICAL_TEXT_DOCUMENT
))); )));
Streams.pipeAll(new ByteArrayInputStream(msg.getBytes(StandardCharsets.UTF_8)), signingStream); Streams.pipeAll(new ByteArrayInputStream(msg.getBytes(StandardCharsets.UTF_8)), signingStream);
signingStream.close(); signingStream.close();
@ -62,8 +65,8 @@ public class VerifyWithMissingPublicKeyCallbackTest {
.addVerificationCert(unrelatedKeys) .addVerificationCert(unrelatedKeys)
.setMissingCertificateCallback(new MissingPublicKeyCallback() { .setMissingCertificateCallback(new MissingPublicKeyCallback() {
@Override @Override
public PGPPublicKeyRing onMissingPublicKeyEncountered(long keyId) { public OpenPGPCertificate onMissingPublicKeyEncountered(@Nonnull KeyIdentifier keyIdentifier) {
assertEquals(signingKey.getKeyIdentifier().getKeyId(), keyId, "Signing key-ID mismatch."); assertEquals(signingKey.getKeyIdentifier(), keyIdentifier, "Signing key-ID mismatch.");
return signingPubKeys; return signingPubKeys;
} }
})); }));

View file

@ -97,7 +97,7 @@ public class ChangeSecretKeyRingPassphraseTest {
extractPrivateKey(subKey, Passphrase.fromPassword("weakPassphrase")); extractPrivateKey(subKey, Passphrase.fromPassword("weakPassphrase"));
PGPSecretKeyRing secretKeys = PGPainless.modifyKeyRing(keyRing) PGPSecretKeyRing secretKeys = PGPainless.modifyKeyRing(keyRing)
.changeSubKeyPassphraseFromOldPassphrase(subKey.getPublicKey().getKeyID(), .changeSubKeyPassphraseFromOldPassphrase(subKey.getPublicKey().getKeyIdentifier(),
Passphrase.fromPassword("weakPassphrase")) Passphrase.fromPassword("weakPassphrase"))
.withSecureDefaultSettings() .withSecureDefaultSettings()
.toNewPassphrase(Passphrase.fromPassword("subKeyPassphrase")) .toNewPassphrase(Passphrase.fromPassword("subKeyPassphrase"))
@ -130,7 +130,7 @@ public class ChangeSecretKeyRingPassphraseTest {
PGPSecretKey subKey = keys.next(); PGPSecretKey subKey = keys.next();
PGPSecretKeyRing secretKeys = PGPainless.modifyKeyRing(keyRing) PGPSecretKeyRing secretKeys = PGPainless.modifyKeyRing(keyRing)
.changeSubKeyPassphraseFromOldPassphrase(subKey.getKeyID(), Passphrase.fromPassword("weakPassphrase")) .changeSubKeyPassphraseFromOldPassphrase(subKey.getKeyIdentifier(), Passphrase.fromPassword("weakPassphrase"))
.withSecureDefaultSettings() .withSecureDefaultSettings()
.toNoPassphrase() .toNoPassphrase()
.done(); .done();

View file

@ -13,11 +13,13 @@ import java.io.IOException;
import java.util.Iterator; import java.util.Iterator;
import java.util.Random; import java.util.Random;
import org.bouncycastle.bcpg.KeyIdentifier;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPKeyRing; import org.bouncycastle.openpgp.PGPKeyRing;
import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
@ -30,13 +32,13 @@ public class CachingSecretKeyRingProtectorTest {
// Dummy passphrase callback that returns the doubled key-id as passphrase // Dummy passphrase callback that returns the doubled key-id as passphrase
private final SecretKeyPassphraseProvider dummyCallback = new SecretKeyPassphraseProvider() { private final SecretKeyPassphraseProvider dummyCallback = new SecretKeyPassphraseProvider() {
@Override @Override
public Passphrase getPassphraseFor(Long keyId) { public Passphrase getPassphraseFor(@NotNull KeyIdentifier keyIdentifier) {
long doubled = keyId * 2; long doubled = keyIdentifier.getKeyId() * 2;
return Passphrase.fromPassword(Long.toString(doubled)); return Passphrase.fromPassword(Long.toString(doubled));
} }
@Override @Override
public boolean hasPassphrase(Long keyId) { public boolean hasPassphrase(@NotNull KeyIdentifier keyIdentifier) {
return true; return true;
} }
}; };
@ -49,15 +51,15 @@ public class CachingSecretKeyRingProtectorTest {
} }
@Test @Test
public void noCallbackReturnsNullForUnknownKeyId() { public void noCallbackReturnsNullForUnknownKeyId() throws PGPException {
assertNull(protector.getDecryptor(123L)); assertNull(protector.getDecryptor(123L));
assertNull(protector.getEncryptor(123L)); assertNull(protector.getEncryptor(123L));
} }
@Test @Test
public void testAddPassphrase() { public void testAddPassphrase() throws PGPException {
Passphrase passphrase = Passphrase.fromPassword("HelloWorld"); Passphrase passphrase = Passphrase.fromPassword("HelloWorld");
protector.addPassphrase(123L, passphrase); protector.addPassphrase(new KeyIdentifier(123L), passphrase);
assertEquals(passphrase, protector.getPassphraseFor(123L)); assertEquals(passphrase, protector.getPassphraseFor(123L));
assertNotNull(protector.getEncryptor(123L)); assertNotNull(protector.getEncryptor(123L));
assertNotNull(protector.getDecryptor(123L)); assertNotNull(protector.getDecryptor(123L));
@ -75,7 +77,7 @@ public class CachingSecretKeyRingProtectorTest {
} }
@Test @Test
public void testAddPassphraseForKeyRing() { public void testAddPassphraseForKeyRing() throws PGPException {
PGPSecretKeyRing keys = PGPainless.generateKeyRing() PGPSecretKeyRing keys = PGPainless.generateKeyRing()
.modernKeyRing("test@test.test", "Passphrase123") .modernKeyRing("test@test.test", "Passphrase123")
.getPGPSecretKeyRing(); .getPGPSecretKeyRing();

View file

@ -11,6 +11,7 @@ import java.io.IOException;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.bouncycastle.bcpg.KeyIdentifier;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -22,10 +23,10 @@ public class MapBasedPassphraseProviderTest {
@Test @Test
public void testMapBasedProvider() throws IOException, PGPException { public void testMapBasedProvider() throws IOException, PGPException {
Map<Long, Passphrase> passphraseMap = new ConcurrentHashMap<>(); Map<KeyIdentifier, Passphrase> passphraseMap = new ConcurrentHashMap<>();
passphraseMap.put(1L, Passphrase.fromPassword("tiger")); passphraseMap.put(new KeyIdentifier(1L), Passphrase.fromPassword("tiger"));
passphraseMap.put(123123123L, Passphrase.fromPassword("snake")); passphraseMap.put(new KeyIdentifier(123123123L), Passphrase.fromPassword("snake"));
passphraseMap.put(69696969L, Passphrase.emptyPassphrase()); passphraseMap.put(new KeyIdentifier(69696969L), Passphrase.emptyPassphrase());
MapBasedPassphraseProvider provider = new MapBasedPassphraseProvider(passphraseMap); MapBasedPassphraseProvider provider = new MapBasedPassphraseProvider(passphraseMap);
assertEquals(Passphrase.fromPassword("tiger"), provider.getPassphraseFor(1L)); assertEquals(Passphrase.fromPassword("tiger"), provider.getPassphraseFor(1L));
@ -35,7 +36,7 @@ public class MapBasedPassphraseProviderTest {
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing(); PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing();
passphraseMap = new ConcurrentHashMap<>(); passphraseMap = new ConcurrentHashMap<>();
passphraseMap.put(secretKeys.getSecretKey().getKeyID(), TestKeys.CRYPTIE_PASSPHRASE); passphraseMap.put(secretKeys.getSecretKey().getKeyIdentifier(), TestKeys.CRYPTIE_PASSPHRASE);
provider = new MapBasedPassphraseProvider(passphraseMap); provider = new MapBasedPassphraseProvider(passphraseMap);
assertEquals(TestKeys.CRYPTIE_PASSPHRASE, provider.getPassphraseFor(secretKeys.getSecretKey())); assertEquals(TestKeys.CRYPTIE_PASSPHRASE, provider.getPassphraseFor(secretKeys.getSecretKey()));

View file

@ -10,9 +10,11 @@ import static org.junit.jupiter.api.Assertions.assertNull;
import java.util.Iterator; import java.util.Iterator;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.bouncycastle.bcpg.KeyIdentifier;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
import org.pgpainless.key.TestKeys; import org.pgpainless.key.TestKeys;
@ -29,8 +31,8 @@ public class PassphraseProtectedKeyTest {
new SecretKeyPassphraseProvider() { new SecretKeyPassphraseProvider() {
@Nullable @Nullable
@Override @Override
public Passphrase getPassphraseFor(Long keyId) { public Passphrase getPassphraseFor(@NotNull KeyIdentifier keyIdentifier) {
if (keyId == TestKeys.CRYPTIE_KEY_ID) { if (keyIdentifier.getKeyId() == TestKeys.CRYPTIE_KEY_ID) {
return new Passphrase(TestKeys.CRYPTIE_PASSWORD.toCharArray()); return new Passphrase(TestKeys.CRYPTIE_PASSWORD.toCharArray());
} else { } else {
return null; return null;
@ -38,19 +40,19 @@ public class PassphraseProtectedKeyTest {
} }
@Override @Override
public boolean hasPassphrase(Long keyId) { public boolean hasPassphrase(@NotNull KeyIdentifier keyIdentifier) {
return keyId == TestKeys.CRYPTIE_KEY_ID; return keyIdentifier.getKeyId() == TestKeys.CRYPTIE_KEY_ID;
} }
}); });
@Test @Test
public void testReturnsNonNullDecryptorEncryptorForPassword() { public void testReturnsNonNullDecryptorEncryptorForPassword() throws PGPException {
assertNotNull(protector.getEncryptor(TestKeys.CRYPTIE_KEY_ID)); assertNotNull(protector.getEncryptor(TestKeys.CRYPTIE_KEY_ID));
assertNotNull(protector.getDecryptor(TestKeys.CRYPTIE_KEY_ID)); assertNotNull(protector.getDecryptor(TestKeys.CRYPTIE_KEY_ID));
} }
@Test @Test
public void testReturnsNullDecryptorEncryptorForNoPassword() { public void testReturnsNullDecryptorEncryptorForNoPassword() throws PGPException {
assertNull(protector.getEncryptor(TestKeys.JULIET_KEY_ID)); assertNull(protector.getEncryptor(TestKeys.JULIET_KEY_ID));
assertNull(protector.getDecryptor(TestKeys.JULIET_KEY_ID)); assertNull(protector.getDecryptor(TestKeys.JULIET_KEY_ID));
} }

View file

@ -15,10 +15,12 @@ import java.util.Map;
import java.util.Random; import java.util.Random;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.bouncycastle.bcpg.KeyIdentifier;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.TestTemplate;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
@ -85,8 +87,8 @@ public class SecretKeyRingProtectorTest {
@Test @Test
public void testFromPassphraseMap() { public void testFromPassphraseMap() {
Map<Long, Passphrase> passphraseMap = new ConcurrentHashMap<>(); Map<KeyIdentifier, Passphrase> passphraseMap = new ConcurrentHashMap<>();
passphraseMap.put(1L, Passphrase.emptyPassphrase()); passphraseMap.put(new KeyIdentifier(1L), Passphrase.emptyPassphrase());
CachingSecretKeyRingProtector protector = CachingSecretKeyRingProtector protector =
(CachingSecretKeyRingProtector) SecretKeyRingProtector.fromPassphraseMap(passphraseMap); (CachingSecretKeyRingProtector) SecretKeyRingProtector.fromPassphraseMap(passphraseMap);
@ -102,17 +104,17 @@ public class SecretKeyRingProtectorTest {
@Test @Test
public void testMissingPassphraseCallback() { public void testMissingPassphraseCallback() {
Map<Long, Passphrase> passphraseMap = new ConcurrentHashMap<>(); Map<KeyIdentifier, Passphrase> passphraseMap = new ConcurrentHashMap<>();
passphraseMap.put(1L, Passphrase.emptyPassphrase()); passphraseMap.put(new KeyIdentifier(1L), Passphrase.emptyPassphrase());
CachingSecretKeyRingProtector protector = new CachingSecretKeyRingProtector(passphraseMap, CachingSecretKeyRingProtector protector = new CachingSecretKeyRingProtector(passphraseMap,
KeyRingProtectionSettings.secureDefaultSettings(), new SecretKeyPassphraseProvider() { KeyRingProtectionSettings.secureDefaultSettings(), new SecretKeyPassphraseProvider() {
@Override @Override
public Passphrase getPassphraseFor(Long keyId) { public Passphrase getPassphraseFor(@NotNull KeyIdentifier keyIdentifier) {
return Passphrase.fromPassword("missingP455w0rd"); return Passphrase.fromPassword("missingP455w0rd");
} }
@Override @Override
public boolean hasPassphrase(Long keyId) { public boolean hasPassphrase(@NotNull KeyIdentifier keyIdentifier) {
return true; return true;
} }
}); });

View file

@ -6,6 +6,7 @@ package org.pgpainless.key.protection;
import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import org.bouncycastle.openpgp.PGPException;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
public class UnprotectedKeysProtectorTest { public class UnprotectedKeysProtectorTest {
@ -13,12 +14,12 @@ public class UnprotectedKeysProtectorTest {
private final UnprotectedKeysProtector protector = new UnprotectedKeysProtector(); private final UnprotectedKeysProtector protector = new UnprotectedKeysProtector();
@Test @Test
public void testKeyProtectorReturnsNullDecryptor() { public void testKeyProtectorReturnsNullDecryptor() throws PGPException {
assertNull(protector.getDecryptor(0L)); assertNull(protector.getDecryptor(0L));
} }
@Test @Test
public void testKeyProtectorReturnsNullEncryptor() { public void testKeyProtectorReturnsNullEncryptor() throws PGPException {
assertNull(protector.getEncryptor(0L)); assertNull(protector.getEncryptor(0L));
} }
} }

View file

@ -48,7 +48,7 @@ public class MultiPassphraseSymmetricEncryptionTest {
for (Passphrase passphrase : new Passphrase[] {Passphrase.fromPassword("p2"), Passphrase.fromPassword("p1")}) { for (Passphrase passphrase : new Passphrase[] {Passphrase.fromPassword("p2"), Passphrase.fromPassword("p1")}) {
DecryptionStream decryptor = PGPainless.decryptAndOrVerify() DecryptionStream decryptor = PGPainless.decryptAndOrVerify()
.onInputStream(new ByteArrayInputStream(ciphertext)) .onInputStream(new ByteArrayInputStream(ciphertext))
.withOptions(new ConsumerOptions() .withOptions(ConsumerOptions.get()
.addMessagePassphrase(passphrase)); .addMessagePassphrase(passphrase));
ByteArrayOutputStream plaintextOut = new ByteArrayOutputStream(); ByteArrayOutputStream plaintextOut = new ByteArrayOutputStream();

View file

@ -65,7 +65,7 @@ public class SymmetricEncryptionTest {
// Test symmetric decryption // Test symmetric decryption
DecryptionStream decryptor = PGPainless.decryptAndOrVerify() DecryptionStream decryptor = PGPainless.decryptAndOrVerify()
.onInputStream(new ByteArrayInputStream(ciphertext)) .onInputStream(new ByteArrayInputStream(ciphertext))
.withOptions(new ConsumerOptions() .withOptions(ConsumerOptions.get()
.addMessagePassphrase(encryptionPassphrase)); .addMessagePassphrase(encryptionPassphrase));
ByteArrayOutputStream decrypted = new ByteArrayOutputStream(); ByteArrayOutputStream decrypted = new ByteArrayOutputStream();
@ -82,7 +82,7 @@ public class SymmetricEncryptionTest {
new SolitaryPassphraseProvider(Passphrase.fromPassword(TestKeys.CRYPTIE_PASSWORD))); new SolitaryPassphraseProvider(Passphrase.fromPassword(TestKeys.CRYPTIE_PASSWORD)));
decryptor = PGPainless.decryptAndOrVerify() decryptor = PGPainless.decryptAndOrVerify()
.onInputStream(new ByteArrayInputStream(ciphertext)) .onInputStream(new ByteArrayInputStream(ciphertext))
.withOptions(new ConsumerOptions() .withOptions(ConsumerOptions.get()
.addDecryptionKeys(decryptionKeys, protector)); .addDecryptionKeys(decryptionKeys, protector));
decrypted = new ByteArrayOutputStream(); decrypted = new ByteArrayOutputStream();
@ -110,7 +110,7 @@ public class SymmetricEncryptionTest {
assertThrows(MissingDecryptionMethodException.class, () -> PGPainless.decryptAndOrVerify() assertThrows(MissingDecryptionMethodException.class, () -> PGPainless.decryptAndOrVerify()
.onInputStream(new ByteArrayInputStream(ciphertextOut.toByteArray())) .onInputStream(new ByteArrayInputStream(ciphertextOut.toByteArray()))
.withOptions(new ConsumerOptions() .withOptions(ConsumerOptions.get()
.setMissingKeyPassphraseStrategy(MissingKeyPassphraseStrategy.THROW_EXCEPTION) .setMissingKeyPassphraseStrategy(MissingKeyPassphraseStrategy.THROW_EXCEPTION)
.addMessagePassphrase(Passphrase.fromPassword("meldir")))); .addMessagePassphrase(Passphrase.fromPassword("meldir"))));
} }

View file

@ -4,9 +4,11 @@
package org.pgpainless.sop package org.pgpainless.sop
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.PGPException import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPSecretKey import org.bouncycastle.openpgp.PGPSecretKey
import org.bouncycastle.openpgp.PGPSecretKeyRing import org.bouncycastle.openpgp.PGPSecretKeyRing
import org.bouncycastle.openpgp.api.OpenPGPKey
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor
import org.pgpainless.bouncycastle.extensions.isDecrypted import org.pgpainless.bouncycastle.extensions.isDecrypted
@ -41,7 +43,7 @@ class MatchMakingSecretKeyRingProtector : SecretKeyRingProtector {
} }
if (testPassphrase(passphrase, subkey)) { if (testPassphrase(passphrase, subkey)) {
protector.addPassphrase(subkey.keyID, passphrase) protector.addPassphrase(subkey.keyIdentifier, passphrase)
} }
} }
} }
@ -54,11 +56,11 @@ class MatchMakingSecretKeyRingProtector : SecretKeyRingProtector {
key.forEach { subkey -> key.forEach { subkey ->
if (subkey.isDecrypted()) { if (subkey.isDecrypted()) {
protector.addPassphrase(subkey.keyID, Passphrase.emptyPassphrase()) protector.addPassphrase(subkey.keyIdentifier, Passphrase.emptyPassphrase())
} else { } else {
passphrases.forEach { passphrase -> passphrases.forEach { passphrase ->
if (testPassphrase(passphrase, subkey)) { if (testPassphrase(passphrase, subkey)) {
protector.addPassphrase(subkey.keyID, passphrase) protector.addPassphrase(subkey.keyIdentifier, passphrase)
} }
} }
} }
@ -74,11 +76,17 @@ class MatchMakingSecretKeyRingProtector : SecretKeyRingProtector {
false false
} }
override fun hasPassphraseFor(keyId: Long): Boolean = protector.hasPassphrase(keyId) override fun hasPassphraseFor(keyIdentifier: KeyIdentifier): Boolean =
protector.hasPassphrase(keyIdentifier)
override fun getDecryptor(keyId: Long): PBESecretKeyDecryptor? = protector.getDecryptor(keyId) override fun getDecryptor(keyIdentifier: KeyIdentifier): PBESecretKeyDecryptor? =
protector.getDecryptor(keyIdentifier)
override fun getEncryptor(keyId: Long): PBESecretKeyEncryptor? = protector.getEncryptor(keyId) override fun getEncryptor(keyIdentifier: KeyIdentifier): PBESecretKeyEncryptor? =
protector.getEncryptor(keyIdentifier)
override fun getKeyPassword(p0: OpenPGPKey.OpenPGPSecretKey): CharArray? =
protector.getKeyPassword(p0)
/** Clear all known passphrases from the protector. */ /** Clear all known passphrases from the protector. */
fun clear() { fun clear() {

View file

@ -4,6 +4,7 @@
package sop.testsuite.pgpainless.operation; package sop.testsuite.pgpainless.operation;
import org.bouncycastle.bcpg.KeyIdentifier;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
@ -38,9 +39,9 @@ public class PGPainlessChangeKeyPasswordTest extends ChangeKeyPasswordTest {
.build() .build()
.getPGPSecretKeyRing(); .getPGPSecretKeyRing();
Iterator<PGPPublicKey> keys = secretKeys.getPublicKeys(); Iterator<PGPPublicKey> keys = secretKeys.getPublicKeys();
long primaryKeyId = keys.next().getKeyID(); KeyIdentifier primaryKeyId = keys.next().getKeyIdentifier();
long signingKeyId = keys.next().getKeyID(); KeyIdentifier signingKeyId = keys.next().getKeyIdentifier();
long encryptKeyId = keys.next().getKeyID(); KeyIdentifier encryptKeyId = keys.next().getKeyIdentifier();
String p1 = "sw0rdf1sh"; String p1 = "sw0rdf1sh";
String p2 = "0r4ng3"; String p2 = "0r4ng3";