decrypt static method

Tuple<List<int>, PubKeyModes> decrypt(
  1. String privKeyEnc,
  2. String passphrase
)

Decrypt a BIP38-encrypted Bitcoin private key without using ECDSA.

This method decrypts a BIP38-encrypted Bitcoin private key without relying on the Elliptic Curve Digital Signature Algorithm (ECDSA). It takes an encrypted private key and a passphrase as inputs and returns the decrypted private key and the selected public key mode (compressed or uncompressed) as a tuple.

  • privKeyEnc: The BIP38-encrypted Bitcoin private key.
  • passphrase: The passphrase for decryption.
  • Returns: A tuple (pair) containing the decrypted private key as a List

Implementation

static Tuple<List<int>, PubKeyModes> decrypt(
    String privKeyEnc, String passphrase) {
  final privKeyEncBytes = Base58Decoder.checkDecode(privKeyEnc);

  if (privKeyEncBytes.length != Bip38NoEcConst.encKeyByteLen) {
    throw ArgumentException(
        'Invalid encrypted key length (${privKeyEncBytes.length})');
  }

  final prefix = privKeyEncBytes.sublist(0, 2);
  final flagbyte = List<int>.from([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(
        'Invalid prefix (${BytesUtils.toHexString(prefix)})');
  }
  if (flagbyte[0] != Bip38NoEcConst.flagbyteCompressed.first &&
      flagbyte[0] != Bip38NoEcConst.flagbyteUncompressed.first) {
    throw ArgumentException(
        'Invalid flagbyte (${BytesUtils.toHexString(flagbyte)})');
  }

  // Derive key halves from the passphrase and address hash
  final derivedHalves =
      Bip38NoEcUtils.deriveKeyHalves(passphrase, addressHash);

  final derivedHalf1 = derivedHalves.item1;
  final derivedHalf2 = derivedHalves.item2;

  // 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(
        'Invalid address hash (expected: ${BytesUtils.toHexString(addressHash)}, '
        'got: ${BytesUtils.toHexString(addressHashGot)})');
  }

  return Tuple(privKeyBytes, pubKeyMode);
}