relax assumption that HD seeds are 128 bits

This commit is contained in:
Devrandom
2014-07-02 14:37:38 -07:00
parent 39befded6b
commit 39d8da6764
3 changed files with 14 additions and 9 deletions

View File

@@ -76,6 +76,7 @@ import static com.google.common.collect.Lists.newLinkedList;
*/
public class DeterministicKeyChain implements EncryptableKeyChain {
private static final Logger log = LoggerFactory.getLogger(DeterministicKeyChain.class);
public static final int DEFAULT_SEED_BITS = 128;
private final ReentrantLock lock = Threading.lock("DeterministicKeyChain");
private DeterministicHierarchy hierarchy;
@@ -123,12 +124,12 @@ public class DeterministicKeyChain implements EncryptableKeyChain {
* Generates a new key chain with a 128 bit seed selected randomly from the given {@link java.security.SecureRandom}
* object.
*/
public DeterministicKeyChain(SecureRandom random) {
this(getRandomSeed(random), Utils.currentTimeSeconds());
public DeterministicKeyChain(SecureRandom random, int bits) {
this(getRandomSeed(random, bits), Utils.currentTimeSeconds());
}
private static byte[] getRandomSeed(SecureRandom random) {
byte[] seed = new byte[128 / 8];
private static byte[] getRandomSeed(SecureRandom random, int bits) {
byte[] seed = new byte[bits / 8];
random.nextBytes(seed);
return seed;
}

View File

@@ -62,6 +62,10 @@ import static com.google.common.base.Preconditions.*;
*/
public class KeyChainGroup {
private static final Logger log = LoggerFactory.getLogger(KeyChainGroup.class);
/** Default and minimum length of HD seed, in bits */
public static final int DEFAULT_SEED_BITS = 128;
private BasicKeyChain basic;
private NetworkParameters params;
private final List<DeterministicKeyChain> chains;
@@ -187,7 +191,7 @@ public class KeyChainGroup {
/** Adds a new HD chain to the chains list, and make it the default chain (from which keys are issued). */
public void createAndActivateNewHDChain() {
// We can't do auto upgrade here because we don't know the rotation time, if any.
final DeterministicKeyChain chain = new DeterministicKeyChain(new SecureRandom());
final DeterministicKeyChain chain = new DeterministicKeyChain(new SecureRandom(), DEFAULT_SEED_BITS);
log.info("Creating and activating a new HD chain: {}", chain);
for (ListenerRegistration<KeyChainEventListener> registration : basic.getListeners())
chain.addEventListener(registration.listener, registration.executor);
@@ -732,12 +736,12 @@ public class KeyChainGroup {
log.info("Auto-upgrading pre-HD wallet using oldest non-rotating private key");
byte[] seed = checkNotNull(keyToUse.getSecretBytes());
// Private keys should be at least 128 bits long.
checkState(seed.length >= 128 / 8);
checkState(seed.length >= DEFAULT_SEED_BITS / 8);
// We reduce the entropy here to 128 bits because people like to write their seeds down on paper, and 128
// bits should be sufficient forever unless the laws of the universe change or ECC is broken; in either case
// we all have bigger problems.
seed = Arrays.copyOfRange(seed, 0, 128 / 8); // final argument is exclusive range.
checkState(seed.length == 128 / 8);
seed = Arrays.copyOfRange(seed, 0, DEFAULT_SEED_BITS / 8); // final argument is exclusive range.
checkState(seed.length == DEFAULT_SEED_BITS / 8);
DeterministicKeyChain chain = new DeterministicKeyChain(seed, keyToUse.getCreationTimeSeconds());
if (aesKey != null) {
chain = chain.toEncrypted(checkNotNull(basic.getKeyCrypter()), aesKey);

View File

@@ -121,7 +121,7 @@ public class DeterministicKeyChainTest {
public void random() {
// Can't test much here but verify the constructor worked and the class is functional. The other tests rely on
// a fixed seed to be deterministic.
chain = new DeterministicKeyChain(new SecureRandom());
chain = new DeterministicKeyChain(new SecureRandom(), 384);
chain.setLookaheadSize(10);
chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).sign(Sha256Hash.ZERO_HASH);
chain.getKey(KeyChain.KeyPurpose.CHANGE).sign(Sha256Hash.ZERO_HASH);