From 6798d2dedab036924be20513dc13c1a8bcfa3f31 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Tue, 11 Feb 2025 16:17:48 +0100 Subject: [PATCH] Even more migration and code compiles again --- .../RoundTripEncryptDecryptCmdTest.java | 3 +- .../java/org/gnupg/GnuPGDummyKeyUtil.java | 3 +- .../exception/WrongPassphraseException.java | 7 +- .../extensions/PGPKeyRingExtensions.kt | 9 +++ .../extensions/PGPSecretKeyRingExtensions.kt | 10 +++ .../ConsumerOptions.kt | 22 +++-- .../MessageMetadata.kt | 2 +- .../MissingPublicKeyCallback.kt | 9 ++- .../OpenPgpMessageInputStream.kt | 81 +++++++++---------- .../org/pgpainless/key/OpenPgpFingerprint.kt | 3 + .../pgpainless/key/OpenPgpV4Fingerprint.kt | 3 + .../pgpainless/key/OpenPgpV5Fingerprint.kt | 3 + .../org/pgpainless/key/SubkeyIdentifier.kt | 7 ++ .../org/pgpainless/key/_64DigitFingerprint.kt | 3 + .../secretkeyring/SecretKeyRingEditor.kt | 13 +-- .../SecretKeyRingEditorInterface.kt | 36 +++++---- .../protection/BaseSecretKeyRingProtector.kt | 20 ++++- .../CachingSecretKeyRingProtector.kt | 75 +++++++++++------ .../PasswordBasedSecretKeyRingProtector.kt | 21 ++--- .../key/protection/SecretKeyRingProtector.kt | 31 ++++--- .../MapBasedPassphraseProvider.kt | 9 ++- .../SecretKeyPassphraseProvider.kt | 11 ++- .../SolitaryPassphraseProvider.kt | 5 +- .../org/pgpainless/key/util/KeyRingUtils.kt | 5 +- .../consumer/CertificateValidator.kt | 7 +- .../consumer/OnePassSignatureCheck.kt | 2 - ...vestigateMultiSEIPMessageHandlingTest.java | 12 +-- ...artialLengthLiteralDataRegressionTest.java | 2 +- .../org/bouncycastle/AsciiArmorCRCTests.java | 2 +- .../DecryptAndVerifyMessageTest.java | 6 +- .../DecryptHiddenRecipientMessageTest.java | 2 +- .../IgnoreUnknownSignatureVersionsTest.java | 2 +- .../MissingPassphraseForDecryptionTest.java | 10 ++- ...tionUsingKeyWithMissingPassphraseTest.java | 21 ++--- ...ntDecryptionUsingNonEncryptionKeyTest.java | 6 +- ...ificationWithoutCertIsStillSignedTest.java | 2 +- .../VerifyDetachedSignatureTest.java | 4 +- .../VerifyNotBeforeNotAfterTest.java | 20 ++--- .../VerifyVersion3SignaturePacketTest.java | 2 +- ...erifyWithMissingPublicKeyCallbackTest.java | 23 +++--- .../ChangeSecretKeyRingPassphraseTest.java | 4 +- .../CachingSecretKeyRingProtectorTest.java | 16 ++-- .../MapBasedPassphraseProviderTest.java | 11 +-- .../PassphraseProtectedKeyTest.java | 14 ++-- .../SecretKeyRingProtectorTest.java | 14 ++-- .../UnprotectedKeysProtectorTest.java | 5 +- ...ultiPassphraseSymmetricEncryptionTest.java | 2 +- .../SymmetricEncryptionTest.java | 6 +- .../sop/MatchMakingSecretKeyRingProtector.kt | 20 +++-- .../PGPainlessChangeKeyPasswordTest.java | 7 +- 50 files changed, 368 insertions(+), 245 deletions(-) diff --git a/pgpainless-cli/src/test/java/org/pgpainless/cli/commands/RoundTripEncryptDecryptCmdTest.java b/pgpainless-cli/src/test/java/org/pgpainless/cli/commands/RoundTripEncryptDecryptCmdTest.java index 9d3b3b9d..e4fd9e0c 100644 --- a/pgpainless-cli/src/test/java/org/pgpainless/cli/commands/RoundTripEncryptDecryptCmdTest.java +++ b/pgpainless-cli/src/test/java/org/pgpainless/cli/commands/RoundTripEncryptDecryptCmdTest.java @@ -14,7 +14,6 @@ import java.io.IOException; import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.pgpainless.PGPainless; import org.pgpainless.algorithm.KeyFlag; @@ -135,7 +134,7 @@ public class RoundTripEncryptDecryptCmdTest extends CLITest { } @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 { File notACert = writeFile("key.asc", KEY); diff --git a/pgpainless-core/src/main/java/org/gnupg/GnuPGDummyKeyUtil.java b/pgpainless-core/src/main/java/org/gnupg/GnuPGDummyKeyUtil.java index 754ef3fa..48390c59 100644 --- a/pgpainless-core/src/main/java/org/gnupg/GnuPGDummyKeyUtil.java +++ b/pgpainless-core/src/main/java/org/gnupg/GnuPGDummyKeyUtil.java @@ -61,8 +61,7 @@ public final class GnuPGDummyKeyUtil { return hardwareBackedKeys; } - public static Builder modify(@Nonnull OpenPGPKey key) - { + public static Builder modify(@Nonnull OpenPGPKey key) { return modify(key.getPGPSecretKeyRing()); } diff --git a/pgpainless-core/src/main/java/org/pgpainless/exception/WrongPassphraseException.java b/pgpainless-core/src/main/java/org/pgpainless/exception/WrongPassphraseException.java index 409db3e2..d039ca6a 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/exception/WrongPassphraseException.java +++ b/pgpainless-core/src/main/java/org/pgpainless/exception/WrongPassphraseException.java @@ -4,6 +4,7 @@ package org.pgpainless.exception; +import org.bouncycastle.bcpg.KeyIdentifier; import org.bouncycastle.openpgp.PGPException; public class WrongPassphraseException extends PGPException { @@ -13,7 +14,11 @@ public class WrongPassphraseException extends PGPException { } public WrongPassphraseException(long keyId, PGPException cause) { - this("Wrong passphrase provided for key " + Long.toHexString(keyId), cause); + this(new KeyIdentifier(keyId), cause); + } + + public WrongPassphraseException(KeyIdentifier keyIdentifier, PGPException cause) { + this("Wrong passphrase provided for key " + keyIdentifier, cause); } public WrongPassphraseException(String message, PGPException cause) { diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/bouncycastle/extensions/PGPKeyRingExtensions.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/bouncycastle/extensions/PGPKeyRingExtensions.kt index 7126db66..5727ee7c 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/bouncycastle/extensions/PGPKeyRingExtensions.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/bouncycastle/extensions/PGPKeyRingExtensions.kt @@ -9,6 +9,8 @@ import org.bouncycastle.openpgp.PGPKeyRing import org.bouncycastle.openpgp.PGPOnePassSignature import org.bouncycastle.openpgp.PGPPublicKey import org.bouncycastle.openpgp.PGPSignature +import org.bouncycastle.openpgp.api.OpenPGPCertificate +import org.bouncycastle.openpgp.api.OpenPGPImplementation import org.pgpainless.PGPainless import org.pgpainless.key.OpenPgpFingerprint import org.pgpainless.key.SubkeyIdentifier @@ -72,3 +74,10 @@ val PGPKeyRing.openPgpFingerprint: OpenPgpFingerprint /** Return this OpenPGP key as an ASCII armored String. */ fun PGPKeyRing.toAsciiArmor(): String = PGPainless.asciiArmor(this) + +@Deprecated("Use toOpenPGPCertificate(implementation) instead.") +fun PGPKeyRing.toOpenPGPCertificate(): OpenPGPCertificate = + toOpenPGPCertificate(PGPainless.getInstance().implementation) + +fun PGPKeyRing.toOpenPGPCertificate(implementation: OpenPGPImplementation): OpenPGPCertificate = + OpenPGPCertificate(this, implementation) diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/bouncycastle/extensions/PGPSecretKeyRingExtensions.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/bouncycastle/extensions/PGPSecretKeyRingExtensions.kt index 53e7e0c5..90c67236 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/bouncycastle/extensions/PGPSecretKeyRingExtensions.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/bouncycastle/extensions/PGPSecretKeyRingExtensions.kt @@ -6,6 +6,9 @@ package org.pgpainless.bouncycastle.extensions import openpgp.openPgpKeyId import org.bouncycastle.openpgp.* +import org.bouncycastle.openpgp.api.OpenPGPImplementation +import org.bouncycastle.openpgp.api.OpenPGPKey +import org.pgpainless.PGPainless import org.pgpainless.key.OpenPgpFingerprint /** OpenPGP certificate containing the public keys of this OpenPGP key. */ @@ -74,3 +77,10 @@ fun PGPSecretKeyRing.getSecretKeyFor(onePassSignature: PGPOnePassSignature): PGP fun PGPSecretKeyRing.getSecretKeyFor(pkesk: PGPPublicKeyEncryptedData): PGPSecretKey? = this.getSecretKey(pkesk.keyIdentifier) + +@Deprecated("Use toOpenPGPKey(implementation) instead.") +fun PGPSecretKeyRing.toOpenPGPKey(): OpenPGPKey = + toOpenPGPKey(PGPainless.getInstance().implementation) + +fun PGPSecretKeyRing.toOpenPGPKey(implementation: OpenPGPImplementation): OpenPGPKey = + OpenPGPKey(this, implementation) diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/ConsumerOptions.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/ConsumerOptions.kt index de03b9d3..363bc7fa 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/ConsumerOptions.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/ConsumerOptions.kt @@ -4,17 +4,16 @@ package org.pgpainless.decryption_verification -import org.bouncycastle.bcpg.KeyIdentifier import java.io.IOException import java.io.InputStream import java.util.* +import org.bouncycastle.bcpg.KeyIdentifier import org.bouncycastle.openpgp.* import org.bouncycastle.openpgp.api.OpenPGPCertificate import org.bouncycastle.openpgp.api.OpenPGPImplementation import org.bouncycastle.openpgp.api.OpenPGPKey import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory import org.pgpainless.PGPainless -import org.pgpainless.bouncycastle.extensions.getPublicKeyFor import org.pgpainless.decryption_verification.cleartext_signatures.InMemoryMultiPassStrategy import org.pgpainless.decryption_verification.cleartext_signatures.MultiPassStrategy import org.pgpainless.key.SubkeyIdentifier @@ -24,9 +23,7 @@ import org.pgpainless.util.Passphrase import org.pgpainless.util.SessionKey /** Options for decryption and signature verification. */ -class ConsumerOptions( - private val implementation: OpenPGPImplementation -) { +class ConsumerOptions { private var ignoreMDCErrors = false var isDisableAsciiArmorCRC = false @@ -183,7 +180,8 @@ class ConsumerOptions( @JvmOverloads fun addDecryptionKey( key: PGPSecretKeyRing, - protector: SecretKeyRingProtector = SecretKeyRingProtector.unprotectedKeys() + protector: SecretKeyRingProtector = SecretKeyRingProtector.unprotectedKeys(), + implementation: OpenPGPImplementation = PGPainless.getInstance().implementation ) = addDecryptionKey(OpenPGPKey(key, implementation), protector) /** @@ -402,8 +400,10 @@ class ConsumerOptions( * * @param certificate certificate */ - fun addCertificate(certificate: PGPPublicKeyRing, - implementation: OpenPGPImplementation = PGPainless.getInstance().implementation + @JvmOverloads + fun addCertificate( + certificate: PGPPublicKeyRing, + implementation: OpenPGPImplementation = PGPainless.getInstance().implementation ) { explicitCertificates.add(OpenPGPCertificate(certificate, implementation)) } @@ -442,10 +442,6 @@ class ConsumerOptions( } companion object { - @JvmStatic - @JvmOverloads - fun get( - implementation: OpenPGPImplementation = PGPainless.getInstance().implementation - ) = ConsumerOptions(implementation) + @JvmStatic fun get() = ConsumerOptions() } } diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/MessageMetadata.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/MessageMetadata.kt index 44321bb2..79a0ca98 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/MessageMetadata.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/MessageMetadata.kt @@ -4,9 +4,9 @@ package org.pgpainless.decryption_verification -import org.bouncycastle.bcpg.KeyIdentifier import java.util.* import javax.annotation.Nonnull +import org.bouncycastle.bcpg.KeyIdentifier import org.bouncycastle.openpgp.PGPKeyRing import org.bouncycastle.openpgp.PGPLiteralData import org.bouncycastle.openpgp.api.OpenPGPCertificate diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/MissingPublicKeyCallback.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/MissingPublicKeyCallback.kt index eb81847f..9da5eb06 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/MissingPublicKeyCallback.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/MissingPublicKeyCallback.kt @@ -4,7 +4,8 @@ package org.pgpainless.decryption_verification -import org.bouncycastle.openpgp.PGPPublicKeyRing +import org.bouncycastle.bcpg.KeyIdentifier +import org.bouncycastle.openpgp.api.OpenPGPCertificate fun interface MissingPublicKeyCallback { @@ -14,14 +15,14 @@ fun interface MissingPublicKeyCallback { * here. PGPainless will then continue verification with the next signature. * * Note: The key-id might belong to a subkey, so be aware that when looking up the - * [PGPPublicKeyRing], you may not only search for the key-id on the key rings primary key! + * [OpenPGPCertificate], you may not only search for the key-id on the key rings primary key! * * It would be super cool to provide the OpenPgp fingerprint here, but unfortunately * one-pass-signatures only contain the key id. * - * @param keyId ID of the missing signing (sub)key + * @param keyIdentifier ID of the missing signing (sub)key * @return keyring containing the key or null * @see RFC */ - fun onMissingPublicKeyEncountered(keyId: Long): PGPPublicKeyRing? + fun onMissingPublicKeyEncountered(keyIdentifier: KeyIdentifier): OpenPGPCertificate? } diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.kt index b4957a75..d193003f 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.kt @@ -21,12 +21,8 @@ import org.bouncycastle.openpgp.PGPException import org.bouncycastle.openpgp.PGPKeyPair import org.bouncycastle.openpgp.PGPOnePassSignature import org.bouncycastle.openpgp.PGPPBEEncryptedData -import org.bouncycastle.openpgp.PGPPrivateKey import org.bouncycastle.openpgp.PGPPublicKey import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData -import org.bouncycastle.openpgp.PGPPublicKeyRing -import org.bouncycastle.openpgp.PGPSecretKey -import org.bouncycastle.openpgp.PGPSecretKeyRing import org.bouncycastle.openpgp.PGPSignature import org.bouncycastle.openpgp.api.OpenPGPCertificate import org.bouncycastle.openpgp.api.OpenPGPKey @@ -40,11 +36,9 @@ import org.pgpainless.algorithm.CompressionAlgorithm import org.pgpainless.algorithm.OpenPgpPacket import org.pgpainless.algorithm.StreamEncoding import org.pgpainless.algorithm.SymmetricKeyAlgorithm -import org.pgpainless.bouncycastle.extensions.getPublicKeyFor import org.pgpainless.bouncycastle.extensions.getSecretKeyFor import org.pgpainless.bouncycastle.extensions.getSigningKeyFor import org.pgpainless.bouncycastle.extensions.issuerKeyId -import org.pgpainless.bouncycastle.extensions.unlock import org.pgpainless.decryption_verification.MessageMetadata.CompressedData import org.pgpainless.decryption_verification.MessageMetadata.EncryptedData import org.pgpainless.decryption_verification.MessageMetadata.Layer @@ -61,18 +55,16 @@ import org.pgpainless.exception.MissingDecryptionMethodException import org.pgpainless.exception.MissingPassphraseException import org.pgpainless.exception.SignatureValidationException import org.pgpainless.exception.UnacceptableAlgorithmException +import org.pgpainless.exception.WrongPassphraseException import org.pgpainless.implementation.ImplementationFactory import org.pgpainless.key.SubkeyIdentifier -import org.pgpainless.key.util.KeyRingUtils import org.pgpainless.policy.Policy import org.pgpainless.signature.consumer.CertificateValidator import org.pgpainless.signature.consumer.OnePassSignatureCheck -import org.pgpainless.signature.consumer.SignatureCheck import org.pgpainless.signature.consumer.SignatureValidator import org.pgpainless.util.ArmoredInputStreamFactory import org.pgpainless.util.SessionKey import org.slf4j.LoggerFactory -import kotlin.math.sign class OpenPgpMessageInputStream( type: Type, @@ -430,10 +422,11 @@ class OpenPgpMessageInputStream( val privateKey = secretKey.unlock(protector) if (decryptWithPrivateKey( - esks, - privateKey, - SubkeyIdentifier(secretKey.openPGPKey.pgpSecretKeyRing, secretKey.keyIdentifier), - pkesk)) { + esks, + privateKey, + SubkeyIdentifier( + secretKey.openPGPKey.pgpSecretKeyRing, secretKey.keyIdentifier), + pkesk)) { return true } } @@ -441,27 +434,24 @@ class OpenPgpMessageInputStream( // try anonymous secret keys for (pkesk in esks.anonPkesks) { - for (decryptionKeys in findPotentialDecryptionKeys(pkesk)) { - if (hasUnsupportedS2KSpecifier(decryptionKeys)) { + for (decryptionKey in findPotentialDecryptionKeys(pkesk)) { + if (hasUnsupportedS2KSpecifier(decryptionKey)) { continue } - LOGGER.debug("Attempt decryption of anonymous PKESK with key $decryptionKeys.") - val protector = options.getSecretKeyProtector(decryptionKeys.openPGPKey) ?: continue + LOGGER.debug("Attempt decryption of anonymous PKESK with key $decryptionKey.") + val protector = options.getSecretKeyProtector(decryptionKey.openPGPKey) ?: continue - if (!protector.hasPassphraseFor(decryptionKeys.keyIdentifier)) { + if (!protector.hasPassphraseFor(decryptionKey.keyIdentifier)) { LOGGER.debug( - "Missing passphrase for key ${decryptionKeys.keyIdentifier}. Postponing decryption until all other keys were tried.") - postponedDueToMissingPassphrase.add(decryptionKeys to pkesk) + "Missing passphrase for key ${decryptionKey.keyIdentifier}. Postponing decryption until all other keys were tried.") + postponedDueToMissingPassphrase.add(decryptionKey to pkesk) continue } - val privateKey = decryptionKeys.unlock(protector) + val privateKey = decryptionKey.unlock(protector) if (decryptWithPrivateKey( - esks, - privateKey, - SubkeyIdentifier(decryptionKeys.openPGPKey.pgpSecretKeyRing, privateKey.keyIdentifier), - pkesk)) { + esks, privateKey, SubkeyIdentifier(decryptionKey), pkesk)) { return true } } @@ -471,7 +461,7 @@ class OpenPgpMessageInputStream( MissingKeyPassphraseStrategy.THROW_EXCEPTION) { // Non-interactive mode: Throw an exception with all locked decryption keys postponedDueToMissingPassphrase - .map { SubkeyIdentifier(getDecryptionKey(it.first.keyID)!!, it.first.keyID) } + .map { SubkeyIdentifier(it.first) } .also { if (it.isNotEmpty()) throw MissingPassphraseException(it.toSet()) } } else if (options.getMissingKeyPassphraseStrategy() == MissingKeyPassphraseStrategy.INTERACTIVE) { @@ -486,7 +476,12 @@ class OpenPgpMessageInputStream( LOGGER.debug( "Attempt decryption with key $decryptionKeyId while interactively requesting its passphrase.") val protector = options.getSecretKeyProtector(decryptionKeys) ?: continue - val privateKey = secretKey.unlock(protector) + val privateKey = + try { + secretKey.unlock(protector) + } catch (e: PGPException) { + throw WrongPassphraseException(secretKey.keyIdentifier, e) + } if (decryptWithPrivateKey(esks, privateKey, decryptionKeyId, pkesk)) { return true } @@ -507,13 +502,12 @@ class OpenPgpMessageInputStream( pkesk: PGPPublicKeyEncryptedData ): Boolean { val decryptorFactory = - ImplementationFactory.getInstance().getPublicKeyDataDecryptorFactory(privateKey.privateKey) + ImplementationFactory.getInstance() + .getPublicKeyDataDecryptorFactory(privateKey.privateKey) return decryptPKESKAndStream(esks, decryptionKeyId, decryptorFactory, pkesk) } - private fun hasUnsupportedS2KSpecifier( - secretKey: OpenPGPSecretKey - ): Boolean { + private fun hasUnsupportedS2KSpecifier(secretKey: OpenPGPSecretKey): Boolean { val s2k = secretKey.pgpSecretKey.s2K if (s2k != null) { if (s2k.type in 100..110) { @@ -686,7 +680,8 @@ class OpenPgpMessageInputStream( private fun getDecryptionKey(keyId: Long): OpenPGPKey? = options.getDecryptionKeys().firstOrNull { - it.pgpSecretKeyRing.any { k -> k.keyID == keyId } + it.pgpSecretKeyRing + .any { k -> k.keyID == keyId } .and( PGPainless.inspectKeyRing(it).decryptionSubkeys.any { k -> k.keyIdentifier.keyId == keyId @@ -855,7 +850,9 @@ class OpenPgpMessageInputStream( val verification = SignatureVerification( signature, - SubkeyIdentifier(check.verificationKeys.pgpPublicKeyRing, check.onePassSignature.keyIdentifier)) + SubkeyIdentifier( + check.verificationKeys.pgpPublicKeyRing, + check.onePassSignature.keyIdentifier)) try { SignatureValidator.signatureWasCreatedInBounds( @@ -902,13 +899,13 @@ class OpenPgpMessageInputStream( if (options.getMissingCertificateCallback() != null) { return options .getMissingCertificateCallback()!! - .onMissingPublicKeyEncountered(signature.keyID) + .onMissingPublicKeyEncountered(signature.keyIdentifiers.first()) } return null // TODO: Missing cert for sig } private fun findCertificate(signature: PGPOnePassSignature): OpenPGPCertificate? { - val cert = options.getCertificateSource().getCertificate(signature.keyID) + val cert = options.getCertificateSource().getCertificate(signature.keyIdentifier) if (cert != null) { return cert } @@ -916,7 +913,7 @@ class OpenPgpMessageInputStream( if (options.getMissingCertificateCallback() != null) { return options .getMissingCertificateCallback()!! - .onMissingPublicKeyEncountered(signature.keyID) + .onMissingPublicKeyEncountered(signature.keyIdentifier) } return null // TODO: Missing cert for sig } @@ -968,15 +965,13 @@ class OpenPgpMessageInputStream( fun finish(layer: Layer, policy: Policy) { for (detached in detachedSignatures) { val verification = - SignatureVerification(detached.signature, detached.signingKeyIdentifier) + SignatureVerification(detached.signature, SubkeyIdentifier(detached.issuer)) try { SignatureValidator.signatureWasCreatedInBounds( options.getVerifyNotBefore(), options.getVerifyNotAfter()) .verify(detached.signature) CertificateValidator.validateCertificateAndVerifyInitializedSignature( - detached.signature, - KeyRingUtils.publicKeys(detached.signingKeyRing), - policy) + detached.signature, detached.issuerCertificate.pgpPublicKeyRing, policy) LOGGER.debug("Acceptable signature by key ${verification.signingKey}") layer.addVerifiedDetachedSignature(verification) } catch (e: SignatureValidationException) { @@ -988,15 +983,13 @@ class OpenPgpMessageInputStream( for (prepended in prependedSignatures) { val verification = - SignatureVerification(prepended.signature, prepended.keyIdentifier) + SignatureVerification(prepended.signature, SubkeyIdentifier(prepended.issuer)) try { SignatureValidator.signatureWasCreatedInBounds( options.getVerifyNotBefore(), options.getVerifyNotAfter()) .verify(prepended.signature) CertificateValidator.validateCertificateAndVerifyInitializedSignature( - prepended.signature, - KeyRingUtils.publicKeys(prepended.signingKeyRing), - policy) + prepended.signature, prepended.issuerCertificate.pgpPublicKeyRing, policy) LOGGER.debug("Acceptable signature by key ${verification.signingKey}") layer.addVerifiedPrependedSignature(verification) } catch (e: SignatureValidationException) { diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/OpenPgpFingerprint.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/OpenPgpFingerprint.kt index 9a2f1f7b..679df490 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/OpenPgpFingerprint.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/OpenPgpFingerprint.kt @@ -5,6 +5,7 @@ package org.pgpainless.key import java.nio.charset.Charset +import org.bouncycastle.bcpg.KeyIdentifier import org.bouncycastle.openpgp.PGPKeyRing import org.bouncycastle.openpgp.PGPPublicKey import org.bouncycastle.openpgp.PGPSecretKey @@ -55,6 +56,8 @@ abstract class OpenPgpFingerprint : CharSequence, Comparable constructor(keys: PGPKeyRing) : this(keys.publicKey) + abstract val keyIdentifier: KeyIdentifier + /** * Check, whether the fingerprint consists of 40 valid hexadecimal characters. * diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/OpenPgpV4Fingerprint.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/OpenPgpV4Fingerprint.kt index e02f0ae7..4d05c4f9 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/OpenPgpV4Fingerprint.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/OpenPgpV4Fingerprint.kt @@ -8,6 +8,7 @@ import java.net.URI import java.nio.Buffer import java.nio.ByteBuffer import java.nio.charset.Charset +import org.bouncycastle.bcpg.KeyIdentifier import org.bouncycastle.openpgp.PGPKeyRing import org.bouncycastle.openpgp.PGPPublicKey import org.bouncycastle.openpgp.PGPSecretKey @@ -39,6 +40,8 @@ class OpenPgpV4Fingerprint : OpenPgpFingerprint { return buf.getLong() } + override val keyIdentifier: KeyIdentifier = KeyIdentifier(bytes) + override fun isValid(fingerprint: String): Boolean { return fingerprint.matches("^[0-9A-F]{40}$".toRegex()) } diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/OpenPgpV5Fingerprint.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/OpenPgpV5Fingerprint.kt index 7bc36cc9..df62ddef 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/OpenPgpV5Fingerprint.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/OpenPgpV5Fingerprint.kt @@ -4,6 +4,7 @@ package org.pgpainless.key +import org.bouncycastle.bcpg.KeyIdentifier import org.bouncycastle.openpgp.PGPKeyRing import org.bouncycastle.openpgp.PGPPublicKey import org.bouncycastle.openpgp.PGPSecretKey @@ -24,4 +25,6 @@ class OpenPgpV5Fingerprint : _64DigitFingerprint { override fun getVersion(): Int { return 5 } + + override val keyIdentifier: KeyIdentifier = KeyIdentifier(bytes) } diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/SubkeyIdentifier.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/SubkeyIdentifier.kt index 56307873..0ee58cc6 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/SubkeyIdentifier.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/SubkeyIdentifier.kt @@ -7,6 +7,7 @@ package org.pgpainless.key import org.bouncycastle.bcpg.KeyIdentifier import org.bouncycastle.openpgp.PGPKeyRing import org.bouncycastle.openpgp.PGPPublicKey +import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentKey /** * Tuple class used to identify a subkey by fingerprints of the primary key of the subkeys key ring, @@ -25,6 +26,12 @@ class SubkeyIdentifier( constructor(keys: PGPKeyRing, keyId: Long) : this(keys, KeyIdentifier(keyId)) + constructor( + key: OpenPGPComponentKey + ) : this( + OpenPgpFingerprint.of(key.certificate.pgpPublicKeyRing), + OpenPgpFingerprint.of(key.pgpPublicKey)) + constructor( keys: PGPKeyRing, subkeyFingerprint: OpenPgpFingerprint diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/_64DigitFingerprint.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/_64DigitFingerprint.kt index a34dd880..f5447d61 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/_64DigitFingerprint.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/_64DigitFingerprint.kt @@ -7,6 +7,7 @@ package org.pgpainless.key import java.nio.Buffer import java.nio.ByteBuffer import java.nio.charset.Charset +import org.bouncycastle.bcpg.KeyIdentifier import org.bouncycastle.openpgp.PGPKeyRing import org.bouncycastle.openpgp.PGPPublicKey import org.bouncycastle.openpgp.PGPSecretKey @@ -51,6 +52,8 @@ open class _64DigitFingerprint : OpenPgpFingerprint { return -1 // might be v5 or v6 } + override val keyIdentifier: KeyIdentifier = KeyIdentifier(bytes) + override fun isValid(fingerprint: String): Boolean { return fingerprint.matches(("^[0-9A-F]{64}$".toRegex())) } diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.kt index d2d5cae2..2af3724a 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.kt @@ -9,6 +9,7 @@ import java.util.function.Predicate import javax.annotation.Nonnull import kotlin.NoSuchElementException import openpgp.openPgpKeyId +import org.bouncycastle.bcpg.KeyIdentifier import org.bouncycastle.bcpg.sig.KeyExpirationTime import org.bouncycastle.openpgp.* import org.pgpainless.PGPainless @@ -248,7 +249,7 @@ class SecretKeyRingEditor( val version = OpenPGPKeyVersion.from(secretKeyRing.getPublicKey().version) val keyPair = KeyRingBuilder.generateKeyPair(keySpec, OpenPGPKeyVersion.v4, referenceTime) val subkeyProtector = - PasswordBasedSecretKeyRingProtector.forKeyId(keyPair.keyID, subkeyPassphrase) + PasswordBasedSecretKeyRingProtector.forKeyId(keyPair.keyIdentifier, subkeyPassphrase) val keyFlags = KeyFlag.fromBitmask(keySpec.subpackets.keyFlags).toMutableList() return addSubKey( keyPair, @@ -555,15 +556,15 @@ class SecretKeyRingEditor( } override fun changeSubKeyPassphraseFromOldPassphrase( - keyId: Long, + keyIdentifier: KeyIdentifier, oldPassphrase: Passphrase, oldProtectionSettings: KeyRingProtectionSettings ): SecretKeyRingEditorInterface.WithKeyRingEncryptionSettings { return WithKeyRingEncryptionSettingsImpl( this, - keyId, + keyIdentifier, CachingSecretKeyRingProtector( - mapOf(keyId to oldPassphrase), oldProtectionSettings, null)) + mapOf(keyIdentifier to oldPassphrase), oldProtectionSettings, null)) } override fun done(): PGPSecretKeyRing { @@ -745,7 +746,7 @@ class SecretKeyRingEditor( private class WithKeyRingEncryptionSettingsImpl( private val editor: SecretKeyRingEditor, - private val keyId: Long?, + private val keyId: KeyIdentifier?, private val oldProtector: SecretKeyRingProtector ) : SecretKeyRingEditorInterface.WithKeyRingEncryptionSettings { @@ -762,7 +763,7 @@ class SecretKeyRingEditor( private class WithPassphraseImpl( private val editor: SecretKeyRingEditor, - private val keyId: Long?, + private val keyId: KeyIdentifier?, private val oldProtector: SecretKeyRingProtector, private val newProtectionSettings: KeyRingProtectionSettings ) : SecretKeyRingEditorInterface.WithPassphrase { diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditorInterface.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditorInterface.kt index 140ff905..ad8e36ff 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditorInterface.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditorInterface.kt @@ -8,6 +8,7 @@ import java.io.IOException import java.security.InvalidAlgorithmParameterException import java.security.NoSuchAlgorithmException import java.util.* +import org.bouncycastle.bcpg.KeyIdentifier import org.bouncycastle.openpgp.* import org.pgpainless.algorithm.KeyFlag import org.pgpainless.key.OpenPgpFingerprint @@ -592,19 +593,9 @@ interface SecretKeyRingEditorInterface { KeyRingProtectionSettings.secureDefaultSettings() ): WithKeyRingEncryptionSettings - /** - * Change the passphrase of a single subkey in the key ring. - * - * Note: While it is a valid use-case to have different passphrases per subKey, this is one of - * the reasons why OpenPGP sucks in practice. - * - * @param keyId id of the subkey - * @param oldPassphrase old passphrase (empty if the key was unprotected) - * @return next builder step - */ + @Deprecated("Pass KeyIdentifier instead.") fun changeSubKeyPassphraseFromOldPassphrase(keyId: Long, oldPassphrase: Passphrase) = - changeSubKeyPassphraseFromOldPassphrase( - keyId, oldPassphrase, KeyRingProtectionSettings.secureDefaultSettings()) + changeSubKeyPassphraseFromOldPassphrase(KeyIdentifier(keyId), oldPassphrase) /** * Change the passphrase of a single subkey in the key ring. @@ -612,13 +603,30 @@ interface SecretKeyRingEditorInterface { * Note: While it is a valid use-case to have different passphrases per subKey, this is one of * the reasons why OpenPGP sucks in practice. * - * @param keyId id of the subkey + * @param keyIdentifier id of the subkey + * @param oldPassphrase old passphrase (empty if the key was unprotected) + * @return next builder step + */ + fun changeSubKeyPassphraseFromOldPassphrase( + keyIdentifier: KeyIdentifier, + oldPassphrase: Passphrase + ) = + changeSubKeyPassphraseFromOldPassphrase( + keyIdentifier, oldPassphrase, KeyRingProtectionSettings.secureDefaultSettings()) + + /** + * Change the passphrase of a single subkey in the key ring. + * + * Note: While it is a valid use-case to have different passphrases per subKey, this is one of + * the reasons why OpenPGP sucks in practice. + * + * @param keyIdentifier id of the subkey * @param oldPassphrase old passphrase (empty if the key was unprotected) * @param oldProtectionSettings custom settings for the old passphrase * @return next builder step */ fun changeSubKeyPassphraseFromOldPassphrase( - keyId: Long, + keyIdentifier: KeyIdentifier, oldPassphrase: Passphrase, oldProtectionSettings: KeyRingProtectionSettings ): WithKeyRingEncryptionSettings diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/BaseSecretKeyRingProtector.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/BaseSecretKeyRingProtector.kt index c5db2086..35a6ebee 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/BaseSecretKeyRingProtector.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/BaseSecretKeyRingProtector.kt @@ -4,6 +4,8 @@ package org.pgpainless.key.protection +import org.bouncycastle.bcpg.KeyIdentifier +import org.bouncycastle.openpgp.api.OpenPGPKey import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor import org.pgpainless.implementation.ImplementationFactory @@ -22,16 +24,21 @@ open class BaseSecretKeyRingProtector( passphraseProvider: SecretKeyPassphraseProvider ) : this(passphraseProvider, KeyRingProtectionSettings.secureDefaultSettings()) - override fun hasPassphraseFor(keyId: Long): Boolean = passphraseProvider.hasPassphrase(keyId) + override fun hasPassphraseFor(keyIdentifier: KeyIdentifier): Boolean { + return passphraseProvider.hasPassphrase(keyIdentifier) + } override fun getDecryptor(keyId: Long): PBESecretKeyDecryptor? = - passphraseProvider.getPassphraseFor(keyId)?.let { + getDecryptor(KeyIdentifier(keyId)) + + override fun getDecryptor(keyIdentifier: KeyIdentifier): PBESecretKeyDecryptor? = + passphraseProvider.getPassphraseFor(keyIdentifier)?.let { if (it.isEmpty) null else ImplementationFactory.getInstance().getPBESecretKeyDecryptor(it) } - override fun getEncryptor(keyId: Long): PBESecretKeyEncryptor? = - passphraseProvider.getPassphraseFor(keyId)?.let { + override fun getEncryptor(keyIdentifier: KeyIdentifier): PBESecretKeyEncryptor? { + return passphraseProvider.getPassphraseFor(keyIdentifier)?.let { if (it.isEmpty) null else ImplementationFactory.getInstance() @@ -41,4 +48,9 @@ open class BaseSecretKeyRingProtector( protectionSettings.s2kCount, it) } + } + + override fun getKeyPassword(p0: OpenPGPKey.OpenPGPSecretKey): CharArray? { + return passphraseProvider.getPassphraseFor(p0.keyIdentifier)?.getChars() + } } diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/CachingSecretKeyRingProtector.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/CachingSecretKeyRingProtector.kt index 20704685..75ba146c 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/CachingSecretKeyRingProtector.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/CachingSecretKeyRingProtector.kt @@ -4,9 +4,12 @@ package org.pgpainless.key.protection -import openpgp.openPgpKeyId +import org.bouncycastle.bcpg.KeyIdentifier import org.bouncycastle.openpgp.PGPKeyRing import org.bouncycastle.openpgp.PGPPublicKey +import org.bouncycastle.openpgp.api.OpenPGPKey +import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor +import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor import org.pgpainless.key.OpenPgpFingerprint import org.pgpainless.key.protection.passphrase_provider.SecretKeyPassphraseProvider import org.pgpainless.util.Passphrase @@ -21,7 +24,7 @@ import org.pgpainless.util.Passphrase */ class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphraseProvider { - private val cache: MutableMap + private val cache: MutableMap private val protector: SecretKeyRingProtector private val provider: SecretKeyPassphraseProvider? @@ -30,12 +33,12 @@ class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphras constructor( missingPassphraseCallback: SecretKeyPassphraseProvider? ) : this( - mapOf(), + mapOf(), KeyRingProtectionSettings.secureDefaultSettings(), missingPassphraseCallback) constructor( - passphrases: Map, + passphrases: Map, protectionSettings: KeyRingProtectionSettings, missingPassphraseCallback: SecretKeyPassphraseProvider? ) { @@ -44,6 +47,10 @@ class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphras this.provider = missingPassphraseCallback } + @Deprecated("Pass KeyIdentifier instead.") + fun addPassphrase(keyId: Long, passphrase: Passphrase) = + addPassphrase(KeyIdentifier(keyId), passphrase) + /** * Add a passphrase to the cache. If the cache already contains a passphrase for the given * key-id, a [IllegalArgumentException] is thrown. The reason for this is to prevent accidental @@ -53,24 +60,30 @@ class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphras * If you can ensure that there will be no key-id clash, and you want to replace the passphrase, * you can use [replacePassphrase] to replace the passphrase. * - * @param keyId id of the key + * @param keyIdentifier id of the key * @param passphrase passphrase */ - fun addPassphrase(keyId: Long, passphrase: Passphrase) = apply { - require(!cache.containsKey(keyId)) { - "The cache already holds a passphrase for ID ${keyId.openPgpKeyId()}.\n" + + fun addPassphrase(keyIdentifier: KeyIdentifier, passphrase: Passphrase) = apply { + require(!cache.containsKey(keyIdentifier)) { + "The cache already holds a passphrase for ID ${keyIdentifier}.\n" + "If you want to replace this passphrase, use replacePassphrase(Long, Passphrase) instead." } - cache[keyId] = passphrase + cache[keyIdentifier] = passphrase } + @Deprecated("Pass KeyIdentifier instead.") + fun replacePassphrase(keyId: Long, passphrase: Passphrase) = + replacePassphrase(KeyIdentifier(keyId), passphrase) + /** * Replace the passphrase for the given key-id in the cache. * * @param keyId keyId * @param passphrase passphrase */ - fun replacePassphrase(keyId: Long, passphrase: Passphrase) = apply { cache[keyId] = passphrase } + fun replacePassphrase(keyId: KeyIdentifier, passphrase: Passphrase) = apply { + cache[keyId] = passphrase + } /** * Remember the given passphrase for all keys in the given key ring. If for the key-id of any @@ -91,14 +104,14 @@ class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphras fun addPassphrase(keyRing: PGPKeyRing, passphrase: Passphrase) = apply { // check for existing passphrases before doing anything keyRing.publicKeys.forEach { - require(!cache.containsKey(it.keyID)) { - "The cache already holds a passphrase for the key with ID ${it.keyID.openPgpKeyId()}.\n" + + require(!cache.containsKey(it.keyIdentifier)) { + "The cache already holds a passphrase for the key with ID ${it.keyIdentifier}.\n" + "If you want to replace the passphrase, use replacePassphrase(PGPKeyRing, Passphrase) instead." } } // only then instert - keyRing.publicKeys.forEach { cache[it.keyID] = passphrase } + keyRing.publicKeys.forEach { cache[it.keyIdentifier] = passphrase } } /** @@ -108,7 +121,7 @@ class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphras * @param passphrase passphrase */ fun replacePassphrase(keyRing: PGPKeyRing, passphrase: Passphrase) = apply { - keyRing.publicKeys.forEach { cache[it.keyID] = passphrase } + keyRing.publicKeys.forEach { cache[it.keyIdentifier] = passphrase } } /** @@ -118,7 +131,7 @@ class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphras * @param passphrase passphrase */ fun addPassphrase(key: PGPPublicKey, passphrase: Passphrase) = - addPassphrase(key.keyID, passphrase) + addPassphrase(key.keyIdentifier, passphrase) /** * Remember the given passphrase for the key with the given fingerprint. @@ -127,14 +140,17 @@ class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphras * @param passphrase passphrase */ fun addPassphrase(fingerprint: OpenPgpFingerprint, passphrase: Passphrase) = - addPassphrase(fingerprint.keyId, passphrase) + addPassphrase(fingerprint.keyIdentifier, passphrase) + + @Deprecated("Pass KeyIdentifier instead.") + fun forgetPassphrase(keyId: Long) = forgetPassphrase(KeyIdentifier(keyId)) /** * Remove a passphrase from the cache. The passphrase will be cleared and then removed. * * @param keyId id of the key */ - fun forgetPassphrase(keyId: Long) = apply { cache.remove(keyId)?.clear() } + fun forgetPassphrase(keyId: KeyIdentifier) = apply { cache.remove(keyId)?.clear() } /** * Forget the passphrase to all keys in the provided key ring. @@ -150,18 +166,27 @@ class CachingSecretKeyRingProtector : SecretKeyRingProtector, SecretKeyPassphras * * @param key key */ - fun forgetPassphrase(key: PGPPublicKey) = apply { forgetPassphrase(key.keyID) } + fun forgetPassphrase(key: PGPPublicKey) = apply { forgetPassphrase(key.keyIdentifier) } - override fun getPassphraseFor(keyId: Long?): Passphrase? { - return if (hasPassphrase(keyId)) cache[keyId] - else provider?.getPassphraseFor(keyId)?.also { cache[keyId] = it } + override fun getPassphraseFor(keyIdentifier: KeyIdentifier): Passphrase? { + return if (hasPassphrase(keyIdentifier)) cache[keyIdentifier] + else provider?.getPassphraseFor(keyIdentifier)?.also { cache[keyIdentifier] = it } } - override fun hasPassphrase(keyId: Long?) = cache[keyId]?.isValid ?: false + override fun hasPassphraseFor(keyIdentifier: KeyIdentifier): Boolean { + return hasPassphrase(keyIdentifier) + } - override fun hasPassphraseFor(keyId: Long) = hasPassphrase(keyId) + override fun hasPassphrase(keyIdentifier: KeyIdentifier): Boolean { + return cache[keyIdentifier]?.isValid ?: false + } - override fun getDecryptor(keyId: Long) = protector.getDecryptor(keyId) + override fun getDecryptor(keyIdentifier: KeyIdentifier): PBESecretKeyDecryptor? = + protector.getDecryptor(keyIdentifier) - override fun getEncryptor(keyId: Long) = protector.getEncryptor(keyId) + override fun getEncryptor(keyIdentifier: KeyIdentifier): PBESecretKeyEncryptor? = + protector.getEncryptor(keyIdentifier) + + override fun getKeyPassword(p0: OpenPGPKey.OpenPGPSecretKey): CharArray? = + getPassphraseFor(p0.keyIdentifier)?.getChars() } diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/PasswordBasedSecretKeyRingProtector.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/PasswordBasedSecretKeyRingProtector.kt index 9eb47e88..a4f9d2bb 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/PasswordBasedSecretKeyRingProtector.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/PasswordBasedSecretKeyRingProtector.kt @@ -4,6 +4,7 @@ package org.pgpainless.key.protection +import org.bouncycastle.bcpg.KeyIdentifier import org.bouncycastle.openpgp.PGPKeyRing import org.bouncycastle.openpgp.PGPSecretKey import org.pgpainless.key.protection.passphrase_provider.SecretKeyPassphraseProvider @@ -38,12 +39,12 @@ class PasswordBasedSecretKeyRingProtector : BaseSecretKeyRingProtector { ): PasswordBasedSecretKeyRingProtector { return object : SecretKeyPassphraseProvider { - override fun getPassphraseFor(keyId: Long?): Passphrase? { - return if (hasPassphrase(keyId)) passphrase else null + override fun getPassphraseFor(keyIdentifier: KeyIdentifier): Passphrase? { + return if (hasPassphrase(keyIdentifier)) passphrase else null } - override fun hasPassphrase(keyId: Long?): Boolean { - return keyId != null && keyRing.getPublicKey(keyId) != null + override fun hasPassphrase(keyIdentifier: KeyIdentifier): Boolean { + return keyRing.getPublicKey(keyIdentifier) != null } } .let { PasswordBasedSecretKeyRingProtector(it) } @@ -51,20 +52,20 @@ class PasswordBasedSecretKeyRingProtector : BaseSecretKeyRingProtector { @JvmStatic fun forKey(key: PGPSecretKey, passphrase: Passphrase): PasswordBasedSecretKeyRingProtector = - forKeyId(key.publicKey.keyID, passphrase) + forKeyId(key.publicKey.keyIdentifier, passphrase) @JvmStatic fun forKeyId( - singleKeyId: Long, + singleKeyIdentifier: KeyIdentifier, passphrase: Passphrase ): PasswordBasedSecretKeyRingProtector { return object : SecretKeyPassphraseProvider { - override fun getPassphraseFor(keyId: Long?): Passphrase? { - return if (hasPassphrase(keyId)) passphrase else null + override fun getPassphraseFor(keyIdentifier: KeyIdentifier): Passphrase? { + return if (hasPassphrase(keyIdentifier)) passphrase else null } - override fun hasPassphrase(keyId: Long?): Boolean { - return keyId == singleKeyId + override fun hasPassphrase(keyIdentifier: KeyIdentifier): Boolean { + return keyIdentifier.matches(singleKeyIdentifier) } } .let { PasswordBasedSecretKeyRingProtector(it) } diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/SecretKeyRingProtector.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/SecretKeyRingProtector.kt index 373c964c..ccab4c27 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/SecretKeyRingProtector.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/SecretKeyRingProtector.kt @@ -4,6 +4,7 @@ package org.pgpainless.key.protection +import kotlin.Throws import org.bouncycastle.bcpg.KeyIdentifier import org.bouncycastle.openpgp.PGPException import org.bouncycastle.openpgp.PGPSecretKey @@ -14,7 +15,6 @@ import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor import org.pgpainless.key.protection.passphrase_provider.SecretKeyPassphraseProvider import org.pgpainless.key.protection.passphrase_provider.SolitaryPassphraseProvider import org.pgpainless.util.Passphrase -import kotlin.Throws /** * Task of the [SecretKeyRingProtector] is to map encryptor/decryptor objects to key-ids. @@ -43,10 +43,11 @@ interface SecretKeyRingProtector : KeyPassphraseProvider { * @param keyId id of the key * @return decryptor for the key */ - @Throws(PGPException::class) fun getDecryptor(keyId: Long): PBESecretKeyDecryptor? = - getDecryptor(KeyIdentifier(keyId)) + @Throws(PGPException::class) + fun getDecryptor(keyId: Long): PBESecretKeyDecryptor? = getDecryptor(KeyIdentifier(keyId)) - @Throws(PGPException::class) fun getDecryptor(keyIdentifier: KeyIdentifier): PBESecretKeyDecryptor? + @Throws(PGPException::class) + fun getDecryptor(keyIdentifier: KeyIdentifier): PBESecretKeyDecryptor? /** * Return an encryptor for the key of id `keyId`. This method returns null if the key is @@ -55,10 +56,11 @@ interface SecretKeyRingProtector : KeyPassphraseProvider { * @param keyId id of the key * @return encryptor for the key */ - @Throws(PGPException::class) fun getEncryptor(keyId: Long): PBESecretKeyEncryptor? = - getEncryptor(KeyIdentifier(keyId)) + @Throws(PGPException::class) + fun getEncryptor(keyId: Long): PBESecretKeyEncryptor? = getEncryptor(KeyIdentifier(keyId)) - @Throws(PGPException::class) fun getEncryptor(keyIdentifier: KeyIdentifier): PBESecretKeyEncryptor? + @Throws(PGPException::class) + fun getEncryptor(keyIdentifier: KeyIdentifier): PBESecretKeyEncryptor? companion object { @@ -97,7 +99,7 @@ interface SecretKeyRingProtector : KeyPassphraseProvider { passphrase: Passphrase, keys: PGPSecretKeyRing ): SecretKeyRingProtector = - fromPassphraseMap(keys.map { it.keyID }.associateWith { passphrase }) + fromPassphraseMap(keys.map { it.keyIdentifier }.associateWith { passphrase }) /** * Use the provided passphrase to unlock any key. @@ -132,12 +134,15 @@ interface SecretKeyRingProtector : KeyPassphraseProvider { * Otherwise, this protector will always return null. * * @param passphrase passphrase - * @param keyId id of the key to lock/unlock + * @param keyIdentifier id of the key to lock/unlock * @return protector */ @JvmStatic - fun unlockSingleKeyWith(passphrase: Passphrase, keyId: Long): SecretKeyRingProtector = - PasswordBasedSecretKeyRingProtector.forKeyId(keyId, passphrase) + fun unlockSingleKeyWith( + passphrase: Passphrase, + keyIdentifier: KeyIdentifier + ): SecretKeyRingProtector = + PasswordBasedSecretKeyRingProtector.forKeyId(keyIdentifier, passphrase) /** * Protector for unprotected keys. This protector returns null for all @@ -159,7 +164,9 @@ interface SecretKeyRingProtector : KeyPassphraseProvider { * @return protector */ @JvmStatic - fun fromPassphraseMap(passphraseMap: Map): SecretKeyRingProtector = + fun fromPassphraseMap( + passphraseMap: Map + ): SecretKeyRingProtector = CachingSecretKeyRingProtector( passphraseMap, KeyRingProtectionSettings.secureDefaultSettings(), null) } diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/passphrase_provider/MapBasedPassphraseProvider.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/passphrase_provider/MapBasedPassphraseProvider.kt index 3457cff7..2ba0e448 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/passphrase_provider/MapBasedPassphraseProvider.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/passphrase_provider/MapBasedPassphraseProvider.kt @@ -4,6 +4,7 @@ package org.pgpainless.key.protection.passphrase_provider +import org.bouncycastle.bcpg.KeyIdentifier import org.pgpainless.util.Passphrase /** @@ -14,9 +15,11 @@ import org.pgpainless.util.Passphrase * * TODO: Make this null-safe and throw an exception instead? */ -class MapBasedPassphraseProvider(val map: Map) : SecretKeyPassphraseProvider { +class MapBasedPassphraseProvider(val map: Map) : + 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) } diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/passphrase_provider/SecretKeyPassphraseProvider.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/passphrase_provider/SecretKeyPassphraseProvider.kt index a80b8bb0..268538f2 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/passphrase_provider/SecretKeyPassphraseProvider.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/passphrase_provider/SecretKeyPassphraseProvider.kt @@ -4,6 +4,7 @@ package org.pgpainless.key.protection.passphrase_provider +import org.bouncycastle.bcpg.KeyIdentifier import org.bouncycastle.openpgp.PGPSecretKey import org.pgpainless.util.Passphrase @@ -19,7 +20,7 @@ interface SecretKeyPassphraseProvider { * @return passphrase or null, if no passphrase record is found. */ fun getPassphraseFor(secretKey: PGPSecretKey): Passphrase? { - return getPassphraseFor(secretKey.keyID) + return getPassphraseFor(secretKey.keyIdentifier) } /** @@ -30,7 +31,11 @@ interface SecretKeyPassphraseProvider { * @param keyId if of the secret key * @return passphrase or null, if no passphrase record has been found. */ - fun getPassphraseFor(keyId: Long?): Passphrase? + fun getPassphraseFor(keyId: Long): Passphrase? = getPassphraseFor(KeyIdentifier(keyId)) - fun hasPassphrase(keyId: Long?): Boolean + fun getPassphraseFor(keyIdentifier: KeyIdentifier): Passphrase? + + fun hasPassphrase(keyId: Long): Boolean = hasPassphrase(KeyIdentifier(keyId)) + + fun hasPassphrase(keyIdentifier: KeyIdentifier): Boolean } diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/passphrase_provider/SolitaryPassphraseProvider.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/passphrase_provider/SolitaryPassphraseProvider.kt index a9f6801d..b846df2d 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/passphrase_provider/SolitaryPassphraseProvider.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/passphrase_provider/SolitaryPassphraseProvider.kt @@ -4,12 +4,13 @@ package org.pgpainless.key.protection.passphrase_provider +import org.bouncycastle.bcpg.KeyIdentifier import org.pgpainless.util.Passphrase /** Implementation of the [SecretKeyPassphraseProvider] that holds a single [Passphrase]. */ class SolitaryPassphraseProvider(val passphrase: Passphrase?) : SecretKeyPassphraseProvider { - override fun getPassphraseFor(keyId: Long?): Passphrase? = passphrase + override fun getPassphraseFor(keyIdentifier: KeyIdentifier): Passphrase? = passphrase - override fun hasPassphrase(keyId: Long?): Boolean = true + override fun hasPassphrase(keyIdentifier: KeyIdentifier): Boolean = true } diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/util/KeyRingUtils.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/util/KeyRingUtils.kt index f83b5486..02624fd1 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/util/KeyRingUtils.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/util/KeyRingUtils.kt @@ -7,6 +7,7 @@ package org.pgpainless.key.util import java.io.ByteArrayOutputStream import kotlin.jvm.Throws import openpgp.openPgpKeyId +import org.bouncycastle.bcpg.KeyIdentifier import org.bouncycastle.bcpg.S2K import org.bouncycastle.bcpg.SecretKeyPacket import org.bouncycastle.openpgp.* @@ -468,7 +469,7 @@ class KeyRingUtils { @JvmStatic @Throws(MissingPassphraseException::class, PGPException::class) fun changePassphrase( - keyId: Long?, + keyId: KeyIdentifier?, secretKeys: PGPSecretKeyRing, oldProtector: SecretKeyRingProtector, newProtector: SecretKeyRingProtector @@ -484,7 +485,7 @@ class KeyRingUtils { secretKeys.secretKeys .asSequence() .map { - if (it.keyID == keyId) { + if (it.keyIdentifier.matches(keyId)) { reencryptPrivateKey(it, oldProtector, newProtector) } else { it diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/signature/consumer/CertificateValidator.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/signature/consumer/CertificateValidator.kt index 83b7e54e..61bdd282 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/signature/consumer/CertificateValidator.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/signature/consumer/CertificateValidator.kt @@ -13,6 +13,7 @@ import org.bouncycastle.openpgp.PGPSignature import org.pgpainless.PGPainless import org.pgpainless.algorithm.KeyFlag import org.pgpainless.algorithm.SignatureType +import org.pgpainless.bouncycastle.extensions.getPublicKey import org.pgpainless.bouncycastle.extensions.issuerKeyId import org.pgpainless.exception.SignatureValidationException import org.pgpainless.key.util.KeyRingUtils @@ -303,10 +304,12 @@ class CertificateValidator { policy: Policy ): Boolean { return validateCertificate( - onePassSignature.signature!!, onePassSignature.verificationKeys, policy) && + onePassSignature.signature!!, + onePassSignature.verificationKeys.pgpPublicKeyRing, + policy) && SignatureVerifier.verifyOnePassSignature( onePassSignature.signature!!, - onePassSignature.verificationKeys.getPublicKey( + onePassSignature.verificationKeys.pgpKeyRing.getPublicKey( onePassSignature.signature!!.issuerKeyId), onePassSignature, policy) diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/signature/consumer/OnePassSignatureCheck.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/signature/consumer/OnePassSignatureCheck.kt index 59d65cdb..7536776e 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/signature/consumer/OnePassSignatureCheck.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/signature/consumer/OnePassSignatureCheck.kt @@ -8,8 +8,6 @@ import org.bouncycastle.openpgp.PGPOnePassSignature import org.bouncycastle.openpgp.PGPPublicKeyRing import org.bouncycastle.openpgp.PGPSignature import org.bouncycastle.openpgp.api.OpenPGPCertificate -import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentKey -import org.pgpainless.bouncycastle.extensions.getSigningKeyFor import org.pgpainless.key.SubkeyIdentifier /** diff --git a/pgpainless-core/src/test/java/investigations/InvestigateMultiSEIPMessageHandlingTest.java b/pgpainless-core/src/test/java/investigations/InvestigateMultiSEIPMessageHandlingTest.java index f37bf690..28488fac 100644 --- a/pgpainless-core/src/test/java/investigations/InvestigateMultiSEIPMessageHandlingTest.java +++ b/pgpainless-core/src/test/java/investigations/InvestigateMultiSEIPMessageHandlingTest.java @@ -21,6 +21,7 @@ import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSignatureGenerator; +import org.bouncycastle.openpgp.api.OpenPGPKey; import org.bouncycastle.openpgp.operator.PGPDataEncryptorBuilder; import org.bouncycastle.util.io.Streams; import org.junit.jupiter.api.Test; @@ -176,12 +177,13 @@ public class InvestigateMultiSEIPMessageHandlingTest { @Test public void testDecryptAndVerifyDetectsAppendedSEIPData() throws IOException, PGPException { - PGPSecretKeyRing ring1 = PGPainless.readKeyRing().secretKeyRing(KEY1); - PGPSecretKeyRing ring2 = PGPainless.readKeyRing().secretKeyRing(KEY2); + PGPainless api = PGPainless.getInstance(); + OpenPGPKey ring1 = api.readKey().parseKey(KEY1); + OpenPGPKey ring2 = api.readKey().parseKey(KEY2); - ConsumerOptions options = new ConsumerOptions() - .addVerificationCert(PGPainless.extractCertificate(ring1)) - .addVerificationCert(PGPainless.extractCertificate(ring2)) + ConsumerOptions options = ConsumerOptions.get() + .addVerificationCert(ring2) + .addVerificationCert(ring2) .addDecryptionKey(ring1); DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() diff --git a/pgpainless-core/src/test/java/investigations/OnePassSignatureVerificationWithPartialLengthLiteralDataRegressionTest.java b/pgpainless-core/src/test/java/investigations/OnePassSignatureVerificationWithPartialLengthLiteralDataRegressionTest.java index 7ec53edb..3afcce54 100644 --- a/pgpainless-core/src/test/java/investigations/OnePassSignatureVerificationWithPartialLengthLiteralDataRegressionTest.java +++ b/pgpainless-core/src/test/java/investigations/OnePassSignatureVerificationWithPartialLengthLiteralDataRegressionTest.java @@ -124,7 +124,7 @@ public class OnePassSignatureVerificationWithPartialLengthLiteralDataRegressionT DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() .onInputStream(in) - .withOptions(new ConsumerOptions() + .withOptions(ConsumerOptions.get() .addVerificationCert(cert) .addDecryptionKey(secretKeys)); diff --git a/pgpainless-core/src/test/java/org/bouncycastle/AsciiArmorCRCTests.java b/pgpainless-core/src/test/java/org/bouncycastle/AsciiArmorCRCTests.java index eb9e7ef5..031c3e73 100644 --- a/pgpainless-core/src/test/java/org/bouncycastle/AsciiArmorCRCTests.java +++ b/pgpainless-core/src/test/java/org/bouncycastle/AsciiArmorCRCTests.java @@ -544,7 +544,7 @@ public class AsciiArmorCRCTests { assertThrows(IOException.class, () -> { DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() .onInputStream(new ByteArrayInputStream(message.getBytes(StandardCharsets.UTF_8))) - .withOptions(new ConsumerOptions().addDecryptionKey( + .withOptions(ConsumerOptions.get().addDecryptionKey( key, SecretKeyRingProtector.unlockAnyKeyWith(passphrase) )); diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/DecryptAndVerifyMessageTest.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/DecryptAndVerifyMessageTest.java index 82796cb9..22372f2e 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/DecryptAndVerifyMessageTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/DecryptAndVerifyMessageTest.java @@ -52,7 +52,7 @@ public class DecryptAndVerifyMessageTest { public void decryptMessageAndVerifySignatureTest() throws Exception { String encryptedMessage = TestKeys.MSG_SIGN_CRYPT_JULIET_JULIET; - ConsumerOptions options = new ConsumerOptions() + ConsumerOptions options = ConsumerOptions.get() .addDecryptionKey(juliet) .addVerificationCert(KeyRingUtils.publicKeyRingFrom(juliet)); @@ -87,7 +87,7 @@ public class DecryptAndVerifyMessageTest { public void decryptMessageAndReadBeyondEndTest() throws Exception { final String encryptedMessage = TestKeys.MSG_SIGN_CRYPT_JULIET_JULIET; - final ConsumerOptions options = new ConsumerOptions() + final ConsumerOptions options = ConsumerOptions.get() .addDecryptionKey(juliet) .addVerificationCert(KeyRingUtils.publicKeyRingFrom(juliet)); @@ -105,7 +105,7 @@ public class DecryptAndVerifyMessageTest { public void decryptMessageAndVerifySignatureByteByByteTest() throws Exception { String encryptedMessage = TestKeys.MSG_SIGN_CRYPT_JULIET_JULIET; - ConsumerOptions options = new ConsumerOptions() + ConsumerOptions options = ConsumerOptions.get() .addDecryptionKey(juliet) .addVerificationCert(KeyRingUtils.publicKeyRingFrom(juliet)); diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/DecryptHiddenRecipientMessageTest.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/DecryptHiddenRecipientMessageTest.java index fc8cf347..a5f39d0f 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/DecryptHiddenRecipientMessageTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/DecryptHiddenRecipientMessageTest.java @@ -128,7 +128,7 @@ public class DecryptHiddenRecipientMessageTest { "=1knQ\n" + "-----END PGP MESSAGE-----\n"; ByteArrayInputStream messageIn = new ByteArrayInputStream(message.getBytes(StandardCharsets.UTF_8)); - ConsumerOptions options = new ConsumerOptions() + ConsumerOptions options = ConsumerOptions.get() .addDecryptionKey(secretKeys); DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/IgnoreUnknownSignatureVersionsTest.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/IgnoreUnknownSignatureVersionsTest.java index 2b222c83..b5c1bed0 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/IgnoreUnknownSignatureVersionsTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/IgnoreUnknownSignatureVersionsTest.java @@ -177,7 +177,7 @@ public class IgnoreUnknownSignatureVersionsTest { private MessageMetadata verifySignature(PGPPublicKeyRing cert, String BASE_CASE) throws PGPException, IOException { DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify().onInputStream(new ByteArrayInputStream(message.getBytes(StandardCharsets.UTF_8))) - .withOptions(new ConsumerOptions() + .withOptions(ConsumerOptions.get() .addVerificationCert(cert) .addVerificationOfDetachedSignatures(new ByteArrayInputStream(BASE_CASE.getBytes(StandardCharsets.UTF_8)))); diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/MissingPassphraseForDecryptionTest.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/MissingPassphraseForDecryptionTest.java index 979587ac..6ff534b0 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/MissingPassphraseForDecryptionTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/MissingPassphraseForDecryptionTest.java @@ -16,11 +16,13 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.List; +import org.bouncycastle.bcpg.KeyIdentifier; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.api.OpenPGPCertificate; import org.bouncycastle.util.io.Streams; +import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.pgpainless.PGPainless; @@ -62,13 +64,13 @@ public class MissingPassphraseForDecryptionTest { // interactive callback SecretKeyPassphraseProvider callback = new SecretKeyPassphraseProvider() { @Override - public Passphrase getPassphraseFor(Long keyId) { + public Passphrase getPassphraseFor(@NotNull KeyIdentifier keyIdentifier) { // is called in interactive mode return Passphrase.fromPassword(passphrase); } @Override - public boolean hasPassphrase(Long keyId) { + public boolean hasPassphrase(@NotNull KeyIdentifier keyIdentifier) { return true; } }; @@ -95,13 +97,13 @@ public class MissingPassphraseForDecryptionTest { SecretKeyPassphraseProvider callback = new SecretKeyPassphraseProvider() { @Override - public Passphrase getPassphraseFor(Long keyId) { + public Passphrase getPassphraseFor(@NotNull KeyIdentifier keyIdentifier) { fail("MUST NOT get called in non-interactive mode."); return null; } @Override - public boolean hasPassphrase(Long keyId) { + public boolean hasPassphrase(@NotNull KeyIdentifier keyIdentifier) { return true; } }; diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/PostponeDecryptionUsingKeyWithMissingPassphraseTest.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/PostponeDecryptionUsingKeyWithMissingPassphraseTest.java index 8489da9a..1a4137f7 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/PostponeDecryptionUsingKeyWithMissingPassphraseTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/PostponeDecryptionUsingKeyWithMissingPassphraseTest.java @@ -12,6 +12,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; +import org.bouncycastle.bcpg.KeyIdentifier; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPSecretKeyRing; 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.util.Passphrase; +import javax.annotation.Nonnull; + public class PostponeDecryptionUsingKeyWithMissingPassphraseTest { private static PGPSecretKeyRing k1; @@ -120,13 +123,13 @@ public class PostponeDecryptionUsingKeyWithMissingPassphraseTest { public void missingPassphraseFirst() throws PGPException, IOException { SecretKeyRingProtector protector1 = new CachingSecretKeyRingProtector(new SecretKeyPassphraseProvider() { @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."); return null; } @Override - public boolean hasPassphrase(Long keyId) { + public boolean hasPassphrase(@Nonnull KeyIdentifier keyIdentifier) { return false; } }); @@ -134,7 +137,7 @@ public class PostponeDecryptionUsingKeyWithMissingPassphraseTest { DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() .onInputStream(new ByteArrayInputStream(ENCRYPTED_FOR_K1_K2.getBytes(StandardCharsets.UTF_8))) - .withOptions(new ConsumerOptions() + .withOptions(ConsumerOptions.get() .addDecryptionKey(k1, protector1) .addDecryptionKey(k2, protector2)); @@ -150,20 +153,20 @@ public class PostponeDecryptionUsingKeyWithMissingPassphraseTest { SecretKeyRingProtector protector1 = SecretKeyRingProtector.unlockEachKeyWith(p1, k1); SecretKeyRingProtector protector2 = new CachingSecretKeyRingProtector(new SecretKeyPassphraseProvider() { @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."); return null; } @Override - public boolean hasPassphrase(Long keyId) { + public boolean hasPassphrase(@Nonnull KeyIdentifier keyIdentifier) { return false; } }); DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() .onInputStream(new ByteArrayInputStream(ENCRYPTED_FOR_K1_K2.getBytes(StandardCharsets.UTF_8))) - .withOptions(new ConsumerOptions() + .withOptions(ConsumerOptions.get() .addDecryptionKey(k1, protector1) .addDecryptionKey(k2, protector2)); @@ -178,13 +181,13 @@ public class PostponeDecryptionUsingKeyWithMissingPassphraseTest { public void messagePassphraseFirst() throws PGPException, IOException { SecretKeyPassphraseProvider provider = new SecretKeyPassphraseProvider() { @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."); return null; } @Override - public boolean hasPassphrase(Long keyId) { + public boolean hasPassphrase(@Nonnull KeyIdentifier keyIdentifier) { return false; } }; @@ -192,7 +195,7 @@ public class PostponeDecryptionUsingKeyWithMissingPassphraseTest { DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() .onInputStream(new ByteArrayInputStream(ENCRYPTED_FOR_K2_PASS_K1.getBytes(StandardCharsets.UTF_8))) - .withOptions(new ConsumerOptions() + .withOptions(ConsumerOptions.get() .addMessagePassphrase(PASSPHRASE) .addDecryptionKey(k1, protector) .addDecryptionKey(k2, protector)); diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/PreventDecryptionUsingNonEncryptionKeyTest.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/PreventDecryptionUsingNonEncryptionKeyTest.java index f06f0233..ea54f2a4 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/PreventDecryptionUsingNonEncryptionKeyTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/PreventDecryptionUsingNonEncryptionKeyTest.java @@ -180,7 +180,7 @@ public class PreventDecryptionUsingNonEncryptionKeyTest { ByteArrayInputStream msgIn = new ByteArrayInputStream(MSG.getBytes(StandardCharsets.UTF_8)); DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() .onInputStream(msgIn) - .withOptions(new ConsumerOptions().addDecryptionKey(secretKeys)); + .withOptions(ConsumerOptions.get().addDecryptionKey(secretKeys)); Streams.drain(decryptionStream); decryptionStream.close(); @@ -196,7 +196,7 @@ public class PreventDecryptionUsingNonEncryptionKeyTest { ByteArrayInputStream msgIn = new ByteArrayInputStream(MSG.getBytes(StandardCharsets.UTF_8)); DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() .onInputStream(msgIn) - .withOptions(new ConsumerOptions().addDecryptionKey(secretKeys)); + .withOptions(ConsumerOptions.get().addDecryptionKey(secretKeys)); Streams.drain(decryptionStream); decryptionStream.close(); @@ -215,6 +215,6 @@ public class PreventDecryptionUsingNonEncryptionKeyTest { assertThrows(MissingDecryptionMethodException.class, () -> PGPainless.decryptAndOrVerify() .onInputStream(msgIn) - .withOptions(new ConsumerOptions().addDecryptionKey(secretKeys))); + .withOptions(ConsumerOptions.get().addDecryptionKey(secretKeys))); } } diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/SignedMessageVerificationWithoutCertIsStillSignedTest.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/SignedMessageVerificationWithoutCertIsStillSignedTest.java index 9f85b241..dfacbaac 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/SignedMessageVerificationWithoutCertIsStillSignedTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/SignedMessageVerificationWithoutCertIsStillSignedTest.java @@ -30,7 +30,7 @@ public class SignedMessageVerificationWithoutCertIsStillSignedTest { @Test public void verifyMissingVerificationCertOptionStillResultsInMessageIsSigned() throws IOException, PGPException { - ConsumerOptions withoutVerificationCert = new ConsumerOptions(); + ConsumerOptions withoutVerificationCert = ConsumerOptions.get(); DecryptionStream verificationStream = PGPainless.decryptAndOrVerify() .onInputStream(new ByteArrayInputStream(message.getBytes(StandardCharsets.UTF_8))) .withOptions(withoutVerificationCert); diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/VerifyDetachedSignatureTest.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/VerifyDetachedSignatureTest.java index e1406f87..e344d55f 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/VerifyDetachedSignatureTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/VerifyDetachedSignatureTest.java @@ -57,7 +57,7 @@ public class VerifyDetachedSignatureTest { DecryptionStream verifier = PGPainless.decryptAndOrVerify() .onInputStream(new ByteArrayInputStream(signedContent.getBytes(StandardCharsets.UTF_8))) .withOptions( - new ConsumerOptions() + ConsumerOptions.get() .addVerificationOfDetachedSignatures(new ByteArrayInputStream(signature.getBytes(StandardCharsets.UTF_8))) .addVerificationCerts(PGPainless.readKeyRing().keyRingCollection(pubkey, true).getPgpPublicKeyRingCollection()) .setMultiPassStrategy(new InMemoryMultiPassStrategy()) @@ -132,7 +132,7 @@ public class VerifyDetachedSignatureTest { DecryptionStream verifier = PGPainless.decryptAndOrVerify() .onInputStream(new ByteArrayInputStream(signedContent.getBytes(StandardCharsets.UTF_8))) .withOptions( - new ConsumerOptions() + ConsumerOptions.get() .addVerificationOfDetachedSignatures(new ByteArrayInputStream(signature.getBytes(StandardCharsets.UTF_8))) .addVerificationCerts(PGPainless.readKeyRing().keyRingCollection(pubkey, true).getPgpPublicKeyRingCollection()) .setMultiPassStrategy(new InMemoryMultiPassStrategy()) diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/VerifyNotBeforeNotAfterTest.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/VerifyNotBeforeNotAfterTest.java index 069a5f2d..e0608723 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/VerifyNotBeforeNotAfterTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/VerifyNotBeforeNotAfterTest.java @@ -62,7 +62,7 @@ public class VerifyNotBeforeNotAfterTest { @Test public void noConstraintsVerifyInlineSig() throws PGPException, IOException { - ConsumerOptions options = new ConsumerOptions() + ConsumerOptions options = ConsumerOptions.get() .addVerificationCert(certificate); DecryptionStream verifier = PGPainless.decryptAndOrVerify() .onInputStream(new ByteArrayInputStream(inlineSigned)) @@ -74,7 +74,7 @@ public class VerifyNotBeforeNotAfterTest { @Test public void noConstraintsVerifyDetachedSig() throws PGPException, IOException { - ConsumerOptions options = new ConsumerOptions() + ConsumerOptions options = ConsumerOptions.get() .addVerificationCert(certificate) .addVerificationOfDetachedSignatures(new ByteArrayInputStream(detachedSignature)); DecryptionStream verifier = PGPainless.decryptAndOrVerify() @@ -87,7 +87,7 @@ public class VerifyNotBeforeNotAfterTest { @Test public void notBeforeT1DoesNotRejectInlineSigMadeAtT1() throws PGPException, IOException { - ConsumerOptions options = new ConsumerOptions() + ConsumerOptions options = ConsumerOptions.get() .verifyNotBefore(T1) .addVerificationCert(certificate); DecryptionStream verifier = PGPainless.decryptAndOrVerify() @@ -99,7 +99,7 @@ public class VerifyNotBeforeNotAfterTest { @Test public void notBeforeT1DoesNotRejectDetachedSigMadeAtT1() throws PGPException, IOException { - ConsumerOptions options = new ConsumerOptions() + ConsumerOptions options = ConsumerOptions.get() .verifyNotBefore(T1) .addVerificationCert(certificate) .addVerificationOfDetachedSignatures(new ByteArrayInputStream(detachedSignature)); @@ -112,7 +112,7 @@ public class VerifyNotBeforeNotAfterTest { @Test public void verifyNotBeforeT2DoesRejectInlineSignatureMadeAtT1() throws PGPException, IOException { - ConsumerOptions options = new ConsumerOptions() + ConsumerOptions options = ConsumerOptions.get() .verifyNotBefore(T2) .addVerificationCert(certificate); DecryptionStream verifier = PGPainless.decryptAndOrVerify() @@ -124,7 +124,7 @@ public class VerifyNotBeforeNotAfterTest { @Test public void verifyNotBeforeT2DoesRejectDetachedSigMadeAtT1() throws PGPException, IOException { - ConsumerOptions options = new ConsumerOptions() + ConsumerOptions options = ConsumerOptions.get() .verifyNotBefore(T2) .addVerificationCert(certificate) .addVerificationOfDetachedSignatures(new ByteArrayInputStream(detachedSignature)); @@ -137,7 +137,7 @@ public class VerifyNotBeforeNotAfterTest { @Test public void verifyNotAfterT1DoesNotRejectInlineSigMadeAtT1() throws PGPException, IOException { - ConsumerOptions options = new ConsumerOptions() + ConsumerOptions options = ConsumerOptions.get() .verifyNotAfter(T1) .addVerificationCert(certificate); DecryptionStream verifier = PGPainless.decryptAndOrVerify() @@ -149,7 +149,7 @@ public class VerifyNotBeforeNotAfterTest { @Test public void verifyNotAfterT1DoesRejectDetachedSigMadeAtT1() throws PGPException, IOException { - ConsumerOptions options = new ConsumerOptions() + ConsumerOptions options = ConsumerOptions.get() .verifyNotAfter(T1) .addVerificationCert(certificate) .addVerificationOfDetachedSignatures(new ByteArrayInputStream(detachedSignature)); @@ -162,7 +162,7 @@ public class VerifyNotBeforeNotAfterTest { @Test public void verifyNotAfterT0DoesRejectInlineSigMadeAtT1() throws PGPException, IOException { - ConsumerOptions options = new ConsumerOptions() + ConsumerOptions options = ConsumerOptions.get() .verifyNotAfter(T0) .addVerificationCert(certificate); DecryptionStream verifier = PGPainless.decryptAndOrVerify() @@ -174,7 +174,7 @@ public class VerifyNotBeforeNotAfterTest { @Test public void verifyNotAfterT0DoesRejectDetachedSigMadeAtT1() throws PGPException, IOException { - ConsumerOptions options = new ConsumerOptions() + ConsumerOptions options = ConsumerOptions.get() .verifyNotAfter(T0) .addVerificationCert(certificate) .addVerificationOfDetachedSignatures(new ByteArrayInputStream(detachedSignature)); diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/VerifyVersion3SignaturePacketTest.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/VerifyVersion3SignaturePacketTest.java index 6b9d9cab..6de4dc72 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/VerifyVersion3SignaturePacketTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/VerifyVersion3SignaturePacketTest.java @@ -35,7 +35,7 @@ class VerifyVersion3SignaturePacketTest { void verifyDetachedVersion3Signature() throws PGPException, IOException { PGPSignature version3Signature = generateV3Signature(); - ConsumerOptions options = new ConsumerOptions() + ConsumerOptions options = ConsumerOptions.get() .addVerificationCert(TestKeys.getEmilPublicKeyRing()) .addVerificationOfDetachedSignatures(new ByteArrayInputStream(version3Signature.getEncoded())); diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/VerifyWithMissingPublicKeyCallbackTest.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/VerifyWithMissingPublicKeyCallbackTest.java index 4845ddab..3bc2c5f0 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/VerifyWithMissingPublicKeyCallbackTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/VerifyWithMissingPublicKeyCallbackTest.java @@ -13,21 +13,23 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; +import org.bouncycastle.bcpg.KeyIdentifier; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.api.OpenPGPCertificate; +import org.bouncycastle.openpgp.api.OpenPGPKey; import org.bouncycastle.util.io.Streams; import org.junit.jupiter.api.Test; import org.pgpainless.PGPainless; import org.pgpainless.algorithm.DocumentSignatureType; +import org.pgpainless.algorithm.OpenPGPKeyVersion; import org.pgpainless.encryption_signing.EncryptionStream; import org.pgpainless.encryption_signing.ProducerOptions; import org.pgpainless.encryption_signing.SigningOptions; import org.pgpainless.key.TestKeys; -import org.pgpainless.key.info.KeyRingInfo; 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, @@ -38,11 +40,12 @@ public class VerifyWithMissingPublicKeyCallbackTest { @Test public void testMissingPublicKeyCallback() throws PGPException, IOException { - PGPSecretKeyRing signingSecKeys = PGPainless.generateKeyRing().modernKeyRing("alice") - .getPGPSecretKeyRing(); + PGPainless api = PGPainless.getInstance(); + + OpenPGPKey signingSecKeys = api.generateKey(OpenPGPKeyVersion.v4).modernKeyRing("alice"); OpenPGPCertificate.OpenPGPComponentKey signingKey = - new KeyRingInfo(signingSecKeys).getSigningSubkeys().get(0); - PGPPublicKeyRing signingPubKeys = KeyRingUtils.publicKeyRingFrom(signingSecKeys); + signingSecKeys.getSigningKeys().get(0); + OpenPGPCertificate signingPubKeys = signingSecKeys.toCertificate(); PGPPublicKeyRing unrelatedKeys = TestKeys.getJulietPublicKeyRing(); 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) .withOptions(ProducerOptions.sign(new SigningOptions().addInlineSignature( SecretKeyRingProtector.unprotectedKeys(), - signingSecKeys, DocumentSignatureType.CANONICAL_TEXT_DOCUMENT + signingSecKeys.getPGPSecretKeyRing(), DocumentSignatureType.CANONICAL_TEXT_DOCUMENT ))); Streams.pipeAll(new ByteArrayInputStream(msg.getBytes(StandardCharsets.UTF_8)), signingStream); signingStream.close(); @@ -62,8 +65,8 @@ public class VerifyWithMissingPublicKeyCallbackTest { .addVerificationCert(unrelatedKeys) .setMissingCertificateCallback(new MissingPublicKeyCallback() { @Override - public PGPPublicKeyRing onMissingPublicKeyEncountered(long keyId) { - assertEquals(signingKey.getKeyIdentifier().getKeyId(), keyId, "Signing key-ID mismatch."); + public OpenPGPCertificate onMissingPublicKeyEncountered(@Nonnull KeyIdentifier keyIdentifier) { + assertEquals(signingKey.getKeyIdentifier(), keyIdentifier, "Signing key-ID mismatch."); return signingPubKeys; } })); diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/modification/ChangeSecretKeyRingPassphraseTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/modification/ChangeSecretKeyRingPassphraseTest.java index ff41aa81..bfafa0a1 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/key/modification/ChangeSecretKeyRingPassphraseTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/key/modification/ChangeSecretKeyRingPassphraseTest.java @@ -97,7 +97,7 @@ public class ChangeSecretKeyRingPassphraseTest { extractPrivateKey(subKey, Passphrase.fromPassword("weakPassphrase")); PGPSecretKeyRing secretKeys = PGPainless.modifyKeyRing(keyRing) - .changeSubKeyPassphraseFromOldPassphrase(subKey.getPublicKey().getKeyID(), + .changeSubKeyPassphraseFromOldPassphrase(subKey.getPublicKey().getKeyIdentifier(), Passphrase.fromPassword("weakPassphrase")) .withSecureDefaultSettings() .toNewPassphrase(Passphrase.fromPassword("subKeyPassphrase")) @@ -130,7 +130,7 @@ public class ChangeSecretKeyRingPassphraseTest { PGPSecretKey subKey = keys.next(); PGPSecretKeyRing secretKeys = PGPainless.modifyKeyRing(keyRing) - .changeSubKeyPassphraseFromOldPassphrase(subKey.getKeyID(), Passphrase.fromPassword("weakPassphrase")) + .changeSubKeyPassphraseFromOldPassphrase(subKey.getKeyIdentifier(), Passphrase.fromPassword("weakPassphrase")) .withSecureDefaultSettings() .toNoPassphrase() .done(); diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/protection/CachingSecretKeyRingProtectorTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/protection/CachingSecretKeyRingProtectorTest.java index 081d8959..d77466bf 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/key/protection/CachingSecretKeyRingProtectorTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/key/protection/CachingSecretKeyRingProtectorTest.java @@ -13,11 +13,13 @@ import java.io.IOException; import java.util.Iterator; import java.util.Random; +import org.bouncycastle.bcpg.KeyIdentifier; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPKeyRing; import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKeyRing; +import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.pgpainless.PGPainless; @@ -30,13 +32,13 @@ public class CachingSecretKeyRingProtectorTest { // Dummy passphrase callback that returns the doubled key-id as passphrase private final SecretKeyPassphraseProvider dummyCallback = new SecretKeyPassphraseProvider() { @Override - public Passphrase getPassphraseFor(Long keyId) { - long doubled = keyId * 2; + public Passphrase getPassphraseFor(@NotNull KeyIdentifier keyIdentifier) { + long doubled = keyIdentifier.getKeyId() * 2; return Passphrase.fromPassword(Long.toString(doubled)); } @Override - public boolean hasPassphrase(Long keyId) { + public boolean hasPassphrase(@NotNull KeyIdentifier keyIdentifier) { return true; } }; @@ -49,15 +51,15 @@ public class CachingSecretKeyRingProtectorTest { } @Test - public void noCallbackReturnsNullForUnknownKeyId() { + public void noCallbackReturnsNullForUnknownKeyId() throws PGPException { assertNull(protector.getDecryptor(123L)); assertNull(protector.getEncryptor(123L)); } @Test - public void testAddPassphrase() { + public void testAddPassphrase() throws PGPException { Passphrase passphrase = Passphrase.fromPassword("HelloWorld"); - protector.addPassphrase(123L, passphrase); + protector.addPassphrase(new KeyIdentifier(123L), passphrase); assertEquals(passphrase, protector.getPassphraseFor(123L)); assertNotNull(protector.getEncryptor(123L)); assertNotNull(protector.getDecryptor(123L)); @@ -75,7 +77,7 @@ public class CachingSecretKeyRingProtectorTest { } @Test - public void testAddPassphraseForKeyRing() { + public void testAddPassphraseForKeyRing() throws PGPException { PGPSecretKeyRing keys = PGPainless.generateKeyRing() .modernKeyRing("test@test.test", "Passphrase123") .getPGPSecretKeyRing(); diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/protection/MapBasedPassphraseProviderTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/protection/MapBasedPassphraseProviderTest.java index 3961a2be..9dd6ba33 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/key/protection/MapBasedPassphraseProviderTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/key/protection/MapBasedPassphraseProviderTest.java @@ -11,6 +11,7 @@ import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import org.bouncycastle.bcpg.KeyIdentifier; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.junit.jupiter.api.Test; @@ -22,10 +23,10 @@ public class MapBasedPassphraseProviderTest { @Test public void testMapBasedProvider() throws IOException, PGPException { - Map passphraseMap = new ConcurrentHashMap<>(); - passphraseMap.put(1L, Passphrase.fromPassword("tiger")); - passphraseMap.put(123123123L, Passphrase.fromPassword("snake")); - passphraseMap.put(69696969L, Passphrase.emptyPassphrase()); + Map passphraseMap = new ConcurrentHashMap<>(); + passphraseMap.put(new KeyIdentifier(1L), Passphrase.fromPassword("tiger")); + passphraseMap.put(new KeyIdentifier(123123123L), Passphrase.fromPassword("snake")); + passphraseMap.put(new KeyIdentifier(69696969L), Passphrase.emptyPassphrase()); MapBasedPassphraseProvider provider = new MapBasedPassphraseProvider(passphraseMap); assertEquals(Passphrase.fromPassword("tiger"), provider.getPassphraseFor(1L)); @@ -35,7 +36,7 @@ public class MapBasedPassphraseProviderTest { PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing(); passphraseMap = new ConcurrentHashMap<>(); - passphraseMap.put(secretKeys.getSecretKey().getKeyID(), TestKeys.CRYPTIE_PASSPHRASE); + passphraseMap.put(secretKeys.getSecretKey().getKeyIdentifier(), TestKeys.CRYPTIE_PASSPHRASE); provider = new MapBasedPassphraseProvider(passphraseMap); assertEquals(TestKeys.CRYPTIE_PASSPHRASE, provider.getPassphraseFor(secretKeys.getSecretKey())); diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/protection/PassphraseProtectedKeyTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/protection/PassphraseProtectedKeyTest.java index 6139ec0a..495d569e 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/key/protection/PassphraseProtectedKeyTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/key/protection/PassphraseProtectedKeyTest.java @@ -10,9 +10,11 @@ import static org.junit.jupiter.api.Assertions.assertNull; import java.util.Iterator; import javax.annotation.Nullable; +import org.bouncycastle.bcpg.KeyIdentifier; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPSecretKeyRing; +import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Test; import org.pgpainless.PGPainless; import org.pgpainless.key.TestKeys; @@ -29,8 +31,8 @@ public class PassphraseProtectedKeyTest { new SecretKeyPassphraseProvider() { @Nullable @Override - public Passphrase getPassphraseFor(Long keyId) { - if (keyId == TestKeys.CRYPTIE_KEY_ID) { + public Passphrase getPassphraseFor(@NotNull KeyIdentifier keyIdentifier) { + if (keyIdentifier.getKeyId() == TestKeys.CRYPTIE_KEY_ID) { return new Passphrase(TestKeys.CRYPTIE_PASSWORD.toCharArray()); } else { return null; @@ -38,19 +40,19 @@ public class PassphraseProtectedKeyTest { } @Override - public boolean hasPassphrase(Long keyId) { - return keyId == TestKeys.CRYPTIE_KEY_ID; + public boolean hasPassphrase(@NotNull KeyIdentifier keyIdentifier) { + return keyIdentifier.getKeyId() == TestKeys.CRYPTIE_KEY_ID; } }); @Test - public void testReturnsNonNullDecryptorEncryptorForPassword() { + public void testReturnsNonNullDecryptorEncryptorForPassword() throws PGPException { assertNotNull(protector.getEncryptor(TestKeys.CRYPTIE_KEY_ID)); assertNotNull(protector.getDecryptor(TestKeys.CRYPTIE_KEY_ID)); } @Test - public void testReturnsNullDecryptorEncryptorForNoPassword() { + public void testReturnsNullDecryptorEncryptorForNoPassword() throws PGPException { assertNull(protector.getEncryptor(TestKeys.JULIET_KEY_ID)); assertNull(protector.getDecryptor(TestKeys.JULIET_KEY_ID)); } diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/protection/SecretKeyRingProtectorTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/protection/SecretKeyRingProtectorTest.java index 92ae553d..73258713 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/key/protection/SecretKeyRingProtectorTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/key/protection/SecretKeyRingProtectorTest.java @@ -15,10 +15,12 @@ import java.util.Map; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; +import org.bouncycastle.bcpg.KeyIdentifier; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; +import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.extension.ExtendWith; @@ -85,8 +87,8 @@ public class SecretKeyRingProtectorTest { @Test public void testFromPassphraseMap() { - Map passphraseMap = new ConcurrentHashMap<>(); - passphraseMap.put(1L, Passphrase.emptyPassphrase()); + Map passphraseMap = new ConcurrentHashMap<>(); + passphraseMap.put(new KeyIdentifier(1L), Passphrase.emptyPassphrase()); CachingSecretKeyRingProtector protector = (CachingSecretKeyRingProtector) SecretKeyRingProtector.fromPassphraseMap(passphraseMap); @@ -102,17 +104,17 @@ public class SecretKeyRingProtectorTest { @Test public void testMissingPassphraseCallback() { - Map passphraseMap = new ConcurrentHashMap<>(); - passphraseMap.put(1L, Passphrase.emptyPassphrase()); + Map passphraseMap = new ConcurrentHashMap<>(); + passphraseMap.put(new KeyIdentifier(1L), Passphrase.emptyPassphrase()); CachingSecretKeyRingProtector protector = new CachingSecretKeyRingProtector(passphraseMap, KeyRingProtectionSettings.secureDefaultSettings(), new SecretKeyPassphraseProvider() { @Override - public Passphrase getPassphraseFor(Long keyId) { + public Passphrase getPassphraseFor(@NotNull KeyIdentifier keyIdentifier) { return Passphrase.fromPassword("missingP455w0rd"); } @Override - public boolean hasPassphrase(Long keyId) { + public boolean hasPassphrase(@NotNull KeyIdentifier keyIdentifier) { return true; } }); diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/protection/UnprotectedKeysProtectorTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/protection/UnprotectedKeysProtectorTest.java index 07f65a59..4f590c8b 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/key/protection/UnprotectedKeysProtectorTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/key/protection/UnprotectedKeysProtectorTest.java @@ -6,6 +6,7 @@ package org.pgpainless.key.protection; import static org.junit.jupiter.api.Assertions.assertNull; +import org.bouncycastle.openpgp.PGPException; import org.junit.jupiter.api.Test; public class UnprotectedKeysProtectorTest { @@ -13,12 +14,12 @@ public class UnprotectedKeysProtectorTest { private final UnprotectedKeysProtector protector = new UnprotectedKeysProtector(); @Test - public void testKeyProtectorReturnsNullDecryptor() { + public void testKeyProtectorReturnsNullDecryptor() throws PGPException { assertNull(protector.getDecryptor(0L)); } @Test - public void testKeyProtectorReturnsNullEncryptor() { + public void testKeyProtectorReturnsNullEncryptor() throws PGPException { assertNull(protector.getEncryptor(0L)); } } diff --git a/pgpainless-core/src/test/java/org/pgpainless/symmetric_encryption/MultiPassphraseSymmetricEncryptionTest.java b/pgpainless-core/src/test/java/org/pgpainless/symmetric_encryption/MultiPassphraseSymmetricEncryptionTest.java index d0d37117..029f59ac 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/symmetric_encryption/MultiPassphraseSymmetricEncryptionTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/symmetric_encryption/MultiPassphraseSymmetricEncryptionTest.java @@ -48,7 +48,7 @@ public class MultiPassphraseSymmetricEncryptionTest { for (Passphrase passphrase : new Passphrase[] {Passphrase.fromPassword("p2"), Passphrase.fromPassword("p1")}) { DecryptionStream decryptor = PGPainless.decryptAndOrVerify() .onInputStream(new ByteArrayInputStream(ciphertext)) - .withOptions(new ConsumerOptions() + .withOptions(ConsumerOptions.get() .addMessagePassphrase(passphrase)); ByteArrayOutputStream plaintextOut = new ByteArrayOutputStream(); diff --git a/pgpainless-core/src/test/java/org/pgpainless/symmetric_encryption/SymmetricEncryptionTest.java b/pgpainless-core/src/test/java/org/pgpainless/symmetric_encryption/SymmetricEncryptionTest.java index dbf7ca24..3fa54bf6 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/symmetric_encryption/SymmetricEncryptionTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/symmetric_encryption/SymmetricEncryptionTest.java @@ -65,7 +65,7 @@ public class SymmetricEncryptionTest { // Test symmetric decryption DecryptionStream decryptor = PGPainless.decryptAndOrVerify() .onInputStream(new ByteArrayInputStream(ciphertext)) - .withOptions(new ConsumerOptions() + .withOptions(ConsumerOptions.get() .addMessagePassphrase(encryptionPassphrase)); ByteArrayOutputStream decrypted = new ByteArrayOutputStream(); @@ -82,7 +82,7 @@ public class SymmetricEncryptionTest { new SolitaryPassphraseProvider(Passphrase.fromPassword(TestKeys.CRYPTIE_PASSWORD))); decryptor = PGPainless.decryptAndOrVerify() .onInputStream(new ByteArrayInputStream(ciphertext)) - .withOptions(new ConsumerOptions() + .withOptions(ConsumerOptions.get() .addDecryptionKeys(decryptionKeys, protector)); decrypted = new ByteArrayOutputStream(); @@ -110,7 +110,7 @@ public class SymmetricEncryptionTest { assertThrows(MissingDecryptionMethodException.class, () -> PGPainless.decryptAndOrVerify() .onInputStream(new ByteArrayInputStream(ciphertextOut.toByteArray())) - .withOptions(new ConsumerOptions() + .withOptions(ConsumerOptions.get() .setMissingKeyPassphraseStrategy(MissingKeyPassphraseStrategy.THROW_EXCEPTION) .addMessagePassphrase(Passphrase.fromPassword("meldir")))); } diff --git a/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/MatchMakingSecretKeyRingProtector.kt b/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/MatchMakingSecretKeyRingProtector.kt index 13347721..74e79511 100644 --- a/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/MatchMakingSecretKeyRingProtector.kt +++ b/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/MatchMakingSecretKeyRingProtector.kt @@ -4,9 +4,11 @@ package org.pgpainless.sop +import org.bouncycastle.bcpg.KeyIdentifier import org.bouncycastle.openpgp.PGPException import org.bouncycastle.openpgp.PGPSecretKey import org.bouncycastle.openpgp.PGPSecretKeyRing +import org.bouncycastle.openpgp.api.OpenPGPKey import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor import org.pgpainless.bouncycastle.extensions.isDecrypted @@ -41,7 +43,7 @@ class MatchMakingSecretKeyRingProtector : SecretKeyRingProtector { } if (testPassphrase(passphrase, subkey)) { - protector.addPassphrase(subkey.keyID, passphrase) + protector.addPassphrase(subkey.keyIdentifier, passphrase) } } } @@ -54,11 +56,11 @@ class MatchMakingSecretKeyRingProtector : SecretKeyRingProtector { key.forEach { subkey -> if (subkey.isDecrypted()) { - protector.addPassphrase(subkey.keyID, Passphrase.emptyPassphrase()) + protector.addPassphrase(subkey.keyIdentifier, Passphrase.emptyPassphrase()) } else { passphrases.forEach { passphrase -> if (testPassphrase(passphrase, subkey)) { - protector.addPassphrase(subkey.keyID, passphrase) + protector.addPassphrase(subkey.keyIdentifier, passphrase) } } } @@ -74,11 +76,17 @@ class MatchMakingSecretKeyRingProtector : SecretKeyRingProtector { 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. */ fun clear() { diff --git a/pgpainless-sop/src/test/java/sop/testsuite/pgpainless/operation/PGPainlessChangeKeyPasswordTest.java b/pgpainless-sop/src/test/java/sop/testsuite/pgpainless/operation/PGPainlessChangeKeyPasswordTest.java index cc6dd4dd..cb45551d 100644 --- a/pgpainless-sop/src/test/java/sop/testsuite/pgpainless/operation/PGPainlessChangeKeyPasswordTest.java +++ b/pgpainless-sop/src/test/java/sop/testsuite/pgpainless/operation/PGPainlessChangeKeyPasswordTest.java @@ -4,6 +4,7 @@ package sop.testsuite.pgpainless.operation; +import org.bouncycastle.bcpg.KeyIdentifier; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPSecretKeyRing; @@ -38,9 +39,9 @@ public class PGPainlessChangeKeyPasswordTest extends ChangeKeyPasswordTest { .build() .getPGPSecretKeyRing(); Iterator keys = secretKeys.getPublicKeys(); - long primaryKeyId = keys.next().getKeyID(); - long signingKeyId = keys.next().getKeyID(); - long encryptKeyId = keys.next().getKeyID(); + KeyIdentifier primaryKeyId = keys.next().getKeyIdentifier(); + KeyIdentifier signingKeyId = keys.next().getKeyIdentifier(); + KeyIdentifier encryptKeyId = keys.next().getKeyIdentifier(); String p1 = "sw0rdf1sh"; String p2 = "0r4ng3";