001// Copyright 2021 Paul Schaub.
002// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
003//
004// SPDX-License-Identifier: Apache-2.0
005
006package org.pgpainless.key.protection;
007
008import org.bouncycastle.openpgp.PGPException;
009import org.bouncycastle.openpgp.PGPPrivateKey;
010import org.bouncycastle.openpgp.PGPSecretKey;
011import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
012import org.pgpainless.exception.KeyIntegrityException;
013import org.pgpainless.exception.WrongPassphraseException;
014import org.pgpainless.key.info.KeyInfo;
015import org.pgpainless.key.util.PublicKeyParameterValidationUtil;
016import org.pgpainless.util.Passphrase;
017
018public final class UnlockSecretKey {
019
020    private UnlockSecretKey() {
021
022    }
023
024    public static PGPPrivateKey unlockSecretKey(PGPSecretKey secretKey, SecretKeyRingProtector protector)
025            throws PGPException, KeyIntegrityException {
026
027        PBESecretKeyDecryptor decryptor = null;
028        if (KeyInfo.isEncrypted(secretKey)) {
029            decryptor = protector.getDecryptor(secretKey.getKeyID());
030        }
031        PGPPrivateKey privateKey = unlockSecretKey(secretKey, decryptor);
032        return privateKey;
033    }
034
035    public static PGPPrivateKey unlockSecretKey(PGPSecretKey secretKey, PBESecretKeyDecryptor decryptor)
036            throws PGPException {
037        PGPPrivateKey privateKey;
038        try {
039            privateKey = secretKey.extractPrivateKey(decryptor);
040        } catch (PGPException e) {
041            throw new WrongPassphraseException(secretKey.getKeyID(), e);
042        }
043
044        if (privateKey == null) {
045            int s2kType = secretKey.getS2K().getType();
046            if (s2kType >= 100 && s2kType <= 110) {
047                throw new PGPException("Cannot decrypt secret key" + Long.toHexString(secretKey.getKeyID()) + ": " +
048                        "Unsupported private S2K usage type " + s2kType);
049            }
050
051            throw new PGPException("Cannot decrypt secret key.");
052        }
053
054        PublicKeyParameterValidationUtil.verifyPublicKeyParameterIntegrity(privateKey, secretKey.getPublicKey());
055
056        return privateKey;
057    }
058
059    public static PGPPrivateKey unlockSecretKey(PGPSecretKey secretKey, Passphrase passphrase)
060            throws PGPException, KeyIntegrityException {
061        return unlockSecretKey(secretKey, SecretKeyRingProtector.unlockSingleKeyWith(passphrase, secretKey));
062    }
063}