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:
parent
c039ab543a
commit
070879ee02
50 changed files with 368 additions and 245 deletions
pgpainless-cli/src/test/java/org/pgpainless/cli/commands
pgpainless-core/src
main
java/org
kotlin/org/pgpainless
bouncycastle/extensions
decryption_verification
key
OpenPgpFingerprint.ktOpenPgpV4Fingerprint.ktOpenPgpV5Fingerprint.ktSubkeyIdentifier.kt_64DigitFingerprint.kt
modification/secretkeyring
protection
BaseSecretKeyRingProtector.ktCachingSecretKeyRingProtector.ktPasswordBasedSecretKeyRingProtector.ktSecretKeyRingProtector.kt
passphrase_provider
util
signature/consumer
test/java
investigations
InvestigateMultiSEIPMessageHandlingTest.javaOnePassSignatureVerificationWithPartialLengthLiteralDataRegressionTest.java
org
bouncycastle
pgpainless
decryption_verification
DecryptAndVerifyMessageTest.javaDecryptHiddenRecipientMessageTest.javaIgnoreUnknownSignatureVersionsTest.javaMissingPassphraseForDecryptionTest.javaPostponeDecryptionUsingKeyWithMissingPassphraseTest.javaPreventDecryptionUsingNonEncryptionKeyTest.javaSignedMessageVerificationWithoutCertIsStillSignedTest.javaVerifyDetachedSignatureTest.javaVerifyNotBeforeNotAfterTest.javaVerifyVersion3SignaturePacketTest.javaVerifyWithMissingPublicKeyCallbackTest.java
key
modification
protection
symmetric_encryption
pgpainless-sop/src
main/kotlin/org/pgpainless/sop
test/java/sop/testsuite/pgpainless/operation
|
@ -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);
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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?
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()))
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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) }
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
/**
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -124,7 +124,7 @@ public class OnePassSignatureVerificationWithPartialLengthLiteralDataRegressionT
|
|||
|
||||
DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify()
|
||||
.onInputStream(in)
|
||||
.withOptions(new ConsumerOptions()
|
||||
.withOptions(ConsumerOptions.get()
|
||||
.addVerificationCert(cert)
|
||||
.addDecryptionKey(secretKeys));
|
||||
|
||||
|
|
|
@ -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)
|
||||
));
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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))));
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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()));
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}));
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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"))));
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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";
|
||||
|
|
Loading…
Add table
Reference in a new issue