001// SPDX-FileCopyrightText: 2020 Paul Schaub <vanitasvitae@fsfe.org>
002//
003// SPDX-License-Identifier: Apache-2.0
004
005package org.pgpainless.implementation;
006
007import java.io.InputStream;
008import java.security.KeyPair;
009import java.util.Date;
010
011import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
012import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
013import org.bouncycastle.openpgp.PGPException;
014import org.bouncycastle.openpgp.PGPKeyPair;
015import org.bouncycastle.openpgp.PGPObjectFactory;
016import org.bouncycastle.openpgp.PGPPrivateKey;
017import org.bouncycastle.openpgp.PGPPublicKey;
018import org.bouncycastle.openpgp.PGPSecretKey;
019import org.bouncycastle.openpgp.PGPSessionKey;
020import org.bouncycastle.openpgp.bc.BcPGPObjectFactory;
021import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
022import org.bouncycastle.openpgp.operator.PBEDataDecryptorFactory;
023import org.bouncycastle.openpgp.operator.PBEKeyEncryptionMethodGenerator;
024import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
025import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
026import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder;
027import org.bouncycastle.openpgp.operator.PGPContentVerifierBuilderProvider;
028import org.bouncycastle.openpgp.operator.PGPDataEncryptorBuilder;
029import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
030import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
031import org.bouncycastle.openpgp.operator.PublicKeyKeyEncryptionMethodGenerator;
032import org.bouncycastle.openpgp.operator.SessionKeyDataDecryptorFactory;
033import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
034import org.bouncycastle.openpgp.operator.bc.BcPBEDataDecryptorFactory;
035import org.bouncycastle.openpgp.operator.bc.BcPBEKeyEncryptionMethodGenerator;
036import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder;
037import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyEncryptorBuilder;
038import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilder;
039import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider;
040import org.bouncycastle.openpgp.operator.bc.BcPGPDataEncryptorBuilder;
041import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider;
042import org.bouncycastle.openpgp.operator.bc.BcPGPKeyConverter;
043import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair;
044import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory;
045import org.bouncycastle.openpgp.operator.bc.BcPublicKeyKeyEncryptionMethodGenerator;
046import org.bouncycastle.openpgp.operator.bc.BcSessionKeyDataDecryptorFactory;
047import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair;
048import org.pgpainless.algorithm.HashAlgorithm;
049import org.pgpainless.algorithm.PublicKeyAlgorithm;
050import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
051import org.pgpainless.util.Passphrase;
052
053public class BcImplementationFactory extends ImplementationFactory {
054
055    @Override
056    public PBESecretKeyEncryptor getPBESecretKeyEncryptor(PGPSecretKey secretKey, Passphrase passphrase)
057            throws PGPException {
058        int keyEncryptionAlgorithm = secretKey.getKeyEncryptionAlgorithm();
059
060        if (secretKey.getS2K() == null) {
061            return getPBESecretKeyEncryptor(SymmetricKeyAlgorithm.fromId(keyEncryptionAlgorithm), passphrase);
062        }
063
064        int hashAlgorithm = secretKey.getS2K().getHashAlgorithm();
065        PGPDigestCalculator digestCalculator = getPGPDigestCalculator(hashAlgorithm);
066        long iterationCount = secretKey.getS2K().getIterationCount();
067
068        return new BcPBESecretKeyEncryptorBuilder(keyEncryptionAlgorithm, digestCalculator, (int) iterationCount)
069                .build(passphrase.getChars());
070    }
071
072    @Override
073    public PBESecretKeyEncryptor getPBESecretKeyEncryptor(SymmetricKeyAlgorithm symmetricKeyAlgorithm,
074                                                          PGPDigestCalculator digestCalculator,
075                                                          Passphrase passphrase) {
076        return new BcPBESecretKeyEncryptorBuilder(symmetricKeyAlgorithm.getAlgorithmId(), digestCalculator)
077                .build(passphrase.getChars());
078    }
079
080    @Override
081    public PBESecretKeyDecryptor getPBESecretKeyDecryptor(Passphrase passphrase) {
082        return new BcPBESecretKeyDecryptorBuilder(getPGPDigestCalculatorProvider())
083                .build(passphrase.getChars());
084    }
085
086    @Override
087    public BcPGPDigestCalculatorProvider getPGPDigestCalculatorProvider() {
088        return new BcPGPDigestCalculatorProvider();
089    }
090
091    @Override
092    public PGPContentVerifierBuilderProvider getPGPContentVerifierBuilderProvider() {
093        return new BcPGPContentVerifierBuilderProvider();
094    }
095
096    @Override
097    public PGPContentSignerBuilder getPGPContentSignerBuilder(int keyAlgorithm, int hashAlgorithm) {
098        return new BcPGPContentSignerBuilder(keyAlgorithm, hashAlgorithm);
099    }
100
101    @Override
102    public KeyFingerPrintCalculator getKeyFingerprintCalculator() {
103        return new BcKeyFingerprintCalculator();
104    }
105
106    @Override
107    public PBEDataDecryptorFactory getPBEDataDecryptorFactory(Passphrase passphrase) {
108        return new BcPBEDataDecryptorFactory(passphrase.getChars(), getPGPDigestCalculatorProvider());
109    }
110
111    @Override
112    public PublicKeyDataDecryptorFactory getPublicKeyDataDecryptorFactory(PGPPrivateKey privateKey) {
113        return new BcPublicKeyDataDecryptorFactory(privateKey);
114    }
115
116    @Override
117    public PublicKeyKeyEncryptionMethodGenerator getPublicKeyKeyEncryptionMethodGenerator(PGPPublicKey key) {
118        return new BcPublicKeyKeyEncryptionMethodGenerator(key);
119    }
120
121    @Override
122    public PBEKeyEncryptionMethodGenerator getPBEKeyEncryptionMethodGenerator(Passphrase passphrase) {
123        return new BcPBEKeyEncryptionMethodGenerator(passphrase.getChars());
124    }
125
126    @Override
127    public PGPDataEncryptorBuilder getPGPDataEncryptorBuilder(int symmetricKeyAlgorithm) {
128        return new BcPGPDataEncryptorBuilder(symmetricKeyAlgorithm);
129    }
130
131    @Override
132    public PGPKeyPair getPGPKeyPair(PublicKeyAlgorithm algorithm, KeyPair keyPair, Date creationDate)
133            throws PGPException {
134        return new BcPGPKeyPair(algorithm.getAlgorithmId(), jceToBcKeyPair(algorithm, keyPair, creationDate), creationDate);
135    }
136
137    @Override
138    public PBESecretKeyEncryptor getPBESecretKeyEncryptor(SymmetricKeyAlgorithm encryptionAlgorithm, HashAlgorithm hashAlgorithm, int s2kCount, Passphrase passphrase) throws PGPException {
139        return new BcPBESecretKeyEncryptorBuilder(
140                encryptionAlgorithm.getAlgorithmId(),
141                getPGPDigestCalculator(hashAlgorithm),
142                s2kCount)
143                .build(passphrase.getChars());
144    }
145
146    @Override
147    public SessionKeyDataDecryptorFactory provideSessionKeyDataDecryptorFactory(PGPSessionKey sessionKey) {
148        return new BcSessionKeyDataDecryptorFactory(sessionKey);
149    }
150
151    @Override
152    public PGPObjectFactory getPGPObjectFactory(byte[] bytes) {
153        return new BcPGPObjectFactory(bytes);
154    }
155
156    @Override
157    public PGPObjectFactory getPGPObjectFactory(InputStream inputStream) {
158        return new BcPGPObjectFactory(inputStream);
159    }
160
161    private AsymmetricCipherKeyPair jceToBcKeyPair(PublicKeyAlgorithm algorithm,
162                                                   KeyPair keyPair,
163                                                   Date creationDate) throws PGPException {
164        BcPGPKeyConverter converter = new BcPGPKeyConverter();
165
166        PGPKeyPair pair = new JcaPGPKeyPair(algorithm.getAlgorithmId(), keyPair, creationDate);
167        AsymmetricKeyParameter publicKey = converter.getPublicKey(pair.getPublicKey());
168        AsymmetricKeyParameter privateKey = converter.getPrivateKey(pair.getPrivateKey());
169
170        return new AsymmetricCipherKeyPair(publicKey, privateKey);
171    }
172}