1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-07-31 15:24:23 +03:00

Element-R: implement {get,store}SessionBackupPrivateKey (#3622)

This commit is contained in:
Richard van der Hoff
2023-07-26 12:00:43 +01:00
committed by GitHub
parent 29b815b678
commit 0e95df5dba
6 changed files with 75 additions and 10 deletions

View File

@ -55,7 +55,7 @@
], ],
"dependencies": { "dependencies": {
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"@matrix-org/matrix-sdk-crypto-wasm": "^1.0.1", "@matrix-org/matrix-sdk-crypto-wasm": "^1.1.0",
"another-json": "^0.2.0", "another-json": "^0.2.0",
"bs58": "^5.0.0", "bs58": "^5.0.0",
"content-type": "^1.0.4", "content-type": "^1.0.4",

View File

@ -503,6 +503,16 @@ describe("RustCrypto", () => {
); );
}); });
}); });
describe("get|storeSessionBackupPrivateKey", () => {
it("can save and restore a key", async () => {
const key = "testtesttesttesttesttesttesttest";
const rustCrypto = await makeTestRustCrypto();
await rustCrypto.storeSessionBackupPrivateKey(new TextEncoder().encode(key));
const fetched = await rustCrypto.getSessionBackupPrivateKey();
expect(new TextDecoder().decode(fetched!)).toEqual(key);
});
});
}); });
/** build a basic RustCrypto instance for testing /** build a basic RustCrypto instance for testing

View File

@ -3726,10 +3726,10 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
backupInfo: IKeyBackupInfo, backupInfo: IKeyBackupInfo,
opts?: IKeyBackupRestoreOpts, opts?: IKeyBackupRestoreOpts,
): Promise<IKeyBackupRestoreResult> { ): Promise<IKeyBackupRestoreResult> {
if (!this.crypto) { if (!this.cryptoBackend) {
throw new Error("End-to-end encryption disabled"); throw new Error("End-to-end encryption disabled");
} }
const privKey = await this.crypto.getSessionBackupPrivateKey(); const privKey = await this.cryptoBackend.getSessionBackupPrivateKey();
if (!privKey) { if (!privKey) {
throw new Error("Couldn't get key"); throw new Error("Couldn't get key");
} }
@ -3767,7 +3767,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
const cacheCompleteCallback = opts?.cacheCompleteCallback; const cacheCompleteCallback = opts?.cacheCompleteCallback;
const progressCallback = opts?.progressCallback; const progressCallback = opts?.progressCallback;
if (!this.crypto) { if (!this.cryptoBackend) {
throw new Error("End-to-end encryption disabled"); throw new Error("End-to-end encryption disabled");
} }
@ -3790,9 +3790,13 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
return Promise.reject(new MatrixError({ errcode: MatrixClient.RESTORE_BACKUP_ERROR_BAD_KEY })); return Promise.reject(new MatrixError({ errcode: MatrixClient.RESTORE_BACKUP_ERROR_BAD_KEY }));
} }
if (!(privKey instanceof Uint8Array)) {
// eslint-disable-next-line @typescript-eslint/no-base-to-string
throw new Error(`restoreKeyBackup expects Uint8Array, got ${privKey}`);
}
// Cache the key, if possible. // Cache the key, if possible.
// This is async. // This is async.
this.crypto this.cryptoBackend
.storeSessionBackupPrivateKey(privKey) .storeSessionBackupPrivateKey(privKey)
.catch((e) => { .catch((e) => {
logger.warn("Error caching session backup key:", e); logger.warn("Error caching session backup key:", e);
@ -3849,7 +3853,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
algorithm.free(); algorithm.free();
} }
await this.getCrypto()?.importRoomKeys(keys, { await this.cryptoBackend.importRoomKeys(keys, {
progressCallback, progressCallback,
untrusted, untrusted,
source: "backup", source: "backup",

View File

@ -284,6 +284,30 @@ export interface CryptoApi {
* @returns a VerificationRequest when the request has been sent to the other party. * @returns a VerificationRequest when the request has been sent to the other party.
*/ */
requestDeviceVerification(userId: string, deviceId: string): Promise<VerificationRequest>; requestDeviceVerification(userId: string, deviceId: string): Promise<VerificationRequest>;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Secure key backup
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Fetch the backup decryption key we have saved in our store.
*
* This can be used for gossiping the key to other devices.
*
* @returns the key, if any, or null
*/
getSessionBackupPrivateKey(): Promise<Uint8Array | null>;
/**
* Store the backup decryption key.
*
* This should be called if the client has received the key from another device via secret sharing (gossiping).
*
* @param key - the backup decryption key
*/
storeSessionBackupPrivateKey(key: Uint8Array): Promise<void>;
} }
/** /**

View File

@ -698,6 +698,33 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, RustCryptoEv
return new RustVerificationRequest(request, this.outgoingRequestProcessor, this._supportedVerificationMethods); return new RustVerificationRequest(request, this.outgoingRequestProcessor, this._supportedVerificationMethods);
} }
/**
* Fetch the backup decryption key we have saved in our store.
*
* Implementation of {@link CryptoApi#getSessionBackupPrivateKey}.
*
* @returns the key, if any, or null
*/
public async getSessionBackupPrivateKey(): Promise<Uint8Array | null> {
const backupKeys: RustSdkCryptoJs.BackupKeys = await this.olmMachine.getBackupKeys();
if (!backupKeys.decryptionKeyBase64) return null;
return Buffer.from(backupKeys.decryptionKeyBase64, "base64");
}
/**
* Store the backup decryption key.
*
* Implementation of {@link CryptoApi#storeSessionBackupPrivateKey}.
*
* @param key - the backup decryption key
*/
public async storeSessionBackupPrivateKey(key: Uint8Array): Promise<void> {
const base64Key = Buffer.from(key).toString("base64");
// TODO get version from backupManager
await this.olmMachine.saveBackupDecryptionKey(RustSdkCryptoJs.BackupDecryptionKey.fromBase64(base64Key), "");
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// SyncCryptoCallbacks implementation // SyncCryptoCallbacks implementation

View File

@ -1482,10 +1482,10 @@
"@jridgewell/resolve-uri" "3.1.0" "@jridgewell/resolve-uri" "3.1.0"
"@jridgewell/sourcemap-codec" "1.4.14" "@jridgewell/sourcemap-codec" "1.4.14"
"@matrix-org/matrix-sdk-crypto-wasm@^1.0.1": "@matrix-org/matrix-sdk-crypto-wasm@^1.1.0":
version "1.0.1" version "1.1.0"
resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-1.0.1.tgz#21a0557a7bb3f60b37c6d412be8906c056fe79b8" resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-1.1.0.tgz#43996a2c5fc8786999eeaaf6df51007244f6b3c4"
integrity sha512-VTwV5IowvhhLXwAsDDAv02bC5/qBQbG2YtpYAije11253sQ3MePIoSR+dS40Ih3lAlEzqQ00GU3O+i45jMzIRQ== integrity sha512-BSMYqXRgQOHG3N18z8b05x3UQcdLL3XDrxjtjjA88t9PadZ7RwNowLm1Sx3ESzdzRX+r1SEVAWs2JnTTs0rv3Q==
"@matrix-org/olm@https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.14.tgz": "@matrix-org/olm@https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.14.tgz":
version "3.2.14" version "3.2.14"