diff --git a/examples/example_26.conf b/examples/example_26.conf new file mode 100644 index 0000000..d86e248 --- /dev/null +++ b/examples/example_26.conf @@ -0,0 +1,9 @@ +PRINT_SEEDS +anyText +6 +brother +canal +? +remove +pitch +hill \ No newline at end of file diff --git a/pom.xml b/pom.xml index eba09f7..4458614 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.pawelgorny lostword - 0.15.0 + 0.16.0 jar diff --git a/src/main/java/com/pawelgorny/lostword/Configuration.java b/src/main/java/com/pawelgorny/lostword/Configuration.java index cdefa8f..7d08c4e 100644 --- a/src/main/java/com/pawelgorny/lostword/Configuration.java +++ b/src/main/java/com/pawelgorny/lostword/Configuration.java @@ -96,7 +96,7 @@ private void parseScript(String targetAddress) { this.coin = Configuration.ETHEREUM; } } - if (!WORK.ONE_UNKNOWN_CHECK_ALL.equals(work) && !WORK.PERMUTATION.equals(work)){ + if (!WORK.ONE_UNKNOWN_CHECK_ALL.equals(work) && !WORK.PERMUTATION.equals(work) && !WORK.PRINT_SEEDS.equals(work)){ if (this.ethereumAddress==null){ switch (getDBscriptType()){ case P2PKH: diff --git a/src/main/java/com/pawelgorny/lostword/Main.java b/src/main/java/com/pawelgorny/lostword/Main.java index c2edad9..478d2e9 100644 --- a/src/main/java/com/pawelgorny/lostword/Main.java +++ b/src/main/java/com/pawelgorny/lostword/Main.java @@ -88,7 +88,7 @@ private static Configuration readConfiguration(String file) { } words.add(line); } - }else if (WORK.KNOWN_POSITION.equals(work) || WORK.PERMUTATION.equals(work) || WORK.PERMUTATION_CHECK.equals(work)){ + }else if (WORK.KNOWN_POSITION.equals(work) || WORK.PERMUTATION.equals(work) || WORK.PERMUTATION_CHECK.equals(work)|| WORK.PRINT_SEEDS.equals(work)){ if (words.size() == size) { path = line; }else if (words.size() < size) { @@ -153,7 +153,7 @@ private static Configuration readConfiguration(String file) { if (WORK.POOL.equals(work)){ configuration.setWORDS_POOL(wordsPool); } - if (WORK.KNOWN_POSITION.equals(work) && words.get(size-1).equalsIgnoreCase("?")){ + if ((WORK.KNOWN_POSITION.equals(work)||WORK.PRINT_SEEDS.equals(work)) && words.get(size-1).equalsIgnoreCase("?")){ for (int s=9, b=3; s<=24; s+=3, b++){ if (s==size){ configuration.setMissingChecksum(true); diff --git a/src/main/java/com/pawelgorny/lostword/WORK.java b/src/main/java/com/pawelgorny/lostword/WORK.java index ceff30b..6a9699d 100644 --- a/src/main/java/com/pawelgorny/lostword/WORK.java +++ b/src/main/java/com/pawelgorny/lostword/WORK.java @@ -1,5 +1,6 @@ package com.pawelgorny.lostword; public enum WORK { - ONE_UNKNOWN, KNOWN_POSITION, ONE_UNKNOWN_CHECK_ALL, POOL, PERMUTATION, PERMUTATION_CHECK + ONE_UNKNOWN, KNOWN_POSITION, ONE_UNKNOWN_CHECK_ALL, POOL, PERMUTATION, PERMUTATION_CHECK, + PRINT_SEEDS } diff --git a/src/main/java/com/pawelgorny/lostword/Worker.java b/src/main/java/com/pawelgorny/lostword/Worker.java index b61a7f6..0abe843 100644 --- a/src/main/java/com/pawelgorny/lostword/Worker.java +++ b/src/main/java/com/pawelgorny/lostword/Worker.java @@ -47,6 +47,8 @@ public class Worker { private final int CONCAT_LEN_BITS_MINUS_CONCAT_LEN_BITS_DIV_33; private final int CONCAT_LEN_BITS_MINUS_CONCAT_LEN_BITS_DIV_33__DIV8; + protected final List PRINT_SEEDS=new ArrayList<>(0); + public Worker(Configuration configuration) { this.configuration = configuration; this.CONCAT_LEN_BITS = 11 * configuration.getSIZE(); @@ -84,9 +86,12 @@ public void run() throws InterruptedException, MnemonicException { case PERMUTATION: worker = new WorkerPermutation(configuration); break; + case PRINT_SEEDS: + worker = new WorkerPrintSeeds(configuration); + break; } System.out.println("--- Starting worker --- "+ SDTF.format(new Date())+" ---"); - if (WORK.PERMUTATION.equals(configuration.getWork())){ + if (WORK.PERMUTATION.equals(configuration.getWork()) || WORK.PRINT_SEEDS.equals(configuration.getWork())){ worker.run(); System.out.println(); return; @@ -173,6 +178,21 @@ protected Boolean check(final List mnemonic, HMac SHA512DIGEST, MessageD return false; } + protected Boolean checkPrint(final List mnemonic, HMac SHA512DIGEST, MessageDigest sha256) throws MnemonicException { + if (!checksumCheck(mnemonic, sha256)){ + return configuration.isMissingChecksum()?null:false; + } + + if (Configuration.ETHEREUM.equals(configuration.getCoin())){ + return checkEthereum(mnemonic); + } + + String seed = Utils.SPACE_JOINER.join(mnemonic); + System.out.println(seed); + PRINT_SEEDS.add(seed); + return true; + } + protected boolean checkEthereum(final List mnemonic) throws MnemonicException { DeterministicSeed seed = new DeterministicSeed(mnemonic, null, "", System.currentTimeMillis()); DeterministicKeyChain chain = DeterministicKeyChain.builder().seed(seed).build(); diff --git a/src/main/java/com/pawelgorny/lostword/WorkerKnownPosition.java b/src/main/java/com/pawelgorny/lostword/WorkerKnownPosition.java index 1fd7fc1..bbdf8a4 100644 --- a/src/main/java/com/pawelgorny/lostword/WorkerKnownPosition.java +++ b/src/main/java/com/pawelgorny/lostword/WorkerKnownPosition.java @@ -16,6 +16,7 @@ public class WorkerKnownPosition extends Worker{ private static int NUMBER_UNKNOWN; private long start = 0; + private long COUNTER = 0L; public WorkerKnownPosition(Configuration configuration) { super(configuration); @@ -109,13 +110,15 @@ private void checkUnknown(int position) throws InterruptedException { private Boolean processSeed(final List seed, int depth, int positionStartSearch, boolean reporter, HMac SHA_512_DIGEST, MessageDigest SHA_256_DIGEST) throws MnemonicException { if (NUMBER_UNKNOWN==depth){ Boolean checkResult = check(seed, SHA_512_DIGEST, SHA_256_DIGEST); + COUNTER++; if (checkResult!=null&&checkResult){ System.out.println(seed); RESULT = new Result(new ArrayList<>(seed)); return true; } if (reporter && (System.currentTimeMillis()-start > STATUS_PERIOD)){ - System.out.println(SDTF.format(new Date())+ " Alive!"); + System.out.println(SDTF.format(new Date())+ " Alive! "+(COUNTER)); + COUNTER = 0; start = System.currentTimeMillis(); } return configuration.isMissingChecksum()?(checkResult==null?false:null):checkResult; diff --git a/src/main/java/com/pawelgorny/lostword/WorkerPermutationCheck.java b/src/main/java/com/pawelgorny/lostword/WorkerPermutationCheck.java index df6e4dd..6f8ef7b 100644 --- a/src/main/java/com/pawelgorny/lostword/WorkerPermutationCheck.java +++ b/src/main/java/com/pawelgorny/lostword/WorkerPermutationCheck.java @@ -17,6 +17,7 @@ public class WorkerPermutationCheck extends Worker{ private MessageDigest SHA_256_DIGEST; private long start = 0; + long counter = 0L; public WorkerPermutationCheck(Configuration configuration) { super(configuration); @@ -114,6 +115,9 @@ private boolean checkElements(String[] target, String[] input, HMac LOCAL_SHA_51 List mnemonic = Arrays.asList(target); try { boolean result = check(mnemonic, LOCAL_SHA_512_DIGEST, LOCAL_SHA_256_DIGEST); + if (REPORTER) { + counter++; + } if (result){ RESULT = new Result(mnemonic); } @@ -121,7 +125,8 @@ private boolean checkElements(String[] target, String[] input, HMac LOCAL_SHA_51 System.out.println(e.getLocalizedMessage()); } if (REPORTER && (System.currentTimeMillis()-start > STATUS_PERIOD)){ - System.out.println(SDTF.format(new Date())+ " Alive!"); + System.out.println(SDTF.format(new Date())+ " Alive! "+counter); + counter = 0; start = System.currentTimeMillis(); } return (RESULT!=null); diff --git a/src/main/java/com/pawelgorny/lostword/WorkerPrintSeeds.java b/src/main/java/com/pawelgorny/lostword/WorkerPrintSeeds.java new file mode 100644 index 0000000..f93d7e2 --- /dev/null +++ b/src/main/java/com/pawelgorny/lostword/WorkerPrintSeeds.java @@ -0,0 +1,205 @@ +package com.pawelgorny.lostword; + +import org.bitcoinj.crypto.MnemonicException; +import org.bouncycastle.crypto.macs.HMac; + +import java.io.FileWriter; +import java.io.IOException; +import java.security.MessageDigest; +import java.util.*; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class WorkerPrintSeeds extends Worker{ + + private static int NUMBER_UNKNOWN; + private long start = 0; + private long COUNTER = 0L; + + public WorkerPrintSeeds(Configuration configuration) { + super(configuration); + THREADS = 1; + } + + public void run() throws InterruptedException, MnemonicException { + check(); + try { + FileWriter fileWriter = new FileWriter(this.configuration.getWork().name() + "_result_" + SDTCF.format(new Date()) + ".txt", false); + for (String seed:PRINT_SEEDS) { + fileWriter.write(seed+"\r\n"); + } + fileWriter.close(); + } catch (IOException e) { + System.out.println("Cannot write to file: " + e.getLocalizedMessage()); + } + } + + private void check() throws MnemonicException, InterruptedException { + NUMBER_UNKNOWN = 0; + int position = -1; + int c=0; + for (String word : configuration.getWORDS()){ + if (Configuration.UNKNOWN_CHAR.equalsIgnoreCase(word)){ + NUMBER_UNKNOWN++; + if (position==-1) { + position = c; + } + } + c++; + } + if (NUMBER_UNKNOWN == 1){ + checkOne(position); + } + else{ + checkUnknown(position); + } + } + + private int getNextUnknown(int startSearch, List list){ + for (int p0=startSearch; p0 mnemonic = new ArrayList<>(configuration.getWORDS()); + List> DICTIONARY = split(); + int nextPosition = getNextUnknown(1+position, configuration.getWORDS()); + + final List SHA_256_DIGESTS= new ArrayList<>(THREADS); + final List SHA_512_DIGESTS= new ArrayList<>(THREADS); + for (int t=0; t SEED = new LinkedList<>(mnemonic); + final List WORDS_TO_WORK = DICTIONARY.get(t); + final boolean REPORTER = t==0; + final int T_NUMBER=t; + executorService.submit(() -> { + if (REPORTER) { + start = System.currentTimeMillis(); + } + final HMac LOCAL_SHA_512_DIGEST = SHA_512_DIGESTS.get(T_NUMBER); + final MessageDigest LOCAL_SHA_256_DIGEST = SHA_256_DIGESTS.get(T_NUMBER); + try { + int WORKING_POSITION_PLUS = WORKING_POSITION+1; + for (int bipPosition = 0; RESULT == null && bipPosition < WORDS_TO_WORK.size(); bipPosition++) { + SEED.set(WORKING_POSITION, WORDS_TO_WORK.get(bipPosition)); + processSeed(SEED, 2, WORKING_POSITION_PLUS, REPORTER, LOCAL_SHA_512_DIGEST, LOCAL_SHA_256_DIGEST); + } + } catch (Exception e) { + Thread.currentThread().interrupt(); + } + latch.countDown(); + }); + } + latch.await(); + executorService.shutdown(); + } + } + + private Boolean processSeed(final List seed, int depth, int positionStartSearch, boolean reporter, HMac SHA_512_DIGEST, MessageDigest SHA_256_DIGEST) throws MnemonicException { + if (NUMBER_UNKNOWN==depth){ + Boolean checkResult = checkPrint(seed, SHA_512_DIGEST, SHA_256_DIGEST); + COUNTER++; + if (checkResult!=null&&checkResult){ + System.out.println(seed); + RESULT = new Result(new ArrayList<>(seed)); + return true; + } + if (reporter && (System.currentTimeMillis()-start > STATUS_PERIOD)){ + System.out.println(SDTF.format(new Date())+ " Alive! "+(COUNTER)); + COUNTER = 0; + start = System.currentTimeMillis(); + } + return configuration.isMissingChecksum()?(checkResult==null?false:null):checkResult; + }else{ + int nextDepth = depth + 1; + int position = getNextUnknown(positionStartSearch, seed); + if(position == -1){ + Boolean checkResult = check(seed, SHA_512_DIGEST, SHA_256_DIGEST); + if (checkResult!=null&&checkResult){ + System.out.println(seed); + RESULT = new Result(new ArrayList<>(seed)); + } + return false; + } + int positionStartNextSearch = 0; + if (nextDepth > DICTIONARY = split(); + System.out.println("Checking missing word at position " + (position + 1)); + Iterator iterator = configuration.getWORDS().iterator(); + int p = 0; + List mnemonic = new ArrayList<>(configuration.getSIZE()); + for (int i = 0; i < configuration.getSIZE(); i++) { + mnemonic.add(""); + } + while (iterator.hasNext()) { + String word = iterator.next(); + if (Configuration.UNKNOWN_CHAR.equalsIgnoreCase(word)){ + continue; + } + if (p == position) { + p++; + } + mnemonic.set(p++, word); + } + final CountDownLatch latch = new CountDownLatch(THREADS); + final ExecutorService executorService = Executors.newFixedThreadPool(THREADS); + for (int t = 0; t < THREADS; t++) { + final int WORKING_POSITION = position; + final List WORDS_TO_WORK = DICTIONARY.get(t); + final List SEED = new ArrayList<>(mnemonic); + executorService.submit(() -> { + try { + final MessageDigest LOCAL_SHA_256_DIGEST = MessageDigest.getInstance("SHA-256"); + final HMac LOCAL_SHA_512_DIGEST = createHmacSha512Digest(); + for (int bipPosition = 0; RESULT == null && bipPosition < WORDS_TO_WORK.size(); bipPosition++) { + SEED.set(WORKING_POSITION, WORDS_TO_WORK.get(bipPosition)); + checkPrint(SEED, LOCAL_SHA_512_DIGEST, LOCAL_SHA_256_DIGEST); + } + } catch (Exception e) { + Thread.currentThread().interrupt(); + } + latch.countDown(); + }); + } + latch.await(); + executorService.shutdown(); + } + +}