load static method

BksKeyStore load(
  1. Uint8List data, {
  2. String? storePassword,
  3. bool tryDecryptKeys = true,
})

Loads a BKS keystore from bytes.

data - The raw keystore bytes. storePassword - The password to verify keystore integrity. If null, integrity check is skipped. tryDecryptKeys - Whether to try decrypting sealed keys using the store password.

Implementation

static BksKeyStore load(
  Uint8List data, {
  String? storePassword,
  bool tryDecryptKeys = true,
}) {
  if (data.length < 8) {
    throw BadKeystoreFormatException('Keystore file too small');
  }

  final view = ByteData.view(data.buffer, data.offsetInBytes, data.length);
  int pos = 0;

  // Read version
  final version = view.getUint32(pos);
  pos += 4;

  if (version != 1 && version != 2) {
    throw UnsupportedKeystoreVersionException(
        'Unsupported BKS keystore version; only V1 and V2 supported, found v$version');
  }

  // Read salt
  final (salt, newPos1) = _readData(data, pos);
  pos = newPos1;

  // Read iteration count
  final iterationCount = view.getUint32(pos);
  pos += 4;

  const storeType = 'bks';

  // Parse entries
  final entriesStartPos = pos;
  final (entries, entriesEndPos) = _loadEntries(
    data.sublist(pos),
    storeType,
    storePassword,
    tryDecryptKeys: tryDecryptKeys,
  );

  pos = entriesStartPos + entriesEndPos;

  // Verify HMAC if password provided
  if (storePassword != null) {
    const hmacDigestSize = 20; // SHA-1

    // For V1, HMAC key is same size as digest
    // For V2, HMAC key is 160 bits (20 bytes)
    final hmacKeySize = version == 1 ? hmacDigestSize : 20;

    // Derive HMAC key using PKCS#12 KDF
    final hmacKey = _derivePkcs12Key(
      storePassword,
      salt,
      iterationCount,
      hmacKeySize,
      3, // PURPOSE_MAC_MATERIAL
    );

    final storeData = data.sublist(entriesStartPos, pos);
    final storeHmac = data.sublist(pos, pos + hmacDigestSize);

    if (storeHmac.length != hmacDigestSize) {
      throw BadKeystoreFormatException(
          'Bad HMAC size; found ${storeHmac.length} bytes, expected $hmacDigestSize bytes');
    }

    // Compute HMAC-SHA1
    final computedHmac = _pkiCrypto.hmacSha1Sync(hmacKey, storeData);

    bool hmacMatch = true;
    for (int i = 0; i < hmacDigestSize; i++) {
      if (computedHmac[i] != storeHmac[i]) {
        hmacMatch = false;
        break;
      }
    }

    if (!hmacMatch) {
      throw KeystoreSignatureException(
          'HMAC mismatch; incorrect keystore password?');
    }
  }

  return BksKeyStore(storeType, entries, version: version);
}