load static method
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);
}