001/*
002 * Copyright 2018 Paul Schaub.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.pgpainless.key.protection;
017
018import javax.annotation.Nonnull;
019import javax.annotation.Nullable;
020
021import org.bouncycastle.openpgp.PGPException;
022import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
023import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
024import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
025import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder;
026import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyEncryptorBuilder;
027import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider;
028import org.pgpainless.util.Passphrase;
029
030/**
031 * Provides {@link PBESecretKeyDecryptor} and {@link PBESecretKeyEncryptor} objects while getting the passphrases
032 * from a {@link SecretKeyPassphraseProvider} and using settings from an {@link KeyRingProtectionSettings}.
033 */
034public class PasswordBasedSecretKeyRingProtector implements SecretKeyRingProtector {
035
036    private static final PGPDigestCalculatorProvider calculatorProvider = new BcPGPDigestCalculatorProvider();
037
038    protected final KeyRingProtectionSettings protectionSettings;
039    protected final SecretKeyPassphraseProvider passphraseProvider;
040
041    /**
042     * Constructor.
043     * Passphrases for keys are sourced from the {@code passphraseProvider} and decryptors/encryptors are constructed
044     * following the settings given in {@code settings}.
045     *
046     * @param settings S2K settings etc.
047     * @param passphraseProvider provider which provides passphrases.
048     */
049    public PasswordBasedSecretKeyRingProtector(@Nonnull KeyRingProtectionSettings settings, @Nonnull SecretKeyPassphraseProvider passphraseProvider) {
050        this.protectionSettings = settings;
051        this.passphraseProvider = passphraseProvider;
052    }
053
054    @Override
055    @Nullable
056    public PBESecretKeyDecryptor getDecryptor(Long keyId) {
057        Passphrase passphrase = passphraseProvider.getPassphraseFor(keyId);
058        return new BcPBESecretKeyDecryptorBuilder(calculatorProvider)
059                .build(passphrase != null ? passphrase.getChars() : null);
060    }
061
062    @Override
063    @Nullable
064    public PBESecretKeyEncryptor getEncryptor(Long keyId) throws PGPException {
065        Passphrase passphrase = passphraseProvider.getPassphraseFor(keyId);
066        return new BcPBESecretKeyEncryptorBuilder(
067                protectionSettings.getEncryptionAlgorithm().getAlgorithmId(),
068                calculatorProvider.get(protectionSettings.getHashAlgorithm().getAlgorithmId()),
069                protectionSettings.getS2kCount())
070                .build(passphrase != null ? passphrase.getChars() : null);
071    }
072}