From 79b2d42f9cb43613943d7e967cd96e6563b88e74 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 11 Feb 2021 16:58:00 +0100 Subject: [PATCH] Add support for more elliptic curves and start implementing KeyInfo class --- .../generation/type/ecc/EllipticCurve.java | 16 ++++- .../java/org/pgpainless/key/info/KeyInfo.java | 67 +++++++++++++++++++ .../generation/BrainpoolKeyGeneration.java | 64 ++++++++++++++++++ 3 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/info/KeyInfo.java create mode 100644 pgpainless-core/src/test/java/org/pgpainless/key/generation/BrainpoolKeyGeneration.java diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/EllipticCurve.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/EllipticCurve.java index 330a635f..0d6eeb0e 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/EllipticCurve.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/EllipticCurve.java @@ -17,10 +17,20 @@ package org.pgpainless.key.generation.type.ecc; import javax.annotation.Nonnull; +/** + * Elliptic curves for use with + * {@link org.pgpainless.key.generation.type.ecc.ecdh.ECDH}/{@link org.pgpainless.key.generation.type.ecc.ecdsa.ECDSA}. + * For curve25519 related curve definitions see + * {@link org.pgpainless.key.generation.type.xdh.XDHCurve} and {@link org.pgpainless.key.generation.type.eddsa.EdDSACurve}. + */ public enum EllipticCurve { - _P256("P-256"), - _P384("P-384"), - _P521("P-521"), + _P256("prime256v1"), // prime256v1 is equivalent to P-256, see https://tools.ietf.org/search/rfc4492#page-32 + _P384("secp384r1"), // secp384r1 is equivalent to P-384, see https://tools.ietf.org/search/rfc4492#page-32 + _P521("secp521r1"), // secp521r1 is equivalent to P-521, see https://tools.ietf.org/search/rfc4492#page-32 + _SECP256K1("secp256k1"), + _BRAINPOOLP256R1("brainpoolP256r1"), + _BRAINPOOLP384R1("brainpoolP384r1"), + _BRAINPOOLP512R1("brainpoolP512r1") ; private final String name; diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/info/KeyInfo.java b/pgpainless-core/src/main/java/org/pgpainless/key/info/KeyInfo.java new file mode 100644 index 00000000..adb7e1ae --- /dev/null +++ b/pgpainless-core/src/main/java/org/pgpainless/key/info/KeyInfo.java @@ -0,0 +1,67 @@ +/* + * Copyright 2021 Paul Schaub. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.pgpainless.key.info; + +import org.bouncycastle.bcpg.ECDHPublicBCPGKey; +import org.bouncycastle.bcpg.ECDSAPublicBCPGKey; +import org.bouncycastle.bcpg.ECPublicBCPGKey; +import org.bouncycastle.bcpg.EdDSAPublicBCPGKey; +import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; +import org.bouncycastle.openpgp.PGPPublicKey; +import org.bouncycastle.openpgp.PGPSecretKey; +import org.pgpainless.algorithm.PublicKeyAlgorithm; + +public class KeyInfo { + + private final PGPSecretKey secretKey; + private final PGPPublicKey publicKey; + + public KeyInfo(PGPSecretKey secretKey) { + this.secretKey = secretKey; + this.publicKey = secretKey.getPublicKey(); + } + + public KeyInfo(PGPPublicKey publicKey) { + this.publicKey = publicKey; + this.secretKey = null; + } + + public static String getCurveName(PGPPublicKey publicKey) { + PublicKeyAlgorithm algorithm = PublicKeyAlgorithm.fromId(publicKey.getAlgorithm()); + ECPublicBCPGKey key; + switch (algorithm) { + case ECDSA: { + key = (ECDSAPublicBCPGKey) publicKey.getPublicKeyPacket().getKey(); + break; + } + case ECDH: { + key = (ECDHPublicBCPGKey) publicKey.getPublicKeyPacket().getKey(); + break; + } + case EDDSA: { + key = (EdDSAPublicBCPGKey) publicKey.getPublicKeyPacket().getKey(); + break; + } + default: + throw new IllegalArgumentException("Not a EC public key (" + algorithm + ")"); + } + return getCurveName(key); + } + + public static String getCurveName(ECPublicBCPGKey key) { + return ECUtil.getCurveName(key.getCurveOID()); + } +} diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/generation/BrainpoolKeyGeneration.java b/pgpainless-core/src/test/java/org/pgpainless/key/generation/BrainpoolKeyGeneration.java new file mode 100644 index 00000000..f3f61fb9 --- /dev/null +++ b/pgpainless-core/src/test/java/org/pgpainless/key/generation/BrainpoolKeyGeneration.java @@ -0,0 +1,64 @@ +/* + * Copyright 2021 Paul Schaub. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.pgpainless.key.generation; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; + +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPPublicKey; +import org.bouncycastle.openpgp.PGPSecretKeyRing; +import org.junit.jupiter.api.Test; +import org.pgpainless.PGPainless; +import org.pgpainless.algorithm.KeyFlag; +import org.pgpainless.algorithm.PublicKeyAlgorithm; +import org.pgpainless.key.generation.type.KeyType; +import org.pgpainless.key.generation.type.ecc.EllipticCurve; +import org.pgpainless.key.info.KeyInfo; + +public class BrainpoolKeyGeneration { + + @Test + public void generateEcKeysTest() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException, IOException { + for (EllipticCurve curve : EllipticCurve.values()) { + PGPSecretKeyRing secretKeys = generateKey( + KeySpec.getBuilder(KeyType.ECDSA(curve)) + .withKeyFlags(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA) + .withDefaultAlgorithms(), + KeySpec.getBuilder(KeyType.ECDH(curve)) + .withKeyFlags(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE) + .withDefaultAlgorithms(), + "Elliptic Curve "); + + assertEquals(PublicKeyAlgorithm.ECDSA, PublicKeyAlgorithm.fromId(secretKeys.getPublicKey().getAlgorithm())); + PGPPublicKey publicKey = secretKeys.getPublicKey(); + assertEquals(curve.getName(), KeyInfo.getCurveName(publicKey)); + } + } + + public PGPSecretKeyRing generateKey(KeySpec primaryKey, KeySpec subKey, String userId) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException { + PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() + .withSubKey(subKey) + .withMasterKey(primaryKey) + .withPrimaryUserId(userId) + .withoutPassphrase() + .build(); + return secretKeys; + } +}