mirror of https://github.com/M66B/FairEmail.git
parent
d4a93ded18
commit
94ed34bec7
@ -0,0 +1,58 @@
|
|||||||
|
package eu.faircode.email;
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of FairEmail.
|
||||||
|
|
||||||
|
FairEmail is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
FairEmail is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Copyright 2018-2022 by Marcel Bokhorst (M66B)
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
|
import io.github.novacrypto.bip39.MnemonicGenerator;
|
||||||
|
import io.github.novacrypto.bip39.Words;
|
||||||
|
import io.github.novacrypto.bip39.wordlists.English;
|
||||||
|
|
||||||
|
public class MnemonicHelper {
|
||||||
|
// https://github.com/NovaCrypto/BIP39
|
||||||
|
|
||||||
|
static String get(byte[] entropy) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
new SecureRandom().nextBytes(entropy);
|
||||||
|
new MnemonicGenerator(English.INSTANCE).createMnemonic(entropy, sb::append);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static String get(String hex) {
|
||||||
|
return get(fromHex(hex));
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte[] generate() {
|
||||||
|
byte[] entropy = new byte[Words.TWELVE.byteLength()];
|
||||||
|
new SecureRandom().nextBytes(entropy);
|
||||||
|
return entropy;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] fromHex(String hex) {
|
||||||
|
int len = hex.length();
|
||||||
|
byte[] data = new byte[len / 2];
|
||||||
|
for (int i = 0; i < len; i += 2) {
|
||||||
|
data[i / 2] =
|
||||||
|
(byte) ((Character.digit(hex.charAt(i), 16) << 4) +
|
||||||
|
Character.digit(hex.charAt(i + 1), 16));
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* BIP39 library, a Java implementation of BIP39
|
||||||
|
* Copyright (C) 2017-2019 Alan Evans, NovaCrypto
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Original source: https://github.com/NovaCrypto/BIP39
|
||||||
|
* You can contact the authors via github issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.novacrypto.bip39;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
enum CharSequenceComparators implements Comparator<CharSequence> {
|
||||||
|
|
||||||
|
ALPHABETICAL {
|
||||||
|
@Override
|
||||||
|
public int compare(final CharSequence o1, final CharSequence o2) {
|
||||||
|
final int length1 = o1.length();
|
||||||
|
final int length2 = o2.length();
|
||||||
|
final int length = Math.min(length1, length2);
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
final int compare = Character.compare(o1.charAt(i), o2.charAt(i));
|
||||||
|
if (compare != 0) return compare;
|
||||||
|
}
|
||||||
|
return Integer.compare(length1, length2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* BIP39 library, a Java implementation of BIP39
|
||||||
|
* Copyright (C) 2017-2019 Alan Evans, NovaCrypto
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Original source: https://github.com/NovaCrypto/BIP39
|
||||||
|
* You can contact the authors via github issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.novacrypto.bip39;
|
||||||
|
|
||||||
|
final class ByteUtils {
|
||||||
|
|
||||||
|
static int next11Bits(byte[] bytes, int offset) {
|
||||||
|
final int skip = offset / 8;
|
||||||
|
final int lowerBitsToRemove = (3 * 8 - 11) - (offset % 8);
|
||||||
|
return (((int) bytes[skip] & 0xff) << 16 |
|
||||||
|
((int) bytes[skip + 1] & 0xff) << 8 |
|
||||||
|
(lowerBitsToRemove < 8
|
||||||
|
? ((int) bytes[skip + 2] & 0xff)
|
||||||
|
: 0)) >> lowerBitsToRemove & (1 << 11) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeNext11(byte[] bytes, int value, int offset) {
|
||||||
|
int skip = offset / 8;
|
||||||
|
int bitSkip = offset % 8;
|
||||||
|
{//byte 0
|
||||||
|
byte firstValue = bytes[skip];
|
||||||
|
byte toWrite = (byte) (value >> (3 + bitSkip));
|
||||||
|
bytes[skip] = (byte) (firstValue | toWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
{//byte 1
|
||||||
|
byte valueInByte = bytes[skip + 1];
|
||||||
|
final int i = 5 - bitSkip;
|
||||||
|
byte toWrite = (byte) (i > 0 ? (value << i) : (value >> -i));
|
||||||
|
bytes[skip + 1] = (byte) (valueInByte | toWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bitSkip >= 6) {//byte 2
|
||||||
|
byte valueInByte = bytes[skip + 2];
|
||||||
|
byte toWrite = (byte) (value << 13 - bitSkip);
|
||||||
|
bytes[skip + 2] = (byte) (valueInByte | toWrite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* BIP39 library, a Java implementation of BIP39
|
||||||
|
* Copyright (C) 2017-2019 Alan Evans, NovaCrypto
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Original source: https://github.com/NovaCrypto/BIP39
|
||||||
|
* You can contact the authors via github issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.novacrypto.bip39;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
final class CharSequenceSplitter {
|
||||||
|
|
||||||
|
private final char separator1;
|
||||||
|
private final char separator2;
|
||||||
|
|
||||||
|
CharSequenceSplitter(final char separator1, final char separator2) {
|
||||||
|
this.separator1 = separator1;
|
||||||
|
this.separator2 = separator2;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<CharSequence> split(final CharSequence charSequence) {
|
||||||
|
final LinkedList<CharSequence> list = new LinkedList<>();
|
||||||
|
int start = 0;
|
||||||
|
final int length = charSequence.length();
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
final char c = charSequence.charAt(i);
|
||||||
|
if (c == separator1 || c == separator2) {
|
||||||
|
list.add(charSequence.subSequence(start, i));
|
||||||
|
start = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list.add(charSequence.subSequence(start, length));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* BIP39 library, a Java implementation of BIP39
|
||||||
|
* Copyright (C) 2017-2019 Alan Evans, NovaCrypto
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Original source: https://github.com/NovaCrypto/BIP39
|
||||||
|
* You can contact the authors via github issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.novacrypto.bip39;
|
||||||
|
|
||||||
|
import io.github.novacrypto.toruntime.CheckedExceptionToRuntime;
|
||||||
|
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import javax.crypto.SecretKeyFactory;
|
||||||
|
import javax.crypto.spec.PBEKeySpec;
|
||||||
|
|
||||||
|
import static io.github.novacrypto.toruntime.CheckedExceptionToRuntime.toRuntime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not available in all Java implementations, for example will not find the implementation before Android API 26+.
|
||||||
|
* See https://developer.android.com/reference/javax/crypto/SecretKeyFactory.html for more details.
|
||||||
|
*/
|
||||||
|
public enum JavaxPBKDF2WithHmacSHA512 implements PBKDF2WithHmacSHA512 {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
private SecretKeyFactory skf = getPbkdf2WithHmacSHA512();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] hash(char[] chars, byte[] salt) {
|
||||||
|
final PBEKeySpec spec = new PBEKeySpec(chars, salt, 2048, 512);
|
||||||
|
final byte[] encoded = generateSecretKey(spec).getEncoded();
|
||||||
|
spec.clearPassword();
|
||||||
|
return encoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SecretKey generateSecretKey(final PBEKeySpec spec) {
|
||||||
|
return toRuntime(new CheckedExceptionToRuntime.Func<SecretKey>() {
|
||||||
|
@Override
|
||||||
|
public SecretKey run() throws Exception {
|
||||||
|
return skf.generateSecret(spec);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SecretKeyFactory getPbkdf2WithHmacSHA512() {
|
||||||
|
return toRuntime(new CheckedExceptionToRuntime.Func<SecretKeyFactory>() {
|
||||||
|
@Override
|
||||||
|
public SecretKeyFactory run() throws Exception {
|
||||||
|
return SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* BIP39 library, a Java implementation of BIP39
|
||||||
|
* Copyright (C) 2017-2019 Alan Evans, NovaCrypto
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Original source: https://github.com/NovaCrypto/BIP39
|
||||||
|
* You can contact the authors via github issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.novacrypto.bip39;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static io.github.novacrypto.bip39.ByteUtils.next11Bits;
|
||||||
|
import static io.github.novacrypto.hashing.Sha256.sha256;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates mnemonics from entropy.
|
||||||
|
*/
|
||||||
|
public final class MnemonicGenerator {
|
||||||
|
|
||||||
|
private final WordList wordList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a generator using the given word list.
|
||||||
|
*
|
||||||
|
* @param wordList A known ordered list of 2048 words to select from.
|
||||||
|
*/
|
||||||
|
public MnemonicGenerator(final WordList wordList) {
|
||||||
|
this.wordList = wordList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Target {
|
||||||
|
void append(final CharSequence string);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a mnemonic from the word list given the entropy.
|
||||||
|
*
|
||||||
|
* @param entropyHex 128-256 bits of hex entropy, number of bits must also be divisible by 32
|
||||||
|
* @param target Where to write the mnemonic to
|
||||||
|
*/
|
||||||
|
public void createMnemonic(
|
||||||
|
final CharSequence entropyHex,
|
||||||
|
final Target target) {
|
||||||
|
final int length = entropyHex.length();
|
||||||
|
if (length % 2 != 0)
|
||||||
|
throw new RuntimeException("Length of hex chars must be divisible by 2");
|
||||||
|
final byte[] entropy = new byte[length / 2];
|
||||||
|
try {
|
||||||
|
for (int i = 0, j = 0; i < length; i += 2, j++) {
|
||||||
|
entropy[j] = (byte) (parseHex(entropyHex.charAt(i)) << 4 | parseHex(entropyHex.charAt(i + 1)));
|
||||||
|
}
|
||||||
|
createMnemonic(entropy, target);
|
||||||
|
} finally {
|
||||||
|
Arrays.fill(entropy, (byte) 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a mnemonic from the word list given the entropy.
|
||||||
|
*
|
||||||
|
* @param entropy 128-256 bits of entropy, number of bits must also be divisible by 32
|
||||||
|
* @param target Where to write the mnemonic to
|
||||||
|
*/
|
||||||
|
public void createMnemonic(
|
||||||
|
final byte[] entropy,
|
||||||
|
final Target target) {
|
||||||
|
final int[] wordIndexes = wordIndexes(entropy);
|
||||||
|
try {
|
||||||
|
createMnemonic(wordIndexes, target);
|
||||||
|
} finally {
|
||||||
|
Arrays.fill(wordIndexes, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createMnemonic(
|
||||||
|
final int[] wordIndexes,
|
||||||
|
final Target target) {
|
||||||
|
final String space = String.valueOf(wordList.getSpace());
|
||||||
|
for (int i = 0; i < wordIndexes.length; i++) {
|
||||||
|
if (i > 0) target.append(space);
|
||||||
|
target.append(wordList.getWord(wordIndexes[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int[] wordIndexes(byte[] entropy) {
|
||||||
|
final int ent = entropy.length * 8;
|
||||||
|
entropyLengthPreChecks(ent);
|
||||||
|
|
||||||
|
final byte[] entropyWithChecksum = Arrays.copyOf(entropy, entropy.length + 1);
|
||||||
|
entropyWithChecksum[entropy.length] = firstByteOfSha256(entropy);
|
||||||
|
|
||||||
|
//checksum length
|
||||||
|
final int cs = ent / 32;
|
||||||
|
//mnemonic length
|
||||||
|
final int ms = (ent + cs) / 11;
|
||||||
|
|
||||||
|
//get the indexes into the word list
|
||||||
|
final int[] wordIndexes = new int[ms];
|
||||||
|
for (int i = 0, wi = 0; wi < ms; i += 11, wi++) {
|
||||||
|
wordIndexes[wi] = next11Bits(entropyWithChecksum, i);
|
||||||
|
}
|
||||||
|
return wordIndexes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte firstByteOfSha256(final byte[] entropy) {
|
||||||
|
final byte[] hash = sha256(entropy);
|
||||||
|
final byte firstByte = hash[0];
|
||||||
|
Arrays.fill(hash, (byte) 0);
|
||||||
|
return firstByte;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void entropyLengthPreChecks(final int ent) {
|
||||||
|
if (ent < 128)
|
||||||
|
throw new RuntimeException("Entropy too low, 128-256 bits allowed");
|
||||||
|
if (ent > 256)
|
||||||
|
throw new RuntimeException("Entropy too high, 128-256 bits allowed");
|
||||||
|
if (ent % 32 > 0)
|
||||||
|
throw new RuntimeException("Number of entropy bits must be divisible by 32");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int parseHex(char c) {
|
||||||
|
if (c >= '0' && c <= '9') return c - '0';
|
||||||
|
if (c >= 'a' && c <= 'f') return (c - 'a') + 10;
|
||||||
|
if (c >= 'A' && c <= 'F') return (c - 'A') + 10;
|
||||||
|
throw new RuntimeException("Invalid hex char '" + c + '\'');
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,190 @@
|
|||||||
|
/*
|
||||||
|
* BIP39 library, a Java implementation of BIP39
|
||||||
|
* Copyright (C) 2017-2019 Alan Evans, NovaCrypto
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Original source: https://github.com/NovaCrypto/BIP39
|
||||||
|
* You can contact the authors via github issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.novacrypto.bip39;
|
||||||
|
|
||||||
|
import io.github.novacrypto.bip39.Validation.InvalidChecksumException;
|
||||||
|
import io.github.novacrypto.bip39.Validation.InvalidWordCountException;
|
||||||
|
import io.github.novacrypto.bip39.Validation.UnexpectedWhiteSpaceException;
|
||||||
|
import io.github.novacrypto.bip39.Validation.WordNotFoundException;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
import static io.github.novacrypto.bip39.MnemonicGenerator.firstByteOfSha256;
|
||||||
|
import static io.github.novacrypto.bip39.Normalization.normalizeNFKD;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains function for validating Mnemonics against the BIP0039 spec.
|
||||||
|
*/
|
||||||
|
public final class MnemonicValidator {
|
||||||
|
private final WordAndIndex[] words;
|
||||||
|
private final CharSequenceSplitter charSequenceSplitter;
|
||||||
|
private final NFKDNormalizer normalizer;
|
||||||
|
|
||||||
|
private MnemonicValidator(final WordList wordList) {
|
||||||
|
normalizer = new WordListMapNormalization(wordList);
|
||||||
|
words = new WordAndIndex[1 << 11];
|
||||||
|
for (int i = 0; i < 1 << 11; i++) {
|
||||||
|
words[i] = new WordAndIndex(i, wordList.getWord(i));
|
||||||
|
}
|
||||||
|
charSequenceSplitter = new CharSequenceSplitter(wordList.getSpace(), normalizeNFKD(wordList.getSpace()));
|
||||||
|
Arrays.sort(words, wordListSortOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a Mnemonic validator for the given word list.
|
||||||
|
* No normalization is currently performed, this is an open issue: https://github.com/NovaCrypto/BIP39/issues/13
|
||||||
|
*
|
||||||
|
* @param wordList A WordList implementation
|
||||||
|
* @return A validator
|
||||||
|
*/
|
||||||
|
public static MnemonicValidator ofWordList(final WordList wordList) {
|
||||||
|
return new MnemonicValidator(wordList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that the supplied mnemonic fits the BIP0039 spec.
|
||||||
|
*
|
||||||
|
* @param mnemonic The memorable list of words
|
||||||
|
* @throws InvalidChecksumException If the last bytes don't match the expected last bytes
|
||||||
|
* @throws InvalidWordCountException If the number of words is not a multiple of 3, 24 or fewer
|
||||||
|
* @throws WordNotFoundException If a word in the mnemonic is not present in the word list
|
||||||
|
* @throws UnexpectedWhiteSpaceException Occurs if one of the supplied words is empty, e.g. a double space
|
||||||
|
*/
|
||||||
|
public void validate(final CharSequence mnemonic) throws
|
||||||
|
InvalidChecksumException,
|
||||||
|
InvalidWordCountException,
|
||||||
|
WordNotFoundException,
|
||||||
|
UnexpectedWhiteSpaceException {
|
||||||
|
validate(charSequenceSplitter.split(mnemonic));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that the supplied mnemonic fits the BIP0039 spec.
|
||||||
|
* <p>
|
||||||
|
* The purpose of this method overload is to avoid constructing a mnemonic String if you have gathered a list of
|
||||||
|
* words from the user.
|
||||||
|
*
|
||||||
|
* @param mnemonic The memorable list of words
|
||||||
|
* @throws InvalidChecksumException If the last bytes don't match the expected last bytes
|
||||||
|
* @throws InvalidWordCountException If the number of words is not a multiple of 3, 24 or fewer
|
||||||
|
* @throws WordNotFoundException If a word in the mnemonic is not present in the word list
|
||||||
|
* @throws UnexpectedWhiteSpaceException Occurs if one of the supplied words is empty
|
||||||
|
*/
|
||||||
|
public void validate(final Collection<? extends CharSequence> mnemonic) throws
|
||||||
|
InvalidChecksumException,
|
||||||
|
InvalidWordCountException,
|
||||||
|
WordNotFoundException,
|
||||||
|
UnexpectedWhiteSpaceException {
|
||||||
|
final int[] wordIndexes = findWordIndexes(mnemonic);
|
||||||
|
try {
|
||||||
|
validate(wordIndexes);
|
||||||
|
} finally {
|
||||||
|
Arrays.fill(wordIndexes, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void validate(final int[] wordIndexes) throws
|
||||||
|
InvalidWordCountException,
|
||||||
|
InvalidChecksumException {
|
||||||
|
final int ms = wordIndexes.length;
|
||||||
|
|
||||||
|
final int entPlusCs = ms * 11;
|
||||||
|
final int ent = (entPlusCs * 32) / 33;
|
||||||
|
final int cs = ent / 32;
|
||||||
|
if (entPlusCs != ent + cs)
|
||||||
|
throw new InvalidWordCountException();
|
||||||
|
final byte[] entropyWithChecksum = new byte[(entPlusCs + 7) / 8];
|
||||||
|
|
||||||
|
wordIndexesToEntropyWithCheckSum(wordIndexes, entropyWithChecksum);
|
||||||
|
Arrays.fill(wordIndexes, 0);
|
||||||
|
|
||||||
|
final byte[] entropy = Arrays.copyOf(entropyWithChecksum, entropyWithChecksum.length - 1);
|
||||||
|
final byte lastByte = entropyWithChecksum[entropyWithChecksum.length - 1];
|
||||||
|
Arrays.fill(entropyWithChecksum, (byte) 0);
|
||||||
|
|
||||||
|
final byte sha = firstByteOfSha256(entropy);
|
||||||
|
|
||||||
|
final byte mask = maskOfFirstNBits(cs);
|
||||||
|
|
||||||
|
if (((sha ^ lastByte) & mask) != 0)
|
||||||
|
throw new InvalidChecksumException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] findWordIndexes(final Collection<? extends CharSequence> split) throws
|
||||||
|
UnexpectedWhiteSpaceException,
|
||||||
|
WordNotFoundException {
|
||||||
|
final int ms = split.size();
|
||||||
|
final int[] result = new int[ms];
|
||||||
|
int i = 0;
|
||||||
|
for (final CharSequence buffer : split) {
|
||||||
|
if (buffer.length() == 0) {
|
||||||
|
throw new UnexpectedWhiteSpaceException();
|
||||||
|
}
|
||||||
|
result[i++] = findWordIndex(buffer);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int findWordIndex(final CharSequence buffer) throws WordNotFoundException {
|
||||||
|
final WordAndIndex key = new WordAndIndex(-1, buffer);
|
||||||
|
final int index = Arrays.binarySearch(words, key, wordListSortOrder);
|
||||||
|
if (index < 0) {
|
||||||
|
final int insertionPoint = -index - 1;
|
||||||
|
int suggestion = insertionPoint == 0 ? insertionPoint : insertionPoint - 1;
|
||||||
|
if (suggestion + 1 == words.length) suggestion--;
|
||||||
|
throw new WordNotFoundException(buffer, words[suggestion].word, words[suggestion + 1].word);
|
||||||
|
|
||||||
|
}
|
||||||
|
return words[index].index;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void wordIndexesToEntropyWithCheckSum(final int[] wordIndexes, final byte[] entropyWithChecksum) {
|
||||||
|
for (int i = 0, bi = 0; i < wordIndexes.length; i++, bi += 11) {
|
||||||
|
ByteUtils.writeNext11(entropyWithChecksum, wordIndexes[i], bi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte maskOfFirstNBits(final int n) {
|
||||||
|
return (byte) ~((1 << (8 - n)) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Comparator<WordAndIndex> wordListSortOrder = new Comparator<WordAndIndex>() {
|
||||||
|
@Override
|
||||||
|
public int compare(final WordAndIndex o1, final WordAndIndex o2) {
|
||||||
|
return CharSequenceComparators.ALPHABETICAL.compare(o1.normalized, o2.normalized);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private class WordAndIndex {
|
||||||
|
final CharSequence word;
|
||||||
|
final String normalized;
|
||||||
|
final int index;
|
||||||
|
|
||||||
|
WordAndIndex(final int i, final CharSequence word) {
|
||||||
|
this.word = word;
|
||||||
|
normalized = normalizer.normalize(word);
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* BIP39 library, a Java implementation of BIP39
|
||||||
|
* Copyright (C) 2017-2019 Alan Evans, NovaCrypto
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Original source: https://github.com/NovaCrypto/BIP39
|
||||||
|
* You can contact the authors via github issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.novacrypto.bip39;
|
||||||
|
|
||||||
|
public interface NFKDNormalizer {
|
||||||
|
|
||||||
|
String normalize(CharSequence charSequence);
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* BIP39 library, a Java implementation of BIP39
|
||||||
|
* Copyright (C) 2017-2019 Alan Evans, NovaCrypto
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Original source: https://github.com/NovaCrypto/BIP39
|
||||||
|
* You can contact the authors via github issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.novacrypto.bip39;
|
||||||
|
|
||||||
|
import java.text.Normalizer;
|
||||||
|
|
||||||
|
final class Normalization {
|
||||||
|
static String normalizeNFKD(final String string) {
|
||||||
|
return Normalizer.normalize(string, Normalizer.Form.NFKD);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char normalizeNFKD(final char c) {
|
||||||
|
return normalizeNFKD("" + c).charAt(0);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* BIP39 library, a Java implementation of BIP39
|
||||||
|
* Copyright (C) 2017-2019 Alan Evans, NovaCrypto
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Original source: https://github.com/NovaCrypto/BIP39
|
||||||
|
* You can contact the authors via github issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.novacrypto.bip39;
|
||||||
|
|
||||||
|
public interface PBKDF2WithHmacSHA512 {
|
||||||
|
|
||||||
|
byte[] hash(final char[] chars, final byte[] salt);
|
||||||
|
}
|
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* BIP39 library, a Java implementation of BIP39
|
||||||
|
* Copyright (C) 2017-2019 Alan Evans, NovaCrypto
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Original source: https://github.com/NovaCrypto/BIP39
|
||||||
|
* You can contact the authors via github issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.novacrypto.bip39;
|
||||||
|
|
||||||
|
import io.github.novacrypto.toruntime.CheckedExceptionToRuntime;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static io.github.novacrypto.bip39.Normalization.normalizeNFKD;
|
||||||
|
import static io.github.novacrypto.toruntime.CheckedExceptionToRuntime.toRuntime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains function for generating seeds from a Mnemonic and Passphrase.
|
||||||
|
*/
|
||||||
|
public final class SeedCalculator {
|
||||||
|
|
||||||
|
private final byte[] fixedSalt = getUtf8Bytes("mnemonic");
|
||||||
|
private final PBKDF2WithHmacSHA512 hashAlgorithm;
|
||||||
|
|
||||||
|
public SeedCalculator(final PBKDF2WithHmacSHA512 hashAlgorithm) {
|
||||||
|
this.hashAlgorithm = hashAlgorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a seed calculator using {@link SpongyCastlePBKDF2WithHmacSHA512} which is the most compatible.
|
||||||
|
* Use {@link SeedCalculator#SeedCalculator(PBKDF2WithHmacSHA512)} to supply another.
|
||||||
|
*/
|
||||||
|
public SeedCalculator() {
|
||||||
|
this(SpongyCastlePBKDF2WithHmacSHA512.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the seed given a mnemonic and corresponding passphrase.
|
||||||
|
* The phrase is not checked for validity here, for that use a {@link MnemonicValidator}.
|
||||||
|
* <p>
|
||||||
|
* Due to normalization, these need to be {@link String}, and not {@link CharSequence}, this is an open issue:
|
||||||
|
* https://github.com/NovaCrypto/BIP39/issues/7
|
||||||
|
* <p>
|
||||||
|
* If you have a list of words selected from a word list, you can use {@link #withWordsFromWordList} then
|
||||||
|
* {@link SeedCalculatorByWordListLookUp#calculateSeed}
|
||||||
|
*
|
||||||
|
* @param mnemonic The memorable list of words
|
||||||
|
* @param passphrase An optional passphrase, use "" if not required
|
||||||
|
* @return a seed for HD wallet generation
|
||||||
|
*/
|
||||||
|
public byte[] calculateSeed(final String mnemonic, final String passphrase) {
|
||||||
|
final char[] chars = normalizeNFKD(mnemonic).toCharArray();
|
||||||
|
try {
|
||||||
|
return calculateSeed(chars, passphrase);
|
||||||
|
} finally {
|
||||||
|
Arrays.fill(chars, '\0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] calculateSeed(final char[] mnemonicChars, final String passphrase) {
|
||||||
|
final String normalizedPassphrase = normalizeNFKD(passphrase);
|
||||||
|
final byte[] salt2 = getUtf8Bytes(normalizedPassphrase);
|
||||||
|
final byte[] salt = combine(fixedSalt, salt2);
|
||||||
|
clear(salt2);
|
||||||
|
final byte[] encoded = hash(mnemonicChars, salt);
|
||||||
|
clear(salt);
|
||||||
|
return encoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SeedCalculatorByWordListLookUp withWordsFromWordList(final WordList wordList) {
|
||||||
|
return new SeedCalculatorByWordListLookUp(this, wordList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] combine(final byte[] array1, final byte[] array2) {
|
||||||
|
final byte[] bytes = new byte[array1.length + array2.length];
|
||||||
|
System.arraycopy(array1, 0, bytes, 0, array1.length);
|
||||||
|
System.arraycopy(array2, 0, bytes, array1.length, bytes.length - array1.length);
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void clear(final byte[] salt) {
|
||||||
|
Arrays.fill(salt, (byte) 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] hash(final char[] chars, final byte[] salt) {
|
||||||
|
return hashAlgorithm.hash(chars, salt);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] getUtf8Bytes(final String string) {
|
||||||
|
return toRuntime(new CheckedExceptionToRuntime.Func<byte[]>() {
|
||||||
|
@Override
|
||||||
|
public byte[] run() throws Exception {
|
||||||
|
return string.getBytes("UTF-8");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* BIP39 library, a Java implementation of BIP39
|
||||||
|
* Copyright (C) 2017-2019 Alan Evans, NovaCrypto
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Original source: https://github.com/NovaCrypto/BIP39
|
||||||
|
* You can contact the authors via github issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.novacrypto.bip39;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public final class SeedCalculatorByWordListLookUp {
|
||||||
|
private final SeedCalculator seedCalculator;
|
||||||
|
private final Map<CharSequence, char[]> map = new HashMap<>();
|
||||||
|
private final NFKDNormalizer normalizer;
|
||||||
|
|
||||||
|
SeedCalculatorByWordListLookUp(final SeedCalculator seedCalculator, final WordList wordList) {
|
||||||
|
this.seedCalculator = seedCalculator;
|
||||||
|
normalizer = new WordListMapNormalization(wordList);
|
||||||
|
for (int i = 0; i < 1 << 11; i++) {
|
||||||
|
final String word = normalizer.normalize(wordList.getWord(i));
|
||||||
|
map.put(word, word.toCharArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the seed given a mnemonic and corresponding passphrase.
|
||||||
|
* The phrase is not checked for validity here, for that use a {@link MnemonicValidator}.
|
||||||
|
* <p>
|
||||||
|
* The purpose of this method is to avoid constructing a mnemonic String if you have gathered a list of
|
||||||
|
* words from the user and also to avoid having to normalize it, all words in the {@link WordList} are normalized
|
||||||
|
* instead.
|
||||||
|
* <p>
|
||||||
|
* Due to normalization, the passphrase still needs to be {@link String}, and not {@link CharSequence}, this is an
|
||||||
|
* open issue: https://github.com/NovaCrypto/BIP39/issues/7
|
||||||
|
*
|
||||||
|
* @param mnemonic The memorable list of words, ideally selected from the word list that was supplied while creating this object.
|
||||||
|
* @param passphrase An optional passphrase, use "" if not required
|
||||||
|
* @return a seed for HD wallet generation
|
||||||
|
*/
|
||||||
|
public byte[] calculateSeed(final Collection<? extends CharSequence> mnemonic, final String passphrase) {
|
||||||
|
final int words = mnemonic.size();
|
||||||
|
final char[][] chars = new char[words][];
|
||||||
|
final List<char[]> toClear = new LinkedList<>();
|
||||||
|
int count = 0;
|
||||||
|
int wordIndex = 0;
|
||||||
|
for (final CharSequence word : mnemonic) {
|
||||||
|
char[] wordChars = map.get(normalizer.normalize(word));
|
||||||
|
if (wordChars == null) {
|
||||||
|
wordChars = normalizer.normalize(word).toCharArray();
|
||||||
|
toClear.add(wordChars);
|
||||||
|
}
|
||||||
|
chars[wordIndex++] = wordChars;
|
||||||
|
count += wordChars.length;
|
||||||
|
}
|
||||||
|
count += words - 1;
|
||||||
|
final char[] mnemonicChars = new char[count];
|
||||||
|
try {
|
||||||
|
int index = 0;
|
||||||
|
for (int i = 0; i < chars.length; i++) {
|
||||||
|
System.arraycopy(chars[i], 0, mnemonicChars, index, chars[i].length);
|
||||||
|
index += chars[i].length;
|
||||||
|
if (i < chars.length - 1) {
|
||||||
|
mnemonicChars[index++] = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return seedCalculator.calculateSeed(mnemonicChars, passphrase);
|
||||||
|
} finally {
|
||||||
|
Arrays.fill(mnemonicChars, '\0');
|
||||||
|
Arrays.fill(chars, null);
|
||||||
|
for (final char[] charsToClear : toClear)
|
||||||
|
Arrays.fill(charsToClear, '\0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* BIP39 library, a Java implementation of BIP39
|
||||||
|
* Copyright (C) 2017-2019 Alan Evans, NovaCrypto
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Original source: https://github.com/NovaCrypto/BIP39
|
||||||
|
* You can contact the authors via github issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.novacrypto.bip39;
|
||||||
|
|
||||||
|
import org.bouncycastle.crypto.PBEParametersGenerator;
|
||||||
|
import org.bouncycastle.crypto.digests.SHA512Digest;
|
||||||
|
import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
|
||||||
|
import org.bouncycastle.crypto.params.KeyParameter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This implementation is useful for older Java implementations, for example it is suitable for all Android API levels.
|
||||||
|
*/
|
||||||
|
public enum SpongyCastlePBKDF2WithHmacSHA512 implements PBKDF2WithHmacSHA512 {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] hash(char[] chars, byte[] salt) {
|
||||||
|
PKCS5S2ParametersGenerator generator = new PKCS5S2ParametersGenerator(new SHA512Digest());
|
||||||
|
generator.init(PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(chars), salt, 2048);
|
||||||
|
KeyParameter key = (KeyParameter) generator.generateDerivedMacParameters(512);
|
||||||
|
return key.getKey();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* BIP39 library, a Java implementation of BIP39
|
||||||
|
* Copyright (C) 2017-2019 Alan Evans, NovaCrypto
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Original source: https://github.com/NovaCrypto/BIP39
|
||||||
|
* You can contact the authors via github issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.novacrypto.bip39.Validation;
|
||||||
|
|
||||||
|
public final class InvalidChecksumException extends Exception {
|
||||||
|
public InvalidChecksumException() {
|
||||||
|
super("Invalid checksum");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* BIP39 library, a Java implementation of BIP39
|
||||||
|
* Copyright (C) 2017-2019 Alan Evans, NovaCrypto
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Original source: https://github.com/NovaCrypto/BIP39
|
||||||
|
* You can contact the authors via github issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.novacrypto.bip39.Validation;
|
||||||
|
|
||||||
|
public final class InvalidWordCountException extends Exception {
|
||||||
|
public InvalidWordCountException() {
|
||||||
|
super("Not a correct number of words");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* BIP39 library, a Java implementation of BIP39
|
||||||
|
* Copyright (C) 2017-2019 Alan Evans, NovaCrypto
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Original source: https://github.com/NovaCrypto/BIP39
|
||||||
|
* You can contact the authors via github issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.novacrypto.bip39.Validation;
|
||||||
|
|
||||||
|
public final class UnexpectedWhiteSpaceException extends Exception {
|
||||||
|
public UnexpectedWhiteSpaceException() {
|
||||||
|
super("Unexpected whitespace");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* BIP39 library, a Java implementation of BIP39
|
||||||
|
* Copyright (C) 2017-2019 Alan Evans, NovaCrypto
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Original source: https://github.com/NovaCrypto/BIP39
|
||||||
|
* You can contact the authors via github issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.novacrypto.bip39.Validation;
|
||||||
|
|
||||||
|
public final class WordNotFoundException extends Exception {
|
||||||
|
private final CharSequence word;
|
||||||
|
private final CharSequence suggestion1;
|
||||||
|
private final CharSequence suggestion2;
|
||||||
|
|
||||||
|
public WordNotFoundException(
|
||||||
|
final CharSequence word,
|
||||||
|
final CharSequence suggestion1,
|
||||||
|
final CharSequence suggestion2) {
|
||||||
|
super(String.format(
|
||||||
|
"Word not found in word list \"%s\", suggestions \"%s\", \"%s\"",
|
||||||
|
word,
|
||||||
|
suggestion1,
|
||||||
|
suggestion2));
|
||||||
|
this.word = word;
|
||||||
|
this.suggestion1 = suggestion1;
|
||||||
|
this.suggestion2 = suggestion2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharSequence getWord() {
|
||||||
|
return word;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharSequence getSuggestion1() {
|
||||||
|
return suggestion1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharSequence getSuggestion2() {
|
||||||
|
return suggestion2;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* BIP39 library, a Java implementation of BIP39
|
||||||
|
* Copyright (C) 2017-2019 Alan Evans, NovaCrypto
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Original source: https://github.com/NovaCrypto/BIP39
|
||||||
|
* You can contact the authors via github issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.novacrypto.bip39;
|
||||||
|
|
||||||
|
public interface WordList {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a word in the word list.
|
||||||
|
*
|
||||||
|
* @param index Index of word in the word list [0..2047] inclusive.
|
||||||
|
* @return the word from the list.
|
||||||
|
*/
|
||||||
|
String getWord(final int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the space character for this language.
|
||||||
|
*
|
||||||
|
* @return a whitespace character.
|
||||||
|
*/
|
||||||
|
char getSpace();
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* BIP39 library, a Java implementation of BIP39
|
||||||
|
* Copyright (C) 2017-2019 Alan Evans, NovaCrypto
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Original source: https://github.com/NovaCrypto/BIP39
|
||||||
|
* You can contact the authors via github issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.novacrypto.bip39;
|
||||||
|
|
||||||
|
import java.text.Normalizer;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
class WordListMapNormalization implements NFKDNormalizer {
|
||||||
|
private final Map<CharSequence, String> normalizedMap = new HashMap<>();
|
||||||
|
|
||||||
|
WordListMapNormalization(final WordList wordList) {
|
||||||
|
for (int i = 0; i < 1 << 11; i++) {
|
||||||
|
final String word = wordList.getWord(i);
|
||||||
|
final String normalized = Normalizer.normalize(word, Normalizer.Form.NFKD);
|
||||||
|
normalizedMap.put(word, normalized);
|
||||||
|
normalizedMap.put(normalized, normalized);
|
||||||
|
normalizedMap.put(Normalizer.normalize(word, Normalizer.Form.NFC), normalized);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String normalize(final CharSequence charSequence) {
|
||||||
|
final String normalized = normalizedMap.get(charSequence);
|
||||||
|
if (normalized != null)
|
||||||
|
return normalized;
|
||||||
|
return Normalizer.normalize(charSequence, Normalizer.Form.NFKD);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* BIP39 library, a Java implementation of BIP39
|
||||||
|
* Copyright (C) 2017-2019 Alan Evans, NovaCrypto
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Original source: https://github.com/NovaCrypto/BIP39
|
||||||
|
* You can contact the authors via github issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.novacrypto.bip39;
|
||||||
|
|
||||||
|
public enum Words {
|
||||||
|
TWELVE(128),
|
||||||
|
FIFTEEN(160),
|
||||||
|
EIGHTEEN(192),
|
||||||
|
TWENTY_ONE(224),
|
||||||
|
TWENTY_FOUR(256);
|
||||||
|
|
||||||
|
private final int bitLength;
|
||||||
|
|
||||||
|
Words(int bitLength) {
|
||||||
|
this.bitLength = bitLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int bitLength() {
|
||||||
|
return bitLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int byteLength() {
|
||||||
|
return bitLength / 8;
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* SHA-256 library
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017-2022 Alan Evans, NovaCrypto
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Original source: https://github.com/NovaCrypto/SHA256
|
||||||
|
* You can contact the authors via github issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.novacrypto.hashing;
|
||||||
|
|
||||||
|
import io.github.novacrypto.toruntime.CheckedExceptionToRuntime;
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
|
||||||
|
import static io.github.novacrypto.toruntime.CheckedExceptionToRuntime.toRuntime;
|
||||||
|
|
||||||
|
public final class Sha256 {
|
||||||
|
|
||||||
|
Sha256() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] sha256(final byte[] bytes) {
|
||||||
|
return sha256(bytes, 0, bytes.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] sha256(final byte[] bytes, final int offset, final int length) {
|
||||||
|
final MessageDigest digest = sha256();
|
||||||
|
digest.update(bytes, offset, length);
|
||||||
|
return digest.digest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] sha256Twice(final byte[] bytes) {
|
||||||
|
return sha256Twice(bytes, 0, bytes.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] sha256Twice(final byte[] bytes, final int offset, final int length) {
|
||||||
|
final MessageDigest digest = sha256();
|
||||||
|
digest.update(bytes, offset, length);
|
||||||
|
digest.update(digest.digest());
|
||||||
|
return digest.digest();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MessageDigest sha256() {
|
||||||
|
return toRuntime(new CheckedExceptionToRuntime.Func<MessageDigest>() {
|
||||||
|
@Override
|
||||||
|
public MessageDigest run() throws Exception {
|
||||||
|
return MessageDigest.getInstance("SHA-256");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* ToRuntime library, Java promotions of checked exceptions to runtime exceptions
|
||||||
|
* Copyright (C) 2017-2022 Alan Evans, NovaCrypto
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Original source: https://github.com/NovaCrypto/ToRuntime
|
||||||
|
* You can contact the authors via github issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.novacrypto.toruntime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Promotes any exceptions thrown to {@link RuntimeException}
|
||||||
|
*/
|
||||||
|
public final class CheckedExceptionToRuntime {
|
||||||
|
|
||||||
|
public interface Func<T> {
|
||||||
|
T run() throws Exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Action {
|
||||||
|
void run() throws Exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Promotes any exceptions thrown to {@link RuntimeException}
|
||||||
|
*
|
||||||
|
* @param function Function to run
|
||||||
|
* @param <T> Return type
|
||||||
|
* @return returns the result of the function
|
||||||
|
*/
|
||||||
|
public static <T> T toRuntime(final Func<T> function) {
|
||||||
|
try {
|
||||||
|
return function.run();
|
||||||
|
} catch (final Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Promotes any exceptions thrown to {@link RuntimeException}
|
||||||
|
*
|
||||||
|
* @param function Function to run
|
||||||
|
*/
|
||||||
|
public static void toRuntime(final Action function) {
|
||||||
|
try {
|
||||||
|
function.run();
|
||||||
|
} catch (final Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue