Permalink
Browse files

added NoEC encryption and decryption for different network parameters

  • Loading branch information...
1 parent a15fbc4 commit 99409edfa292cbaad538af568fd599c43df19a7e @dbasch committed Jan 24, 2014
View
49 src/main/java/com/fruitcat/bitcoin/BIP38.java
@@ -247,16 +247,16 @@ public static String decryptEC(String passphrase, byte[] encryptedKey) throws Un
byte flagByte = encryptedKey[2];
byte[] passFactor;
+ boolean hasLot = (flagByte & 4) == 4;
byte[] ownerSalt = Arrays.copyOfRange(encryptedKey, 7, 15 - (flagByte & 4));
- if ((flagByte & 4) == 0) {
+ if (!hasLot) {
passFactor = SCrypt.scrypt(passphrase.getBytes("UTF8"), ownerSalt, 16384, 8, 8, 32);
}
else {
byte[] preFactor = SCrypt.scrypt(passphrase.getBytes("UTF8"), ownerSalt, 16384, 8, 8, 32);
byte[] ownerEntropy = Arrays.copyOfRange(encryptedKey, 7, 15);
byte[] tmp = Utils.concat(preFactor, ownerEntropy);
passFactor = Utils.doubleHash(tmp, 0, 40);
-
}
byte[] addressHash = Arrays.copyOfRange(encryptedKey, 3, 7);
@@ -310,12 +310,29 @@ public static String decryptEC(String passphrase, byte[] encryptedKey) throws Un
*/
public static String encryptNoEC(String passphrase, String encodedPrivateKey, boolean isCompressed)
throws GeneralSecurityException, UnsupportedEncodingException, AddressFormatException {
+ return encryptNoEC(passphrase, encodedPrivateKey, isCompressed, MainNetParams.get());
+ }
- DumpedPrivateKey dk = new DumpedPrivateKey(MainNetParams.get(), encodedPrivateKey);
+ /**
+ * Encrypts a key without using EC multiplication.
+ * @param encodedPrivateKey
+ * @param passphrase
+ * @param isCompressed
+ * @param params
+ * @return
+ * @throws GeneralSecurityException
+ * @throws UnsupportedEncodingException
+ * @throws AddressFormatException
+ */
+ public static String encryptNoEC(String passphrase, String encodedPrivateKey, boolean isCompressed, NetworkParameters params)
+ throws GeneralSecurityException, UnsupportedEncodingException, AddressFormatException {
- ECKey key = dk.getKey();
- byte[] keyBytes = key.getPrivKeyBytes();
- String address = key.toAddress(MainNetParams.get()).toString();
+ DumpedPrivateKey dk = new DumpedPrivateKey(params, encodedPrivateKey);
+
+ ECKey ktmp = dk.getKey();
+ byte[] keyBytes = ktmp.getPrivKeyBytes();
+ ECKey key = new ECKey(new BigInteger(1, keyBytes), null, isCompressed);
+ String address = key.toAddress(params).toString();
byte[] tmp = address.getBytes("ASCII");
byte[] hash = Utils.doubleHash(tmp, 0, tmp.length);
byte[] addressHash = Arrays.copyOfRange(hash, 0, 4);
@@ -347,7 +364,20 @@ public static String encryptNoEC(String passphrase, String encodedPrivateKey, bo
* @throws UnsupportedEncodingException
* @throws GeneralSecurityException
*/
- public static String decryptNoEC(String passphrase, byte[] encryptedKey) throws UnsupportedEncodingException, GeneralSecurityException{
+ public static String decryptNoEC(String passphrase, byte[] encryptedKey) throws UnsupportedEncodingException, GeneralSecurityException {
+ return decryptNoEC(passphrase, encryptedKey, MainNetParams.get());
+ }
+
+ /**
+ * Decrypts a key that was encrypted without EC multiplication.
+ * @param passphrase
+ * @param encryptedKey
+ * @param params
+ * @return the key, Base58-encoded
+ * @throws UnsupportedEncodingException
+ * @throws GeneralSecurityException
+ */
+ public static String decryptNoEC(String passphrase, byte[] encryptedKey, NetworkParameters params) throws UnsupportedEncodingException, GeneralSecurityException {
byte[] addressHash = Arrays.copyOfRange(encryptedKey, 3, 7);
byte[] scryptKey = SCrypt.scrypt(passphrase.getBytes("UTF8"), addressHash, 16384, 8, 8, 64);
@@ -366,15 +396,16 @@ public static String decryptNoEC(String passphrase, byte[] encryptedKey) throws
boolean compressed = (encryptedKey[2] & (byte) 0x20) == 0x20;
ECKey k = new ECKey(new BigInteger(1, keyBytes), null, compressed);
- return k.getPrivateKeyEncoded(MainNetParams.get()).toString();
+ return k.getPrivateKeyEncoded(params).toString();
}
// command line encryption and decryption.
public static void main(String args[]) throws Exception {
+
switch(args.length) {
case 3:
if (args[0].equals("-e")) {
- System.out.println(encryptNoEC(args[1], args[2], false));
+ System.out.println(encryptNoEC(args[1], args[2], true));
}
else if (args[0].equals("-d")) {
System.out.println(decrypt(args[1], args[2]));
View
22 src/main/java/com/fruitcat/bitcoin/Utils.java
@@ -17,12 +17,15 @@
package com.fruitcat.bitcoin;
+import com.google.bitcoin.core.AddressFormatException;
import com.google.bitcoin.core.Base58;
import org.bouncycastle.math.ec.ECPoint;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.MessageDigest;
@@ -125,6 +128,25 @@ public static String base58Check(byte [] b) throws NoSuchAlgorithmException {
return baos.toByteArray();
}
+ /**
+ * Gets the lot and sequence for a key (-1, -1 if not present)
+ * @param encryptedKey
+ * @return 4096 * lot + sequence
+ * @throws AddressFormatException
+ */
+ public static long getLotSequence(String encryptedKey) throws AddressFormatException {
+
+ long ret = -4097; //-1 lot, -1 sequence
+ byte[] keyBytes = Base58.decode(encryptedKey);
+ byte flagByte = keyBytes[2];
+ if ((flagByte & 4) == 4) {
+ ByteBuffer b = ByteBuffer.wrap(keyBytes, 11, 4);
+ b.order(ByteOrder.BIG_ENDIAN);
+ ret = (long) b.getInt() & 0xffffffffL;
+ }
+ return ret;
+ }
+
//for debugging
protected static void pb(String name, byte[] x) {
System.out.print(name + ": ");
View
14 src/test/java/com/fruitcat/bitcoin/BIP38Test.java
@@ -50,12 +50,19 @@ public void ecMultiplyNoCompressionNoLot() throws Exception {
String encryptedKey = "6PfQu77ygVyJLZjfvMLyhLMQbYnu5uguoJJ4kMCLqWwPEdfpwANVS76gTX";
String key = "5K4caxezwjGCGfnoPTZ8tMcJBLB7Jvyjv4xxeacadhq8nLisLR2";
String decryptedKey = BIP38.decrypt(testPass, encryptedKey);
+ long ls = Utils.getLotSequence(encryptedKey);
assertEquals(key, decryptedKey);
+ assertEquals(-1, ls / 4096);
+ assertEquals(-1, ls % 4096);
//test 2
key = "5KJ51SgxWaAYR13zd9ReMhJpwrcX47xTJh2D3fGPG9CM8vkv5sH";
encryptedKey = "6PfLGnQs6VZnrNpmVKfjotbnQuaJK4KZoPFrAjx1JMJUa1Ft8gnf5WxfKd";
decryptedKey = BIP38.decrypt("Satoshi", encryptedKey);
assertEquals(key, decryptedKey);
+ ls = Utils.getLotSequence(encryptedKey);
+ assertEquals(key, decryptedKey);
+ assertEquals(-1, ls / 4096);
+ assertEquals(-1, ls % 4096);
}
//EC multiply, no compression, lot/sequence
@@ -65,12 +72,19 @@ public void ecMultiplyNoCompressionLot() throws Exception {
String encryptedKey = "6PgNBNNzDkKdhkT6uJntUXwwzQV8Rr2tZcbkDcuC9DZRsS6AtHts4Ypo1j";
String key = "5JLdxTtcTHcfYcmJsNVy1v2PMDx432JPoYcBTVVRHpPaxUrdtf8";
String decryptedKey = BIP38.decrypt("MOLON LABE", encryptedKey);
+ long ls = Utils.getLotSequence(encryptedKey);
+ assertEquals(ls / 4096, 263183);
+ assertEquals(ls % 4096, 1);
+
assertEquals(key, decryptedKey);
//test 2
encryptedKey = "6PgGWtx25kUg8QWvwuJAgorN6k9FbE25rv5dMRwu5SKMnfpfVe5mar2ngH";
key = "5KMKKuUmAkiNbA3DazMQiLfDq47qs8MAEThm4yL8R2PhV1ov33D";
decryptedKey = BIP38.decrypt("ΜΟΛΩΝ ΛΑΒΕ", encryptedKey);
assertEquals(key, decryptedKey);
+ ls = Utils.getLotSequence(encryptedKey);
+ assertEquals(ls / 4096, 806938);
+ assertEquals(ls % 4096, 1);
}
//round encrypt and decrypt with a random ascii password

0 comments on commit 99409ed

Please sign in to comment.