save method
Saves the keystore to BKS format bytes (Version 2).
storePassword - The password to protect keystore integrity (HMAC).
keyPassword - The password to seal private keys. If not provided, defaults to storePassword.
Implementation
Uint8List save(String storePassword, {String? keyPassword}) {
final salt = _pkiCrypto.randomBytes(20);
const iterationCount = 10000;
final header = BytesBuilder();
header.add(_int32ToBytes(2));
header.add(_int32ToBytes(salt.length));
header.add(salt);
header.add(_int32ToBytes(iterationCount));
final entriesData = BytesBuilder();
void writeEntriesV2(BytesBuilder b) {
for (final entry in entries.values) {
if (entry is BksTrustedCertEntry || entry is TrustedCertEntry) {
b.addByte(bksEntryTypeCertificate);
_writeUtf(b, entry.alias);
b.add(_int64ToBytes(entry.timestamp));
b.add(_int32ToBytes(0)); // Chain len
final c = entry as TrustedCertEntry;
_writeUtf(b, c.certType);
_writeData(b, c.certData);
} else if (entry is PrivateKeyEntry) {
final inner = BytesBuilder();
inner.addByte(bksKeyTypePrivate);
_writeUtf(inner, 'PKCS#8');
_writeUtf(inner, "RSA");
final pkcs8 = entry.pkcs8PrivateKey ?? entry.rawPrivateKey;
if (pkcs8 == null) {
throw KeystoreException("No private key for ${entry.alias}");
}
_writeData(inner, pkcs8);
final kPwd = keyPassword ?? storePassword;
final sealed = _seal(inner.toBytes(), kPwd);
b.addByte(bksEntryTypeSealed);
_writeUtf(b, entry.alias);
b.add(_int64ToBytes(entry.timestamp));
b.add(_int32ToBytes(entry.certChain.length));
for (final c in entry.certChain) {
_writeUtf(b, c.$1);
_writeData(b, c.$2);
}
_writeData(b, sealed);
} else if (entry is BksSealedKeyEntry) {
if (!entry.isDecrypted()) {
throw KeystoreException(
"Cannot save undecrypted BksSealedKeyEntry ${entry.alias}",
);
}
final nested = entry.nestedEntry;
final inner = BytesBuilder();
inner.addByte(nested.keyType);
_writeUtf(inner, nested.format);
_writeUtf(inner, nested.algorithm);
_writeData(inner, nested.encoded);
final kPwd = keyPassword ?? storePassword;
final sealed = _seal(inner.toBytes(), kPwd);
b.addByte(bksEntryTypeSealed);
_writeUtf(b, entry.alias);
b.add(_int64ToBytes(entry.timestamp));
b.add(_int32ToBytes(nested.certChain.length));
for (final c in nested.certChain) {
_writeUtf(b, c.certType);
_writeData(b, c.certData);
}
_writeData(b, sealed);
}
}
b.addByte(0);
}
writeEntriesV2(entriesData);
final entriesBytes = entriesData.toBytes();
final hmacKey = BksKeyStore._derivePkcs12Key(
storePassword, salt, iterationCount, 20, 3);
final signatureBytes = _pkiCrypto.hmacSha1Sync(hmacKey, entriesBytes);
final out = BytesBuilder();
out.add(header.toBytes());
out.add(entriesBytes);
out.add(signatureBytes);
return out.toBytes();
}