diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java index 230a0a9a..3c81332c 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java @@ -61,14 +61,18 @@ import org.pgpainless.provider.ProviderFactory; import org.pgpainless.util.Passphrase; import org.pgpainless.signature.subpackets.SignatureSubpacketGeneratorUtil; -public class KeyRingBuilder implements KeyRingBuilderInterface { +public class KeyRingBuilder implements KeyRingBuilderInterface { private final Charset UTF8 = Charset.forName("UTF-8"); - private final List keySpecs = new ArrayList<>(); - private String userId; - private final Set additionalUserIds = new LinkedHashSet<>(); - private Passphrase passphrase; + private PGPSignatureGenerator signatureGenerator; + private PGPDigestCalculator digestCalculator; + private PBESecretKeyEncryptor secretKeyEncryptor; + + private KeySpec primaryKeySpec; + private final List subkeySpecs = new ArrayList<>(); + private final Set userIds = new LinkedHashSet<>(); + private Passphrase passphrase = null; private Date expirationDate = null; /** @@ -126,17 +130,14 @@ public class KeyRingBuilder implements KeyRingBuilderInterface { */ public PGPSecretKeyRing simpleRsaKeyRing(@Nonnull String userId, @Nonnull RsaLength length, String password) throws PGPException, NoSuchAlgorithmException, InvalidAlgorithmParameterException { - WithAdditionalUserIdOrPassphrase builder = this - .withPrimaryKey(KeySpec - .getBuilder(KeyType.RSA(length), KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA, KeyFlag.ENCRYPT_COMMS) - .build()) - .withPrimaryUserId(userId); + KeyRingBuilder builder = new KeyRingBuilder() + .setPrimaryKey(KeySpec.getBuilder(KeyType.RSA(length), KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA, KeyFlag.ENCRYPT_COMMS)) + .addUserId(userId); - if (password == null) { - return builder.withoutPassphrase().build(); - } else { - return builder.withPassphrase(new Passphrase(password.toCharArray())).build(); + if (!isNullOrEmpty(password)) { + builder.setPassphrase(Passphrase.fromPassword(password)); } + return builder.build(); } /** @@ -194,20 +195,15 @@ public class KeyRingBuilder implements KeyRingBuilderInterface { */ public PGPSecretKeyRing simpleEcKeyRing(@Nonnull String userId, String password) throws PGPException, NoSuchAlgorithmException, InvalidAlgorithmParameterException { - WithAdditionalUserIdOrPassphrase builder = this - .withSubKey( - KeySpec.getBuilder(KeyType.XDH(XDHSpec._X25519), KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS) - .build()) - .withPrimaryKey( - KeySpec.getBuilder(KeyType.EDDSA(EdDSACurve._Ed25519), KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA) - .build()) - .withPrimaryUserId(userId); + KeyRingBuilder builder = new KeyRingBuilder() + .setPrimaryKey(KeySpec.getBuilder(KeyType.EDDSA(EdDSACurve._Ed25519), KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)) + .addSubkey(KeySpec.getBuilder(KeyType.XDH(XDHSpec._X25519), KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS)) + .addUserId(userId); - if (password == null) { - return builder.withoutPassphrase().build(); - } else { - return builder.withPassphrase(new Passphrase(password.toCharArray())).build(); + if (!isNullOrEmpty(password)) { + builder.setPassphrase(Passphrase.fromPassword(password)); } + return builder.build(); } /** @@ -220,37 +216,59 @@ public class KeyRingBuilder implements KeyRingBuilderInterface { */ public PGPSecretKeyRing modernKeyRing(String userId, String password) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException { - WithAdditionalUserIdOrPassphrase builder = this - .withSubKey( - KeySpec.getBuilder(KeyType.XDH(XDHSpec._X25519), KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS) - .build()) - .withSubKey( - KeySpec.getBuilder(KeyType.EDDSA(EdDSACurve._Ed25519), KeyFlag.SIGN_DATA) - .build()) - .withPrimaryKey( - KeySpec.getBuilder(KeyType.EDDSA(EdDSACurve._Ed25519), KeyFlag.CERTIFY_OTHER) - .build()) - .withPrimaryUserId(userId); - - if (password == null) { - return builder.withoutPassphrase().build(); - } else { - return builder.withPassphrase(new Passphrase(password.toCharArray())).build(); + KeyRingBuilder builder = new KeyRingBuilder() + .setPrimaryKey(KeySpec.getBuilder(KeyType.EDDSA(EdDSACurve._Ed25519), KeyFlag.CERTIFY_OTHER)) + .addSubkey(KeySpec.getBuilder(KeyType.XDH(XDHSpec._X25519), KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS)) + .addSubkey(KeySpec.getBuilder(KeyType.EDDSA(EdDSACurve._Ed25519), KeyFlag.SIGN_DATA)) + .addUserId(userId); + if (!isNullOrEmpty(password)) { + builder.setPassphrase(Passphrase.fromPassword(password)); } + return builder.build(); } @Override - public KeyRingBuilderInterface withSubKey(@Nonnull KeySpec type) { - KeyRingBuilder.this.keySpecs.add(type); + public KeyRingBuilder setPrimaryKey(@Nonnull KeySpec keySpec) { + verifyMasterKeyCanCertify(keySpec); + this.primaryKeySpec = keySpec; return this; } @Override - public WithPrimaryUserId withPrimaryKey(@Nonnull KeySpec spec) { - verifyMasterKeyCanCertify(spec); + public KeyRingBuilder addSubkey(@Nonnull KeySpec keySpec) { + this.subkeySpecs.add(keySpec); + return this; + } - KeyRingBuilder.this.keySpecs.add(0, spec); - return new WithPrimaryUserIdImpl(); + @Override + public KeyRingBuilder addUserId(@Nonnull String userId) { + this.userIds.add(userId.trim()); + return this; + } + + @Override + public KeyRingBuilder addUserId(@Nonnull byte[] userId) { + return addUserId(new String(userId, UTF8)); + } + + @Override + public KeyRingBuilder setExpirationDate(@Nonnull Date expirationDate) { + Date now = new Date(); + if (now.after(expirationDate)) { + throw new IllegalArgumentException("Expiration date must be in the future."); + } + this.expirationDate = expirationDate; + return this; + } + + @Override + public KeyRingBuilder setPassphrase(@Nonnull Passphrase passphrase) { + this.passphrase = passphrase; + return this; + } + + private static boolean isNullOrEmpty(String password) { + return password == null || password.trim().isEmpty(); } private void verifyMasterKeyCanCertify(KeySpec spec) { @@ -270,196 +288,139 @@ public class KeyRingBuilder implements KeyRingBuilderInterface { return keySpec.getKeyType().canCertify(); } - class WithPrimaryUserIdImpl implements WithPrimaryUserId { + @Override + public PGPSecretKeyRing build() throws NoSuchAlgorithmException, PGPException, + InvalidAlgorithmParameterException { + if (userIds.isEmpty()) { + throw new IllegalStateException("At least one user-id is required."); + } + digestCalculator = buildDigestCalculator(); + secretKeyEncryptor = buildSecretKeyEncryptor(); + PBESecretKeyDecryptor secretKeyDecryptor = buildSecretKeyDecryptor(); - @Override - public WithAdditionalUserIdOrPassphrase withPrimaryUserId(@Nonnull String userId) { - KeyRingBuilder.this.userId = userId.trim(); - return new WithAdditionalUserIdOrPassphraseImpl(); + if (passphrase != null) { + passphrase.clear(); } - @Override - public WithAdditionalUserIdOrPassphrase withPrimaryUserId(@Nonnull byte[] userId) { - return withPrimaryUserId(new String(userId, UTF8)); + // Generate Primary Key + PGPKeyPair certKey = generateKeyPair(primaryKeySpec); + PGPContentSignerBuilder signer = buildContentSigner(certKey); + signatureGenerator = new PGPSignatureGenerator(signer); + PGPSignatureSubpacketGenerator hashedSubPacketGenerator = primaryKeySpec.getSubpacketGenerator(); + hashedSubPacketGenerator.setPrimaryUserID(false, true); + if (expirationDate != null) { + SignatureSubpacketGeneratorUtil.setExpirationDateInSubpacketGenerator( + expirationDate, new Date(), hashedSubPacketGenerator); + } + PGPSignatureSubpacketVector hashedSubPackets = hashedSubPacketGenerator.generate(); + + // Generator which the user can get the key pair from + PGPKeyRingGenerator ringGenerator = buildRingGenerator(certKey, signer, hashedSubPackets); + + addSubKeys(certKey, ringGenerator); + + // Generate secret key ring with only primary user id + PGPSecretKeyRing secretKeyRing = ringGenerator.generateSecretKeyRing(); + + Iterator secretKeys = secretKeyRing.getSecretKeys(); + + // Attempt to add additional user-ids to the primary public key + PGPPublicKey primaryPubKey = secretKeys.next().getPublicKey(); + PGPPrivateKey privateKey = UnlockSecretKey.unlockSecretKey(secretKeyRing.getSecretKey(), secretKeyDecryptor); + Iterator additionalUserIds = userIds.iterator(); + additionalUserIds.next(); // Skip primary user id + while (additionalUserIds.hasNext()) { + String additionalUserId = additionalUserIds.next(); + signatureGenerator.init(SignatureType.POSITIVE_CERTIFICATION.getCode(), privateKey); + PGPSignature additionalUserIdSignature = + signatureGenerator.generateCertification(additionalUserId, primaryPubKey); + primaryPubKey = PGPPublicKey.addCertification(primaryPubKey, + additionalUserId, additionalUserIdSignature); + } + + // "reassemble" secret key ring with modified primary key + PGPSecretKey primarySecKey = new PGPSecretKey( + privateKey, + primaryPubKey, digestCalculator, true, secretKeyEncryptor); + List secretKeyList = new ArrayList<>(); + secretKeyList.add(primarySecKey); + while (secretKeys.hasNext()) { + secretKeyList.add(secretKeys.next()); + } + secretKeyRing = new PGPSecretKeyRing(secretKeyList); + + return secretKeyRing; + } + + private PGPKeyRingGenerator buildRingGenerator(PGPKeyPair certKey, + PGPContentSignerBuilder signer, + PGPSignatureSubpacketVector hashedSubPackets) + throws PGPException { + String primaryUserId = userIds.iterator().next(); + return new PGPKeyRingGenerator( + SignatureType.POSITIVE_CERTIFICATION.getCode(), certKey, + primaryUserId, digestCalculator, + hashedSubPackets, null, signer, secretKeyEncryptor); + } + + private void addSubKeys(PGPKeyPair primaryKey, PGPKeyRingGenerator ringGenerator) + throws NoSuchAlgorithmException, PGPException, InvalidAlgorithmParameterException { + for (KeySpec subKeySpec : subkeySpecs) { + PGPKeyPair subKey = generateKeyPair(subKeySpec); + if (subKeySpec.isInheritedSubPackets()) { + ringGenerator.addSubKey(subKey); + } else { + PGPSignatureSubpacketVector hashedSubpackets = subKeySpec.getSubpackets(); + try { + hashedSubpackets = addPrimaryKeyBindingSignatureIfNecessary(primaryKey, subKey, hashedSubpackets); + } catch (IOException e) { + throw new PGPException("Exception while adding primary key binding signature to signing subkey", e); + } + ringGenerator.addSubKey(subKey, hashedSubpackets, null); + } } } - class WithAdditionalUserIdOrPassphraseImpl implements WithAdditionalUserIdOrPassphrase { - - @Override - public WithAdditionalUserIdOrPassphrase setExpirationDate(@Nonnull Date expirationDate) { - Date now = new Date(); - if (now.after(expirationDate)) { - throw new IllegalArgumentException("Expiration date must be in the future."); - } - KeyRingBuilder.this.expirationDate = expirationDate; - return this; + private PGPSignatureSubpacketVector addPrimaryKeyBindingSignatureIfNecessary(PGPKeyPair primaryKey, PGPKeyPair subKey, PGPSignatureSubpacketVector hashedSubpackets) throws PGPException, IOException { + int keyFlagMask = hashedSubpackets.getKeyFlags(); + if (!KeyFlag.hasKeyFlag(keyFlagMask, KeyFlag.SIGN_DATA) && !KeyFlag.hasKeyFlag(keyFlagMask, KeyFlag.CERTIFY_OTHER)) { + return hashedSubpackets; } - @Override - public WithAdditionalUserIdOrPassphrase withAdditionalUserId(@Nonnull String userId) { - String trimmed = userId.trim(); - if (KeyRingBuilder.this.userId.equals(trimmed)) { - throw new IllegalArgumentException("Additional user-id MUST NOT be equal to primary user-id."); - } - KeyRingBuilder.this.additionalUserIds.add(trimmed); - return this; - } + PGPSignatureGenerator bindingSignatureGenerator = new PGPSignatureGenerator(buildContentSigner(subKey)); + bindingSignatureGenerator.init(SignatureType.PRIMARYKEY_BINDING.getCode(), subKey.getPrivateKey()); + PGPSignature primaryKeyBindingSig = bindingSignatureGenerator.generateCertification(primaryKey.getPublicKey(), subKey.getPublicKey()); + PGPSignatureSubpacketGenerator subpacketGenerator = new PGPSignatureSubpacketGenerator(hashedSubpackets); + subpacketGenerator.addEmbeddedSignature(false, primaryKeyBindingSig); + return subpacketGenerator.generate(); + } - @Override - public WithAdditionalUserIdOrPassphrase withAdditionalUserId(@Nonnull byte[] userId) { - return withAdditionalUserId(new String(userId, UTF8)); - } + private PGPContentSignerBuilder buildContentSigner(PGPKeyPair certKey) { + HashAlgorithm hashAlgorithm = PGPainless.getPolicy().getSignatureHashAlgorithmPolicy().defaultHashAlgorithm(); + return ImplementationFactory.getInstance().getPGPContentSignerBuilder( + certKey.getPublicKey().getAlgorithm(), + hashAlgorithm.getAlgorithmId()); + } - @Override - public Build withPassphrase(@Nonnull Passphrase passphrase) { - KeyRingBuilder.this.passphrase = passphrase; - return new BuildImpl(); - } + private PBESecretKeyEncryptor buildSecretKeyEncryptor() { + SymmetricKeyAlgorithm keyEncryptionAlgorithm = PGPainless.getPolicy().getSymmetricKeyEncryptionAlgorithmPolicy() + .getDefaultSymmetricKeyAlgorithm(); + PBESecretKeyEncryptor encryptor = passphrase == null || passphrase.isEmpty() ? + null : // unencrypted key pair, otherwise AES-256 encrypted + ImplementationFactory.getInstance().getPBESecretKeyEncryptor( + keyEncryptionAlgorithm, digestCalculator, passphrase); + return encryptor; + } - @Override - public Build withoutPassphrase() { - KeyRingBuilder.this.passphrase = null; - return new BuildImpl(); - } + private PBESecretKeyDecryptor buildSecretKeyDecryptor() throws PGPException { + PBESecretKeyDecryptor decryptor = passphrase == null || passphrase.isEmpty() ? + null : + ImplementationFactory.getInstance().getPBESecretKeyDecryptor(passphrase); + return decryptor; + } - class BuildImpl implements Build { - - private PGPSignatureGenerator signatureGenerator; - private PGPDigestCalculator digestCalculator; - private PBESecretKeyEncryptor secretKeyEncryptor; - - @Override - public PGPSecretKeyRing build() throws NoSuchAlgorithmException, PGPException, - InvalidAlgorithmParameterException { - digestCalculator = buildDigestCalculator(); - secretKeyEncryptor = buildSecretKeyEncryptor(); - PBESecretKeyDecryptor secretKeyDecryptor = buildSecretKeyDecryptor(); - - if (passphrase != null) { - passphrase.clear(); - } - - // First key is the Master Key - KeySpec certKeySpec = keySpecs.remove(0); - - // Generate Master Key - PGPKeyPair certKey = generateKeyPair(certKeySpec); - PGPContentSignerBuilder signer = buildContentSigner(certKey); - signatureGenerator = new PGPSignatureGenerator(signer); - PGPSignatureSubpacketGenerator hashedSubPacketGenerator = certKeySpec.getSubpacketGenerator(); - hashedSubPacketGenerator.setPrimaryUserID(false, true); - if (expirationDate != null) { - SignatureSubpacketGeneratorUtil.setExpirationDateInSubpacketGenerator( - expirationDate, new Date(), hashedSubPacketGenerator); - } - PGPSignatureSubpacketVector hashedSubPackets = hashedSubPacketGenerator.generate(); - - // Generator which the user can get the key pair from - PGPKeyRingGenerator ringGenerator = buildRingGenerator(certKey, signer, hashedSubPackets); - - addSubKeys(certKey, ringGenerator); - - // Generate secret key ring with only primary user id - PGPSecretKeyRing secretKeyRing = ringGenerator.generateSecretKeyRing(); - - Iterator secretKeys = secretKeyRing.getSecretKeys(); - - // Attempt to add additional user-ids to the primary public key - PGPPublicKey primaryPubKey = secretKeys.next().getPublicKey(); - PGPPrivateKey privateKey = UnlockSecretKey.unlockSecretKey(secretKeyRing.getSecretKey(), secretKeyDecryptor); - for (String additionalUserId : additionalUserIds) { - signatureGenerator.init(SignatureType.POSITIVE_CERTIFICATION.getCode(), privateKey); - PGPSignature additionalUserIdSignature = - signatureGenerator.generateCertification(additionalUserId, primaryPubKey); - primaryPubKey = PGPPublicKey.addCertification(primaryPubKey, - additionalUserId, additionalUserIdSignature); - } - - // "reassemble" secret key ring with modified primary key - PGPSecretKey primarySecKey = new PGPSecretKey( - privateKey, - primaryPubKey, digestCalculator, true, secretKeyEncryptor); - List secretKeyList = new ArrayList<>(); - secretKeyList.add(primarySecKey); - while (secretKeys.hasNext()) { - secretKeyList.add(secretKeys.next()); - } - secretKeyRing = new PGPSecretKeyRing(secretKeyList); - - return secretKeyRing; - } - - private PGPKeyRingGenerator buildRingGenerator(PGPKeyPair certKey, - PGPContentSignerBuilder signer, - PGPSignatureSubpacketVector hashedSubPackets) - throws PGPException { - return new PGPKeyRingGenerator( - SignatureType.POSITIVE_CERTIFICATION.getCode(), certKey, - userId, digestCalculator, - hashedSubPackets, null, signer, secretKeyEncryptor); - } - - private void addSubKeys(PGPKeyPair primaryKey, PGPKeyRingGenerator ringGenerator) - throws NoSuchAlgorithmException, PGPException, InvalidAlgorithmParameterException { - for (KeySpec subKeySpec : keySpecs) { - PGPKeyPair subKey = generateKeyPair(subKeySpec); - if (subKeySpec.isInheritedSubPackets()) { - ringGenerator.addSubKey(subKey); - } else { - PGPSignatureSubpacketVector hashedSubpackets = subKeySpec.getSubpackets(); - try { - hashedSubpackets = addPrimaryKeyBindingSignatureIfNecessary(primaryKey, subKey, hashedSubpackets); - } catch (IOException e) { - throw new PGPException("Exception while adding primary key binding signature to signing subkey", e); - } - ringGenerator.addSubKey(subKey, hashedSubpackets, null); - } - } - } - - private PGPSignatureSubpacketVector addPrimaryKeyBindingSignatureIfNecessary(PGPKeyPair primaryKey, PGPKeyPair subKey, PGPSignatureSubpacketVector hashedSubpackets) throws PGPException, IOException { - int keyFlagMask = hashedSubpackets.getKeyFlags(); - if (!KeyFlag.hasKeyFlag(keyFlagMask, KeyFlag.SIGN_DATA) && !KeyFlag.hasKeyFlag(keyFlagMask, KeyFlag.CERTIFY_OTHER)) { - return hashedSubpackets; - } - - PGPSignatureGenerator bindingSignatureGenerator = new PGPSignatureGenerator(buildContentSigner(subKey)); - bindingSignatureGenerator.init(SignatureType.PRIMARYKEY_BINDING.getCode(), subKey.getPrivateKey()); - PGPSignature primaryKeyBindingSig = bindingSignatureGenerator.generateCertification(primaryKey.getPublicKey(), subKey.getPublicKey()); - PGPSignatureSubpacketGenerator subpacketGenerator = new PGPSignatureSubpacketGenerator(hashedSubpackets); - subpacketGenerator.addEmbeddedSignature(false, primaryKeyBindingSig); - return subpacketGenerator.generate(); - } - - private PGPContentSignerBuilder buildContentSigner(PGPKeyPair certKey) { - HashAlgorithm hashAlgorithm = PGPainless.getPolicy().getSignatureHashAlgorithmPolicy().defaultHashAlgorithm(); - return ImplementationFactory.getInstance().getPGPContentSignerBuilder( - certKey.getPublicKey().getAlgorithm(), - hashAlgorithm.getAlgorithmId()); - } - - private PBESecretKeyEncryptor buildSecretKeyEncryptor() { - SymmetricKeyAlgorithm keyEncryptionAlgorithm = PGPainless.getPolicy().getSymmetricKeyEncryptionAlgorithmPolicy() - .getDefaultSymmetricKeyAlgorithm(); - PBESecretKeyEncryptor encryptor = passphrase == null || passphrase.isEmpty() ? - null : // unencrypted key pair, otherwise AES-256 encrypted - ImplementationFactory.getInstance().getPBESecretKeyEncryptor( - keyEncryptionAlgorithm, digestCalculator, passphrase); - return encryptor; - } - - private PBESecretKeyDecryptor buildSecretKeyDecryptor() throws PGPException { - PBESecretKeyDecryptor decryptor = passphrase == null || passphrase.isEmpty() ? - null : - ImplementationFactory.getInstance().getPBESecretKeyDecryptor(passphrase); - return decryptor; - } - - private PGPDigestCalculator buildDigestCalculator() throws PGPException { - return ImplementationFactory.getInstance().getPGPDigestCalculator(HashAlgorithm.SHA1); - } - } + private PGPDigestCalculator buildDigestCalculator() throws PGPException { + return ImplementationFactory.getInstance().getPGPDigestCalculator(HashAlgorithm.SHA1); } public static PGPKeyPair generateKeyPair(KeySpec spec) diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilderInterface.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilderInterface.java index 8ddaff34..1113158b 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilderInterface.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilderInterface.java @@ -25,50 +25,32 @@ import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.pgpainless.key.util.UserId; import org.pgpainless.util.Passphrase; -public interface KeyRingBuilderInterface { +public interface KeyRingBuilderInterface> { - KeyRingBuilderInterface withSubKey(@Nonnull KeySpec keySpec); - - WithPrimaryUserId withPrimaryKey(@Nonnull KeySpec keySpec); - - interface WithPrimaryUserId { - - default WithAdditionalUserIdOrPassphrase withPrimaryUserId(@Nonnull UserId userId) { - return withPrimaryUserId(userId.toString()); - } - - WithAdditionalUserIdOrPassphrase withPrimaryUserId(@Nonnull String userId); - - WithAdditionalUserIdOrPassphrase withPrimaryUserId(@Nonnull byte[] userId); + B setPrimaryKey(@Nonnull KeySpec keySpec); + default B setPrimaryKey(@Nonnull KeySpecBuilder builder) { + return setPrimaryKey(builder.build()); } - interface WithAdditionalUserIdOrPassphrase { + B addSubkey(@Nonnull KeySpec keySpec); - default WithAdditionalUserIdOrPassphrase withAdditionalUserId(@Nonnull UserId userId) { - return withAdditionalUserId(userId.toString()); - } - - /** - * Set an expiration date for the key. - * - * @param expirationDate date on which the key will expire. - * @return builder - */ - WithAdditionalUserIdOrPassphrase setExpirationDate(@Nonnull Date expirationDate); - - WithAdditionalUserIdOrPassphrase withAdditionalUserId(@Nonnull String userId); - - WithAdditionalUserIdOrPassphrase withAdditionalUserId(@Nonnull byte[] userId); - - Build withPassphrase(@Nonnull Passphrase passphrase); - - Build withoutPassphrase(); + default B addSubkey(@Nonnull KeySpecBuilder builder) { + return addSubkey(builder.build()); } - interface Build { + default B addUserId(UserId userId) { + return addUserId(userId.toString()); + } - PGPSecretKeyRing build() throws NoSuchAlgorithmException, PGPException, + B addUserId(@Nonnull String userId); + + B addUserId(@Nonnull byte[] userId); + + B setExpirationDate(@Nonnull Date expirationDate); + + B setPassphrase(@Nonnull Passphrase passphrase); + + PGPSecretKeyRing build() throws NoSuchAlgorithmException, PGPException, InvalidAlgorithmParameterException; - } } diff --git a/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/EncryptDecryptTest.java b/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/EncryptDecryptTest.java index c7bd68dc..175ea7ac 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/EncryptDecryptTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/EncryptDecryptTest.java @@ -88,14 +88,13 @@ public class EncryptDecryptTest { ImplementationFactory.setFactoryImplementation(implementationFactory); PGPSecretKeyRing sender = PGPainless.generateKeyRing().simpleRsaKeyRing("romeo@montague.lit", RsaLength._3072); PGPSecretKeyRing recipient = PGPainless.generateKeyRing() - .withSubKey(KeySpec.getBuilder( - ElGamal.withLength(ElGamalLength._3072), - KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS) - .build()) - .withPrimaryKey(KeySpec.getBuilder( + .setPrimaryKey(KeySpec.getBuilder( KeyType.RSA(RsaLength._4096), - KeyFlag.SIGN_DATA, KeyFlag.CERTIFY_OTHER).build()) - .withPrimaryUserId("juliet@capulet.lit").withoutPassphrase().build(); + KeyFlag.SIGN_DATA, KeyFlag.CERTIFY_OTHER)) + .addSubkey(KeySpec.getBuilder( + ElGamal.withLength(ElGamalLength._3072), + KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS)) + .addUserId("juliet@capulet.lit").build(); encryptDecryptForSecretKeyRings(sender, recipient); } diff --git a/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/EncryptionOptionsTest.java b/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/EncryptionOptionsTest.java index f0aef576..f8971467 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/EncryptionOptionsTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/EncryptionOptionsTest.java @@ -59,14 +59,13 @@ public class EncryptionOptionsTest { @BeforeAll public static void generateKey() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException { secretKeys = PGPainless.generateKeyRing() - .withSubKey(KeySpec.getBuilder(KeyType.XDH(XDHSpec._X25519), KeyFlag.ENCRYPT_COMMS) + .setPrimaryKey(KeySpec.getBuilder(KeyType.EDDSA(EdDSACurve._Ed25519), KeyFlag.CERTIFY_OTHER) .build()) - .withSubKey(KeySpec.getBuilder(KeyType.XDH(XDHSpec._X25519), KeyFlag.ENCRYPT_STORAGE) + .addSubkey(KeySpec.getBuilder(KeyType.XDH(XDHSpec._X25519), KeyFlag.ENCRYPT_COMMS) .build()) - .withPrimaryKey(KeySpec.getBuilder(KeyType.EDDSA(EdDSACurve._Ed25519), KeyFlag.CERTIFY_OTHER) + .addSubkey(KeySpec.getBuilder(KeyType.XDH(XDHSpec._X25519), KeyFlag.ENCRYPT_STORAGE) .build()) - .withPrimaryUserId("test@pgpainless.org") - .withoutPassphrase() + .addUserId("test@pgpainless.org") .build(); publicKeys = KeyRingUtils.publicKeyRingFrom(secretKeys); @@ -139,10 +138,9 @@ public class EncryptionOptionsTest { public void testAddRecipient_KeyWithoutEncryptionKeyFails() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException { EncryptionOptions options = new EncryptionOptions(); PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() - .withPrimaryKey(KeySpec.getBuilder(KeyType.EDDSA(EdDSACurve._Ed25519), KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA) - .build()) - .withPrimaryUserId("test@pgpainless.org") - .withoutPassphrase().build(); + .setPrimaryKey(KeySpec.getBuilder(KeyType.EDDSA(EdDSACurve._Ed25519), KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)) + .addUserId("test@pgpainless.org") + .build(); PGPPublicKeyRing publicKeys = KeyRingUtils.publicKeyRingFrom(secretKeys); assertThrows(IllegalArgumentException.class, () -> options.addRecipient(publicKeys)); diff --git a/pgpainless-core/src/test/java/org/pgpainless/example/GenerateKeys.java b/pgpainless-core/src/test/java/org/pgpainless/example/GenerateKeys.java index 75e847f5..e88c906f 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/example/GenerateKeys.java +++ b/pgpainless-core/src/test/java/org/pgpainless/example/GenerateKeys.java @@ -21,6 +21,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; +import java.util.Date; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPublicKeyRing; @@ -34,6 +35,7 @@ import org.pgpainless.algorithm.KeyFlag; import org.pgpainless.algorithm.PublicKeyAlgorithm; import org.pgpainless.algorithm.SymmetricKeyAlgorithm; import org.pgpainless.key.generation.KeySpec; +import org.pgpainless.key.generation.KeySpecBuilder; import org.pgpainless.key.generation.type.KeyType; import org.pgpainless.key.generation.type.ecc.EllipticCurve; import org.pgpainless.key.generation.type.eddsa.EdDSACurve; @@ -156,10 +158,11 @@ public class GenerateKeys { * algorithm preferences. * * If the target key amalgamation (key ring) should consist of more than just a single (sub-)key, start by providing - * the specifications for the subkeys first (in {@link org.pgpainless.key.generation.KeyRingBuilderInterface#withSubKey(KeySpec)}) - * and add the primary key specification last (in {@link org.pgpainless.key.generation.KeyRingBuilderInterface#withPrimaryKey(KeySpec)}. + * the primary key specification using {@link org.pgpainless.key.generation.KeyRingBuilder#setPrimaryKey(KeySpec)}. + * Any additional subkeys can be then added using {@link org.pgpainless.key.generation.KeyRingBuilder#addSubkey(KeySpec)}. * - * {@link KeySpec} objects can best be obtained by using the {@link KeySpec#getBuilder(KeyType, KeyFlag...)} method and providing a {@link KeyType}. + * {@link KeySpec} objects can best be obtained by using the {@link KeySpec#getBuilder(KeyType, KeyFlag, KeyFlag...)} + * method and providing a {@link KeyType}. * There are a bunch of factory methods for different {@link KeyType} implementations present in {@link KeyType} itself * (such as {@link KeyType#ECDH(EllipticCurve)}. {@link KeyFlag KeyFlags} determine * the use of the key, like encryption, signing data or certifying subkeys. @@ -171,16 +174,18 @@ public class GenerateKeys { * * Note, that if you set preferred algorithms, the preference lists are sorted from high priority to low priority. * - * When setting the primary key spec ({@link org.pgpainless.key.generation.KeyRingBuilder#withPrimaryKey(KeySpec)}), + * When setting the primary key spec ({@link org.pgpainless.key.generation.KeyRingBuilder#setPrimaryKey(KeySpecBuilder)}), * make sure that the primary key spec has the {@link KeyFlag} {@link KeyFlag#CERTIFY_OTHER} set, as this is a requirement * for primary keys. * * Furthermore you have to set at least the primary user-id via - * {@link org.pgpainless.key.generation.KeyRingBuilderInterface.WithPrimaryUserId#withPrimaryUserId(String)}, - * but you can also add additional user-ids via - * {@link org.pgpainless.key.generation.KeyRingBuilderInterface.WithAdditionalUserIdOrPassphrase#withAdditionalUserId(String)}. + * {@link org.pgpainless.key.generation.KeyRingBuilder#addUserId(String)}, + * but you can also add additional user-ids. * - * Lastly you can decide whether to set a passphrase to protect the secret key. + * If you want the key to expire at a certain point in time, call + * {@link org.pgpainless.key.generation.KeyRingBuilder#setExpirationDate(Date)}. + * Lastly you can decide whether to set a passphrase to protect the secret key using + * {@link org.pgpainless.key.generation.KeyRingBuilder#setPassphrase(Passphrase)}. * * @throws PGPException * @throws InvalidAlgorithmParameterException @@ -201,43 +206,35 @@ public class GenerateKeys { Passphrase passphrase = Passphrase.fromPassword("1nters3x"); PGPSecretKeyRing secretKey = PGPainless.generateKeyRing() + .setPrimaryKey(KeySpec.getBuilder(KeyType.EDDSA(EdDSACurve._Ed25519), + // The primary key MUST carry the CERTIFY_OTHER flag, but CAN carry additional flags + KeyFlag.CERTIFY_OTHER)) // Add the first subkey (in this case encryption) - .withSubKey( - KeySpec.getBuilder( - // We choose an ECDH key over the brainpoolp256r1 curve - KeyType.ECDH(EllipticCurve._BRAINPOOLP256R1), - // Our key can encrypt both communication data, as well as data at rest - KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS - ) - // Optionally: Configure the subkey with custom algorithm preferences - // Is is recommended though to go with PGPainless' defaults which can be found in the - // AlgorithmSuite class. - .overridePreferredSymmetricKeyAlgorithms(SymmetricKeyAlgorithm.AES_256, SymmetricKeyAlgorithm.AES_192, SymmetricKeyAlgorithm.AES_128) - .overridePreferredHashAlgorithms(HashAlgorithm.SHA512, HashAlgorithm.SHA384, HashAlgorithm.SHA256) - .overridePreferredCompressionAlgorithms(CompressionAlgorithm.ZIP, CompressionAlgorithm.BZIP2, CompressionAlgorithm.ZLIB) - .build() - ) + .addSubkey(KeySpec.getBuilder( + // We choose an ECDH key over the brainpoolp256r1 curve + KeyType.ECDH(EllipticCurve._BRAINPOOLP256R1), + // Our key can encrypt both communication data, as well as data at rest + KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS + ) + // Optionally: Configure the subkey with custom algorithm preferences + // Is is recommended though to go with PGPainless' defaults which can be found in the + // AlgorithmSuite class. + .overridePreferredSymmetricKeyAlgorithms(SymmetricKeyAlgorithm.AES_256, SymmetricKeyAlgorithm.AES_192, SymmetricKeyAlgorithm.AES_128) + .overridePreferredHashAlgorithms(HashAlgorithm.SHA512, HashAlgorithm.SHA384, HashAlgorithm.SHA256) + .overridePreferredCompressionAlgorithms(CompressionAlgorithm.ZIP, CompressionAlgorithm.BZIP2, CompressionAlgorithm.ZLIB) + .build()) // Add the second subkey (signing) - .withSubKey( - KeySpec.getBuilder( - KeyType.ECDSA(EllipticCurve._BRAINPOOLP384R1), - // This key is used for creating signatures only - KeyFlag.SIGN_DATA - ).build() - ) - // Lastly we add the primary key (certification only in our case) - .withPrimaryKey( - KeySpec.getBuilder(KeyType.EDDSA(EdDSACurve._Ed25519), - // The primary key MUST carry the CERTIFY_OTHER flag, but CAN carry additional flags - KeyFlag.CERTIFY_OTHER) - .build() - ) + .addSubkey(KeySpec.getBuilder( + KeyType.ECDSA(EllipticCurve._BRAINPOOLP384R1), + // This key is used for creating signatures only + KeyFlag.SIGN_DATA + )) // Set primary user-id - .withPrimaryUserId(userId) + .addUserId(userId) // Add an additional user id. This step can be repeated - .withAdditionalUserId(additionalUserId) + .addUserId(additionalUserId) // Set passphrase. Alternatively use .withoutPassphrase() to leave key unprotected. - .withPassphrase(passphrase) + .setPassphrase(passphrase) .build(); diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/generation/BrainpoolKeyGenerationTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/generation/BrainpoolKeyGenerationTest.java index aeafaf59..b94d5622 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/key/generation/BrainpoolKeyGenerationTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/key/generation/BrainpoolKeyGenerationTest.java @@ -83,17 +83,15 @@ public class BrainpoolKeyGenerationTest { ImplementationFactory.setFactoryImplementation(implementationFactory); PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() - .withSubKey(KeySpec.getBuilder(KeyType.EDDSA(EdDSACurve._Ed25519), KeyFlag.SIGN_DATA).build()) - .withSubKey(KeySpec.getBuilder( - KeyType.XDH(XDHSpec._X25519), KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE) - .build()) - .withSubKey(KeySpec.getBuilder( - KeyType.RSA(RsaLength._3072), KeyFlag.SIGN_DATA) - .build()) - .withPrimaryKey(KeySpec.getBuilder( - KeyType.ECDSA(EllipticCurve._BRAINPOOLP384R1), KeyFlag.CERTIFY_OTHER).build()) - .withPrimaryUserId(UserId.nameAndEmail("Alice", "alice@pgpainless.org")) - .withPassphrase(Passphrase.fromPassword("passphrase")) + .setPrimaryKey(KeySpec.getBuilder( + KeyType.ECDSA(EllipticCurve._BRAINPOOLP384R1), KeyFlag.CERTIFY_OTHER)) + .addSubkey(KeySpec.getBuilder(KeyType.EDDSA(EdDSACurve._Ed25519), KeyFlag.SIGN_DATA)) + .addSubkey(KeySpec.getBuilder( + KeyType.XDH(XDHSpec._X25519), KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE)) + .addSubkey(KeySpec.getBuilder( + KeyType.RSA(RsaLength._3072), KeyFlag.SIGN_DATA)) + .addUserId(UserId.nameAndEmail("Alice", "alice@pgpainless.org")) + .setPassphrase(Passphrase.fromPassword("passphrase")) .build(); for (PGPSecretKey key : secretKeys) { @@ -131,10 +129,9 @@ public class BrainpoolKeyGenerationTest { public PGPSecretKeyRing generateKey(KeySpec primaryKey, KeySpec subKey, String userId) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException { PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() - .withSubKey(subKey) - .withPrimaryKey(primaryKey) - .withPrimaryUserId(userId) - .withoutPassphrase() + .setPrimaryKey(primaryKey) + .addSubkey(subKey) + .addUserId(userId) .build(); return secretKeys; } diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/generation/CertificationKeyMustBeAbleToCertifyTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/generation/CertificationKeyMustBeAbleToCertifyTest.java index 65b7a71f..ff48d159 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/key/generation/CertificationKeyMustBeAbleToCertifyTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/key/generation/CertificationKeyMustBeAbleToCertifyTest.java @@ -46,11 +46,9 @@ public class CertificationKeyMustBeAbleToCertifyTest { for (KeyType type : typesIncapableOfCreatingVerifications) { assertThrows(IllegalArgumentException.class, () -> PGPainless .generateKeyRing() - .withPrimaryKey(KeySpec - .getBuilder(type, KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA) - .build()) - .withPrimaryUserId("should@throw.ex") - .withoutPassphrase().build()); + .setPrimaryKey(KeySpec.getBuilder(type, KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)) + .addUserId("should@throw.ex") + .build()); } } } diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateEllipticCurveKeyTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateEllipticCurveKeyTest.java index 9e60eca6..bf28aac0 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateEllipticCurveKeyTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateEllipticCurveKeyTest.java @@ -41,13 +41,11 @@ public class GenerateEllipticCurveKeyTest { public void generateEllipticCurveKeys(ImplementationFactory implementationFactory) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException, IOException { ImplementationFactory.setFactoryImplementation(implementationFactory); PGPSecretKeyRing keyRing = PGPainless.generateKeyRing() - .withSubKey(KeySpec.getBuilder(KeyType.XDH(XDHSpec._X25519), KeyFlag.ENCRYPT_COMMS).build()) - .withPrimaryKey(KeySpec.getBuilder( + .setPrimaryKey(KeySpec.getBuilder( KeyType.EDDSA(EdDSACurve._Ed25519), - KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA) - .build()) - .withPrimaryUserId(UserId.onlyEmail("alice@wonderland.lit").toString()) - .withoutPassphrase() + KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)) + .addSubkey(KeySpec.getBuilder(KeyType.XDH(XDHSpec._X25519), KeyFlag.ENCRYPT_COMMS)) + .addUserId(UserId.onlyEmail("alice@wonderland.lit").toString()) .build(); assertEquals(PublicKeyAlgorithm.EDDSA.getAlgorithmId(), keyRing.getPublicKey().getAlgorithm()); diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateKeyWithAdditionalUserIdTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateKeyWithAdditionalUserIdTest.java index 33db6fc5..f3378df0 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateKeyWithAdditionalUserIdTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateKeyWithAdditionalUserIdTest.java @@ -47,16 +47,14 @@ public class GenerateKeyWithAdditionalUserIdTest { ImplementationFactory.setFactoryImplementation(implementationFactory); Date expiration = new Date(DateUtil.now().getTime() + 60 * 1000); PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() - .withPrimaryKey(KeySpec.getBuilder( + .setPrimaryKey(KeySpec.getBuilder( KeyType.RSA(RsaLength._3072), - KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA, KeyFlag.ENCRYPT_COMMS) - .build()) - .withPrimaryUserId(UserId.onlyEmail("primary@user.id")) - .withAdditionalUserId(UserId.onlyEmail("additional@user.id")) - .withAdditionalUserId(UserId.onlyEmail("additional2@user.id")) - .withAdditionalUserId("\ttrimThis@user.id ") + KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA, KeyFlag.ENCRYPT_COMMS)) + .addUserId(UserId.onlyEmail("primary@user.id")) + .addUserId(UserId.onlyEmail("additional@user.id")) + .addUserId(UserId.onlyEmail("additional2@user.id")) + .addUserId("\ttrimThis@user.id ") .setExpirationDate(expiration) - .withoutPassphrase() .build(); PGPPublicKeyRing publicKeys = KeyRingUtils.publicKeyRingFrom(secretKeys); diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateWithEmptyPassphrase.java b/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateWithEmptyPassphraseTest.java similarity index 88% rename from pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateWithEmptyPassphrase.java rename to pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateWithEmptyPassphraseTest.java index 60e7c131..39d1e6ef 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateWithEmptyPassphrase.java +++ b/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateWithEmptyPassphraseTest.java @@ -38,7 +38,7 @@ import org.pgpainless.util.Passphrase; * The issue is that the implementation of {@link Passphrase#emptyPassphrase()} would set the underlying * char array to null, which caused an NPE later on. */ -public class GenerateWithEmptyPassphrase { +public class GenerateWithEmptyPassphraseTest { @ParameterizedTest @MethodSource("org.pgpainless.util.TestImplementationFactoryProvider#provideImplementationFactories") @@ -46,12 +46,11 @@ public class GenerateWithEmptyPassphrase { ImplementationFactory.setFactoryImplementation(implementationFactory); assertNotNull(PGPainless.generateKeyRing() - .withPrimaryKey(KeySpec.getBuilder( + .setPrimaryKey(KeySpec.getBuilder( KeyType.RSA(RsaLength._3072), - KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA, KeyFlag.ENCRYPT_COMMS) - .build()) - .withPrimaryUserId("primary@user.id") - .withPassphrase(Passphrase.emptyPassphrase()) + KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA, KeyFlag.ENCRYPT_COMMS)) + .addUserId("primary@user.id") + .setPassphrase(Passphrase.emptyPassphrase()) .build()); } } diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/info/KeyRingInfoTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/info/KeyRingInfoTest.java index f1413a97..fe2191e5 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/key/info/KeyRingInfoTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/key/info/KeyRingInfoTest.java @@ -221,16 +221,14 @@ public class KeyRingInfoTest { ImplementationFactory.setFactoryImplementation(implementationFactory); PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() - .withSubKey(KeySpec.getBuilder( + .setPrimaryKey(KeySpec.getBuilder( + KeyType.EDDSA(EdDSACurve._Ed25519), KeyFlag.CERTIFY_OTHER)) + .addSubkey(KeySpec.getBuilder( KeyType.ECDH(EllipticCurve._BRAINPOOLP384R1), - KeyFlag.ENCRYPT_STORAGE).build()) - .withSubKey(KeySpec.getBuilder( - KeyType.ECDSA(EllipticCurve._BRAINPOOLP384R1), KeyFlag.SIGN_DATA) - .build()) - .withPrimaryKey(KeySpec.getBuilder( - KeyType.EDDSA(EdDSACurve._Ed25519), KeyFlag.CERTIFY_OTHER).build()) - .withPrimaryUserId(UserId.newBuilder().withName("Alice").withEmail("alice@pgpainless.org").build()) - .withoutPassphrase() + KeyFlag.ENCRYPT_STORAGE)) + .addSubkey(KeySpec.getBuilder( + KeyType.ECDSA(EllipticCurve._BRAINPOOLP384R1), KeyFlag.SIGN_DATA)) + .addUserId(UserId.newBuilder().withName("Alice").withEmail("alice@pgpainless.org").build()) .build(); Iterator keys = secretKeys.iterator(); diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/info/UserIdRevocationTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/info/UserIdRevocationTest.java index fce78fcd..a6d9a006 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/key/info/UserIdRevocationTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/key/info/UserIdRevocationTest.java @@ -51,16 +51,13 @@ public class UserIdRevocationTest { @Test public void testRevocationWithoutRevocationAttributes() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException { PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() - .withSubKey(KeySpec.getBuilder( - KeyType.XDH(XDHSpec._X25519), KeyFlag.ENCRYPT_COMMS) - .build()) - .withPrimaryKey(KeySpec.getBuilder( + .setPrimaryKey(KeySpec.getBuilder( KeyType.EDDSA(EdDSACurve._Ed25519), - KeyFlag.SIGN_DATA, KeyFlag.CERTIFY_OTHER) - .build()) - .withPrimaryUserId("primary@key.id") - .withAdditionalUserId("secondary@key.id") - .withoutPassphrase() + KeyFlag.SIGN_DATA, KeyFlag.CERTIFY_OTHER)) + .addSubkey(KeySpec.getBuilder( + KeyType.XDH(XDHSpec._X25519), KeyFlag.ENCRYPT_COMMS)) + .addUserId("primary@key.id") + .addUserId("secondary@key.id") .build(); // make a copy with revoked subkey @@ -92,15 +89,12 @@ public class UserIdRevocationTest { @Test public void testRevocationWithRevocationReason() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException { PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() - .withSubKey(KeySpec.getBuilder(KeyType.XDH(XDHSpec._X25519), KeyFlag.ENCRYPT_COMMS) - .build()) - .withPrimaryKey(KeySpec.getBuilder( + .setPrimaryKey(KeySpec.getBuilder( KeyType.EDDSA(EdDSACurve._Ed25519), - KeyFlag.SIGN_DATA, KeyFlag.CERTIFY_OTHER) - .build()) - .withPrimaryUserId("primary@key.id") - .withAdditionalUserId("secondary@key.id") - .withoutPassphrase() + KeyFlag.SIGN_DATA, KeyFlag.CERTIFY_OTHER)) + .addSubkey(KeySpec.getBuilder(KeyType.XDH(XDHSpec._X25519), KeyFlag.ENCRYPT_COMMS)) + .addUserId("primary@key.id") + .addUserId("secondary@key.id") .build(); secretKeys = PGPainless.modifyKeyRing(secretKeys) @@ -147,6 +141,6 @@ public class UserIdRevocationTest { assertThrows(IllegalArgumentException.class, () -> PGPainless.modifyKeyRing(secretKeys) .revokeUserId("cryptie@encrypted.key", protector, RevocationAttributes.createKeyRevocation().withReason(RevocationAttributes.Reason.KEY_RETIRED) - .withDescription("This is not a valid certification revocation reason."))); + .withDescription("This is not a valid certification revocation reason."))); } } diff --git a/pgpainless-core/src/test/java/org/pgpainless/util/BCUtilTest.java b/pgpainless-core/src/test/java/org/pgpainless/util/BCUtilTest.java index 7cee1a7c..fc71b3f3 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/util/BCUtilTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/util/BCUtilTest.java @@ -47,12 +47,12 @@ public class BCUtilTest { throws PGPException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, IOException { PGPSecretKeyRing sec = PGPainless.generateKeyRing() - .withSubKey(KeySpec.getBuilder(KeyType.RSA(RsaLength._3072), KeyFlag.ENCRYPT_COMMS).build()) - .withPrimaryKey(KeySpec.getBuilder( + .setPrimaryKey(KeySpec.getBuilder( KeyType.RSA(RsaLength._3072), - KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA) - .build()) - .withPrimaryUserId("donald@duck.tails").withoutPassphrase().build(); + KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)) + .addSubkey(KeySpec.getBuilder(KeyType.RSA(RsaLength._3072), KeyFlag.ENCRYPT_COMMS)) + .addUserId("donald@duck.tails") + .build(); PGPPublicKeyRing pub = KeyRingUtils.publicKeyRingFrom(sec); diff --git a/pgpainless-core/src/test/java/org/pgpainless/util/GuessPreferredHashAlgorithmTest.java b/pgpainless-core/src/test/java/org/pgpainless/util/GuessPreferredHashAlgorithmTest.java index 05f676cf..ab3ba986 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/util/GuessPreferredHashAlgorithmTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/util/GuessPreferredHashAlgorithmTest.java @@ -41,14 +41,12 @@ public class GuessPreferredHashAlgorithmTest { @Test public void guessPreferredHashAlgorithmsAssumesHashAlgoUsedBySelfSig() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException, IOException { PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() - .withPrimaryKey(KeySpec.getBuilder(KeyType.EDDSA(EdDSACurve._Ed25519), + .setPrimaryKey(KeySpec.getBuilder(KeyType.EDDSA(EdDSACurve._Ed25519), KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA) .overridePreferredHashAlgorithms(new HashAlgorithm[] {}) .overridePreferredSymmetricKeyAlgorithms(new SymmetricKeyAlgorithm[] {}) - .overridePreferredCompressionAlgorithms(new CompressionAlgorithm[] {}) - .build()) - .withPrimaryUserId("test@test.test") - .withoutPassphrase() + .overridePreferredCompressionAlgorithms(new CompressionAlgorithm[] {})) + .addUserId("test@test.test") .build(); PGPPublicKey publicKey = secretKeys.getPublicKey(); diff --git a/pgpainless-core/src/test/java/org/pgpainless/weird_keys/TestEncryptCommsStorageFlagsDifferentiated.java b/pgpainless-core/src/test/java/org/pgpainless/weird_keys/TestEncryptCommsStorageFlagsDifferentiated.java index 4bf93212..e08bd54a 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/weird_keys/TestEncryptCommsStorageFlagsDifferentiated.java +++ b/pgpainless-core/src/test/java/org/pgpainless/weird_keys/TestEncryptCommsStorageFlagsDifferentiated.java @@ -38,14 +38,13 @@ public class TestEncryptCommsStorageFlagsDifferentiated { @Test public void testThatEncryptionDifferentiatesBetweenPurposeKeyFlags() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException, IOException { PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() - .withPrimaryKey(KeySpec.getBuilder( + .setPrimaryKey(KeySpec.getBuilder( KeyType.RSA(RsaLength._3072), KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA, KeyFlag.ENCRYPT_STORAGE // no ENCRYPT_COMMS - ).build()) - .withPrimaryUserId("cannot@encrypt.comms") - .withoutPassphrase() + )) + .addUserId("cannot@encrypt.comms") .build(); PGPPublicKeyRing publicKeys = KeyRingUtils.publicKeyRingFrom(secretKeys);