1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2025-04-22 06:24:47 +02:00

Even more migration and code compiles again

This commit is contained in:
Paul Schaub 2025-02-11 16:17:48 +01:00
parent c039ab543a
commit 070879ee02
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
50 changed files with 368 additions and 245 deletions
pgpainless-cli/src/test/java/org/pgpainless/cli/commands
pgpainless-core/src
main
test/java
pgpainless-sop/src
main/kotlin/org/pgpainless/sop
test/java/sop/testsuite/pgpainless/operation

View file

@ -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);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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()

View file

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

View file

@ -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)
));

View file

@ -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));

View file

@ -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()

View file

@ -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))));

View file

@ -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;
}
};

View file

@ -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));

View file

@ -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)));
}
}

View file

@ -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);

View file

@ -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())

View file

@ -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));

View file

@ -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()));

View file

@ -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;
}
}));

View file

@ -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();

View file

@ -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();

View file

@ -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<Long, Passphrase> passphraseMap = new ConcurrentHashMap<>();
passphraseMap.put(1L, Passphrase.fromPassword("tiger"));
passphraseMap.put(123123123L, Passphrase.fromPassword("snake"));
passphraseMap.put(69696969L, Passphrase.emptyPassphrase());
Map<KeyIdentifier, Passphrase> 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()));

View file

@ -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));
}

View file

@ -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<Long, Passphrase> passphraseMap = new ConcurrentHashMap<>();
passphraseMap.put(1L, Passphrase.emptyPassphrase());
Map<KeyIdentifier, Passphrase> 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<Long, Passphrase> passphraseMap = new ConcurrentHashMap<>();
passphraseMap.put(1L, Passphrase.emptyPassphrase());
Map<KeyIdentifier, Passphrase> 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;
}
});

View file

@ -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));
}
}

View file

@ -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();

View file

@ -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"))));
}

View file

@ -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() {

View file

@ -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<PGPPublicKey> 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";