Fixed merge issues
This commit is contained in:
commit
66197aa0d2
9 changed files with 367 additions and 9 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -75,3 +75,5 @@ atlassian-ide-plugin.xml
|
|||
# Logs
|
||||
# ----
|
||||
/*.log
|
||||
|
||||
src/main/java/com/luminiasoft/bitshares/mycelium/*
|
||||
|
|
|
@ -1,19 +1,56 @@
|
|||
package com.luminiasoft.bitshares;
|
||||
|
||||
import com.luminiasoft.bitshares.crypto.AndroidRandomSource;
|
||||
import com.luminiasoft.bitshares.crypto.SecureRandomStrengthener;
|
||||
import org.bitcoinj.core.ECKey;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* Created by nelson on 11/19/16.
|
||||
* Class used to encapsulate all BrainKey-related operations.
|
||||
*/
|
||||
public class BrainKey {
|
||||
// The size of the word dictionary
|
||||
public static final int DICT_WORD_COUNT = 49744;
|
||||
|
||||
// The required number of words
|
||||
public static final int BRAINKEY_WORD_COUNT = 12;
|
||||
|
||||
private ECKey mPrivateKey;
|
||||
|
||||
/**
|
||||
* Method that will generate a random brain key
|
||||
* @param words The list of words from the graphene specification dictionary.
|
||||
* @return A random sequence of words
|
||||
*/
|
||||
public static String suggest(String words){
|
||||
String[] wordArray = words.split(",");
|
||||
ArrayList<String> suggestedBrainKey = new ArrayList<String>();
|
||||
assert(wordArray.length == DICT_WORD_COUNT);
|
||||
SecureRandomStrengthener randomStrengthener = SecureRandomStrengthener.getInstance();
|
||||
randomStrengthener.addEntropySource(new AndroidRandomSource());
|
||||
SecureRandom secureRandom = randomStrengthener.generateAndSeedRandomNumberGenerator();
|
||||
int index;
|
||||
for(int i = 0; i < BRAINKEY_WORD_COUNT; i++){
|
||||
index = secureRandom.nextInt(DICT_WORD_COUNT - 1);
|
||||
suggestedBrainKey.add(wordArray[index].toUpperCase());
|
||||
}
|
||||
String result = String.join(" ", suggestedBrainKey.toArray(new String[suggestedBrainKey.size()]));
|
||||
System.out.println("result: '"+result+"'");
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* BrainKey constructor that takes as argument a specific brain key word sequence and generates the
|
||||
* private key and address from that.
|
||||
* @param words The brain key specifying the private key
|
||||
* @param sequence Sequence number
|
||||
*/
|
||||
public BrainKey(String words, int sequence) {
|
||||
String encoded = String.format("%s %d", words, sequence);
|
||||
try {
|
||||
|
@ -32,4 +69,8 @@ public class BrainKey {
|
|||
public String getPublicKey() {
|
||||
return Base64.getEncoder().encodeToString(mPrivateKey.getPubKey());
|
||||
}
|
||||
|
||||
public ECKey getPrivateKey(){
|
||||
return mPrivateKey;
|
||||
}
|
||||
}
|
|
@ -7,13 +7,18 @@ import java.io.IOException;
|
|||
public class Main {
|
||||
// Brain key from Nelson's app referencing the bilthon-83 account
|
||||
public static final String BRAIN_KEY = "PUMPER ISOTOME SERE STAINER CLINGER MOONLIT CHAETA UPBRIM AEDILIC BERTHER NIT SHAP SAID SHADING JUNCOUS CHOUGH";
|
||||
|
||||
public static final String BIP39_KEY = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
|
||||
|
||||
// WIF from Nelson's app referencing the bilthon-83 account
|
||||
public static final String WIF = "5J96pne45qWM1WpektoeazN6k9Mt93jQ7LyueRxFfEMTiy6yxjM";
|
||||
// public static final String WIF = "5J96pne45qWM1WpektoeazN6k9Mt93jQ7LyueRxFfEMTiy6yxjM";
|
||||
|
||||
// Brain key from an empty account created by the cli_wallet
|
||||
// public static final String BRAIN_KEY = "TWIXT SERMO TRILLI AUDIO PARDED PLUMET BIWA REHUNG MAUDLE VALVULA OUTBURN FEWNESS ALIENER UNTRACE PRICH TROKER";
|
||||
|
||||
// WIF from an emty account created by the cli_wallet
|
||||
public static final String WIF = "5KMzB2GqGhnh7ufhgddmz1eKPHS72uTLeL9hHjSvPb1UywWknF5";
|
||||
|
||||
// WIF from the cli_wallet instance
|
||||
// public static final String WIF = "5KMzB2GqGhnh7ufhgddmz1eKPHS72uTLeL9hHjSvPb1UywWknF5";
|
||||
public static final String EXTERNAL_SIGNATURE = "1f36c41acb774fcbc9c231b5895ec9701d6872729098d8ea56d78dda72a6b54252694db85d7591de5751b7aea06871da15d63a1028758421607ffc143e53ef3306";
|
||||
|
||||
// Static block information used for transaction serialization tests
|
||||
|
@ -61,6 +66,7 @@ public class Main {
|
|||
// test.testRandomNumberGeneration();
|
||||
|
||||
test.testBrainKeyOperations();
|
||||
|
||||
test.testBip39Opertion();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,9 +16,10 @@ import org.spongycastle.crypto.Digest;
|
|||
import org.spongycastle.crypto.digests.SHA512Digest;
|
||||
import org.spongycastle.crypto.prng.DigestRandomGenerator;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Paths;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
|
@ -506,11 +507,40 @@ public class Test {
|
|||
* Main.BRAIN_KEY into the WIF at Main.WIF
|
||||
*/
|
||||
public void testBrainKeyOperations(){
|
||||
try {
|
||||
String current = new java.io.File( "." ).getCanonicalPath();
|
||||
File file = new File(current + "/src/main/java/com/luminiasoft/bitshares/brainkeydict.txt");
|
||||
|
||||
BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
String words = bufferedReader.readLine();
|
||||
String suggestion = BrainKey.suggest(words);
|
||||
BrainKey brainKey = new BrainKey(Main.BRAIN_KEY, 0);
|
||||
ECKey key = brainKey.getPrivateKey();
|
||||
String wif = key.getPrivateKeyAsWiF(NetworkParameters.fromID(NetworkParameters.ID_MAINNET));
|
||||
System.out.println("wif compressed: "+wif);
|
||||
String wif2 = key.decompress().getPrivateKeyAsWiF(NetworkParameters.fromID(NetworkParameters.ID_MAINNET));
|
||||
System.out.println("wif decompressed: "+wif2);
|
||||
|
||||
byte[] pubKey1 = key.decompress().getPubKey();
|
||||
System.out.println("decompressed public key: "+Base58.encode(pubKey1));
|
||||
byte[] pubKey2 = key.getPubKey();
|
||||
System.out.println("compressed public key: "+Base58.encode(pubKey2));
|
||||
|
||||
System.out.println("pub key compressed : "+Util.bytesToHex(pubKey1));
|
||||
System.out.println("pub key uncompressed : "+Util.bytesToHex(pubKey2));
|
||||
|
||||
byte[] pubKey3 = key.getPubKeyPoint().getEncoded(true);
|
||||
System.out.println("pub key compressed : "+Base58.encode(pubKey3));
|
||||
|
||||
} catch (FileNotFoundException e) {
|
||||
System.out.println("FileNotFoundException. Msg: "+e.getMessage());
|
||||
} catch (IOException e) {
|
||||
System.out.println("IOException. Msg: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testBip39Opertion() {
|
||||
BIP39 bip39 = new BIP39(Main.BIP39_KEY, "");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
1
src/main/java/com/luminiasoft/bitshares/brainkeydict.txt
Normal file
1
src/main/java/com/luminiasoft/bitshares/brainkeydict.txt
Normal file
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright 2013, 2014 Megion Research and Development GmbH
|
||||
*
|
||||
* Licensed under the Microsoft Reference Source License (MS-RSL)
|
||||
*
|
||||
* This license governs use of the accompanying software. If you use the software, you accept this license.
|
||||
* If you do not accept the license, do not use the software.
|
||||
*
|
||||
* 1. Definitions
|
||||
* The terms "reproduce," "reproduction," and "distribution" have the same meaning here as under U.S. copyright law.
|
||||
* "You" means the licensee of the software.
|
||||
* "Your company" means the company you worked for when you downloaded the software.
|
||||
* "Reference use" means use of the software within your company as a reference, in read only form, for the sole purposes
|
||||
* of debugging your products, maintaining your products, or enhancing the interoperability of your products with the
|
||||
* software, and specifically excludes the right to distribute the software outside of your company.
|
||||
* "Licensed patents" means any Licensor patent claims which read directly on the software as distributed by the Licensor
|
||||
* under this license.
|
||||
*
|
||||
* 2. Grant of Rights
|
||||
* (A) Copyright Grant- Subject to the terms of this license, the Licensor grants you a non-transferable, non-exclusive,
|
||||
* worldwide, royalty-free copyright license to reproduce the software for reference use.
|
||||
* (B) Patent Grant- Subject to the terms of this license, the Licensor grants you a non-transferable, non-exclusive,
|
||||
* worldwide, royalty-free patent license under licensed patents for reference use.
|
||||
*
|
||||
* 3. Limitations
|
||||
* (A) No Trademark License- This license does not grant you any rights to use the Licensor’s name, logo, or trademarks.
|
||||
* (B) If you begin patent litigation against the Licensor over patents that you think may apply to the software
|
||||
* (including a cross-claim or counterclaim in a lawsuit), your license to the software ends automatically.
|
||||
* (C) The software is licensed "as-is." You bear the risk of using it. The Licensor gives no express warranties,
|
||||
* guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot
|
||||
* change. To the extent permitted under your local laws, the Licensor excludes the implied warranties of merchantability,
|
||||
* fitness for a particular purpose and non-infringement.
|
||||
*/
|
||||
|
||||
package com.luminiasoft.bitshares.crypto;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
||||
public class AndroidRandomSource implements RandomSource, EntropySource {
|
||||
|
||||
@Override
|
||||
public synchronized void nextBytes(byte[] bytes) {
|
||||
// On Android we use /dev/urandom for providing random data
|
||||
File file = new File("/dev/urandom");
|
||||
if (!file.exists()) {
|
||||
throw new RuntimeException("Unable to generate random bytes on this Android device");
|
||||
}
|
||||
try {
|
||||
FileInputStream stream = new FileInputStream(file);
|
||||
DataInputStream dis = new DataInputStream(stream);
|
||||
dis.readFully(bytes);
|
||||
dis.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Unable to generate random bytes on this Android device", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer provideEntropy() {
|
||||
byte[] buffer = new byte[ 256 / 8];
|
||||
nextBytes(buffer);
|
||||
ByteBuffer byteBuffer = ByteBuffer.allocate(buffer.length);
|
||||
byteBuffer.put(buffer, 0, buffer.length);
|
||||
return byteBuffer;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package com.luminiasoft.bitshares.crypto;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* A simple interface that can be used to retrieve entropy from any source.
|
||||
*
|
||||
* @author owlstead
|
||||
*/
|
||||
public interface EntropySource {
|
||||
/**
|
||||
* Retrieves the entropy.
|
||||
* The position of the ByteBuffer must be advanced to the limit by any users calling this method.
|
||||
* The values of the bytes between the position and limit should be set to zero by any users calling this method.
|
||||
*
|
||||
* @return entropy within the position and limit of the given buffer
|
||||
*/
|
||||
ByteBuffer provideEntropy();
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2013, 2014 Megion Research & Development GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.luminiasoft.bitshares.crypto;
|
||||
|
||||
public interface RandomSource {
|
||||
/**
|
||||
* Generates a user specified number of random bytes
|
||||
*
|
||||
* @param bytes
|
||||
* The array to fill with random bytes
|
||||
*/
|
||||
void nextBytes(byte[] bytes);
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
package com.luminiasoft.bitshares.crypto;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.DigestException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A strengthener that can be used to generate and re-seed random number
|
||||
* generators that do not seed themselves appropriately.
|
||||
*
|
||||
* @author owlstead
|
||||
*/
|
||||
public class SecureRandomStrengthener {
|
||||
private static final String DEFAULT_PSEUDO_RANDOM_NUMBER_GENERATOR = "SHA1PRNG";
|
||||
|
||||
private static final EntropySource mTimeEntropySource = new EntropySource() {
|
||||
|
||||
final ByteBuffer timeBuffer = ByteBuffer.allocate(Long.SIZE / Byte.SIZE
|
||||
* 2);
|
||||
|
||||
@Override
|
||||
public ByteBuffer provideEntropy() {
|
||||
this.timeBuffer.clear();
|
||||
this.timeBuffer.putLong(System.currentTimeMillis());
|
||||
this.timeBuffer.putLong(System.nanoTime());
|
||||
this.timeBuffer.flip();
|
||||
return this.timeBuffer;
|
||||
}
|
||||
};
|
||||
|
||||
private final String algorithm;
|
||||
private final List<EntropySource> entropySources = new LinkedList<EntropySource>();
|
||||
private final MessageDigest digest;
|
||||
private final ByteBuffer seedBuffer;
|
||||
|
||||
/**
|
||||
* Generates an instance of a {@link SecureRandomStrengthener} that
|
||||
* generates and re-seeds instances of {@code "SHA1PRNG"}.
|
||||
*
|
||||
* @return the strengthener, never null
|
||||
*/
|
||||
public static SecureRandomStrengthener getInstance() {
|
||||
return new SecureRandomStrengthener(
|
||||
DEFAULT_PSEUDO_RANDOM_NUMBER_GENERATOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an instance of a {@link SecureRandomStrengthener} that
|
||||
* generates instances of the given argument. Note that the availability of
|
||||
* the given algorithm arguments in not tested until generation.
|
||||
*
|
||||
* @param algorithm
|
||||
* the algorithm indicating the {@link SecureRandom} instance to
|
||||
* use
|
||||
* @return the strengthener, never null
|
||||
*/
|
||||
public static SecureRandomStrengthener getInstance(final String algorithm) {
|
||||
return new SecureRandomStrengthener(algorithm);
|
||||
}
|
||||
|
||||
private SecureRandomStrengthener(final String algorithm) {
|
||||
if (algorithm == null || algorithm.length() == 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Please provide a PRNG algorithm string such as SHA1PRNG");
|
||||
}
|
||||
|
||||
this.algorithm = algorithm;
|
||||
try {
|
||||
this.digest = MessageDigest.getInstance("SHA1");
|
||||
} catch (final NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException(
|
||||
"MessageDigest to create seed not available", e);
|
||||
}
|
||||
this.seedBuffer = ByteBuffer.allocate(this.digest.getDigestLength());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an entropy source, which will be called for each generation and
|
||||
* re-seeding of the given random number generator.
|
||||
*
|
||||
* @param source
|
||||
* the source of entropy
|
||||
*/
|
||||
public void addEntropySource(final EntropySource source) {
|
||||
if (source == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"EntropySource should not be null");
|
||||
}
|
||||
this.entropySources.add(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and seeds a random number generator of the configured
|
||||
* algorithm. Calls the {@link EntropySource#provideEntropy()} method of all
|
||||
* added sources of entropy.
|
||||
*
|
||||
* @return the random number generator
|
||||
*/
|
||||
public SecureRandom generateAndSeedRandomNumberGenerator() {
|
||||
final SecureRandom secureRandom;
|
||||
try {
|
||||
secureRandom = SecureRandom.getInstance(this.algorithm);
|
||||
} catch (final NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException("PRNG is not available", e);
|
||||
}
|
||||
|
||||
reseed(secureRandom);
|
||||
return secureRandom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-seeds the random number generator. Calls the
|
||||
* {@link EntropySource#provideEntropy()} method of all added sources of
|
||||
* entropy.
|
||||
*
|
||||
* @param secureRandom
|
||||
* the random number generator to re-seed
|
||||
*/
|
||||
public void reseed(final SecureRandom secureRandom) {
|
||||
this.seedBuffer.clear();
|
||||
secureRandom.nextBytes(this.seedBuffer.array());
|
||||
|
||||
for (final EntropySource source : this.entropySources) {
|
||||
final ByteBuffer entropy = source.provideEntropy();
|
||||
if (entropy == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final ByteBuffer wipeBuffer = entropy.duplicate();
|
||||
this.digest.update(entropy);
|
||||
wipe(wipeBuffer);
|
||||
}
|
||||
|
||||
this.digest.update(mTimeEntropySource.provideEntropy());
|
||||
this.digest.update(this.seedBuffer);
|
||||
this.seedBuffer.clear();
|
||||
// remove data from seedBuffer so it won't be retrievable
|
||||
|
||||
// reuse
|
||||
|
||||
try {
|
||||
this.digest.digest(this.seedBuffer.array(), 0,
|
||||
this.seedBuffer.capacity());
|
||||
} catch (final DigestException e) {
|
||||
throw new IllegalStateException(
|
||||
"DigestException should not be thrown", e);
|
||||
}
|
||||
secureRandom.setSeed(this.seedBuffer.array());
|
||||
|
||||
wipe(this.seedBuffer);
|
||||
}
|
||||
|
||||
private void wipe(final ByteBuffer buf) {
|
||||
while (buf.hasRemaining()) {
|
||||
buf.put((byte) 0);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue