createKey method
Creates a new secret storage key, optional encrypts it with passphrase
and stores it in the user's accountData
.
Implementation
Future<OpenSSSS> createKey([String? passphrase]) async {
Uint8List privateKey;
final content = SecretStorageKeyContent();
if (passphrase != null) {
// we need to derive the key off of the passphrase
content.passphrase = PassphraseInfo(
iterations: pbkdf2DefaultIterations,
salt: base64.encode(uc.secureRandomBytes(pbkdf2SaltLength)),
algorithm: AlgorithmTypes.pbkdf2,
bits: ssssKeyLength * 8,
);
privateKey = await Future.value(
client.nativeImplementations.keyFromPassphrase(
KeyFromPassphraseArgs(
passphrase: passphrase,
info: content.passphrase!,
),
),
).timeout(Duration(seconds: 10));
} else {
// we need to just generate a new key from scratch
privateKey = Uint8List.fromList(uc.secureRandomBytes(ssssKeyLength));
}
// now that we have the private key, let's create the iv and mac
final encrypted = await encryptAes(zeroStr, privateKey, '');
content.iv = encrypted.iv;
content.mac = encrypted.mac;
content.algorithm = AlgorithmTypes.secretStorageV1AesHmcSha2;
const keyidByteLength = 24;
// make sure we generate a unique key id
final keyId = () sync* {
for (;;) {
yield base64.encode(uc.secureRandomBytes(keyidByteLength));
}
}()
.firstWhere((keyId) => getKey(keyId) == null);
final accountDataType = EventTypes.secretStorageKey(keyId);
// noooow we set the account data
final waitForAccountData = client.onSync.stream.firstWhere((syncUpdate) =>
syncUpdate.accountData != null &&
syncUpdate.accountData!
.any((accountData) => accountData.type == accountDataType));
await client.setAccountData(
client.userID!, accountDataType, content.toJson());
await waitForAccountData;
final key = open(keyId);
await key.setPrivateKey(privateKey);
return key;
}