diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java b/domain/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java index 5e3fd8a..7538926 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java @@ -66,7 +66,7 @@ public class BitmessageAddress { // but for the address and its checksum they need to be stripped int offset = Bytes.numberOfLeadingZeros(ripe); os.write(ripe, offset, ripe.length - offset); - checksum = Security.doubleSha512(os.toByteArray(), ripe); + checksum = Security.doubleSha512(os.toByteArray()); os.write(checksum, 0, 4); this.address = "BM-" + Base58.encode(os.toByteArray()); } catch (IOException e) { diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Pubkey.java b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Pubkey.java index abf7244..7225acb 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Pubkey.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Pubkey.java @@ -16,8 +16,6 @@ package ch.dissem.bitmessage.entity.payload; -import ch.dissem.bitmessage.utils.Bytes; - import java.util.ArrayList; import static ch.dissem.bitmessage.utils.Security.ripemd160; @@ -29,6 +27,10 @@ import static ch.dissem.bitmessage.utils.Security.sha512; public abstract class Pubkey extends ObjectPayload { public final static long LATEST_VERSION = 4; + public static byte[] getRipe(byte[] publicSigningKey, byte[] publicEncryptionKey) { + return ripemd160(sha512(publicSigningKey, publicEncryptionKey)); + } + public abstract long getVersion(); public abstract byte[] getSigningKey(); @@ -39,8 +41,8 @@ public abstract class Pubkey extends ObjectPayload { return ripemd160(sha512(getSigningKey(), getEncryptionKey())); } - protected byte[] add0x04(byte[] key){ - if (key.length==65) return key; + protected byte[] add0x04(byte[] key) { + if (key.length == 65) return key; byte[] result = new byte[65]; result[0] = 4; System.arraycopy(key, 0, result, 1, 64); @@ -75,10 +77,10 @@ public abstract class Pubkey extends ObjectPayload { return bits; } - public static Feature[] features(int bitfield){ + public static Feature[] features(int bitfield) { ArrayList features = new ArrayList<>(Feature.values().length); - for (Feature feature:Feature.values()){ - if ((bitfield & feature.bit) != 0){ + for (Feature feature : Feature.values()) { + if ((bitfield & feature.bit) != 0) { features.add(feature); } } diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java b/domain/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java index af97047..5fb7a39 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java @@ -35,9 +35,21 @@ public class PrivateKey implements Streamable { private final Pubkey pubkey; - public PrivateKey(long stream, long nonceTrialsPerByte, long extraBytes, Pubkey.Feature... features) { - this.privateSigningKey = Security.randomBytes(64); - this.privateEncryptionKey = Security.randomBytes(64); + public PrivateKey(boolean shorter, long stream, long nonceTrialsPerByte, long extraBytes, Pubkey.Feature... features) { + byte[] privSK; + byte[] pubSK; + byte[] privEK; + byte[] pubEK; + byte[] ripe; + do { + privSK = Security.randomBytes(64); + privEK = Security.randomBytes(64); + pubSK = Security.createPublicKey(privSK).getEncoded(false); + pubEK = Security.createPublicKey(privEK).getEncoded(false); + ripe = Pubkey.getRipe(pubSK, pubEK); + } while (ripe[0] != 0 || (shorter && ripe[1] != 0)); + this.privateSigningKey = privSK; + this.privateEncryptionKey = privEK; this.pubkey = Security.createPubkey(Pubkey.LATEST_VERSION, stream, privateSigningKey, privateEncryptionKey, nonceTrialsPerByte, extraBytes, features); } @@ -60,14 +72,6 @@ public class PrivateKey implements Streamable { } } - public byte[] getPrivateSigningKey() { - return privateSigningKey; - } - - public byte[] getPrivateEncryptionKey() { - return privateEncryptionKey; - } - public static PrivateKey read(InputStream is) throws IOException { int version = (int) Decode.varInt(is); long stream = Decode.varInt(is); @@ -80,6 +84,14 @@ public class PrivateKey implements Streamable { return new PrivateKey(signingKey, encryptionKey, pubkey); } + public byte[] getPrivateSigningKey() { + return privateSigningKey; + } + + public byte[] getPrivateEncryptionKey() { + return privateEncryptionKey; + } + public Pubkey getPubkey() { return pubkey; } diff --git a/domain/src/main/java/ch/dissem/bitmessage/factory/Factory.java b/domain/src/main/java/ch/dissem/bitmessage/factory/Factory.java index 44f4b1a..fb1d5cf 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/factory/Factory.java +++ b/domain/src/main/java/ch/dissem/bitmessage/factory/Factory.java @@ -96,8 +96,8 @@ public class Factory { } } - public static BitmessageAddress generatePrivateAddress(long stream, Pubkey.Feature... features) { - return new BitmessageAddress(new PrivateKey(stream, 1000, 1000, features)); + public static BitmessageAddress generatePrivateAddress(boolean shorter, long stream, Pubkey.Feature... features) { + return new BitmessageAddress(new PrivateKey(shorter, stream, 1000, 1000, features)); } static ObjectPayload getObjectPayload(long objectType, long version, long streamNumber, InputStream stream, int length) throws IOException { diff --git a/domain/src/test/java/ch/dissem/bitmessage/EncryptionTest.java b/domain/src/test/java/ch/dissem/bitmessage/EncryptionTest.java index 8f7745b..508d34d 100644 --- a/domain/src/test/java/ch/dissem/bitmessage/EncryptionTest.java +++ b/domain/src/test/java/ch/dissem/bitmessage/EncryptionTest.java @@ -36,7 +36,7 @@ public class EncryptionTest { public void ensureDecryptedDataIsSameAsBeforeEncryption() throws IOException { GenericPayload before = new GenericPayload(1, Security.randomBytes(100)); - PrivateKey privateKey = new PrivateKey(1, 1000, 1000); + PrivateKey privateKey = new PrivateKey(false, 1, 1000, 1000); CryptoBox cryptoBox = new CryptoBox(before, privateKey.getPubkey().getEncryptionKey()); GenericPayload after = GenericPayload.read(cryptoBox.decrypt(privateKey.getPrivateEncryptionKey()), 1, 100); diff --git a/domain/src/test/java/ch/dissem/bitmessage/SignatureTest.java b/domain/src/test/java/ch/dissem/bitmessage/SignatureTest.java index 9bffef1..7985b4f 100644 --- a/domain/src/test/java/ch/dissem/bitmessage/SignatureTest.java +++ b/domain/src/test/java/ch/dissem/bitmessage/SignatureTest.java @@ -38,7 +38,7 @@ public class SignatureTest { @Test public void ensureSigningWorks() throws IOException { - PrivateKey privateKey = new PrivateKey(1, 1000, 1000); + PrivateKey privateKey = new PrivateKey(false, 1, 1000, 1000); BitmessageAddress address = new BitmessageAddress(privateKey); ObjectMessage objectMessage = new ObjectMessage.Builder() diff --git a/domain/src/test/java/ch/dissem/bitmessage/entity/BitmessageAddressTest.java b/domain/src/test/java/ch/dissem/bitmessage/entity/BitmessageAddressTest.java index bdec638..609282a 100644 --- a/domain/src/test/java/ch/dissem/bitmessage/entity/BitmessageAddressTest.java +++ b/domain/src/test/java/ch/dissem/bitmessage/entity/BitmessageAddressTest.java @@ -24,6 +24,7 @@ import ch.dissem.bitmessage.utils.*; import org.junit.Test; import java.io.IOException; +import java.util.Arrays; import static ch.dissem.bitmessage.entity.payload.Pubkey.Feature.DOES_ACK; import static org.junit.Assert.*; @@ -54,7 +55,7 @@ public class BitmessageAddressTest { @Test public void testCreateAddress() { - BitmessageAddress address = new BitmessageAddress(new PrivateKey(1, 1000, 1000, DOES_ACK)); + BitmessageAddress address = new BitmessageAddress(new PrivateKey(false, 1, 1000, 1000, DOES_ACK)); assertNotNull(address.getPubkey()); } @@ -90,7 +91,7 @@ public class BitmessageAddressTest { } @Test - public void testV3Import() throws IOException { + public void testV3AddressImport() throws IOException { String address_string = "BM-2DAjcCFrqFrp88FUxExhJ9kPqHdunQmiyn"; assertEquals(3, new BitmessageAddress(address_string).getVersion()); assertEquals(1, new BitmessageAddress(address_string).getStream()); @@ -107,7 +108,7 @@ public class BitmessageAddressTest { @Test public void testGetSecret() throws IOException { - assertHexEquals("040C28FCA386C7A227600B2FE50B7CAE11EC86D3BF1FBE471BE89827E19D72AA1D", + assertHexEquals("0C28FCA386C7A227600B2FE50B7CAE11EC86D3BF1FBE471BE89827E19D72AA1D", getSecret("5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ")); } @@ -122,19 +123,16 @@ public class BitmessageAddressTest { for (int i = 0; i < 4; i++) { if (hash[i] != bytes[33 + i]) throw new IOException("Hash check failed for secret " + walletImportFormat); } - byte[] result = new byte[33]; - result[0] = 0x04; - System.arraycopy(bytes, 1, result, 1, 32); - return result; + return Arrays.copyOfRange(bytes, 1, 33); } @Test - public void testV4Import() { + public void testV4AddressImport() throws IOException { assertEquals(4, new BitmessageAddress("BM-2cV5f9EpzaYARxtoruSpa6pDoucSf9ZNke").getVersion()); - byte[] privsigningkey = Base58.decode("5KMWqfCyJZGFgW6QrnPJ6L9Gatz25B51y7ErgqNr1nXUVbtZbdU"); - byte[] privencryptionkey = Base58.decode("5JXXWEuhHQEPk414SzEZk1PHDRi8kCuZd895J7EnKeQSahJPxGz"); + byte[] privsigningkey = getSecret("5KMWqfCyJZGFgW6QrnPJ6L9Gatz25B51y7ErgqNr1nXUVbtZbdU"); + byte[] privencryptionkey = getSecret("5JXXWEuhHQEPk414SzEZk1PHDRi8kCuZd895J7EnKeQSahJPxGz"); BitmessageAddress address = new BitmessageAddress(new PrivateKey(privsigningkey, privencryptionkey, - Security.createPubkey(3, 1, privsigningkey, privencryptionkey, 320, 14000))); + Security.createPubkey(4, 1, privsigningkey, privencryptionkey, 320, 14000))); assertEquals("BM-2cV5f9EpzaYARxtoruSpa6pDoucSf9ZNke", address.getAddress()); }