From 1bfc54828c42675f020a20d45596644564e22279 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Wed, 27 Jun 2018 12:33:47 +0200 Subject: [PATCH] Add PassphraseMapKeyRingProtector --- .../key/KeyRingProtectionSettings.java | 44 ++++++++++++ .../key/PassphraseMapKeyRingProtector.java | 70 +++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 src/main/java/de/vanitasvitae/crypto/pgpainless/key/KeyRingProtectionSettings.java create mode 100644 src/main/java/de/vanitasvitae/crypto/pgpainless/key/PassphraseMapKeyRingProtector.java diff --git a/src/main/java/de/vanitasvitae/crypto/pgpainless/key/KeyRingProtectionSettings.java b/src/main/java/de/vanitasvitae/crypto/pgpainless/key/KeyRingProtectionSettings.java new file mode 100644 index 00000000..f7c5b9da --- /dev/null +++ b/src/main/java/de/vanitasvitae/crypto/pgpainless/key/KeyRingProtectionSettings.java @@ -0,0 +1,44 @@ +/* + * Copyright 2018 Paul Schaub. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.vanitasvitae.crypto.pgpainless.key; + +import de.vanitasvitae.crypto.pgpainless.algorithm.HashAlgorithm; +import de.vanitasvitae.crypto.pgpainless.algorithm.SymmetricKeyAlgorithm; + +public class KeyRingProtectionSettings { + + private final SymmetricKeyAlgorithm encryptionAlgorithm; + private final HashAlgorithm hashAlgorithm; + private final int s2kCount; + + public KeyRingProtectionSettings(SymmetricKeyAlgorithm encryptionAlgorithm, HashAlgorithm hashAlgorithm, int s2kCount) { + this.encryptionAlgorithm = encryptionAlgorithm; + this.hashAlgorithm = hashAlgorithm; + this.s2kCount = s2kCount; + } + + public SymmetricKeyAlgorithm getEncryptionAlgorithm() { + return encryptionAlgorithm; + } + + public HashAlgorithm getHashAlgorithm() { + return hashAlgorithm; + } + + public int getS2kCount() { + return s2kCount; + } +} diff --git a/src/main/java/de/vanitasvitae/crypto/pgpainless/key/PassphraseMapKeyRingProtector.java b/src/main/java/de/vanitasvitae/crypto/pgpainless/key/PassphraseMapKeyRingProtector.java new file mode 100644 index 00000000..6051f5a4 --- /dev/null +++ b/src/main/java/de/vanitasvitae/crypto/pgpainless/key/PassphraseMapKeyRingProtector.java @@ -0,0 +1,70 @@ +/* + * Copyright 2018 Paul Schaub. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.vanitasvitae.crypto.pgpainless.key; + +import java.util.HashMap; +import java.util.Map; + +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; +import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; +import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider; +import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder; +import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyEncryptorBuilder; +import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider; + +/** + * Implementation of the {@link SecretKeyRingProtector} which holds a map of key ids and their passwords. + */ +public class PassphraseMapKeyRingProtector implements SecretKeyRingProtector { + + private static final PGPDigestCalculatorProvider calculatorProvider = new BcPGPDigestCalculatorProvider(); + + private final Map passphrases = new HashMap<>(); + private final KeyRingProtectionSettings protectionSettings; + + public PassphraseMapKeyRingProtector(Map passphrases, KeyRingProtectionSettings protectionSettings) { + this.passphrases.putAll(passphrases); + this.protectionSettings = protectionSettings; + } + + public void addPassphrase(Long keyId, char[] passphrase) { + this.passphrases.put(keyId, passphrase); + } + + public void forgetPassphrase(Long keyId) { + char[] passphrase = passphrases.get(keyId); + // Overwrite the passphrase in memory with zeros + for (int i = 0; i < passphrase.length; i++) { + passphrase[i] = '0'; + } + passphrases.remove(keyId); + } + + @Override + public PBESecretKeyDecryptor getDecryptor(Long keyId) { + return new BcPBESecretKeyDecryptorBuilder(calculatorProvider).build(passphrases.get(keyId)); + } + + @Override + public PBESecretKeyEncryptor getEncryptor(Long keyId) throws PGPException { + return new BcPBESecretKeyEncryptorBuilder( + protectionSettings.getEncryptionAlgorithm().getAlgorithmId(), + calculatorProvider.get(protectionSettings.getHashAlgorithm().getAlgorithmId()), + protectionSettings.getS2kCount()) + .build(passphrases.get(keyId)); + } +}