decrypt static method
Decrypt a BIP38-encrypted Bitcoin private key without using ECDSA.
privKeyEnc: The BIP38-encrypted Bitcoin private key.passphrase: The passphrase for decryption.
Implementation
static (List<int>, PubKeyModes) decrypt(
String privKeyEnc,
String passphrase,
) {
final privKeyEncBytes = Base58Decoder.checkDecode(privKeyEnc);
if (privKeyEncBytes.length != Bip38NoEcConst.encKeyByteLen) {
throw ArgumentException.invalidOperationArguments(
"decrypt",
reason: "Invalid encrypted key length.",
);
}
final prefix = privKeyEncBytes.sublist(0, 2);
final flagbyte = [privKeyEncBytes[2]];
final addressHash = privKeyEncBytes.sublist(3, 7);
final encryptedHalf1 = privKeyEncBytes.sublist(7, 23);
final encryptedHalf2 = privKeyEncBytes.sublist(23);
// Check prefix and flagbyte
if (!BytesUtils.bytesEqual(prefix, Bip38NoEcConst.encKeyPrefix)) {
throw ArgumentException.invalidOperationArguments(
"decrypt",
reason: "Invalid prefix",
);
}
if (flagbyte[0] != Bip38NoEcConst.flagbyteCompressed.first &&
flagbyte[0] != Bip38NoEcConst.flagbyteUncompressed.first) {
throw ArgumentException.invalidOperationArguments(
"decrypt",
reason: "Invalid flagbyte",
);
}
// Derive key halves from the passphrase and address hash
final derivedHalves = Bip38NoEcUtils.deriveKeyHalves(
passphrase,
addressHash,
);
final derivedHalf1 = derivedHalves.$1;
final derivedHalf2 = derivedHalves.$2;
// Get the private key back by decrypting
final privKeyBytes = _decryptAndGetPrivKey(
encryptedHalf1,
encryptedHalf2,
derivedHalf1,
derivedHalf2,
);
// Get public key mode
final pubKeyMode =
flagbyte[0] == Bip38NoEcConst.flagbyteCompressed.first
? PubKeyModes.compressed
: PubKeyModes.uncompressed;
// Verify the address hash
final addressHashGot = Bip38NoEcUtils.addressHash(privKeyBytes, pubKeyMode);
if (!BytesUtils.bytesEqual(addressHash, addressHashGot)) {
throw ArgumentException.invalidOperationArguments(
"decrypt",
reason: "Invalid address hash.",
);
}
return (privKeyBytes, pubKeyMode);
}