From 2d46fb18f775d6298b95d3f2dcd331d573b45e08 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Tue, 13 Dec 2022 17:02:53 +0100 Subject: [PATCH] SOP: Allow generation of keys without user-ids --- .../key/generation/KeyRingTemplates.java | 53 ++++++++++--------- .../org/pgpainless/sop/GenerateKeyImpl.java | 9 ++-- .../org/pgpainless/sop/GenerateKeyTest.java | 7 --- 3 files changed, 32 insertions(+), 37 deletions(-) diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingTemplates.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingTemplates.java index 444e7d74..42eb7efa 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingTemplates.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingTemplates.java @@ -7,6 +7,7 @@ package org.pgpainless.key.generation; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPSecretKeyRing; @@ -38,9 +39,9 @@ public final class KeyRingTemplates { * @throws NoSuchAlgorithmException in case of missing algorithm implementation in the crypto provider * @throws PGPException in case of an OpenPGP related error */ - public PGPSecretKeyRing simpleRsaKeyRing(@Nonnull UserId userId, @Nonnull RsaLength length) + public PGPSecretKeyRing simpleRsaKeyRing(@Nullable UserId userId, @Nonnull RsaLength length) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException { - return simpleRsaKeyRing(userId.toString(), length); + return simpleRsaKeyRing(userId == null ? null : userId.toString(), length); } /** @@ -56,7 +57,7 @@ public final class KeyRingTemplates { * @throws NoSuchAlgorithmException in case of missing algorithm implementation in the crypto provider * @throws PGPException in case of an OpenPGP related error */ - public PGPSecretKeyRing simpleRsaKeyRing(@Nonnull String userId, @Nonnull RsaLength length) + public PGPSecretKeyRing simpleRsaKeyRing(@Nullable String userId, @Nonnull RsaLength length) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException { return simpleRsaKeyRing(userId, length, Passphrase.emptyPassphrase()); } @@ -75,9 +76,9 @@ public final class KeyRingTemplates { * @throws NoSuchAlgorithmException in case of missing algorithm implementation in the crypto provider * @throws PGPException in case of an OpenPGP related error */ - public PGPSecretKeyRing simpleRsaKeyRing(@Nonnull UserId userId, @Nonnull RsaLength length, String password) + public PGPSecretKeyRing simpleRsaKeyRing(@Nullable UserId userId, @Nonnull RsaLength length, @Nullable String password) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException { - return simpleRsaKeyRing(userId.toString(), length, password); + return simpleRsaKeyRing(userId == null ? null : userId.toString(), length, password); } /** @@ -94,7 +95,7 @@ public final class KeyRingTemplates { * @throws NoSuchAlgorithmException in case of missing algorithm implementation in the crypto provider * @throws PGPException in case of an OpenPGP related error */ - public PGPSecretKeyRing simpleRsaKeyRing(@Nonnull String userId, @Nonnull RsaLength length, String password) + public PGPSecretKeyRing simpleRsaKeyRing(@Nullable String userId, @Nonnull RsaLength length, @Nullable String password) throws PGPException, NoSuchAlgorithmException, InvalidAlgorithmParameterException { Passphrase passphrase = Passphrase.emptyPassphrase(); if (!isNullOrEmpty(password)) { @@ -103,12 +104,14 @@ public final class KeyRingTemplates { return simpleRsaKeyRing(userId, length, passphrase); } - public PGPSecretKeyRing simpleRsaKeyRing(@Nonnull String userId, @Nonnull RsaLength length, @Nonnull Passphrase passphrase) + public PGPSecretKeyRing simpleRsaKeyRing(@Nullable String userId, @Nonnull RsaLength length, @Nonnull Passphrase passphrase) throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException { KeyRingBuilder builder = PGPainless.buildKeyRing() .setPrimaryKey(KeySpec.getBuilder(KeyType.RSA(length), KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA, KeyFlag.ENCRYPT_COMMS)) - .addUserId(userId) .setPassphrase(passphrase); + if (userId != null) { + builder.addUserId(userId); + } return builder.build(); } @@ -125,9 +128,9 @@ public final class KeyRingTemplates { * @throws NoSuchAlgorithmException in case of missing algorithm implementation in the crypto provider * @throws PGPException in case of an OpenPGP related error */ - public PGPSecretKeyRing simpleEcKeyRing(@Nonnull UserId userId) + public PGPSecretKeyRing simpleEcKeyRing(@Nullable UserId userId) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException { - return simpleEcKeyRing(userId.toString()); + return simpleEcKeyRing(userId == null ? null : userId.toString()); } /** @@ -143,7 +146,7 @@ public final class KeyRingTemplates { * @throws NoSuchAlgorithmException in case of missing algorithm implementation in the crypto provider * @throws PGPException in case of an OpenPGP related error */ - public PGPSecretKeyRing simpleEcKeyRing(@Nonnull String userId) + public PGPSecretKeyRing simpleEcKeyRing(@Nullable String userId) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException { return simpleEcKeyRing(userId, Passphrase.emptyPassphrase()); } @@ -162,9 +165,9 @@ public final class KeyRingTemplates { * @throws NoSuchAlgorithmException in case of missing algorithm implementation in the crypto provider * @throws PGPException in case of an OpenPGP related error */ - public PGPSecretKeyRing simpleEcKeyRing(@Nonnull UserId userId, String password) + public PGPSecretKeyRing simpleEcKeyRing(@Nullable UserId userId, String password) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException { - return simpleEcKeyRing(userId.toString(), password); + return simpleEcKeyRing(userId == null ? null : userId.toString(), password); } /** @@ -181,7 +184,7 @@ public final class KeyRingTemplates { * @throws NoSuchAlgorithmException in case of missing algorithm implementation in the crypto provider * @throws PGPException in case of an OpenPGP related error */ - public PGPSecretKeyRing simpleEcKeyRing(@Nonnull String userId, String password) + public PGPSecretKeyRing simpleEcKeyRing(@Nullable String userId, String password) throws PGPException, NoSuchAlgorithmException, InvalidAlgorithmParameterException { Passphrase passphrase = Passphrase.emptyPassphrase(); if (!isNullOrEmpty(password)) { @@ -190,13 +193,15 @@ public final class KeyRingTemplates { return simpleEcKeyRing(userId, passphrase); } - public PGPSecretKeyRing simpleEcKeyRing(@Nonnull String userId, @Nonnull Passphrase passphrase) + public PGPSecretKeyRing simpleEcKeyRing(@Nullable String userId, @Nonnull Passphrase passphrase) throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException { KeyRingBuilder builder = PGPainless.buildKeyRing() .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) .setPassphrase(passphrase); + if (userId != null) { + builder.addUserId(userId); + } return builder.build(); } @@ -211,8 +216,8 @@ public final class KeyRingTemplates { * @throws NoSuchAlgorithmException in case of missing algorithm implementation in the crypto provider * @throws PGPException in case of an OpenPGP related error */ - public PGPSecretKeyRing modernKeyRing(String userId) throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException { - return modernKeyRing(userId, (Passphrase) null); + public PGPSecretKeyRing modernKeyRing(@Nullable String userId) throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException { + return modernKeyRing(userId, Passphrase.emptyPassphrase()); } /** @@ -227,21 +232,21 @@ public final class KeyRingTemplates { * @throws NoSuchAlgorithmException in case of missing algorithm implementation in the crypto provider * @throws PGPException in case of an OpenPGP related error */ - public PGPSecretKeyRing modernKeyRing(String userId, String password) + public PGPSecretKeyRing modernKeyRing(@Nullable String userId, @Nullable String password) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException { - Passphrase passphrase = (password != null ? Passphrase.fromPassword(password) : null); + Passphrase passphrase = (password != null ? Passphrase.fromPassword(password) : Passphrase.emptyPassphrase()); return modernKeyRing(userId, passphrase); } - public PGPSecretKeyRing modernKeyRing(String userId, Passphrase passphrase) + public PGPSecretKeyRing modernKeyRing(@Nullable String userId, @Nonnull Passphrase passphrase) throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException { KeyRingBuilder builder = PGPainless.buildKeyRing() .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 (passphrase != null && !passphrase.isEmpty()) { - builder.setPassphrase(passphrase); + .setPassphrase(passphrase); + if (userId != null) { + builder.addUserId(userId); } return builder.build(); } diff --git a/pgpainless-sop/src/main/java/org/pgpainless/sop/GenerateKeyImpl.java b/pgpainless-sop/src/main/java/org/pgpainless/sop/GenerateKeyImpl.java index 893c8dd8..c75087c8 100644 --- a/pgpainless-sop/src/main/java/org/pgpainless/sop/GenerateKeyImpl.java +++ b/pgpainless-sop/src/main/java/org/pgpainless/sop/GenerateKeyImpl.java @@ -28,7 +28,7 @@ public class GenerateKeyImpl implements GenerateKey { private boolean armor = true; private final Set userIds = new LinkedHashSet<>(); - private Passphrase passphrase; + private Passphrase passphrase = Passphrase.emptyPassphrase(); @Override public GenerateKey noArmor() { @@ -51,14 +51,11 @@ public class GenerateKeyImpl implements GenerateKey { @Override public Ready generate() throws SOPGPException.MissingArg, SOPGPException.UnsupportedAsymmetricAlgo { Iterator userIdIterator = userIds.iterator(); - if (!userIdIterator.hasNext()) { - throw new SOPGPException.MissingArg("Missing user-id."); - } - PGPSecretKeyRing key; try { + String primaryUserId = userIdIterator.hasNext() ? userIdIterator.next() : null; key = PGPainless.generateKeyRing() - .modernKeyRing(userIdIterator.next(), passphrase); + .modernKeyRing(primaryUserId, passphrase); if (userIdIterator.hasNext()) { SecretKeyRingEditorInterface editor = PGPainless.modifyKeyRing(key); diff --git a/pgpainless-sop/src/test/java/org/pgpainless/sop/GenerateKeyTest.java b/pgpainless-sop/src/test/java/org/pgpainless/sop/GenerateKeyTest.java index 7f1710fd..a71eda12 100644 --- a/pgpainless-sop/src/test/java/org/pgpainless/sop/GenerateKeyTest.java +++ b/pgpainless-sop/src/test/java/org/pgpainless/sop/GenerateKeyTest.java @@ -6,7 +6,6 @@ package org.pgpainless.sop; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; @@ -17,7 +16,6 @@ import org.junit.jupiter.api.Test; import org.pgpainless.PGPainless; import org.pgpainless.key.info.KeyRingInfo; import sop.SOP; -import sop.exception.SOPGPException; public class GenerateKeyTest { @@ -28,11 +26,6 @@ public class GenerateKeyTest { sop = new SOPImpl(); } - @Test - public void testMissingUserId() { - assertThrows(SOPGPException.MissingArg.class, () -> sop.generateKey().generate()); - } - @Test public void generateKey() throws IOException { byte[] bytes = sop.generateKey()