Skip to content

Commit

Permalink
More crypto tests and refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
mikera committed Aug 16, 2024
1 parent c636af4 commit 4fdfb67
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 48 deletions.
2 changes: 1 addition & 1 deletion convex-core/src/main/java/convex/core/crypto/AKeyPair.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public final boolean equals(Object a) {
public abstract ASignature sign(AArrayBlob message);

/**
* Create a deterministic key pair with the given seed.
* Create a deterministic key pair with the given long seed.
*
* SECURITY: Never use this for valuable keys or real assets: intended for deterministic testing only.
* @param seed Any long value. The same seed will produce the same key pair.
Expand Down
4 changes: 2 additions & 2 deletions convex-core/src/main/java/convex/core/crypto/BIP39.java
Original file line number Diff line number Diff line change
Expand Up @@ -261,14 +261,14 @@ public static Blob seedToEd25519Seed(Blob seed) {
}

/**
* Return true if the string is a valid mnemonic phrase
* Tests if the string is a valid mnemonic phrase, returns null if no problem
* @param s String to be tested as a mnemonic phrase
* @return String containing reason that mnemonic is not valid, or null if OK
*/
public static String checkMnemonic(String s) {
List<String> words=getWords(s);
if (words.size()<MIN_WORDS) return "Insufficient words in BIP39 mnemonic (min="+MIN_WORDS+")";
return null;
return checkWords(words);
}

/**
Expand Down
7 changes: 5 additions & 2 deletions convex-core/src/main/java/convex/core/crypto/PEMTools.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
import org.bouncycastle.util.io.pem.PemObject;

public class PEMTools {
// private static String encryptionAlgorithm="AES-128-CBC";
/**
* Default iteration count for PBE. TODO: is this sane?
*/
private static final int PBE_ITERATIONS=65536;

static {
// Ensure we have BC provider initialised etc.
Expand All @@ -43,7 +46,7 @@ public static String encryptPrivateKeyToPEM(AKeyPair keyPair, char[] password) t

try {
JcePKCSPBEOutputEncryptorBuilder builder = new JcePKCSPBEOutputEncryptorBuilder(PKCS8Generator.PBE_SHA1_RC2_128);
builder.setIterationCount(4096); // TODO: double check requirements here?
builder.setIterationCount(PBE_ITERATIONS); // TODO: double check requirements here?
OutputEncryptor encryptor = builder.build(password);
JcaPKCS8Generator generator = new JcaPKCS8Generator(privateKey, encryptor);
writer.writeObject(generator);
Expand Down
21 changes: 11 additions & 10 deletions convex-core/src/main/java/convex/core/crypto/SLIP10.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ public class SLIP10 {

/**
* Gets the the master key for a given seed according to SLIP10
* @param seed BIP39 seed value (or other source of good entropy!)
* @return Blob containing the seed (bip39 seed, or some other good entropy source)
* @param bip39seed BIP39 seed value (or other source of good entropy!)
* @return Blob containing the SLIP10 master key
*/
public static Blob getMaster(Blob seed) {
public static Blob getMaster(Blob bip39seed) {
try {
Mac hmac=Mac.getInstance(HMAC_ALGORITHM);

hmac.init(masterKey);
byte[] data=seed.getBytes();
byte[] data=bip39seed.getBytes();
hmac.update(data);
Blob result=Blob.wrap(hmac.doFinal());
return result;
Expand All @@ -50,11 +50,12 @@ public static Blob getMaster(Blob seed) {
*/
public static Blob derive(Blob master, int... ixs) {
if (ixs.length==0) return master;
try {
byte[] bs=master.getBytes();
if (bs.length!=64) throw new Error("Invalid SLIP10 master key, must be 64 bytes");
byte[] data=new byte[1+32+4]; // 0x00 || ser256(kpar) || ser32(i)) from SLIP-10
if (ixs.length>255) throw new IllegalArgumentException("Maximum BIP32 path length exceeded (must be 255 or less)");
byte[] bs=master.getBytes();
if (bs.length!=64) throw new IllegalArgumentException("Invalid SLIP10 master key, must be 64 bytes");
byte[] data=new byte[1+32+4]; // 0x00 || ser256(kpar) || ser32(i)) from SLIP-10

try {
Mac hmac=Mac.getInstance(HMAC_ALGORITHM);

for (int i=0; i<ixs.length; i++) {
Expand All @@ -75,8 +76,8 @@ public static Blob derive(Blob master, int... ixs) {
}
}

public static AKeyPair deriveKeyPair(Blob seed, int... ixs) {
Blob master = getMaster(seed);
public static AKeyPair deriveKeyPair(Blob bip39seed, int... ixs) {
Blob master = getMaster(bip39seed);
Blob keySeed = derive(master,ixs).slice(0, 32);
AKeyPair kp=AKeyPair.create(keySeed);
return kp;
Expand Down
67 changes: 67 additions & 0 deletions convex-core/src/test/java/convex/core/crypto/KeyPairTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package convex.core.crypto;

import static org.junit.jupiter.api.Assertions.assertTrue;
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 org.junit.jupiter.api.Test;

import convex.core.data.Blob;
import convex.core.data.Blobs;

public class KeyPairTest {

@Test
public void testSeeded() {
AKeyPair kp1 = AKeyPair.createSeeded(13);
AKeyPair kp2 = AKeyPair.createSeeded(13);
assertTrue(kp1.equals(kp2));
AKeyPair kp3 = AKeyPair.createSeeded(1337);
assertFalse(kp1.equals(kp3) );
}

@Test public void testBadSeed() {
assertThrows(Exception.class,()->AKeyPair.create(Blobs.empty()));
}

@Test
public void testBaseSeed() {
// by hard-coding this, we catch unexpected changes in deterministic generation. Aeren't we clever?
assertEquals("3b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29",AKeyPair.createSeeded(0).getAccountKey().toHexString());
}

/**
* Test vectors from RFC 8032
*/
@Test
public void testVectors() {
Blob seed1=Blob.fromHex("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60");
AKeyPair kp1=AKeyPair.create(seed1);
assertEquals("d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a",kp1.getAccountKey().toHexString());
Blob msg1=Blobs.empty();
assertEquals("e5564300c360ac729086e2cc806e828a"
+ "84877f1eb8e5d974d873e06522490155"
+ "5fb8821590a33bacc61e39701cf9b46b"
+ "d25bf5f0595bbe24655141438e7a100b",kp1.sign(msg1).toHexString());

Blob seed2=Blob.fromHex("4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb");
AKeyPair kp2=AKeyPair.create(seed2);
assertEquals("3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c",kp2.getAccountKey().toHexString());
Blob msg2=Blob.fromHex("72");
assertEquals("92a009a9f0d4cab8720e820b5f642540"
+ "a2b27b5416503f8fb3762223ebdb69da"
+ "085ac1e43e15996e458f3613d0f11d8c"
+ "387b2eaeb4302aeeb00d291612bb0c00",kp2.sign(msg2).toHexString());

Blob seed3=Blob.fromHex("c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7");
AKeyPair kp3=AKeyPair.create(seed3);
Blob msg3=Blob.fromHex("af82");
assertEquals("fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025",kp3.getAccountKey().toHexString());
assertEquals("6291d657deec24024827e69c3abe01a3"
+ "0ce548a284743a445e3680d7db5ac3ac"
+ "18ff9b538d16f290ae67f760984dc659"
+ "4a7c15e9716ed28dc027beceea1ec40a",kp3.sign(msg3).toHexString());

}
}
10 changes: 5 additions & 5 deletions convex-core/src/test/java/convex/core/crypto/PEMToolsTest.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package convex.core.crypto;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.security.SecureRandom;

import org.junit.jupiter.api.Test;

import convex.core.data.AString;
import convex.core.data.Blob;
import convex.core.data.Strings;
import convex.core.util.Utils;

Expand Down Expand Up @@ -37,11 +39,9 @@ public void testPEMPrivateKey() throws Exception {
ASignature rightSignature = importKeyPair.sign(data.getHash());
assertTrue(leftSignature.equals(rightSignature));

// TODO: fix equality testing
// Blob key1 = keyPair.getEncodedPrivateKey();
// Blob key2 = importKeyPair.getEncodedPrivateKey();
//assertEquals(key1,key2);
//(keyPair,importKeyPair);
Blob seed1 = keyPair.getSeed();
Blob seed2 = importKeyPair.getSeed();
assertEquals(seed1,seed2);
}

public static void main(String... args) throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public void testSLIP10EdgeCases () throws InvalidKeyException, NoSuchAlgorithmEx

@Test
public void testSLIP10Fails () {
assertThrows(Error.class,()->SLIP10.derive(Blobs.empty(),1,2));
assertThrows(IllegalArgumentException.class,()->SLIP10.derive(Blobs.empty(),1,2));
}

}
27 changes: 0 additions & 27 deletions convex-core/src/test/java/convex/core/crypto/SignKeyPairTest.java

This file was deleted.

0 comments on commit 4fdfb67

Please sign in to comment.