From 1668e75eed009307ce7bd2bbf6694ab014d61b76 Mon Sep 17 00:00:00 2001 From: imills Date: Thu, 24 Feb 2022 20:42:59 +0000 Subject: [PATCH 1/2] issues/85 - Implements support for key pair generation using seed for random number generation for both SECP256K1 and Ed25519 key pairs --- .../sdk/service/signing/AbstractKeyPairBuilder.java | 5 +++-- .../sdk/service/signing/Ed25519KeyPariBuilder.java | 4 ++-- .../casper/sdk/service/signing/KeyPairBuilder.java | 5 +++-- .../service/signing/Secp256k1KeyPairBuilder.java | 5 +++-- .../casper/sdk/service/signing/SigningService.java | 13 ++++++++++++- 5 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/casper/sdk/service/signing/AbstractKeyPairBuilder.java b/src/main/java/com/casper/sdk/service/signing/AbstractKeyPairBuilder.java index 3a7690652..f028898ff 100644 --- a/src/main/java/com/casper/sdk/service/signing/AbstractKeyPairBuilder.java +++ b/src/main/java/com/casper/sdk/service/signing/AbstractKeyPairBuilder.java @@ -27,11 +27,12 @@ public Algorithm getAlgorithm() { return algorithm; } - KeyPair generateKeyPair(final String algorithm, final String curve) { + KeyPair generateKeyPair(final String algorithm, final String curve, final byte[] seed) { try { final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm, PROVIDER); final ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec(curve); - keyPairGenerator.initialize(ecGenParameterSpec, new SecureRandom()); + final SecureRandom secureRandom = seed != null ? new SecureRandom(seed) : new SecureRandom(); + keyPairGenerator.initialize(ecGenParameterSpec, secureRandom); return keyPairGenerator.generateKeyPair(); } catch (Exception e) { throw new SignatureException(e); diff --git a/src/main/java/com/casper/sdk/service/signing/Ed25519KeyPariBuilder.java b/src/main/java/com/casper/sdk/service/signing/Ed25519KeyPariBuilder.java index b439a19c5..5fec0c2a9 100644 --- a/src/main/java/com/casper/sdk/service/signing/Ed25519KeyPariBuilder.java +++ b/src/main/java/com/casper/sdk/service/signing/Ed25519KeyPariBuilder.java @@ -22,8 +22,8 @@ class Ed25519KeyPariBuilder extends AbstractKeyPairBuilder { } @Override - public KeyPair generateKeyPair() { - return generateKeyPair(ALGORITHM, ALGORITHM); + public KeyPair generateKeyPair(final byte[] seed) { + return generateKeyPair(ALGORITHM, ALGORITHM, seed); } @Override diff --git a/src/main/java/com/casper/sdk/service/signing/KeyPairBuilder.java b/src/main/java/com/casper/sdk/service/signing/KeyPairBuilder.java index 24a999f0e..49c611260 100644 --- a/src/main/java/com/casper/sdk/service/signing/KeyPairBuilder.java +++ b/src/main/java/com/casper/sdk/service/signing/KeyPairBuilder.java @@ -3,6 +3,7 @@ import com.casper.sdk.types.Algorithm; +import javax.annotation.Nullable; import java.security.KeyPair; import java.security.PublicKey; @@ -13,10 +14,10 @@ public interface KeyPairBuilder { /** * Generates a new key pair - * + * @param seed the optional entropy source to be used when generating a key pair * @return a new key pain */ - KeyPair generateKeyPair(); + KeyPair generateKeyPair(@Nullable final byte [] seed); /** * The algorithm of the signer diff --git a/src/main/java/com/casper/sdk/service/signing/Secp256k1KeyPairBuilder.java b/src/main/java/com/casper/sdk/service/signing/Secp256k1KeyPairBuilder.java index bb4365a62..ae6aa38c1 100644 --- a/src/main/java/com/casper/sdk/service/signing/Secp256k1KeyPairBuilder.java +++ b/src/main/java/com/casper/sdk/service/signing/Secp256k1KeyPairBuilder.java @@ -33,8 +33,9 @@ public class Secp256k1KeyPairBuilder extends AbstractKeyPairBuilder { super(Algorithm.SECP256K1); } - public KeyPair generateKeyPair() { - return generateKeyPair(ALGORITHM, CURVE_NAME); + @Override + public KeyPair generateKeyPair(final byte[] seed) { + return generateKeyPair(ALGORITHM, CURVE_NAME, seed); } @Override diff --git a/src/main/java/com/casper/sdk/service/signing/SigningService.java b/src/main/java/com/casper/sdk/service/signing/SigningService.java index a0a0ef07b..1ceab1d74 100644 --- a/src/main/java/com/casper/sdk/service/signing/SigningService.java +++ b/src/main/java/com/casper/sdk/service/signing/SigningService.java @@ -37,7 +37,18 @@ public class SigningService { * @return a new key pair of the specified algorithm */ public KeyPair generateKeyPair(final Algorithm algorithm) { - return getKeyPairBuilder(algorithm).generateKeyPair(); + return getKeyPairBuilder(algorithm).generateKeyPair(null); + } + + /** + * Generates a key pair for the specified algorithm. + * + * @param algorithm the algorithm of new key pair to generate + * @param seed the entropy source to be used when generating a key pair + * @return a new key pair of the specified algorithm + */ + public KeyPair generateKeyPair(final Algorithm algorithm, final byte[] seed) { + return getKeyPairBuilder(algorithm).generateKeyPair(seed); } /** From c5617b737b96294932facc226ee9044a7353439e Mon Sep 17 00:00:00 2001 From: imills Date: Fri, 25 Feb 2022 16:13:48 +0000 Subject: [PATCH 2/2] issues/85 - Added tests for key generation with seed value --- .../service/signing/SigningServiceTest.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/test/java/com/casper/sdk/service/signing/SigningServiceTest.java b/src/test/java/com/casper/sdk/service/signing/SigningServiceTest.java index 747f93c4c..328448bd1 100644 --- a/src/test/java/com/casper/sdk/service/signing/SigningServiceTest.java +++ b/src/test/java/com/casper/sdk/service/signing/SigningServiceTest.java @@ -15,6 +15,7 @@ import java.nio.charset.StandardCharsets; import java.security.KeyPair; import java.security.PrivateKey; +import java.security.SecureRandom; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; @@ -88,6 +89,25 @@ void generateEd25519KeyPair() { assertThat(signingService.verifySignature(keyPair.getPublic(), message, signature), is(true)); } + @Test + void generateEd25519KeyPairFromSeed() { + + final SecureRandom random = new SecureRandom(); + byte[] seed = new byte[20]; + random.nextBytes(seed); + + final KeyPair keyPair = signingService.generateKeyPair(Algorithm.ED25519, seed); + assertThat(keyPair.getPublic(), is(notNullValue())); + assertThat(keyPair.getPrivate(), is(notNullValue())); + + // the message + byte[] message = "Message to sign".getBytes(StandardCharsets.UTF_8); + + byte[] signature = signingService.signWithPrivateKey(keyPair.getPrivate(), message); + + assertThat(signingService.verifySignature(keyPair.getPublic(), message, signature), is(true)); + } + @Test @SuppressWarnings("ConstantConditions") void loadSecp256k1KeyPair() throws Exception { @@ -123,6 +143,32 @@ void generateSecp256k1KeyPair() { assertThat(signingService.verifySignature(keyPair.getPublic(), message, signedMessage), is(true)); } + + @Test + void generateSecp256k1KeyPairFromSeed() { + + final SecureRandom random = new SecureRandom(); + byte[] seed = new byte[20]; + random.nextBytes(seed); + + final byte[] message = { + (byte) 153, (byte) 144, (byte) 19, (byte) 83, (byte) 219, (byte) 161, (byte) 143, (byte) 137, (byte) 59, + (byte) 67, (byte) 187, (byte) 238, (byte) 65, (byte) 111, (byte) 80, (byte) 243, (byte) 142, (byte) 77, + (byte) 113, (byte) 46, (byte) 2, (byte) 166, (byte) 121, (byte) 118, (byte) 34, (byte) 205, (byte) 123, + (byte) 14, (byte) 215, (byte) 85, (byte) 234, (byte) 161 + }; + + final KeyPair keyPair = signingService.generateKeyPair(Algorithm.SECP256K1, seed); + + assertThat(keyPair, is(notNullValue())); + assertThat(keyPair.getPublic(), is(notNullValue())); + assertThat(keyPair.getPrivate(), is(notNullValue())); + + final byte[] signedMessage = signingService.signWithPrivateKey(keyPair.getPrivate(), message); + + assertThat(signingService.verifySignature(keyPair.getPublic(), message, signedMessage), is(true)); + } + @Test @SuppressWarnings("ConstantConditions") void signWithSecp256k1PrivateKeyAndVerifySignature() throws Exception {