decrypt static method

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

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);
}