Skip to content

Commit

Permalink
Adding Language enum and support to multiple (PT, ES, FR) dictionaries
Browse files Browse the repository at this point in the history
  • Loading branch information
AB3rtz committed May 23, 2022
1 parent 9e7d4e2 commit 94f007c
Show file tree
Hide file tree
Showing 11 changed files with 10,361 additions and 36 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.syntifi.crypto.key.mnemonic;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Locale;

public enum Language {
EN("english.txt", "ad90bf3beb7b0eb7e5acd74727dc0da96e0a280a258354e7293fb7e211ac03db", StandardCharsets.UTF_8, Locale.ENGLISH),
PT("portuguese.txt", "eed387d44cf8f32f60754527e265230d8019e8a2277937c71ef812e7a46c93fd", StandardCharsets.UTF_8, Locale.forLanguageTag("PT")),
ES("spanish.txt", "a556a26c6a5bb36db0fb7d8bf579cb7465fcaeec03957c0dda61b569962d9da5", StandardCharsets.UTF_8, Locale.forLanguageTag("ES")),
FR("french.txt", "9cbdaadbd3ce9cbaee1b360fce45e935b21e3e2c56d9fcd56b3398ced2371866", StandardCharsets.UTF_8, Locale.FRENCH),
CNS("chinese_simplified.txt", "bfd683b91db88609fabad8968c7efe4bf69606bf5a49ac4a4ba5e355955670cb", StandardCharsets.UTF_8, Locale.CHINA),
CNT("chinese_traditional.txt", "", StandardCharsets.UTF_8, Locale.CHINESE);

private final String fileName;
private final String checkSum;
private final Charset charset;
private final Locale locale;

Language(String fileName, String checkSum, Charset charset, Locale locale) {
this.fileName = fileName;
this.checkSum = checkSum;
this.charset = charset;
this.locale = locale;
}


public String getFileName() {
return fileName;
}

public String getCheckSum() {
return checkSum;
}

public Charset getCharset() {
return charset;
}

public Locale getLocale() {
return locale;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* - Removing logs, watches, ...
* - Removing internal dependencies to helper/utils
* - Adding method to secure random derive the key
* - Adding support for multiple languages
*
*/

Expand All @@ -37,14 +38,10 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.Collections;
import java.util.ArrayList;
import java.text.Collator;
import java.util.*;
import java.util.stream.Collectors;

/**
Expand All @@ -60,14 +57,9 @@
*/

public class MnemonicCode {
private static final Map<String, String> checkSum = new HashMap<String, String>() {{
put("english", "ad90bf3beb7b0eb7e5acd74727dc0da96e0a280a258354e7293fb7e211ac03db");
}};
private static final Map<String, Charset> charSet = new HashMap<String, Charset>() {{
put("english", StandardCharsets.UTF_8);
}};
private static final int PBKDF2_ROUNDS = 2048;
private final List<String> wordList;
private Language language;

/**
* Creates an MnemonicCode object, initializing with words read from the supplied input stream.
Expand All @@ -77,13 +69,12 @@ public class MnemonicCode {
* @throws IOException
* @throws IllegalArgumentException
*/
public MnemonicCode(String language) throws IOException, IllegalArgumentException {
InputStream wordStream = getClass().getResourceAsStream("/" + language + ".txt");
public MnemonicCode(Language language) throws IOException, IllegalArgumentException {
this.language = language;
InputStream wordStream = getClass().getResourceAsStream("/" + language.getFileName());
if (wordStream == null)
throw new FileNotFoundException(language);
String checksum = checkSum.get(language);
Charset charset = charSet.get(language);
try (BufferedReader br = new BufferedReader(new InputStreamReader(wordStream, charset))) {
throw new FileNotFoundException(language.getFileName());
try (BufferedReader br = new BufferedReader(new InputStreamReader(wordStream, language.getCharset()))) {
this.wordList = br.lines()
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
}
Expand All @@ -92,14 +83,14 @@ public MnemonicCode(String language) throws IOException, IllegalArgumentExceptio
throw new IllegalArgumentException("input stream did not contain 2048 bytes");

// If a wordListDigest is supplied check to make sure it matches.
if (checksum != null) {
if (language.getCheckSum()!= null) {
StringBuilder stringBuilder = new StringBuilder();
for (String s : this.getWordList()) {
stringBuilder.append(s);
}
byte[] digest = Sha256.digest(String.valueOf(stringBuilder).getBytes(charset));
byte[] digest = Sha256.digest(String.valueOf(stringBuilder).getBytes(language.getCharset()));
String hexDigest = Hex.encode(digest);
if (!hexDigest.equals(checksum))
if (!hexDigest.equals(language.getCheckSum()))
throw new IllegalArgumentException("wordlist checksum mismatch");
}
}
Expand Down Expand Up @@ -176,9 +167,12 @@ public byte[] toEntropy(List<String> words) throws MnemonicException.MnemonicLen
int concatLenBits = words.size() * 11;
boolean[] concatBits = new boolean[concatLenBits];
int wordindex = 0;
Collator collator = Collator.getInstance(language.getLocale());
//collator.setDecomposition(Collator.FULL_DECOMPOSITION);
//collator.setStrength(Collator.PRIMARY);
for (String word : words) {
// Find the words index in the wordlist.
int ndx = Collections.binarySearch(this.wordList, word);
int ndx = Collections.binarySearch(this.wordList, word, collator);
if (ndx < 0)
throw new MnemonicException.MnemonicWordException(word);

Expand Down Expand Up @@ -269,14 +263,14 @@ public void check(List<String> words) throws MnemonicException {
}

/**
* Method to generate words from securerandom entropy
*
* @param language
* @return
* @return list of mnemonic words
* @throws IOException
* @throws MnemonicException.MnemonicLengthException
*/
public static List<String> generateSecureRandomWords(String language) throws IOException, MnemonicException.MnemonicLengthException {
MnemonicCode mnemonicCode = new MnemonicCode(language);
public List<String> generateSecureRandomWords() throws IOException, MnemonicException.MnemonicLengthException {
MnemonicCode mnemonicCode = new MnemonicCode(this.language);
SecureRandom rnd = new SecureRandom();
byte[] entropy = new byte[16];
rnd.nextBytes(entropy);
Expand Down
Loading

0 comments on commit 94f007c

Please sign in to comment.