public TypedKey getKey() throws BadPassphraseException { return getKey(null); }
private void parseBip38(String key) throws KeyFormatException { byte[] bytes = parseBase58(key); if (version != 0x01) clearDataAndThrow(bytes, "Mismatched version number: " + version); if (bytes.length != 38) clearDataAndThrow(bytes, "Wrong number of bytes, excluding version byte: " + bytes.length); hasLotAndSequence = (bytes[1] & 0x04) != 0; // bit 2 compressed = (bytes[1] & 0x20) != 0; // bit 5 if ((bytes[1] & 0x01) != 0) // bit 0 clearDataAndThrow(bytes, "Bit 0x01 reserved for future use."); if ((bytes[1] & 0x02) != 0) // bit 1 clearDataAndThrow(bytes, "Bit 0x02 reserved for future use."); if ((bytes[1] & 0x08) != 0) // bit 3 clearDataAndThrow(bytes, "Bit 0x08 reserved for future use."); if ((bytes[1] & 0x10) != 0) // bit 4 clearDataAndThrow(bytes, "Bit 0x10 reserved for future use."); final int byte0 = bytes[0] & 0xff; if (byte0 == 0x42) { clearDataAndThrow(bytes, "Bits 0x40 and 0x80 must be set for non-EC-multiplied keys."); ecMultiply = false; if (hasLotAndSequence) clearDataAndThrow(bytes, "Non-EC-multiplied keys cannot have lot/sequence."); } else if (byte0 == 0x43) { clearDataAndThrow(bytes, "Bits 0x40 and 0x80 must be cleared for EC-multiplied keys."); ecMultiply = true; } else { clearDataAndThrow(bytes, "Second byte must by 0x42 or 0x43.");
public TypedKey getKey(@Nullable String passphrase) throws BadPassphraseException { switch (keyType) { case WIF: return getFromWifKey(); case BIP38: return decryptBip38(passphrase); case MINI: return getFromMiniKey(); default: throw new RuntimeException("Unknown key format."); // Should not happen } }
@Test public void testWif() throws Exception { SerializedKey serializedKey = new SerializedKey(BTC_WIF_PRIV); assertFalse(serializedKey.isEncrypted()); SerializedKey.TypedKey key = serializedKey.getKey(); assertTrue(key.possibleType.contains(BTC)); assertEquals(BTC_WIF_ADDR, key.key.toAddress(BTC).toString()); }
SerializedKey.TypedKey rawKey; try { if (key.isEncrypted()) { rawKey = key.getKey(keyPassword); } else { rawKey = key.getKey();
private void parseMini(String key) throws KeyFormatException { byte[] bytes = key.getBytes(); byte[] checkBytes = new byte[31]; // 30 chars + '?' List<byte[]> allBytes = ImmutableList.of(bytes, checkBytes); if (!key.startsWith("S")) { clearDataAndThrow(allBytes, "Mini private keys must start with 'S'"); } if (bytes.length != 30) { clearDataAndThrow(allBytes, "Mini private keys must be 30 characters long"); } System.arraycopy(bytes, 0, checkBytes, 0, 30); checkBytes[30] = '?'; // Check if the sha256 hash of key + "?" starts with 0x00 if (Sha256Hash.create(checkBytes).getBytes()[0] != 0x00) { clearDataAndThrow(allBytes, "Not well formed mini private key"); } compressed = false; // Mini keys are not compressed content = Sha256Hash.create(bytes).getBytes(); clearData(allBytes); }
private boolean validatePrivateKey(boolean isTyping) { if (privateKeyText == null) return false; String privateKey = privateKeyText.getText().toString().trim(); if (privateKey.isEmpty()) return false; try { serializedKey = new SerializedKey(privateKey); error = Error.NONE; } catch (SerializedKey.KeyFormatException e) { serializedKey = null; if (isTyping) { error = Error.NONE; } else { log.info("Invalid private key: {}", e.getMessage()); error = Error.BAD_FORMAT; } } updateView(); return serializedKey != null; }
public TypedKey decryptBip38(String passphrase) throws BadPassphraseException { String normalizedPassphrase = Normalizer.normalize(passphrase, Normalizer.Form.NFC); ECKey key = ecMultiply ? decryptBip38EC(normalizedPassphrase) : decryptBip38NoEC(normalizedPassphrase); String address = null; for (CoinType type : CoinID.getSupportedCoins()) { String possibleAddress = key.toAddress(type).toString(); Sha256Hash hash = Sha256Hash.createDouble(possibleAddress.getBytes(Charsets.US_ASCII)); byte[] actualAddressHash = Arrays.copyOfRange(hash.getBytes(), 0, 4); if (Arrays.equals(actualAddressHash, addressHash)) { address = possibleAddress; } } if (address == null) { throw new BadPassphraseException(); } try { return new TypedKey(GenericUtils.getPossibleTypes(address), key); } catch (AddressMalformedException e) { throw new RuntimeException(e); // Should not happen } }
setVisible(privateKeyInputView); if (serializedKey != null && serializedKey.isEncrypted()) { passwordView.setVisibility(View.VISIBLE); } else {
private static void clearData(List<byte[]> bytes) { for (byte[] b : bytes) { clearData(b); } }
@Test public void testMini() throws Exception { SerializedKey serializedKey = new SerializedKey(BTC_MINI_PRIV); assertFalse(serializedKey.isEncrypted()); SerializedKey.TypedKey key = serializedKey.getKey(); assertTrue(key.possibleType.contains(BTC)); assertEquals(BTC_MINI_ADDR, key.key.toAddress(BTC).toString()); } }
private void clearDataAndThrow(byte[] bytes, String message) throws KeyFormatException { clearData(bytes); throw new KeyFormatException(message); }
@Test public void testBip38() throws Exception { SerializedKey serializedKey = new SerializedKey(BTC_BIP38_WIF_PRIV); assertTrue(serializedKey.isEncrypted()); SerializedKey.TypedKey key = serializedKey.getKey(BIP38_PASS); assertTrue(key.possibleType.contains(BTC)); assertEquals(BTC_WIF_ADDR, key.key.toAddress(BTC).toString()); serializedKey = new SerializedKey(BTC_BIP38_PRIV); assertTrue(serializedKey.isEncrypted()); key = serializedKey.getKey(BIP38_PASS); assertTrue(key.possibleType.contains(BTC)); assertEquals(BTC_BIP38_ADDR, key.key.toAddress(BTC).toString()); serializedKey = new SerializedKey(DOGE_BIP38_PRIV); assertTrue(serializedKey.isEncrypted()); key = serializedKey.getKey(BIP38_PASS); assertTrue(key.possibleType.contains(DOGE)); assertEquals(DOGE_BIP38_ADDR, key.key.toAddress(DOGE).toString()); }
private void parseWif(String key) throws KeyFormatException { byte[] keyBytes = parseBase58(key); // Check if compatible boolean isCompatible = false; for (CoinType type : CoinID.getSupportedCoins()) { if (version == type.getDumpedPrivateKeyHeader()) { isCompatible = true; } } if (!isCompatible) { clearDataAndThrow(keyBytes, "No coin with private key version: " + version); } if (keyBytes.length == 33 && keyBytes[32] == 1) { compressed = true; content = Arrays.copyOf(keyBytes, 32); // Chop off the additional marker byte. clearData(keyBytes); } else if (keyBytes.length == 32) { compressed = false; content = keyBytes; } else { clearDataAndThrow(keyBytes, "Wrong number of bytes for a private key, not 32 or 33"); } }
private void clearDataAndThrow(List<byte[]> bytes, String message) throws KeyFormatException { clearData(bytes); throw new KeyFormatException(message); }
private byte[] parseBase58(String key) throws KeyFormatException { byte[] versionAndDataBytes; try { versionAndDataBytes = Base58.decodeChecked(key); } catch (AddressFormatException e) { throw new KeyFormatException(e); } version = versionAndDataBytes[0] & 0xFF; byte[] payload = new byte[versionAndDataBytes.length - 1]; System.arraycopy(versionAndDataBytes, 1, payload, 0, versionAndDataBytes.length - 1); clearData(versionAndDataBytes); return payload; }