check mac of dehydrated key to match default 4s key mac before adopting
This commit is contained in:
parent
567cdd5510
commit
8a36eb4532
3 changed files with 32 additions and 14 deletions
|
@ -437,7 +437,7 @@ export class Session {
|
||||||
// enable session backup, this requests the latest backup version
|
// enable session backup, this requests the latest backup version
|
||||||
if (!this._sessionBackup) {
|
if (!this._sessionBackup) {
|
||||||
if (dehydratedDevice) {
|
if (dehydratedDevice) {
|
||||||
const ssssKey = await createSSSSKeyFromDehydratedDeviceKey(dehydratedDevice.key, this._storage);
|
const ssssKey = await createSSSSKeyFromDehydratedDeviceKey(dehydratedDevice.key, this._storage, this._platform);
|
||||||
if (ssssKey) {
|
if (ssssKey) {
|
||||||
this._writeSSSSKey(ssssKey);
|
this._writeSSSSKey(ssssKey);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,23 +32,20 @@ export class KeyDescription {
|
||||||
return this._keyDescription?.algorithm;
|
return this._keyDescription?.algorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
isCompatible(d) {
|
async isCompatible(key, platform) {
|
||||||
const kd = this._keyDescription;
|
if (this.algorithm === "m.secret_storage.v1.aes-hmac-sha2") {
|
||||||
const kdOther = d._keyDescription;
|
const kd = this._keyDescription;
|
||||||
if (kd.algorithm === "m.secret_storage.v1.aes-hmac-sha2") {
|
if (kd.mac) {
|
||||||
if (kdOther.algorithm !== kd.algorithm) {
|
const otherMac = await calculateKeyMac(key.binaryKey, kd.iv, platform);
|
||||||
return false;
|
return kd.mac === otherMac;
|
||||||
}
|
} else if (kd.passphrase) {
|
||||||
if (kd.passphrase) {
|
const kdOther = key.description._keyDescription;
|
||||||
if (!kdOther.passphrase) {
|
if (!kdOther.passphrase) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return kd.passphrase.algorithm === kdOther.passphrase.algorithm &&
|
return kd.passphrase.algorithm === kdOther.passphrase.algorithm &&
|
||||||
kd.passphrase.iterations === kdOther.passphrase.iterations &&
|
kd.passphrase.iterations === kdOther.passphrase.iterations &&
|
||||||
kd.passphrase.salt === kdOther.passphrase.salt;
|
kd.passphrase.salt === kdOther.passphrase.salt;
|
||||||
} else {
|
|
||||||
return !!kd.iv && kd.iv === kdOther.iv &&
|
|
||||||
!!kd.mac && kd.mac === kdOther.mac;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -81,3 +78,24 @@ export class Key {
|
||||||
return this._keyDescription.algorithm;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -80,9 +80,9 @@ export async function keyFromCredentialAndDescription(type, credential, keyDescr
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function keyFromDehydratedDeviceKey(key, storage) {
|
export async function keyFromDehydratedDeviceKey(key, storage, platform) {
|
||||||
const keyDescription = await readDefaultKeyDescription(storage);
|
const keyDescription = await readDefaultKeyDescription(storage);
|
||||||
if (key.description.isCompatible(keyDescription)) {
|
if (await keyDescription.isCompatible(key, platform)) {
|
||||||
return key.withDescription(keyDescription);
|
return key.withDescription(keyDescription);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue