001// SPDX-FileCopyrightText: 2018 Paul Schaub <vanitasvitae@fsfe.org>
002//
003// SPDX-License-Identifier: Apache-2.0
004
005package org.pgpainless.key.protection;
006
007import javax.annotation.Nonnull;
008import javax.annotation.Nullable;
009
010import org.bouncycastle.openpgp.PGPKeyRing;
011import org.bouncycastle.openpgp.PGPSecretKey;
012import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
013import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
014import org.pgpainless.key.protection.passphrase_provider.SecretKeyPassphraseProvider;
015import org.pgpainless.util.Passphrase;
016
017/**
018 * Provides {@link PBESecretKeyDecryptor} and {@link PBESecretKeyEncryptor} objects while getting the passphrases
019 * from a {@link SecretKeyPassphraseProvider} and using settings from an {@link KeyRingProtectionSettings}.
020 */
021public class PasswordBasedSecretKeyRingProtector extends BaseSecretKeyRingProtector {
022
023    public PasswordBasedSecretKeyRingProtector(@Nonnull SecretKeyPassphraseProvider passphraseProvider) {
024        super(passphraseProvider);
025    }
026
027    /**
028     * Constructor.
029     * Passphrases for keys are sourced from the {@code passphraseProvider} and decryptors/encryptors are constructed
030     * following the settings given in {@code settings}.
031     *
032     * @param settings S2K settings etc.
033     * @param passphraseProvider provider which provides passphrases.
034     */
035    public PasswordBasedSecretKeyRingProtector(@Nonnull KeyRingProtectionSettings settings, @Nonnull SecretKeyPassphraseProvider passphraseProvider) {
036        super(passphraseProvider, settings);
037    }
038
039    public static PasswordBasedSecretKeyRingProtector forKey(PGPKeyRing keyRing, Passphrase passphrase) {
040        SecretKeyPassphraseProvider passphraseProvider = new SecretKeyPassphraseProvider() {
041            @Override
042            @Nullable
043            public Passphrase getPassphraseFor(Long keyId) {
044                return hasPassphrase(keyId) ? passphrase : null;
045            }
046
047            @Override
048            public boolean hasPassphrase(Long keyId) {
049                return keyRing.getPublicKey(keyId) != null;
050            }
051        };
052        return new PasswordBasedSecretKeyRingProtector(passphraseProvider);
053    }
054
055    public static PasswordBasedSecretKeyRingProtector forKey(PGPSecretKey key, Passphrase passphrase) {
056        return forKeyId(key.getPublicKey().getKeyID(), passphrase);
057    }
058
059    public static PasswordBasedSecretKeyRingProtector forKeyId(long singleKeyId, Passphrase passphrase) {
060        SecretKeyPassphraseProvider passphraseProvider = new SecretKeyPassphraseProvider() {
061            @Nullable
062            @Override
063            public Passphrase getPassphraseFor(Long keyId) {
064                if (keyId == singleKeyId) {
065                    return passphrase;
066                }
067                return null;
068            }
069
070            @Override
071            public boolean hasPassphrase(Long keyId) {
072                return keyId == singleKeyId;
073            }
074        };
075        return new PasswordBasedSecretKeyRingProtector(passphraseProvider);
076    }
077
078}