Simplify Key Generator API and allow EC keys to be generated

This commit is contained in:
Paul Schaub 2018-06-04 14:50:09 +02:00
parent 22eb8f487c
commit ebb06494dd
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
33 changed files with 443 additions and 301 deletions

View File

@ -1,5 +1,15 @@
plugins { plugins {
id 'java' id 'java'
id 'ru.vyarus.animalsniffer' version '1.4.3'
}
apply plugin: 'ru.vyarus.animalsniffer'
dependencies {
signature "net.sf.androidscents.signature:android-api-level-9:2.3.1_r2@signature"
}
animalsniffer {
sourceSets = [sourceSets.main]
} }
group 'de.vanitasvitae.crypto' group 'de.vanitasvitae.crypto'

View File

@ -1,5 +1,6 @@
#Sat Jun 02 23:06:04 CEST 2018
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip

View File

@ -1,5 +0,0 @@
package de.vanitasvitae.crypto.pgpainless;
public class EncryptionBuilder {
}

View File

@ -1,15 +1,11 @@
package de.vanitasvitae.crypto.pgpainless; package de.vanitasvitae.crypto.pgpainless;
import java.io.IOException; import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException; import java.security.NoSuchProviderException;
import java.security.Security; import java.security.Security;
import java.util.Base64;
import de.vanitasvitae.crypto.pgpainless.key.algorithm.KeyFlag;
import de.vanitasvitae.crypto.pgpainless.key.generation.KeySpec;
import de.vanitasvitae.crypto.pgpainless.key.generation.type.DSA;
import de.vanitasvitae.crypto.pgpainless.key.generation.type.RSA_GENERAL;
import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
@ -17,28 +13,13 @@ import org.bouncycastle.openpgp.PGPSecretKeyRing;
public class Main { public class Main {
public static void main(String[] args) public static void main(String[] args)
throws NoSuchAlgorithmException, PGPException, NoSuchProviderException, IOException { throws NoSuchAlgorithmException, PGPException, NoSuchProviderException, IOException,
InvalidAlgorithmParameterException {
Security.addProvider(new BouncyCastleProvider()); Security.addProvider(new BouncyCastleProvider());
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
.generateCompositeKeyRing() .simpleEcKeyRing("elliptic@cur.ve");
.withSubKey(
KeySpec.getBuilder()
.ofType(RSA_GENERAL._4096)
.withKeyFlags(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE)
.withStandardConfiguration())
.done()
.withCertificationKeyType(
KeySpec.getBuilder()
.ofType(DSA._3072)
.withKeyFlags(KeyFlag.SIGN_DATA)
.withStandardConfiguration())
.withPrimaryUserId("Test123")
.done()
.withoutPassphrase()
.build();
byte[] base64 = Base64.getEncoder().encode(secretKeys.getEncoded()); //System.out.println(Base64.getEncoder().encodeToString(secretKeys.getEncoded()));
System.out.println(new String(base64));
} }
} }

View File

@ -1,5 +1,7 @@
package de.vanitasvitae.crypto.pgpainless; package de.vanitasvitae.crypto.pgpainless;
import de.vanitasvitae.crypto.pgpainless.decryption_verification.DecryptionBuilder;
import de.vanitasvitae.crypto.pgpainless.encryption_signing.EncryptionBuilder;
import de.vanitasvitae.crypto.pgpainless.key.generation.KeyRingBuilder; import de.vanitasvitae.crypto.pgpainless.key.generation.KeyRingBuilder;
public class PGPainless { public class PGPainless {
@ -7,4 +9,13 @@ public class PGPainless {
public static KeyRingBuilder generateKeyRing() { public static KeyRingBuilder generateKeyRing() {
return new KeyRingBuilder(); return new KeyRingBuilder();
} }
public static EncryptionBuilder createEncryptor() {
return new EncryptionBuilder();
}
public static DecryptionBuilder createDecryptor() {
return new DecryptionBuilder();
}
} }

View File

@ -1,12 +1,10 @@
package de.vanitasvitae.crypto.pgpainless.key.algorithm; package de.vanitasvitae.crypto.pgpainless.algorithm;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import com.sun.istack.internal.NotNull;
public class AlgorithmSuite { public class AlgorithmSuite {
private static AlgorithmSuite defaultAlgorithmSuite = new AlgorithmSuite( private static AlgorithmSuite defaultAlgorithmSuite = new AlgorithmSuite(
@ -18,8 +16,7 @@ public class AlgorithmSuite {
HashAlgorithm.SHA512, HashAlgorithm.SHA512,
HashAlgorithm.SHA384, HashAlgorithm.SHA384,
HashAlgorithm.SHA256, HashAlgorithm.SHA256,
HashAlgorithm.SHA224, HashAlgorithm.SHA224),
HashAlgorithm.SHA1),
Arrays.asList( Arrays.asList(
CompressionAlgorithm.ZLIB, CompressionAlgorithm.ZLIB,
CompressionAlgorithm.BZIP2, CompressionAlgorithm.BZIP2,
@ -31,15 +28,15 @@ public class AlgorithmSuite {
private List<HashAlgorithm> hashAlgorithms; private List<HashAlgorithm> hashAlgorithms;
private List<CompressionAlgorithm> compressionAlgorithms; private List<CompressionAlgorithm> compressionAlgorithms;
public AlgorithmSuite(@NotNull List<SymmetricKeyAlgorithm> symmetricKeyAlgorithms, public AlgorithmSuite(List<SymmetricKeyAlgorithm> symmetricKeyAlgorithms,
@NotNull List<HashAlgorithm> hashAlgorithms, List<HashAlgorithm> hashAlgorithms,
@NotNull List<CompressionAlgorithm> compressionAlgorithms) { List<CompressionAlgorithm> compressionAlgorithms) {
this.symmetricKeyAlgorithms = Collections.unmodifiableList(symmetricKeyAlgorithms); this.symmetricKeyAlgorithms = Collections.unmodifiableList(symmetricKeyAlgorithms);
this.hashAlgorithms = Collections.unmodifiableList(hashAlgorithms); this.hashAlgorithms = Collections.unmodifiableList(hashAlgorithms);
this.compressionAlgorithms = Collections.unmodifiableList(compressionAlgorithms); this.compressionAlgorithms = Collections.unmodifiableList(compressionAlgorithms);
} }
public void setSymmetricKeyAlgorithms(@NotNull List<SymmetricKeyAlgorithm> symmetricKeyAlgorithms) { public void setSymmetricKeyAlgorithms(List<SymmetricKeyAlgorithm> symmetricKeyAlgorithms) {
this.symmetricKeyAlgorithms = symmetricKeyAlgorithms; this.symmetricKeyAlgorithms = symmetricKeyAlgorithms;
} }
@ -55,7 +52,7 @@ public class AlgorithmSuite {
return array; return array;
} }
public void setHashAlgorithms(@NotNull List<HashAlgorithm> hashAlgorithms) { public void setHashAlgorithms(List<HashAlgorithm> hashAlgorithms) {
this.hashAlgorithms = hashAlgorithms; this.hashAlgorithms = hashAlgorithms;
} }
@ -71,7 +68,7 @@ public class AlgorithmSuite {
return array; return array;
} }
public void setCompressionAlgorithms(@NotNull List<CompressionAlgorithm> compressionAlgorithms) { public void setCompressionAlgorithms(List<CompressionAlgorithm> compressionAlgorithms) {
this.compressionAlgorithms = compressionAlgorithms; this.compressionAlgorithms = compressionAlgorithms;
} }

View File

@ -1,4 +1,4 @@
package de.vanitasvitae.crypto.pgpainless.key.algorithm; package de.vanitasvitae.crypto.pgpainless.algorithm;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;

View File

@ -1,4 +1,4 @@
package de.vanitasvitae.crypto.pgpainless.key.algorithm; package de.vanitasvitae.crypto.pgpainless.algorithm;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;

View File

@ -1,4 +1,4 @@
package de.vanitasvitae.crypto.pgpainless.key.algorithm; package de.vanitasvitae.crypto.pgpainless.algorithm;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;

View File

@ -1,4 +1,4 @@
package de.vanitasvitae.crypto.pgpainless.key.algorithm; package de.vanitasvitae.crypto.pgpainless.algorithm;
import org.bouncycastle.bcpg.sig.KeyFlags; import org.bouncycastle.bcpg.sig.KeyFlags;

View File

@ -1,4 +1,4 @@
package de.vanitasvitae.crypto.pgpainless.key.algorithm; package de.vanitasvitae.crypto.pgpainless.algorithm;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;

View File

@ -1,4 +1,4 @@
package de.vanitasvitae.crypto.pgpainless.key.algorithm; package de.vanitasvitae.crypto.pgpainless.algorithm;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;

View File

@ -0,0 +1,5 @@
package de.vanitasvitae.crypto.pgpainless.decryption_verification;
public class DecryptionBuilder {
}

View File

@ -0,0 +1,5 @@
package de.vanitasvitae.crypto.pgpainless.encryption_signing;
public class EncryptionBuilder {
}

View File

@ -2,6 +2,7 @@ package de.vanitasvitae.crypto.pgpainless.key.generation;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.KeyPairGenerator; import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
@ -10,9 +11,15 @@ import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import de.vanitasvitae.crypto.pgpainless.key.algorithm.KeyFlag; import de.vanitasvitae.crypto.pgpainless.algorithm.KeyFlag;
import de.vanitasvitae.crypto.pgpainless.key.generation.type.ECDH;
import de.vanitasvitae.crypto.pgpainless.key.generation.type.ECDSA;
import de.vanitasvitae.crypto.pgpainless.key.generation.type.KeyType; import de.vanitasvitae.crypto.pgpainless.key.generation.type.KeyType;
import de.vanitasvitae.crypto.pgpainless.key.generation.type.RSA_GENERAL;
import de.vanitasvitae.crypto.pgpainless.key.generation.type.curve.EllipticCurve;
import de.vanitasvitae.crypto.pgpainless.key.generation.type.length.RsaLength;
import org.bouncycastle.bcpg.HashAlgorithmTags; import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.sig.KeyFlags;
import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPEncryptedData; import org.bouncycastle.openpgp.PGPEncryptedData;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
@ -20,7 +27,7 @@ import org.bouncycastle.openpgp.PGPKeyPair;
import org.bouncycastle.openpgp.PGPKeyRingGenerator; import org.bouncycastle.openpgp.PGPKeyRingGenerator;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; import org.bouncycastle.openpgp.PGPSignatureSubpacketVector;
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder; import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder;
import org.bouncycastle.openpgp.operator.PGPDigestCalculator; import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
@ -34,78 +41,65 @@ public class KeyRingBuilder implements KeyRingBuilderInterface {
private final Charset UTF8 = Charset.forName("UTF-8"); private final Charset UTF8 = Charset.forName("UTF-8");
private List<KeySpec> keySpecs = new ArrayList<>(); private List<KeySpec> keySpecs = new ArrayList<>();
private List<String> userIds = new ArrayList<>(); private String userId;
private char[] passphrase; private char[] passphrase;
@Override public PGPSecretKeyRing simpleRsaKeyRing(String userId, RsaLength length)
public WithSubKeyType generateCompositeKeyRing() { throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
return new WithSubKeyTypeImpl(); return withMasterKey(
KeySpec.getBuilder()
.ofType(RSA_GENERAL.withLength(length))
.withDefaultKeyFlags()
.withDefaultAlgorithms())
.withPrimaryUserId(userId)
.withoutPassphrase()
.build();
}
public PGPSecretKeyRing simpleEcKeyRing(String userId)
throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
return withSubKey(
KeySpec.getBuilder()
.ofType(ECDH.fromCurve(EllipticCurve._P256))
.withKeyFlags(KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS)
.withDefaultAlgorithms())
.withMasterKey(
KeySpec.getBuilder()
.ofType(ECDSA.fromCurve(EllipticCurve._P256))
.withKeyFlags(KeyFlag.AUTHENTICATION, KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)
.withDefaultAlgorithms())
.withPrimaryUserId(userId)
.withoutPassphrase()
.build();
} }
@Override @Override
public WithCertificationKeyType generateSingleKeyKeyRing() { public KeyRingBuilderInterface withSubKey(KeySpec type) {
return new WithCertificationKeyTypeImpl(); KeyRingBuilder.this.keySpecs.add(type);
return this;
} }
class WithSubKeyTypeImpl implements WithSubKeyType { @Override
public WithPrimaryUserId withMasterKey(KeySpec spec) {
@Override if ((spec.getSubpackets().getKeyFlags() & KeyFlags.CERTIFY_OTHER) == 0) {
public WithSubKeyType withSubKey(KeySpec type) { throw new IllegalArgumentException("Certification Key MUST have KeyFlag CERTIFY_OTHER");
KeyRingBuilder.this.keySpecs.add(type);
return this;
}
@Override
public WithCertificationKeyType done() {
return new WithCertificationKeyTypeImpl();
}
}
class WithCertificationKeyTypeImpl implements WithCertificationKeyType {
@Override
public WithPrimaryUserId withCertificationKeyType(KeySpec spec) {
if ((spec.getKeyFlags() & KeyFlag.CERTIFY_OTHER.getFlag()) == 0) {
throw new IllegalArgumentException("Certification Key MUST have KeyFlag CERTIFY_OTHER");
}
KeyRingBuilder.this.keySpecs.add(spec);
return new WithPrimaryUserIdImpl();
} }
KeyRingBuilder.this.keySpecs.add(0, spec);
return new WithPrimaryUserIdImpl();
} }
class WithPrimaryUserIdImpl implements WithPrimaryUserId { class WithPrimaryUserIdImpl implements WithPrimaryUserId {
@Override @Override
public WithAdditionalUserIds withPrimaryUserId(String userId) { public WithPassphrase withPrimaryUserId(String userId) {
KeyRingBuilder.this.userIds.add(userId); KeyRingBuilder.this.userId = userId;
return new WithAdditionalUserIdsImpl();
}
@Override
public WithAdditionalUserIds withPrimaryUserId(byte[] userId) {
return withPrimaryUserId(new String(userId, UTF8));
}
}
class WithAdditionalUserIdsImpl implements WithAdditionalUserIds {
@Deprecated
@Override
public WithAdditionalUserIds withAdditionalUserId(String userId) {
KeyRingBuilder.this.userIds.add(userId);
return this;
}
@Deprecated
@Override
public WithAdditionalUserIds withAdditionalUserId(byte[] userId) {
return withAdditionalUserId(new String(userId, UTF8));
}
@Override
public WithPassphrase done() {
return new WithPassphraseImpl(); return new WithPassphraseImpl();
} }
@Override
public WithPassphrase withPrimaryUserId(byte[] userId) {
return withPrimaryUserId(new String(userId, UTF8));
}
} }
class WithPassphraseImpl implements WithPassphrase { class WithPassphraseImpl implements WithPassphrase {
@ -130,7 +124,8 @@ public class KeyRingBuilder implements KeyRingBuilderInterface {
class BuildImpl implements Build { class BuildImpl implements Build {
@Override @Override
public PGPSecretKeyRing build() throws NoSuchAlgorithmException, PGPException, NoSuchProviderException { public PGPSecretKeyRing build() throws NoSuchAlgorithmException, PGPException, NoSuchProviderException,
InvalidAlgorithmParameterException {
// Hash Calculator // Hash Calculator
PGPDigestCalculator calculator = new JcaPGPDigestCalculatorProviderBuilder() PGPDigestCalculator calculator = new JcaPGPDigestCalculatorProviderBuilder()
@ -147,64 +142,51 @@ public class KeyRingBuilder implements KeyRingBuilderInterface {
// First key is the Master Key // First key is the Master Key
KeySpec certKeySpec = keySpecs.get(0); KeySpec certKeySpec = keySpecs.get(0);
KeyType certKeyType = certKeySpec.getKeyType(); // Remove master key, so that we later only add sub keys.
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);
// Signer for creating self-signature // Signer for creating self-signature
PGPContentSignerBuilder signer = new JcaPGPContentSignerBuilder( PGPContentSignerBuilder signer = new JcaPGPContentSignerBuilder(
certKey.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA256); certKey.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA512)
.setProvider(BouncyCastleProvider.PROVIDER_NAME);
// Mimic GnuPGs signature sub packets PGPSignatureSubpacketVector hashedSubPackets = certKeySpec.getSubpackets();
PGPSignatureSubpacketGenerator hashedSubPackets = new PGPSignatureSubpacketGenerator();
// Key flags
hashedSubPackets.setKeyFlags(true, certKeySpec.getKeyFlags());
// Encryption Algorithms
hashedSubPackets.setPreferredSymmetricAlgorithms(true,
certKeySpec.getPreferredAlgorithms().getSymmetricKeyAlgorithmIds());
// Hash Algorithms
hashedSubPackets.setPreferredHashAlgorithms(true,
certKeySpec.getPreferredAlgorithms().getHashAlgorithmIds());
// Compression Algorithms
hashedSubPackets.setPreferredCompressionAlgorithms(true,
certKeySpec.getPreferredAlgorithms().getCompressionAlgorithmIds());
// Modification Detection
hashedSubPackets.setFeature(true, certKeySpec.getFeatures());
// 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 = new PGPKeyRingGenerator(
PGPSignature.POSITIVE_CERTIFICATION, certKey, PGPSignature.POSITIVE_CERTIFICATION, certKey,
userIds.get(0), calculator, userId, calculator,
hashedSubPackets.generate(), null, signer, encryptor); hashedSubPackets, null, signer, encryptor);
for (KeySpec subKeySpec : keySpecs) { for (KeySpec subKeySpec : keySpecs) {
PGPKeyPair subKey = generateKeyPair(subKeySpec); PGPKeyPair subKey = generateKeyPair(subKeySpec);
ringGenerator.addSubKey(subKey); if (subKeySpec.isInheritedSubPackets()) {
ringGenerator.addSubKey(subKey);
} else {
ringGenerator.addSubKey(subKey, subKeySpec.getSubpackets(), null);
}
} }
return ringGenerator.generateSecretKeyRing(); return ringGenerator.generateSecretKeyRing();
} }
private PGPKeyPair generateKeyPair(KeySpec spec) private PGPKeyPair generateKeyPair(KeySpec spec)
throws NoSuchProviderException, NoSuchAlgorithmException, PGPException { throws NoSuchProviderException, NoSuchAlgorithmException, PGPException,
InvalidAlgorithmParameterException {
KeyType type = spec.getKeyType(); KeyType type = spec.getKeyType();
KeyPairGenerator certKeyGenerator = KeyPairGenerator.getInstance( KeyPairGenerator certKeyGenerator = KeyPairGenerator.getInstance(
type.getName(), BouncyCastleProvider.PROVIDER_NAME); type.getName(), BouncyCastleProvider.PROVIDER_NAME);
certKeyGenerator.initialize(type.getLength()); certKeyGenerator.initialize(type.getAlgorithmSpec());
// Create raw Key Pair // Create raw Key Pair
KeyPair rawKeyPair = certKeyGenerator.generateKeyPair(); KeyPair keyPair = certKeyGenerator.generateKeyPair();
// Form PGP key pair // Form PGP key pair
PGPKeyPair pgpKeyPair = new JcaPGPKeyPair(type.getAlgorithm().getAlgorithmId(), PGPKeyPair pgpKeyPair = new JcaPGPKeyPair(type.getAlgorithm().getAlgorithmId(),
rawKeyPair, new Date()); keyPair, new Date());
return pgpKeyPair; return pgpKeyPair;
} }

View File

@ -1,5 +1,6 @@
package de.vanitasvitae.crypto.pgpainless.key.generation; package de.vanitasvitae.crypto.pgpainless.key.generation;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException; import java.security.NoSuchProviderException;
@ -8,36 +9,15 @@ import org.bouncycastle.openpgp.PGPSecretKeyRing;
public interface KeyRingBuilderInterface { public interface KeyRingBuilderInterface {
WithSubKeyType generateCompositeKeyRing(); KeyRingBuilderInterface withSubKey(KeySpec keySpec);
WithCertificationKeyType generateSingleKeyKeyRing(); WithPrimaryUserId withMasterKey(KeySpec keySpec);
interface WithSubKeyType {
WithSubKeyType withSubKey(KeySpec keySpec);
WithCertificationKeyType done();
}
interface WithCertificationKeyType {
WithPrimaryUserId withCertificationKeyType(KeySpec keySpec);
}
interface WithPrimaryUserId { interface WithPrimaryUserId {
WithAdditionalUserIds withPrimaryUserId(String userId); WithPassphrase withPrimaryUserId(String userId);
WithAdditionalUserIds withPrimaryUserId(byte[] userId); WithPassphrase withPrimaryUserId(byte[] userId);
}
interface WithAdditionalUserIds {
WithAdditionalUserIds withAdditionalUserId(String userId);
WithAdditionalUserIds withAdditionalUserId(byte[] userId);
WithPassphrase done();
} }
@ -52,7 +32,8 @@ public interface KeyRingBuilderInterface {
interface Build { interface Build {
PGPSecretKeyRing build() throws NoSuchAlgorithmException, PGPException, NoSuchProviderException; PGPSecretKeyRing build() throws NoSuchAlgorithmException, PGPException, NoSuchProviderException,
InvalidAlgorithmParameterException;
} }
} }

View File

@ -1,46 +1,33 @@
package de.vanitasvitae.crypto.pgpainless.key.generation; package de.vanitasvitae.crypto.pgpainless.key.generation;
import java.util.Set;
import de.vanitasvitae.crypto.pgpainless.key.algorithm.AlgorithmSuite;
import de.vanitasvitae.crypto.pgpainless.key.algorithm.Feature;
import de.vanitasvitae.crypto.pgpainless.key.generation.type.KeyType; import de.vanitasvitae.crypto.pgpainless.key.generation.type.KeyType;
import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator;
import org.bouncycastle.openpgp.PGPSignatureSubpacketVector;
public class KeySpec { public class KeySpec {
private final KeyType keyType; private final KeyType keyType;
private final int keyFlags; private final PGPSignatureSubpacketGenerator subpacketGenerator;
private final AlgorithmSuite algorithmSuite; private final boolean inheritedSubPackets;
private final Set<Feature> features;
KeySpec(KeyType type, KeySpec(KeyType type,
int keyFlags, PGPSignatureSubpacketGenerator subpacketGenerator,
AlgorithmSuite preferredAlgorithms, boolean inheritedSubPackets) {
Set<Feature> features) {
this.keyType = type; this.keyType = type;
this.keyFlags = keyFlags; this.subpacketGenerator = subpacketGenerator;
this.algorithmSuite = preferredAlgorithms; this.inheritedSubPackets = inheritedSubPackets;
this.features = features;
} }
KeyType getKeyType() { KeyType getKeyType() {
return keyType; return keyType;
} }
int getKeyFlags() { PGPSignatureSubpacketVector getSubpackets() {
return keyFlags; return subpacketGenerator.generate();
} }
AlgorithmSuite getPreferredAlgorithms() { boolean isInheritedSubPackets() {
return algorithmSuite; return inheritedSubPackets;
}
byte getFeatures() {
byte val = 0;
for (Feature f : features) {
val |= f.getFeatureId();
}
return val;
} }
public static KeySpecBuilder getBuilder() { public static KeySpecBuilder getBuilder() {

View File

@ -1,23 +1,21 @@
package de.vanitasvitae.crypto.pgpainless.key.generation; package de.vanitasvitae.crypto.pgpainless.key.generation;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import de.vanitasvitae.crypto.pgpainless.key.algorithm.AlgorithmSuite; import de.vanitasvitae.crypto.pgpainless.algorithm.AlgorithmSuite;
import de.vanitasvitae.crypto.pgpainless.key.algorithm.CompressionAlgorithm; import de.vanitasvitae.crypto.pgpainless.algorithm.CompressionAlgorithm;
import de.vanitasvitae.crypto.pgpainless.key.algorithm.Feature; import de.vanitasvitae.crypto.pgpainless.algorithm.Feature;
import de.vanitasvitae.crypto.pgpainless.key.algorithm.HashAlgorithm; import de.vanitasvitae.crypto.pgpainless.algorithm.HashAlgorithm;
import de.vanitasvitae.crypto.pgpainless.key.algorithm.KeyFlag; import de.vanitasvitae.crypto.pgpainless.algorithm.KeyFlag;
import de.vanitasvitae.crypto.pgpainless.key.algorithm.SymmetricKeyAlgorithm; import de.vanitasvitae.crypto.pgpainless.algorithm.SymmetricKeyAlgorithm;
import de.vanitasvitae.crypto.pgpainless.key.generation.type.KeyType; import de.vanitasvitae.crypto.pgpainless.key.generation.type.KeyType;
import org.bouncycastle.bcpg.sig.Features;
import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator;
public class KeySpecBuilder implements KeySpecBuilderInterface { public class KeySpecBuilder implements KeySpecBuilderInterface {
private KeyType type; private KeyType type;
private int keyFlags; private PGPSignatureSubpacketGenerator hashedSubPackets = new PGPSignatureSubpacketGenerator();
private AlgorithmSuite algorithmSuite = AlgorithmSuite.getDefaultAlgorithmSuite();
private Set<Feature> features = new HashSet<>();
@Override @Override
public WithKeyFlags ofType(KeyType type) { public WithKeyFlags ofType(KeyType type) {
@ -33,7 +31,7 @@ public class KeySpecBuilder implements KeySpecBuilderInterface {
for (KeyFlag f : flags) { for (KeyFlag f : flags) {
val |= f.getFlag(); val |= f.getFlag();
} }
KeySpecBuilder.this.keyFlags = val; KeySpecBuilder.this.hashedSubPackets.setKeyFlags(false, val);
return new WithDetailedConfigurationImpl(); return new WithDetailedConfigurationImpl();
} }
@ -46,6 +44,11 @@ public class KeySpecBuilder implements KeySpecBuilderInterface {
KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_STORAGE,
KeyFlag.AUTHENTICATION); KeyFlag.AUTHENTICATION);
} }
@Override
public KeySpec withInheritedSubPackets() {
return new KeySpec(type, null, true);
}
} }
class WithDetailedConfigurationImpl implements WithDetailedConfiguration { class WithDetailedConfigurationImpl implements WithDetailedConfiguration {
@ -57,12 +60,16 @@ public class KeySpecBuilder implements KeySpecBuilderInterface {
} }
@Override @Override
public KeySpec withStandardConfiguration() { public KeySpec withDefaultAlgorithms() {
AlgorithmSuite defaultSuite = AlgorithmSuite.getDefaultAlgorithmSuite();
hashedSubPackets.setPreferredCompressionAlgorithms(false, defaultSuite.getCompressionAlgorithmIds());
hashedSubPackets.setPreferredSymmetricAlgorithms(false, defaultSuite.getSymmetricKeyAlgorithmIds());
hashedSubPackets.setPreferredHashAlgorithms(false, defaultSuite.getHashAlgorithmIds());
hashedSubPackets.setFeature(false, Features.FEATURE_MODIFICATION_DETECTION);
return new KeySpec( return new KeySpec(
KeySpecBuilder.this.type, KeySpecBuilder.this.type,
KeySpecBuilder.this.keyFlags, KeySpecBuilder.this.hashedSubPackets,
KeySpecBuilder.this.algorithmSuite, false);
KeySpecBuilder.this.features);
} }
} }
@ -70,20 +77,29 @@ public class KeySpecBuilder implements KeySpecBuilderInterface {
@Override @Override
public WithPreferredHashAlgorithms withPreferredSymmetricAlgorithms(SymmetricKeyAlgorithm... algorithms) { public WithPreferredHashAlgorithms withPreferredSymmetricAlgorithms(SymmetricKeyAlgorithm... algorithms) {
KeySpecBuilder.this.algorithmSuite.setSymmetricKeyAlgorithms(Arrays.asList(algorithms)); int[] ids = new int[algorithms.length];
for (int i = 0; i < ids.length; i++) {
ids[i] = algorithms[i].getAlgorithmId();
}
KeySpecBuilder.this.hashedSubPackets.setPreferredSymmetricAlgorithms(false, ids);
return new WithPreferredHashAlgorithmsImpl(); return new WithPreferredHashAlgorithmsImpl();
} }
@Override @Override
public WithPreferredHashAlgorithms withDefaultSymmetricAlgorithms() { public WithPreferredHashAlgorithms withDefaultSymmetricAlgorithms() {
KeySpecBuilder.this.algorithmSuite.setSymmetricKeyAlgorithms( KeySpecBuilder.this.hashedSubPackets.setPreferredSymmetricAlgorithms(false,
AlgorithmSuite.getDefaultAlgorithmSuite().getSymmetricKeyAlgorithms()); AlgorithmSuite.getDefaultAlgorithmSuite().getSymmetricKeyAlgorithmIds());
return new WithPreferredHashAlgorithmsImpl(); return new WithPreferredHashAlgorithmsImpl();
} }
@Override @Override
public WithFeatures withDefaultAlgorithms() { public WithFeatures withDefaultAlgorithms() {
KeySpecBuilder.this.algorithmSuite = AlgorithmSuite.getDefaultAlgorithmSuite(); hashedSubPackets.setPreferredSymmetricAlgorithms(false,
AlgorithmSuite.getDefaultAlgorithmSuite().getSymmetricKeyAlgorithmIds());
hashedSubPackets.setPreferredCompressionAlgorithms(false,
AlgorithmSuite.getDefaultAlgorithmSuite().getCompressionAlgorithmIds());
hashedSubPackets.setPreferredHashAlgorithms(false,
AlgorithmSuite.getDefaultAlgorithmSuite().getHashAlgorithmIds());
return new WithFeaturesImpl(); return new WithFeaturesImpl();
} }
} }
@ -92,14 +108,18 @@ public class KeySpecBuilder implements KeySpecBuilderInterface {
@Override @Override
public WithPreferredCompressionAlgorithms withPreferredHashAlgorithms(HashAlgorithm... algorithms) { public WithPreferredCompressionAlgorithms withPreferredHashAlgorithms(HashAlgorithm... algorithms) {
KeySpecBuilder.this.algorithmSuite.setHashAlgorithms(Arrays.asList(algorithms)); int[] ids = new int[algorithms.length];
for (int i = 0; i < ids.length; i++) {
ids[i] = algorithms[i].getAlgorithmId();
}
KeySpecBuilder.this.hashedSubPackets.setPreferredHashAlgorithms(false, ids);
return new WithPreferredCompressionAlgorithmsImpl(); return new WithPreferredCompressionAlgorithmsImpl();
} }
@Override @Override
public WithPreferredCompressionAlgorithms withDefaultHashAlgorithms() { public WithPreferredCompressionAlgorithms withDefaultHashAlgorithms() {
KeySpecBuilder.this.algorithmSuite.setHashAlgorithms( KeySpecBuilder.this.hashedSubPackets.setPreferredHashAlgorithms(false,
AlgorithmSuite.getDefaultAlgorithmSuite().getHashAlgorithms()); AlgorithmSuite.getDefaultAlgorithmSuite().getHashAlgorithmIds());
return new WithPreferredCompressionAlgorithmsImpl(); return new WithPreferredCompressionAlgorithmsImpl();
} }
} }
@ -108,14 +128,18 @@ public class KeySpecBuilder implements KeySpecBuilderInterface {
@Override @Override
public WithFeatures withPreferredCompressionAlgorithms(CompressionAlgorithm... algorithms) { public WithFeatures withPreferredCompressionAlgorithms(CompressionAlgorithm... algorithms) {
KeySpecBuilder.this.algorithmSuite.setCompressionAlgorithms(Arrays.asList(algorithms)); int[] ids = new int[algorithms.length];
for (int i = 0; i < ids.length; i++) {
ids[i] = algorithms[i].getAlgorithmId();
}
KeySpecBuilder.this.hashedSubPackets.setPreferredCompressionAlgorithms(false, ids);
return new WithFeaturesImpl(); return new WithFeaturesImpl();
} }
@Override @Override
public WithFeatures withDefaultCompressionAlgorithms() { public WithFeatures withDefaultCompressionAlgorithms() {
KeySpecBuilder.this.algorithmSuite.setCompressionAlgorithms( KeySpecBuilder.this.hashedSubPackets.setPreferredCompressionAlgorithms(false,
AlgorithmSuite.getDefaultAlgorithmSuite().getCompressionAlgorithms()); AlgorithmSuite.getDefaultAlgorithmSuite().getCompressionAlgorithmIds());
return new WithFeaturesImpl(); return new WithFeaturesImpl();
} }
} }
@ -124,7 +148,7 @@ public class KeySpecBuilder implements KeySpecBuilderInterface {
@Override @Override
public WithFeatures withFeature(Feature feature) { public WithFeatures withFeature(Feature feature) {
KeySpecBuilder.this.features.add(feature); KeySpecBuilder.this.hashedSubPackets.setFeature(false, feature.getFeatureId());
return this; return this;
} }
@ -132,9 +156,8 @@ public class KeySpecBuilder implements KeySpecBuilderInterface {
public KeySpec done() { public KeySpec done() {
return new KeySpec( return new KeySpec(
KeySpecBuilder.this.type, KeySpecBuilder.this.type,
KeySpecBuilder.this.keyFlags, hashedSubPackets,
KeySpecBuilder.this.algorithmSuite, false);
KeySpecBuilder.this.features);
} }
} }
} }

View File

@ -1,11 +1,10 @@
package de.vanitasvitae.crypto.pgpainless.key.generation; package de.vanitasvitae.crypto.pgpainless.key.generation;
import de.vanitasvitae.crypto.pgpainless.key.algorithm.AlgorithmSuite; import de.vanitasvitae.crypto.pgpainless.algorithm.CompressionAlgorithm;
import de.vanitasvitae.crypto.pgpainless.key.algorithm.CompressionAlgorithm; import de.vanitasvitae.crypto.pgpainless.algorithm.Feature;
import de.vanitasvitae.crypto.pgpainless.key.algorithm.Feature; import de.vanitasvitae.crypto.pgpainless.algorithm.HashAlgorithm;
import de.vanitasvitae.crypto.pgpainless.key.algorithm.HashAlgorithm; import de.vanitasvitae.crypto.pgpainless.algorithm.KeyFlag;
import de.vanitasvitae.crypto.pgpainless.key.algorithm.KeyFlag; import de.vanitasvitae.crypto.pgpainless.algorithm.SymmetricKeyAlgorithm;
import de.vanitasvitae.crypto.pgpainless.key.algorithm.SymmetricKeyAlgorithm;
import de.vanitasvitae.crypto.pgpainless.key.generation.type.KeyType; import de.vanitasvitae.crypto.pgpainless.key.generation.type.KeyType;
public interface KeySpecBuilderInterface { public interface KeySpecBuilderInterface {
@ -17,13 +16,15 @@ public interface KeySpecBuilderInterface {
WithDetailedConfiguration withKeyFlags(KeyFlag... flags); WithDetailedConfiguration withKeyFlags(KeyFlag... flags);
WithDetailedConfiguration withDefaultKeyFlags(); WithDetailedConfiguration withDefaultKeyFlags();
KeySpec withInheritedSubPackets();
} }
interface WithDetailedConfiguration { interface WithDetailedConfiguration {
WithPreferredSymmetricAlgorithms withDetailedConfiguration(); WithPreferredSymmetricAlgorithms withDetailedConfiguration();
KeySpec withStandardConfiguration(); KeySpec withDefaultAlgorithms();
} }
interface WithPreferredSymmetricAlgorithms { interface WithPreferredSymmetricAlgorithms {

View File

@ -1,36 +0,0 @@
package de.vanitasvitae.crypto.pgpainless.key.generation.type;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import de.vanitasvitae.crypto.pgpainless.key.algorithm.PublicKeyAlgorithm;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public enum DSA implements KeyType {
_1024(1024),
_2048(2048),
_3072(3072),
;
private final int length;
DSA(int length) {
this.length = length;
}
@Override
public int getLength() {
return length;
}
@Override
public String getName() {
return "DSA";
}
@Override
public PublicKeyAlgorithm getAlgorithm() {
return PublicKeyAlgorithm.DSA;
}
}

View File

@ -0,0 +1,35 @@
package de.vanitasvitae.crypto.pgpainless.key.generation.type;
import java.security.spec.AlgorithmParameterSpec;
import de.vanitasvitae.crypto.pgpainless.algorithm.PublicKeyAlgorithm;
import de.vanitasvitae.crypto.pgpainless.key.generation.type.curve.EllipticCurve;
import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec;
public class ECDH implements KeyType {
private final EllipticCurve curve;
ECDH(EllipticCurve curve) {
this.curve = curve;
}
public static ECDH fromCurve(EllipticCurve curve) {
return new ECDH(curve);
}
@Override
public String getName() {
return "ECDH";
}
@Override
public PublicKeyAlgorithm getAlgorithm() {
return PublicKeyAlgorithm.ECDH;
}
@Override
public AlgorithmParameterSpec getAlgorithmSpec() {
return new ECNamedCurveGenParameterSpec(curve.getName());
}
}

View File

@ -0,0 +1,25 @@
package de.vanitasvitae.crypto.pgpainless.key.generation.type;
import de.vanitasvitae.crypto.pgpainless.algorithm.PublicKeyAlgorithm;
import de.vanitasvitae.crypto.pgpainless.key.generation.type.curve.EllipticCurve;
public class ECDSA extends ECDH {
ECDSA(EllipticCurve curve) {
super(curve);
}
public static ECDSA fromCurve(EllipticCurve curve) {
return new ECDSA(curve);
}
@Override
public String getName() {
return "ECDSA";
}
@Override
public PublicKeyAlgorithm getAlgorithm() {
return PublicKeyAlgorithm.ECDSA;
}
}

View File

@ -1,28 +1,12 @@
package de.vanitasvitae.crypto.pgpainless.key.generation.type; package de.vanitasvitae.crypto.pgpainless.key.generation.type;
import de.vanitasvitae.crypto.pgpainless.key.algorithm.PublicKeyAlgorithm; import de.vanitasvitae.crypto.pgpainless.algorithm.PublicKeyAlgorithm;
import de.vanitasvitae.crypto.pgpainless.key.generation.type.length.ElGamalLength;
public enum ElGamal_ENCRYPT implements KeyType { public class ElGamal_ENCRYPT extends ElGamal_GENERAL {
_1024(1024), ElGamal_ENCRYPT(ElGamalLength length) {
_2048(2048), super(length);
_3072(3072),
;
private final int length;
ElGamal_ENCRYPT(int length) {
this.length = length;
}
@Override
public int getLength() {
return length;
}
@Override
public String getName() {
return "ElGamal";
} }
@Override @Override

View File

@ -0,0 +1,35 @@
package de.vanitasvitae.crypto.pgpainless.key.generation.type;
import java.security.spec.AlgorithmParameterSpec;
import de.vanitasvitae.crypto.pgpainless.algorithm.PublicKeyAlgorithm;
import de.vanitasvitae.crypto.pgpainless.key.generation.type.length.ElGamalLength;
import org.bouncycastle.jce.spec.ElGamalGenParameterSpec;
public class ElGamal_GENERAL implements KeyType {
private final ElGamalLength length;
ElGamal_GENERAL(ElGamalLength length) {
this.length = length;
}
public static ElGamal_GENERAL withLength(ElGamalLength length) {
return new ElGamal_GENERAL(length);
}
@Override
public String getName() {
return "ElGamal";
}
@Override
public PublicKeyAlgorithm getAlgorithm() {
return PublicKeyAlgorithm.ELGAMAL_GENERAL;
}
@Override
public AlgorithmParameterSpec getAlgorithmSpec() {
return new ElGamalGenParameterSpec(length.getLength());
}
}

View File

@ -1,12 +1,14 @@
package de.vanitasvitae.crypto.pgpainless.key.generation.type; package de.vanitasvitae.crypto.pgpainless.key.generation.type;
import de.vanitasvitae.crypto.pgpainless.key.algorithm.PublicKeyAlgorithm; import java.security.spec.AlgorithmParameterSpec;
import de.vanitasvitae.crypto.pgpainless.algorithm.PublicKeyAlgorithm;
public interface KeyType { public interface KeyType {
int getLength();
String getName(); String getName();
PublicKeyAlgorithm getAlgorithm(); PublicKeyAlgorithm getAlgorithm();
AlgorithmParameterSpec getAlgorithmSpec();
} }

View File

@ -0,0 +1,16 @@
package de.vanitasvitae.crypto.pgpainless.key.generation.type;
import de.vanitasvitae.crypto.pgpainless.algorithm.PublicKeyAlgorithm;
import de.vanitasvitae.crypto.pgpainless.key.generation.type.length.RsaLength;
public class RSA_ENCRYPT extends RSA_GENERAL {
RSA_ENCRYPT(RsaLength length) {
super(length);
}
@Override
public PublicKeyAlgorithm getAlgorithm() {
return PublicKeyAlgorithm.RSA_ENCRYPT;
}
}

View File

@ -1,27 +1,21 @@
package de.vanitasvitae.crypto.pgpainless.key.generation.type; package de.vanitasvitae.crypto.pgpainless.key.generation.type;
import de.vanitasvitae.crypto.pgpainless.key.algorithm.PublicKeyAlgorithm; import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.RSAKeyGenParameterSpec;
public enum RSA_GENERAL implements KeyType { import de.vanitasvitae.crypto.pgpainless.algorithm.PublicKeyAlgorithm;
import de.vanitasvitae.crypto.pgpainless.key.generation.type.length.RsaLength;
@Deprecated public class RSA_GENERAL implements KeyType {
_1024(1024),
@Deprecated
_2048(2048),
_3072(3072),
_4096(4096),
_8192(8192),
;
private final int length; private final RsaLength length;
RSA_GENERAL(int length) { RSA_GENERAL(RsaLength length) {
this.length = length; this.length = length;
} }
@Override public static RSA_GENERAL withLength(RsaLength length) {
public int getLength() { return new RSA_GENERAL(length);
return length;
} }
@Override @Override
@ -33,4 +27,9 @@ public enum RSA_GENERAL implements KeyType {
public PublicKeyAlgorithm getAlgorithm() { public PublicKeyAlgorithm getAlgorithm() {
return PublicKeyAlgorithm.RSA_GENERAL; return PublicKeyAlgorithm.RSA_GENERAL;
} }
@Override
public AlgorithmParameterSpec getAlgorithmSpec() {
return new RSAKeyGenParameterSpec(length.getLength(), RSAKeyGenParameterSpec.F4);
}
} }

View File

@ -0,0 +1,16 @@
package de.vanitasvitae.crypto.pgpainless.key.generation.type;
import de.vanitasvitae.crypto.pgpainless.algorithm.PublicKeyAlgorithm;
import de.vanitasvitae.crypto.pgpainless.key.generation.type.length.RsaLength;
public class RSA_SIGN extends RSA_GENERAL {
RSA_SIGN(RsaLength length) {
super(length);
}
@Override
public PublicKeyAlgorithm getAlgorithm() {
return PublicKeyAlgorithm.RSA_SIGN;
}
}

View File

@ -0,0 +1,16 @@
package de.vanitasvitae.crypto.pgpainless.key.generation.type.curve;
public enum EllipticCurve {
_P256("P-256"),
;
private final String name;
EllipticCurve(String name) {
this.name = name;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,21 @@
package de.vanitasvitae.crypto.pgpainless.key.generation.type.length;
public enum DiffieHellmanLength implements KeyLength {
_1024(1024),
_2048(2048),
_3072(3072),
;
private final int length;
DiffieHellmanLength(int length) {
this.length = length;
}
@Override
public int getLength() {
return length;
}
}

View File

@ -0,0 +1,21 @@
package de.vanitasvitae.crypto.pgpainless.key.generation.type.length;
public enum ElGamalLength implements KeyLength {
_1024(1024),
_2048(2048),
_3072(3072),
;
private final int length;
ElGamalLength(int length) {
this.length = length;
}
@Override
public int getLength() {
return length;
}
}

View File

@ -0,0 +1,6 @@
package de.vanitasvitae.crypto.pgpainless.key.generation.type.length;
public interface KeyLength {
int getLength();
}

View File

@ -0,0 +1,23 @@
package de.vanitasvitae.crypto.pgpainless.key.generation.type.length;
public enum RsaLength implements KeyLength {
@Deprecated
_1024(1024),
@Deprecated
_2048(2048),
_3072(3072),
_4096(4096),
_8192(8192),
;
private final int length;
RsaLength(int length) {
this.length = length;
}
@Override
public int getLength() {
return length;
}
}