1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-09-27 18:19:34 +02:00

Refactor KeyRingBuilder

This commit is contained in:
Paul Schaub 2020-01-12 15:40:50 +01:00
parent 79b04d1535
commit 81c3a471a7
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
2 changed files with 59 additions and 34 deletions

View file

@ -50,4 +50,8 @@ public enum KeyFlag {
} }
return flags; return flags;
} }
public static boolean hasKeyFlag(int mask, KeyFlag flag) {
return (mask & flag.getFlag()) == 0;
}
} }

View file

@ -26,7 +26,6 @@ import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import org.bouncycastle.bcpg.sig.KeyFlags;
import org.bouncycastle.openpgp.PGPEncryptedData; import org.bouncycastle.openpgp.PGPEncryptedData;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPKeyPair; import org.bouncycastle.openpgp.PGPKeyPair;
@ -69,6 +68,7 @@ public class KeyRingBuilder implements KeyRingBuilderInterface {
* @param userId user id. * @param userId user id.
* @param length length in bits. * @param length length in bits.
* @return {@link PGPSecretKeyRing} containing the KeyPair. * @return {@link PGPSecretKeyRing} containing the KeyPair.
*
* @throws PGPException * @throws PGPException
* @throws NoSuchAlgorithmException * @throws NoSuchAlgorithmException
* @throws InvalidAlgorithmParameterException * @throws InvalidAlgorithmParameterException
@ -91,6 +91,7 @@ public class KeyRingBuilder implements KeyRingBuilderInterface {
* *
* @param userId user-id * @param userId user-id
* @return {@link PGPSecretKeyRing} containing the key pairs. * @return {@link PGPSecretKeyRing} containing the key pairs.
*
* @throws PGPException * @throws PGPException
* @throws NoSuchAlgorithmException * @throws NoSuchAlgorithmException
* @throws InvalidAlgorithmParameterException * @throws InvalidAlgorithmParameterException
@ -118,13 +119,18 @@ public class KeyRingBuilder implements KeyRingBuilderInterface {
@Override @Override
public WithPrimaryUserId withMasterKey(@Nonnull KeySpec spec) { public WithPrimaryUserId withMasterKey(@Nonnull KeySpec spec) {
if ((spec.getSubpackets().getKeyFlags() & KeyFlags.CERTIFY_OTHER) == 0) { if (canCertifyOthers(spec)) {
throw new IllegalArgumentException("Certification Key MUST have KeyFlag CERTIFY_OTHER"); throw new IllegalArgumentException("Certification Key MUST have KeyFlag CERTIFY_OTHER");
} }
KeyRingBuilder.this.keySpecs.add(0, spec); KeyRingBuilder.this.keySpecs.add(0, spec);
return new WithPrimaryUserIdImpl(); return new WithPrimaryUserIdImpl();
} }
private boolean canCertifyOthers(KeySpec keySpec) {
return KeyFlag.hasKeyFlag(keySpec.getSubpackets().getKeyFlags(), KeyFlag.CERTIFY_OTHER);
}
class WithPrimaryUserIdImpl implements WithPrimaryUserId { class WithPrimaryUserIdImpl implements WithPrimaryUserId {
@Override @Override
@ -155,47 +161,42 @@ public class KeyRingBuilder implements KeyRingBuilderInterface {
class BuildImpl implements Build { class BuildImpl implements Build {
private PGPDigestCalculator digestCalculator;
private PBESecretKeyEncryptor secretKeyEncryptor;
@Override @Override
public PGPKeyRing build() throws NoSuchAlgorithmException, PGPException, public PGPKeyRing build() throws NoSuchAlgorithmException, PGPException,
InvalidAlgorithmParameterException { InvalidAlgorithmParameterException {
digestCalculator = buildDigestCalculator();
// Hash Calculator secretKeyEncryptor = buildSecretKeyEncryptor();
PGPDigestCalculator calculator = new JcaPGPDigestCalculatorProviderBuilder()
.setProvider(ProviderFactory.getProvider())
.build()
.get(HashAlgorithm.SHA1.getAlgorithmId());
// Encryptor for encrypting secret keys
PBESecretKeyEncryptor encryptor = passphrase == null ?
null : // unencrypted key pair, otherwise AES-256 encrypted
new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256, calculator)
.build(passphrase != null ? passphrase.getChars() : null);
if (passphrase != null) {
passphrase.clear();
}
// First key is the Master Key // First key is the Master Key
KeySpec certKeySpec = keySpecs.get(0); KeySpec certKeySpec = keySpecs.remove(0);
// Remove master key, so that we later only add sub keys.
keySpecs.remove(0);
// Generate Master Key // Generate Master Key
PGPKeyPair certKey = generateKeyPair(certKeySpec); PGPKeyPair certKey = generateKeyPair(certKeySpec);
PGPContentSignerBuilder signer = buildContentSigner(certKey);
// Signer for creating self-signature
PGPContentSignerBuilder signer = new JcaPGPContentSignerBuilder(
certKey.getPublicKey().getAlgorithm(), HashAlgorithm.SHA512.getAlgorithmId())
.setProvider(ProviderFactory.getProvider());
PGPSignatureSubpacketVector hashedSubPackets = certKeySpec.getSubpackets(); PGPSignatureSubpacketVector hashedSubPackets = certKeySpec.getSubpackets();
// Generator which the user can get the key pair from // Generator which the user can get the key pair from
PGPKeyRingGenerator ringGenerator = new PGPKeyRingGenerator( PGPKeyRingGenerator ringGenerator = buildRingGenerator(certKey, signer, hashedSubPackets);
PGPSignature.POSITIVE_CERTIFICATION, certKey,
userId, calculator,
hashedSubPackets, null, signer, encryptor);
addSubKeys(ringGenerator);
PGPPublicKeyRing publicKeys = ringGenerator.generatePublicKeyRing();
PGPSecretKeyRing secretKeys = ringGenerator.generateSecretKeyRing();
return new PGPKeyRing(publicKeys, secretKeys);
}
private PGPKeyRingGenerator buildRingGenerator(PGPKeyPair certKey, PGPContentSignerBuilder signer, PGPSignatureSubpacketVector hashedSubPackets) throws PGPException {
return new PGPKeyRingGenerator(
PGPSignature.POSITIVE_CERTIFICATION, certKey,
userId, digestCalculator,
hashedSubPackets, null, signer, secretKeyEncryptor);
}
private void addSubKeys(PGPKeyRingGenerator ringGenerator) throws NoSuchAlgorithmException, PGPException, InvalidAlgorithmParameterException {
for (KeySpec subKeySpec : keySpecs) { for (KeySpec subKeySpec : keySpecs) {
PGPKeyPair subKey = generateKeyPair(subKeySpec); PGPKeyPair subKey = generateKeyPair(subKeySpec);
if (subKeySpec.isInheritedSubPackets()) { if (subKeySpec.isInheritedSubPackets()) {
@ -204,11 +205,31 @@ public class KeyRingBuilder implements KeyRingBuilderInterface {
ringGenerator.addSubKey(subKey, subKeySpec.getSubpackets(), null); ringGenerator.addSubKey(subKey, subKeySpec.getSubpackets(), null);
} }
} }
}
PGPPublicKeyRing publicKeys = ringGenerator.generatePublicKeyRing(); private PGPContentSignerBuilder buildContentSigner(PGPKeyPair certKey) {
PGPSecretKeyRing secretKeys = ringGenerator.generateSecretKeyRing(); return new JcaPGPContentSignerBuilder(
certKey.getPublicKey().getAlgorithm(), HashAlgorithm.SHA512.getAlgorithmId())
.setProvider(ProviderFactory.getProvider());
}
return new PGPKeyRing(publicKeys, secretKeys); private PBESecretKeyEncryptor buildSecretKeyEncryptor() {
PBESecretKeyEncryptor encryptor = passphrase == null ?
null : // unencrypted key pair, otherwise AES-256 encrypted
new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256, digestCalculator)
.setProvider(ProviderFactory.getProvider())
.build(passphrase.getChars());
if (passphrase != null) {
passphrase.clear();
}
return encryptor;
}
private PGPDigestCalculator buildDigestCalculator() throws PGPException {
return new JcaPGPDigestCalculatorProviderBuilder()
.setProvider(ProviderFactory.getProvider())
.build()
.get(HashAlgorithm.SHA1.getAlgorithmId());
} }
private PGPKeyPair generateKeyPair(KeySpec spec) private PGPKeyPair generateKeyPair(KeySpec spec)