mirror of
https://github.com/bitcoinj/bitcoinj.git
synced 2025-01-19 05:33:44 +01:00
Refactorings.
Make a convenience ECKey.decrypt(KeyParameter) that doesn't require the keycrypter to be manually specified, as often (always?) the key knows it already. Introduce a KeyBag interface that just contains findKeyBy* methods, then make Wallet implement it and change Transaction.signInputs to use it. Take out the encrypted-key specific stuff here: Transaction now requires unencrypted keys. Create a DecryptingKeyBag class that just forwards calls to Wallet and decrypts the returned keys. This decouples the signing code from Wallet a bit. Should be all API compatible.
This commit is contained in:
parent
9ca891c709
commit
24e41f01c6
@ -567,7 +567,7 @@ public class ECKey implements EncryptableItem, Serializable {
|
|||||||
if (crypter != null) {
|
if (crypter != null) {
|
||||||
if (aesKey == null)
|
if (aesKey == null)
|
||||||
throw new KeyIsEncryptedException();
|
throw new KeyIsEncryptedException();
|
||||||
return decrypt(crypter, aesKey).sign(input);
|
return decrypt(aesKey).sign(input);
|
||||||
} else {
|
} else {
|
||||||
// No decryption of private key required.
|
// No decryption of private key required.
|
||||||
if (priv == null)
|
if (priv == null)
|
||||||
@ -966,7 +966,6 @@ public class ECKey implements EncryptableItem, Serializable {
|
|||||||
*
|
*
|
||||||
* @param keyCrypter The keyCrypter that specifies exactly how the decrypted bytes are created.
|
* @param keyCrypter The keyCrypter that specifies exactly how the decrypted bytes are created.
|
||||||
* @param aesKey The KeyParameter with the AES encryption key (usually constructed with keyCrypter#deriveKey and cached).
|
* @param aesKey The KeyParameter with the AES encryption key (usually constructed with keyCrypter#deriveKey and cached).
|
||||||
* @return unencryptedKey
|
|
||||||
*/
|
*/
|
||||||
public ECKey decrypt(KeyCrypter keyCrypter, KeyParameter aesKey) throws KeyCrypterException {
|
public ECKey decrypt(KeyCrypter keyCrypter, KeyParameter aesKey) throws KeyCrypterException {
|
||||||
checkNotNull(keyCrypter);
|
checkNotNull(keyCrypter);
|
||||||
@ -984,6 +983,20 @@ public class ECKey implements EncryptableItem, Serializable {
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a decrypted private key with AES key. Note that if the AES key is wrong, this
|
||||||
|
* has some chance of throwing KeyCrypterException due to the corrupted padding that will result, but it can also
|
||||||
|
* just yield a garbage key.
|
||||||
|
*
|
||||||
|
* @param aesKey The KeyParameter with the AES encryption key (usually constructed with keyCrypter#deriveKey and cached).
|
||||||
|
*/
|
||||||
|
public ECKey decrypt(KeyParameter aesKey) throws KeyCrypterException {
|
||||||
|
final KeyCrypter crypter = getKeyCrypter();
|
||||||
|
if (crypter == null)
|
||||||
|
throw new KeyCrypterException("No key crypter available");
|
||||||
|
return decrypt(crypter, aesKey);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Check that it is possible to decrypt the key with the keyCrypter and that the original key is returned.</p>
|
* <p>Check that it is possible to decrypt the key with the keyCrypter and that the original key is returned.</p>
|
||||||
*
|
*
|
||||||
|
@ -22,7 +22,8 @@ import com.google.bitcoin.crypto.TransactionSignature;
|
|||||||
import com.google.bitcoin.script.Script;
|
import com.google.bitcoin.script.Script;
|
||||||
import com.google.bitcoin.script.ScriptBuilder;
|
import com.google.bitcoin.script.ScriptBuilder;
|
||||||
import com.google.bitcoin.script.ScriptOpCodes;
|
import com.google.bitcoin.script.ScriptOpCodes;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.bitcoin.wallet.DecryptingKeyBag;
|
||||||
|
import com.google.bitcoin.wallet.KeyBag;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.primitives.Ints;
|
import com.google.common.primitives.Ints;
|
||||||
import com.google.common.primitives.Longs;
|
import com.google.common.primitives.Longs;
|
||||||
@ -849,7 +850,22 @@ public class Transaction extends ChildMessage implements Serializable {
|
|||||||
* @param wallet A wallet is required to fetch the keys needed for signing.
|
* @param wallet A wallet is required to fetch the keys needed for signing.
|
||||||
* @param aesKey The AES key to use to decrypt the key before signing. Null if no decryption is required.
|
* @param aesKey The AES key to use to decrypt the key before signing. Null if no decryption is required.
|
||||||
*/
|
*/
|
||||||
public synchronized void signInputs(SigHash hashType, Wallet wallet, @Nullable KeyParameter aesKey) throws ScriptException {
|
public void signInputs(SigHash hashType, Wallet wallet, @Nullable KeyParameter aesKey) throws ScriptException {
|
||||||
|
if (aesKey == null) {
|
||||||
|
signInputs(hashType, false, wallet);
|
||||||
|
} else {
|
||||||
|
signInputs(hashType, false, new DecryptingKeyBag(wallet, aesKey));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signs as many inputs as possible using keys from the given key bag, which are expected to be usable for
|
||||||
|
* signing, i.e. not encrypted and not missing the private key part.
|
||||||
|
*
|
||||||
|
* @param hashType This should always be set to SigHash.ALL currently. Other types are unused.
|
||||||
|
* @param keyBag a provider of keys that are usable as-is for signing.
|
||||||
|
*/
|
||||||
|
public synchronized void signInputs(SigHash hashType, boolean anyoneCanPay, KeyBag keyBag) throws ScriptException {
|
||||||
checkState(inputs.size() > 0);
|
checkState(inputs.size() > 0);
|
||||||
checkState(outputs.size() > 0);
|
checkState(outputs.size() > 0);
|
||||||
|
|
||||||
@ -885,16 +901,15 @@ public class Transaction extends ChildMessage implements Serializable {
|
|||||||
if (input.getScriptBytes().length != 0)
|
if (input.getScriptBytes().length != 0)
|
||||||
log.warn("Re-signing an already signed transaction! Be sure this is what you want.");
|
log.warn("Re-signing an already signed transaction! Be sure this is what you want.");
|
||||||
// Find the signing key we'll need to use.
|
// Find the signing key we'll need to use.
|
||||||
ECKey key = input.getOutpoint().getConnectedKey(wallet);
|
ECKey key = input.getOutpoint().getConnectedKey(keyBag);
|
||||||
// This assert should never fire. If it does, it means the wallet is inconsistent.
|
// This assert should never fire. If it does, it means the wallet is inconsistent.
|
||||||
checkNotNull(key, "Transaction exists in wallet that we cannot redeem: %s", input.getOutpoint().getHash());
|
checkNotNull(key, "Transaction exists in wallet that we cannot redeem: %s", input.getOutpoint().getHash());
|
||||||
// Keep the key around for the script creation step below.
|
// Keep the key around for the script creation step below.
|
||||||
signingKeys[i] = key;
|
signingKeys[i] = key;
|
||||||
// The anyoneCanPay feature isn't used at the moment.
|
// The anyoneCanPay feature isn't used at the moment.
|
||||||
boolean anyoneCanPay = false;
|
|
||||||
byte[] connectedPubKeyScript = input.getOutpoint().getConnectedPubKeyScript();
|
byte[] connectedPubKeyScript = input.getOutpoint().getConnectedPubKeyScript();
|
||||||
try {
|
try {
|
||||||
signatures[i] = calculateSignature(i, key, aesKey, connectedPubKeyScript, hashType, anyoneCanPay);
|
signatures[i] = calculateSignature(i, key, connectedPubKeyScript, hashType, anyoneCanPay);
|
||||||
} catch (ECKey.KeyIsEncryptedException e) {
|
} catch (ECKey.KeyIsEncryptedException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (ECKey.MissingPrivateKeyException e) {
|
} catch (ECKey.MissingPrivateKeyException e) {
|
||||||
@ -935,22 +950,21 @@ public class Transaction extends ChildMessage implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* Calculates a signature that is valid for being inserted into the input at the given position. This is simply
|
* Calculates a signature that is valid for being inserted into the input at the given position. This is simply
|
||||||
* a wrapper around calling {@link Transaction#hashForSignature(int, byte[], com.google.bitcoin.core.Transaction.SigHash, boolean)}
|
* a wrapper around calling {@link Transaction#hashForSignature(int, byte[], com.google.bitcoin.core.Transaction.SigHash, boolean)}
|
||||||
* followed by {@link ECKey#sign(Sha256Hash, org.spongycastle.crypto.params.KeyParameter)} and then returning
|
* followed by {@link ECKey#sign(Sha256Hash)} and then returning a new {@link TransactionSignature}. The key
|
||||||
* a new {@link TransactionSignature}.
|
* must be usable for signing as-is: if the key is encrypted it must be decrypted first external to this method.
|
||||||
*
|
*
|
||||||
* @param inputIndex Which input to calculate the signature for, as an index.
|
* @param inputIndex Which input to calculate the signature for, as an index.
|
||||||
* @param key The private key used to calculate the signature.
|
* @param key The private key used to calculate the signature.
|
||||||
* @param aesKey If not null, this will be used to decrypt the key.
|
|
||||||
* @param connectedPubKeyScript Byte-exact contents of the scriptPubKey that is being satisified.
|
* @param connectedPubKeyScript Byte-exact contents of the scriptPubKey that is being satisified.
|
||||||
* @param hashType Signing mode, see the enum for documentation.
|
* @param hashType Signing mode, see the enum for documentation.
|
||||||
* @param anyoneCanPay Signing mode, see the SigHash enum for documentation.
|
* @param anyoneCanPay Signing mode, see the SigHash enum for documentation.
|
||||||
* @return A newly calculated signature object that wraps the r, s and sighash components.
|
* @return A newly calculated signature object that wraps the r, s and sighash components.
|
||||||
*/
|
*/
|
||||||
public synchronized TransactionSignature calculateSignature(int inputIndex, ECKey key, @Nullable KeyParameter aesKey,
|
public synchronized TransactionSignature calculateSignature(int inputIndex, ECKey key,
|
||||||
byte[] connectedPubKeyScript,
|
byte[] connectedPubKeyScript,
|
||||||
SigHash hashType, boolean anyoneCanPay) {
|
SigHash hashType, boolean anyoneCanPay) {
|
||||||
Sha256Hash hash = hashForSignature(inputIndex, connectedPubKeyScript, hashType, anyoneCanPay);
|
Sha256Hash hash = hashForSignature(inputIndex, connectedPubKeyScript, hashType, anyoneCanPay);
|
||||||
return new TransactionSignature(key.sign(hash, aesKey), hashType, anyoneCanPay);
|
return new TransactionSignature(key.sign(hash), hashType, anyoneCanPay);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package com.google.bitcoin.core;
|
package com.google.bitcoin.core;
|
||||||
|
|
||||||
import com.google.bitcoin.script.Script;
|
import com.google.bitcoin.script.Script;
|
||||||
|
import com.google.bitcoin.wallet.KeyBag;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -134,19 +135,20 @@ public class TransactionOutPoint extends ChildMessage implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* Returns the ECKey identified in the connected output, for either pay-to-address scripts or pay-to-key scripts.
|
* Returns the ECKey identified in the connected output, for either pay-to-address scripts or pay-to-key scripts.
|
||||||
* If the script forms cannot be understood, throws ScriptException.
|
* If the script forms cannot be understood, throws ScriptException.
|
||||||
|
*
|
||||||
* @return an ECKey or null if the connected key cannot be found in the wallet.
|
* @return an ECKey or null if the connected key cannot be found in the wallet.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public ECKey getConnectedKey(Wallet wallet) throws ScriptException {
|
public ECKey getConnectedKey(KeyBag keyBag) throws ScriptException {
|
||||||
TransactionOutput connectedOutput = getConnectedOutput();
|
TransactionOutput connectedOutput = getConnectedOutput();
|
||||||
checkNotNull(connectedOutput, "Input is not connected so cannot retrieve key");
|
checkNotNull(connectedOutput, "Input is not connected so cannot retrieve key");
|
||||||
Script connectedScript = connectedOutput.getScriptPubKey();
|
Script connectedScript = connectedOutput.getScriptPubKey();
|
||||||
if (connectedScript.isSentToAddress()) {
|
if (connectedScript.isSentToAddress()) {
|
||||||
byte[] addressBytes = connectedScript.getPubKeyHash();
|
byte[] addressBytes = connectedScript.getPubKeyHash();
|
||||||
return wallet.findKeyFromPubHash(addressBytes);
|
return keyBag.findKeyFromPubHash(addressBytes);
|
||||||
} else if (connectedScript.isSentToRawPubKey()) {
|
} else if (connectedScript.isSentToRawPubKey()) {
|
||||||
byte[] pubkeyBytes = connectedScript.getPubKey();
|
byte[] pubkeyBytes = connectedScript.getPubKey();
|
||||||
return wallet.findKeyFromPubKey(pubkeyBytes);
|
return keyBag.findKeyFromPubKey(pubkeyBytes);
|
||||||
} else {
|
} else {
|
||||||
throw new ScriptException("Could not understand form of connected output script: " + connectedScript);
|
throw new ScriptException("Could not understand form of connected output script: " + connectedScript);
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,7 @@ import static com.google.common.base.Preconditions.*;
|
|||||||
* {@link Wallet#autosaveToFile(java.io.File, long, java.util.concurrent.TimeUnit, com.google.bitcoin.wallet.WalletFiles.Listener)}
|
* {@link Wallet#autosaveToFile(java.io.File, long, java.util.concurrent.TimeUnit, com.google.bitcoin.wallet.WalletFiles.Listener)}
|
||||||
* for more information about this.</p>
|
* for more information about this.</p>
|
||||||
*/
|
*/
|
||||||
public class Wallet extends BaseTaggableObject implements Serializable, BlockChainListener, PeerFilterProvider {
|
public class Wallet extends BaseTaggableObject implements Serializable, BlockChainListener, PeerFilterProvider, KeyBag {
|
||||||
private static final Logger log = LoggerFactory.getLogger(Wallet.class);
|
private static final Logger log = LoggerFactory.getLogger(Wallet.class);
|
||||||
private static final long serialVersionUID = 2L;
|
private static final long serialVersionUID = 2L;
|
||||||
private static final int MINIMUM_BLOOM_DATA_LENGTH = 8;
|
private static final int MINIMUM_BLOOM_DATA_LENGTH = 8;
|
||||||
|
@ -240,6 +240,11 @@ public class DeterministicKey extends ECKey {
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeterministicKey decrypt(KeyParameter aesKey) throws KeyCrypterException {
|
||||||
|
return (DeterministicKey) super.decrypt(aesKey);
|
||||||
|
}
|
||||||
|
|
||||||
// For when a key is encrypted, either decrypt our encrypted private key bytes, or work up the tree asking parents
|
// For when a key is encrypted, either decrypt our encrypted private key bytes, or work up the tree asking parents
|
||||||
// to decrypt and re-derive.
|
// to decrypt and re-derive.
|
||||||
private BigInteger findOrDeriveEncryptedPrivateKey(KeyCrypter keyCrypter, KeyParameter aesKey) {
|
private BigInteger findOrDeriveEncryptedPrivateKey(KeyCrypter keyCrypter, KeyParameter aesKey) {
|
||||||
|
@ -424,7 +424,7 @@ public class BasicKeyChain implements EncryptableKeyChain {
|
|||||||
throw new KeyCrypterException("Password/key was incorrect.");
|
throw new KeyCrypterException("Password/key was incorrect.");
|
||||||
BasicKeyChain decrypted = new BasicKeyChain();
|
BasicKeyChain decrypted = new BasicKeyChain();
|
||||||
for (ECKey key : hashToKeys.values()) {
|
for (ECKey key : hashToKeys.values()) {
|
||||||
decrypted.importKeyLocked(key.decrypt(keyCrypter, aesKey));
|
decrypted.importKeyLocked(key.decrypt(aesKey));
|
||||||
}
|
}
|
||||||
return decrypted;
|
return decrypted;
|
||||||
} finally {
|
} finally {
|
||||||
@ -467,7 +467,7 @@ public class BasicKeyChain implements EncryptableKeyChain {
|
|||||||
checkState(first != null, "No encrypted keys in the wallet");
|
checkState(first != null, "No encrypted keys in the wallet");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ECKey rebornKey = first.decrypt(keyCrypter, aesKey);
|
ECKey rebornKey = first.decrypt(aesKey);
|
||||||
return Arrays.equals(first.getPubKey(), rebornKey.getPubKey());
|
return Arrays.equals(first.getPubKey(), rebornKey.getPubKey());
|
||||||
} catch (KeyCrypterException e) {
|
} catch (KeyCrypterException e) {
|
||||||
// The AES key supplied is incorrect.
|
// The AES key supplied is incorrect.
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2014 The bitcoinj authors.
|
||||||
|
*
|
||||||
|
* 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.google.bitcoin.wallet;
|
||||||
|
|
||||||
|
import com.google.bitcoin.core.ECKey;
|
||||||
|
import org.spongycastle.crypto.params.KeyParameter;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A DecryptingKeyBag filters a pre-existing key bag, decrypting keys as they are requested using the provided
|
||||||
|
* AES key.
|
||||||
|
*/
|
||||||
|
public class DecryptingKeyBag implements KeyBag {
|
||||||
|
protected final KeyBag target;
|
||||||
|
protected final KeyParameter aesKey;
|
||||||
|
|
||||||
|
public DecryptingKeyBag(KeyBag target, KeyParameter aesKey) {
|
||||||
|
this.target = checkNotNull(target);
|
||||||
|
this.aesKey = checkNotNull(aesKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private ECKey maybeDecrypt(ECKey key) {
|
||||||
|
return key == null ? null : key.decrypt(aesKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public ECKey findKeyFromPubHash(byte[] pubkeyHash) {
|
||||||
|
return maybeDecrypt(target.findKeyFromPubHash(pubkeyHash));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public ECKey findKeyFromPubKey(byte[] pubkey) {
|
||||||
|
return maybeDecrypt(target.findKeyFromPubKey(pubkey));
|
||||||
|
}
|
||||||
|
}
|
@ -583,7 +583,7 @@ public class DeterministicKeyChain implements EncryptableKeyChain {
|
|||||||
checkNotNull(aesKey);
|
checkNotNull(aesKey);
|
||||||
checkState(getKeyCrypter() != null, "Key chain not encrypted");
|
checkState(getKeyCrypter() != null, "Key chain not encrypted");
|
||||||
try {
|
try {
|
||||||
return rootKey.decrypt(getKeyCrypter(), aesKey).getPubKeyPoint().equals(rootKey.getPubKeyPoint());
|
return rootKey.decrypt(aesKey).getPubKeyPoint().equals(rootKey.getPubKeyPoint());
|
||||||
} catch (KeyCrypterException e) {
|
} catch (KeyCrypterException e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
40
core/src/main/java/com/google/bitcoin/wallet/KeyBag.java
Normal file
40
core/src/main/java/com/google/bitcoin/wallet/KeyBag.java
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2014 The bitcoinj authors.
|
||||||
|
*
|
||||||
|
* 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.google.bitcoin.wallet;
|
||||||
|
|
||||||
|
import com.google.bitcoin.core.ECKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A KeyBag is simply an object that can map public keys and their 160-bit hashes to ECKey objects. All
|
||||||
|
* {@link com.google.bitcoin.wallet.KeyChain}s are key bags.
|
||||||
|
*/
|
||||||
|
public interface KeyBag {
|
||||||
|
/**
|
||||||
|
* Locates a keypair from the keychain given the hash of the public key. This is needed when finding out which
|
||||||
|
* key we need to use to redeem a transaction output.
|
||||||
|
*
|
||||||
|
* @return ECKey object or null if no such key was found.
|
||||||
|
*/
|
||||||
|
public ECKey findKeyFromPubHash(byte[] pubkeyHash);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locates a keypair from the keychain given the raw public key bytes.
|
||||||
|
*
|
||||||
|
* @return ECKey or null if no such key was found.
|
||||||
|
*/
|
||||||
|
public ECKey findKeyFromPubKey(byte[] pubkey);
|
||||||
|
}
|
@ -34,21 +34,7 @@ import java.util.concurrent.Executor;
|
|||||||
* restrictions is to support key chains that may be handled by external hardware or software, or which are derived
|
* restrictions is to support key chains that may be handled by external hardware or software, or which are derived
|
||||||
* deterministically from a seed (and thus the notion of importing a key is meaningless).</p>
|
* deterministically from a seed (and thus the notion of importing a key is meaningless).</p>
|
||||||
*/
|
*/
|
||||||
public interface KeyChain {
|
public interface KeyChain extends KeyBag {
|
||||||
/**
|
|
||||||
* Locates a keypair from the keychain given the hash of the public key. This is needed when finding out which
|
|
||||||
* key we need to use to redeem a transaction output.
|
|
||||||
*
|
|
||||||
* @return ECKey object or null if no such key was found.
|
|
||||||
*/
|
|
||||||
public ECKey findKeyFromPubHash(byte[] pubkeyHash);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Locates a keypair from the keychain given the raw public key bytes.
|
|
||||||
* @return ECKey or null if no such key was found.
|
|
||||||
*/
|
|
||||||
public ECKey findKeyFromPubKey(byte[] pubkey);
|
|
||||||
|
|
||||||
/** Returns true if the given key is in the chain. */
|
/** Returns true if the given key is in the chain. */
|
||||||
public boolean hasKey(ECKey key);
|
public boolean hasKey(ECKey key);
|
||||||
|
|
||||||
|
@ -32,16 +32,12 @@ import com.google.common.util.concurrent.MoreExecutors;
|
|||||||
import com.google.protobuf.ByteString;
|
import com.google.protobuf.ByteString;
|
||||||
import org.bitcoinj.wallet.Protos;
|
import org.bitcoinj.wallet.Protos;
|
||||||
import org.bitcoinj.wallet.Protos.ScryptParameters;
|
import org.bitcoinj.wallet.Protos.ScryptParameters;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.spongycastle.crypto.params.ECDomainParameters;
|
|
||||||
import org.spongycastle.crypto.params.KeyParameter;
|
import org.spongycastle.crypto.params.KeyParameter;
|
||||||
import org.spongycastle.util.encoders.DecoderException;
|
import org.spongycastle.util.encoders.DecoderException;
|
||||||
import org.spongycastle.math.ec.ECCurve;
|
|
||||||
import org.spongycastle.math.ec.ECPoint;
|
|
||||||
import org.spongycastle.util.encoders.Hex;
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -273,7 +269,7 @@ public class ECKeyTest {
|
|||||||
assertEquals(time, encryptedKey.getCreationTimeSeconds());
|
assertEquals(time, encryptedKey.getCreationTimeSeconds());
|
||||||
assertTrue(encryptedKey.isEncrypted());
|
assertTrue(encryptedKey.isEncrypted());
|
||||||
assertNull(encryptedKey.getSecretBytes());
|
assertNull(encryptedKey.getSecretBytes());
|
||||||
key = encryptedKey.decrypt(keyCrypter, keyCrypter.deriveKey(PASSWORD1));
|
key = encryptedKey.decrypt(keyCrypter.deriveKey(PASSWORD1));
|
||||||
assertTrue(!key.isEncrypted());
|
assertTrue(!key.isEncrypted());
|
||||||
assertArrayEquals(originalPrivateKeyBytes, key.getPrivKeyBytes());
|
assertArrayEquals(originalPrivateKeyBytes, key.getPrivKeyBytes());
|
||||||
}
|
}
|
||||||
@ -287,7 +283,7 @@ public class ECKeyTest {
|
|||||||
ECKey encryptedKey = ECKey.fromEncrypted(encryptedPrivateKey, keyCrypter, unencryptedKey.getPubKey());
|
ECKey encryptedKey = ECKey.fromEncrypted(encryptedPrivateKey, keyCrypter, unencryptedKey.getPubKey());
|
||||||
assertTrue(encryptedKey.isEncrypted());
|
assertTrue(encryptedKey.isEncrypted());
|
||||||
assertNull(encryptedKey.getSecretBytes());
|
assertNull(encryptedKey.getSecretBytes());
|
||||||
ECKey rebornUnencryptedKey = encryptedKey.decrypt(keyCrypter, keyCrypter.deriveKey(PASSWORD1));
|
ECKey rebornUnencryptedKey = encryptedKey.decrypt(keyCrypter.deriveKey(PASSWORD1));
|
||||||
assertTrue(!rebornUnencryptedKey.isEncrypted());
|
assertTrue(!rebornUnencryptedKey.isEncrypted());
|
||||||
assertArrayEquals(originalPrivateKeyBytes, rebornUnencryptedKey.getPrivKeyBytes());
|
assertArrayEquals(originalPrivateKeyBytes, rebornUnencryptedKey.getPrivKeyBytes());
|
||||||
}
|
}
|
||||||
|
@ -133,13 +133,13 @@ public class ChildKeyDerivationTest {
|
|||||||
|
|
||||||
DeterministicKey key1 = HDKeyDerivation.createMasterPrivateKey("it was all a hoax".getBytes());
|
DeterministicKey key1 = HDKeyDerivation.createMasterPrivateKey("it was all a hoax".getBytes());
|
||||||
DeterministicKey encryptedKey1 = key1.encrypt(scrypter, aesKey, null);
|
DeterministicKey encryptedKey1 = key1.encrypt(scrypter, aesKey, null);
|
||||||
DeterministicKey decryptedKey1 = encryptedKey1.decrypt(scrypter, aesKey);
|
DeterministicKey decryptedKey1 = encryptedKey1.decrypt(aesKey);
|
||||||
assertEquals(key1, decryptedKey1);
|
assertEquals(key1, decryptedKey1);
|
||||||
|
|
||||||
DeterministicKey key2 = HDKeyDerivation.deriveChildKey(key1, ChildNumber.ZERO);
|
DeterministicKey key2 = HDKeyDerivation.deriveChildKey(key1, ChildNumber.ZERO);
|
||||||
DeterministicKey derivedKey2 = HDKeyDerivation.deriveChildKey(encryptedKey1, ChildNumber.ZERO);
|
DeterministicKey derivedKey2 = HDKeyDerivation.deriveChildKey(encryptedKey1, ChildNumber.ZERO);
|
||||||
assertTrue(derivedKey2.isEncrypted()); // parent is encrypted.
|
assertTrue(derivedKey2.isEncrypted()); // parent is encrypted.
|
||||||
DeterministicKey decryptedKey2 = derivedKey2.decrypt(scrypter, aesKey);
|
DeterministicKey decryptedKey2 = derivedKey2.decrypt(aesKey);
|
||||||
assertFalse(decryptedKey2.isEncrypted());
|
assertFalse(decryptedKey2.isEncrypted());
|
||||||
assertEquals(key2, decryptedKey2);
|
assertEquals(key2, decryptedKey2);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user