check mac of dehydrated key to match default 4s key mac before adopting

This commit is contained in:
Bruno Windels 2021-11-03 02:07:57 +01:00
parent 567cdd5510
commit 8a36eb4532
3 changed files with 32 additions and 14 deletions

View file

@ -437,7 +437,7 @@ export class Session {
// enable session backup, this requests the latest backup version
if (!this._sessionBackup) {
if (dehydratedDevice) {
const ssssKey = await createSSSSKeyFromDehydratedDeviceKey(dehydratedDevice.key, this._storage);
const ssssKey = await createSSSSKeyFromDehydratedDeviceKey(dehydratedDevice.key, this._storage, this._platform);
if (ssssKey) {
this._writeSSSSKey(ssssKey);
}

View file

@ -32,23 +32,20 @@ export class KeyDescription {
return this._keyDescription?.algorithm;
}
isCompatible(d) {
const kd = this._keyDescription;
const kdOther = d._keyDescription;
if (kd.algorithm === "m.secret_storage.v1.aes-hmac-sha2") {
if (kdOther.algorithm !== kd.algorithm) {
return false;
}
if (kd.passphrase) {
async isCompatible(key, platform) {
if (this.algorithm === "m.secret_storage.v1.aes-hmac-sha2") {
const kd = this._keyDescription;
if (kd.mac) {
const otherMac = await calculateKeyMac(key.binaryKey, kd.iv, platform);
return kd.mac === otherMac;
} else if (kd.passphrase) {
const kdOther = key.description._keyDescription;
if (!kdOther.passphrase) {
return false;
}
return kd.passphrase.algorithm === kdOther.passphrase.algorithm &&
kd.passphrase.iterations === kdOther.passphrase.iterations &&
kd.passphrase.salt === kdOther.passphrase.salt;
} else {
return !!kd.iv && kd.iv === kdOther.iv &&
!!kd.mac && kd.mac === kdOther.mac;
}
}
return false;
@ -81,3 +78,24 @@ export class Key {
return this._keyDescription.algorithm;
}
}
async function calculateKeyMac(key, ivStr, platform) {
const {crypto, encoding} = platform;
const {utf8, base64} = encoding;
const {derive, aes, hmac} = crypto;
const iv = base64.decode(ivStr);
// salt for HKDF, with 8 bytes of zeros
const zerosalt = new Uint8Array(8);
const ZERO_STR = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
const info = utf8.encode("");
const keybits = await derive.hkdf(key, zerosalt, info, "SHA-256", 512);
const aesKey = keybits.slice(0, 32);
const hmacKey = keybits.slice(32);
const ciphertext = await aes.encryptCTR({key: aesKey, iv, data: utf8.encode(ZERO_STR)});
const mac = await hmac.compute(hmacKey, ciphertext, "SHA-256");
return base64.encode(mac);
}

View file

@ -80,9 +80,9 @@ export async function keyFromCredentialAndDescription(type, credential, keyDescr
return key;
}
export async function keyFromDehydratedDeviceKey(key, storage) {
export async function keyFromDehydratedDeviceKey(key, storage, platform) {
const keyDescription = await readDefaultKeyDescription(storage);
if (key.description.isCompatible(keyDescription)) {
if (await keyDescription.isCompatible(key, platform)) {
return key.withDescription(keyDescription);
}
}