diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/protection/UnlockSecretKey.java b/pgpainless-core/src/main/java/org/pgpainless/key/protection/UnlockSecretKey.java deleted file mode 100644 index 154a1aa1..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/protection/UnlockSecretKey.java +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2021 Paul Schaub. -// SPDX-FileCopyrightText: 2021 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package org.pgpainless.key.protection; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPrivateKey; -import org.bouncycastle.openpgp.PGPSecretKey; -import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.pgpainless.PGPainless; -import org.pgpainless.exception.KeyIntegrityException; -import org.pgpainless.exception.WrongPassphraseException; -import org.pgpainless.key.info.KeyInfo; -import org.pgpainless.key.util.PublicKeyParameterValidationUtil; -import org.pgpainless.util.Passphrase; - -public final class UnlockSecretKey { - - private UnlockSecretKey() { - - } - - public static PGPPrivateKey unlockSecretKey(PGPSecretKey secretKey, SecretKeyRingProtector protector) - throws PGPException, KeyIntegrityException { - - PBESecretKeyDecryptor decryptor = null; - if (KeyInfo.isEncrypted(secretKey)) { - decryptor = protector.getDecryptor(secretKey.getKeyID()); - } - PGPPrivateKey privateKey = unlockSecretKey(secretKey, decryptor); - return privateKey; - } - - public static PGPPrivateKey unlockSecretKey(PGPSecretKey secretKey, PBESecretKeyDecryptor decryptor) - throws PGPException { - PGPPrivateKey privateKey; - try { - privateKey = secretKey.extractPrivateKey(decryptor); - } catch (PGPException e) { - throw new WrongPassphraseException(secretKey.getKeyID(), e); - } - - if (privateKey == null) { - int s2kType = secretKey.getS2K().getType(); - if (s2kType >= 100 && s2kType <= 110) { - throw new PGPException("Cannot decrypt secret key" + Long.toHexString(secretKey.getKeyID()) + ": " + - "Unsupported private S2K usage type " + s2kType); - } - - throw new PGPException("Cannot decrypt secret key."); - } - - if (PGPainless.getPolicy().isEnableKeyParameterValidation()) { - PublicKeyParameterValidationUtil.verifyPublicKeyParameterIntegrity(privateKey, secretKey.getPublicKey()); - } - - return privateKey; - } - - public static PGPPrivateKey unlockSecretKey(PGPSecretKey secretKey, Passphrase passphrase) - throws PGPException, KeyIntegrityException { - return unlockSecretKey(secretKey, SecretKeyRingProtector.unlockSingleKeyWith( - passphrase == null ? Passphrase.emptyPassphrase() : passphrase, secretKey)); - } -} diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.kt index a255e90e..1f34ec23 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.kt @@ -350,7 +350,7 @@ class OpenPgpMessageInputStream( } LOGGER.debug("Attempt decryption with key $decryptionKeyId while interactively requesting its passphrase.") - val protector = options.getSecretKeyProtector(decryptionKeys) + val protector = options.getSecretKeyProtector(decryptionKeys) ?: continue val privateKey = UnlockSecretKey.unlockSecretKey(secretKey, protector) if (decryptWithPrivateKey(esks, privateKey, decryptionKeyId, pkesk)) { return true diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/UnlockSecretKey.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/UnlockSecretKey.kt new file mode 100644 index 00000000..533b33a7 --- /dev/null +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/protection/UnlockSecretKey.kt @@ -0,0 +1,68 @@ +// Copyright 2023 Paul Schaub. +// SPDX-FileCopyrightText: 2021 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.key.protection + +import org.bouncycastle.openpgp.PGPException +import org.bouncycastle.openpgp.PGPPrivateKey +import org.bouncycastle.openpgp.PGPSecretKey +import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor +import org.pgpainless.PGPainless +import org.pgpainless.exception.KeyIntegrityException +import org.pgpainless.exception.WrongPassphraseException +import org.pgpainless.key.info.KeyInfo +import org.pgpainless.key.util.KeyIdUtil +import org.pgpainless.key.util.PublicKeyParameterValidationUtil +import org.pgpainless.util.Passphrase +import kotlin.jvm.Throws + +class UnlockSecretKey { + + companion object { + + @JvmStatic + @Throws(PGPException::class, KeyIntegrityException::class) + fun unlockSecretKey(secretKey: PGPSecretKey, protector: SecretKeyRingProtector): PGPPrivateKey { + return if (KeyInfo.isEncrypted(secretKey)) { + unlockSecretKey(secretKey, protector.getDecryptor(secretKey.keyID)) + } else { + unlockSecretKey(secretKey, null as PBESecretKeyDecryptor?) + } + } + + @JvmStatic + @Throws(PGPException::class) + fun unlockSecretKey(secretKey: PGPSecretKey, decryptor: PBESecretKeyDecryptor?): PGPPrivateKey { + val privateKey = try { + secretKey.extractPrivateKey(decryptor) + } catch (e : PGPException) { + throw WrongPassphraseException(secretKey.keyID, e) + } + + if (privateKey == null) { + if (secretKey.s2K.type in 100..110) { + throw PGPException("Cannot decrypt secret key ${KeyIdUtil.formatKeyId(secretKey.keyID)}: \n" + + "Unsupported private S2K type ${secretKey.s2K.type}") + } + throw PGPException("Cannot decrypt secret key.") + } + + if (PGPainless.getPolicy().isEnableKeyParameterValidation()) { + PublicKeyParameterValidationUtil.verifyPublicKeyParameterIntegrity(privateKey, secretKey.publicKey) + } + + return privateKey + } + + @JvmStatic + fun unlockSecretKey(secretKey: PGPSecretKey, passphrase: Passphrase?): PGPPrivateKey { + return if (passphrase == null) { + unlockSecretKey(secretKey, SecretKeyRingProtector.unprotectedKeys()) + } else { + unlockSecretKey(secretKey, SecretKeyRingProtector.unlockSingleKeyWith(passphrase, secretKey)) + } + } + } +} \ No newline at end of file