/** * Get the wallet pocket's KeyCrypter, or null if the wallet pocket is not encrypted. * (Used in encrypting/ decrypting an ECKey). */ @Nullable @Override public KeyCrypter getKeyCrypter() { lock.lock(); try { return keys.getKeyCrypter(); } finally { lock.unlock(); } }
@Override public boolean checkPassword(CharSequence password) { checkNotNull(password,"Password is null"); checkState(getKeyCrypter() != null, "Key chain not encrypted"); return checkAESKey(getKeyCrypter().deriveKey(password)); }
@Override public SimpleHDKeyChain toDecrypted(CharSequence password) { checkNotNull(password, "Attempt to decrypt with a null password."); checkArgument(password.length() > 0, "Attempt to decrypt with an empty password."); KeyCrypter crypter = getKeyCrypter(); checkState(crypter != null, "Chain not encrypted"); KeyParameter derivedKey = crypter.deriveKey(password); return toDecrypted(derivedKey); }
@Override public boolean checkAESKey(KeyParameter aesKey) { checkNotNull(aesKey, "Cannot check null KeyParameter"); checkState(getKeyCrypter() != null, "Key chain not encrypted"); try { return rootKey.decrypt(aesKey).getPubKeyPoint().equals(rootKey.getPubKeyPoint()); } catch (KeyCrypterException e) { return false; } }
@Override public SimpleHDKeyChain toDecrypted(KeyParameter aesKey) { checkState(getKeyCrypter() != null, "Key chain not encrypted"); checkState(rootKey.isEncrypted(), "Root key not encrypted"); DeterministicKey decKey = rootKey.decrypt(getKeyCrypter(), aesKey); SimpleHDKeyChain chain = new SimpleHDKeyChain(decKey); // Now double check that the keys match to catch the case where the key is wrong but padding didn't catch it. if (!chain.getWatchingKey().getPubKeyPoint().equals(getWatchingKey().getPubKeyPoint())) throw new KeyCrypterException("Provided AES key is wrong"); chain.lookaheadSize = lookaheadSize; // Now copy the (pubkey only) leaf keys across to avoid rederiving them. The private key bytes are missing // anyway so there's nothing to decrypt. for (ECKey eckey : simpleKeyChain.getKeys()) { DeterministicKey key = (DeterministicKey) eckey; if (!isLeaf(key)) continue; // Not a leaf key. checkState(key.isEncrypted(), "Key is not encrypted"); DeterministicKey parent = chain.hierarchy.get(checkNotNull(key.getParent(), "Key has null parent").getPath(), false, false); // Clone the key to the new decrypted hierarchy. key = new DeterministicKey(key.getPubOnly(), parent); chain.hierarchy.putKey(key); chain.simpleKeyChain.importKeys(key); } chain.issuedExternalKeys = issuedExternalKeys; chain.issuedInternalKeys = issuedInternalKeys; return chain; }
private void checkEncryptedKeyChain(SimpleHDKeyChain encChain, DeterministicKey key1) { // Check we can look keys up and extend the chain without the AES key being provided. DeterministicKey encKey1 = encChain.findKeyFromPubKey(key1.getPubKey()); DeterministicKey encKey2 = encChain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS); assertFalse(key1.isEncrypted()); assertTrue(encKey1.isEncrypted()); assertEquals(encKey1.getPubKeyPoint(), key1.getPubKeyPoint()); final KeyParameter aesKey = checkNotNull(encChain.getKeyCrypter()).deriveKey("open secret"); encKey1.sign(Sha256Hash.ZERO_HASH, aesKey); encKey2.sign(Sha256Hash.ZERO_HASH, aesKey); assertTrue(encChain.checkAESKey(aesKey)); assertFalse(encChain.checkPassword("access denied")); assertTrue(encChain.checkPassword("open secret")); }
public void encryption(SimpleHDKeyChain unencChain) throws UnreadableWalletException { DeterministicKey key1 = unencChain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS); SimpleHDKeyChain encChain = unencChain.toEncrypted("open secret"); DeterministicKey encKey1 = encChain.findKeyFromPubKey(key1.getPubKey()); checkEncryptedKeyChain(encChain, key1); // Round-trip to ensure de/serialization works and that we can store two chains and they both deserialize. List<Protos.Key> serialized = encChain.toProtobuf(); System.out.println(protoToString(serialized)); encChain = SimpleHDKeyChain.fromProtobuf(serialized, encChain.getKeyCrypter()); checkEncryptedKeyChain(encChain, unencChain.findKeyFromPubKey(key1.getPubKey())); DeterministicKey encKey2 = encChain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS); // Decrypt and check the keys match. SimpleHDKeyChain decChain = encChain.toDecrypted("open secret"); DeterministicKey decKey1 = decChain.findKeyFromPubHash(encKey1.getPubKeyHash()); DeterministicKey decKey2 = decChain.findKeyFromPubHash(encKey2.getPubKeyHash()); assertEquals(decKey1.getPubKeyPoint(), encKey1.getPubKeyPoint()); assertEquals(decKey2.getPubKeyPoint(), encKey2.getPubKeyPoint()); assertFalse(decKey1.isEncrypted()); assertFalse(decKey2.isEncrypted()); assertNotEquals(encKey1.getParent(), decKey1.getParent()); // parts of a different hierarchy // Check we can once again derive keys from the decrypted chain. decChain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).sign(Sha256Hash.ZERO_HASH); decChain.getKey(KeyChain.KeyPurpose.CHANGE).sign(Sha256Hash.ZERO_HASH); }