1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-11-26 17:03:12 +03:00

Element-R: use the pickleKey to encrypt the crypto store (#3732)

* Element-R: use the pickleKey to encrypt the crypto store

`pickleKey` is a passphrase set by the application for this express purpose.

* update tests

* fix tests, again
This commit is contained in:
Richard van der Hoff
2023-09-20 13:35:32 +02:00
committed by GitHub
parent a3e273d6f1
commit 425cf6b91e
4 changed files with 98 additions and 10 deletions

View File

@@ -41,7 +41,7 @@ describe("MatrixClient.initRustCrypto", () => {
await expect(() => unknownDeviceClient.initRustCrypto()).rejects.toThrow("unknown deviceId");
});
it("should create the indexed dbs", async () => {
it("should create the indexed db", async () => {
const matrixClient = createClient({
baseUrl: "http://test.server",
userId: "@alice:localhost",
@@ -53,7 +53,25 @@ describe("MatrixClient.initRustCrypto", () => {
await matrixClient.initRustCrypto();
// should have two dbs now
// should have an indexed db now
const databaseNames = (await indexedDB.databases()).map((db) => db.name);
expect(databaseNames).toEqual(expect.arrayContaining(["matrix-js-sdk::matrix-sdk-crypto"]));
});
it("should create the meta db if given a pickleKey", async () => {
const matrixClient = createClient({
baseUrl: "http://test.server",
userId: "@alice:localhost",
deviceId: "aliceDevice",
pickleKey: "testKey",
});
// No databases.
expect(await indexedDB.databases()).toHaveLength(0);
await matrixClient.initRustCrypto();
// should have two indexed dbs now
const databaseNames = (await indexedDB.databases()).map((db) => db.name);
expect(databaseNames).toEqual(
expect.arrayContaining(["matrix-js-sdk::matrix-sdk-crypto", "matrix-js-sdk::matrix-sdk-crypto-meta"]),
@@ -78,6 +96,7 @@ describe("MatrixClient.clearStores", () => {
baseUrl: "http://test.server",
userId: "@alice:localhost",
deviceId: "aliceDevice",
pickleKey: "testKey",
});
await matrixClient.initRustCrypto();

View File

@@ -54,6 +54,56 @@ const TEST_DEVICE_ID = "TEST_DEVICE";
afterEach(() => {
fetchMock.reset();
jest.restoreAllMocks();
});
describe("initRustCrypto", () => {
function makeTestOlmMachine(): Mocked<OlmMachine> {
return {
registerRoomKeyUpdatedCallback: jest.fn(),
registerUserIdentityUpdatedCallback: jest.fn(),
outgoingRequests: jest.fn(),
} as unknown as Mocked<OlmMachine>;
}
it("passes through the store params", async () => {
const testOlmMachine = makeTestOlmMachine();
jest.spyOn(OlmMachine, "initialize").mockResolvedValue(testOlmMachine);
await initRustCrypto(
{} as MatrixClient["http"],
TEST_USER,
TEST_DEVICE_ID,
{} as ServerSideSecretStorage,
{} as CryptoCallbacks,
"storePrefix",
"storePassphrase",
);
expect(OlmMachine.initialize).toHaveBeenCalledWith(
expect.anything(),
expect.anything(),
"storePrefix",
"storePassphrase",
);
});
it("suppresses the storePassphrase if storePrefix is unset", async () => {
const testOlmMachine = makeTestOlmMachine();
jest.spyOn(OlmMachine, "initialize").mockResolvedValue(testOlmMachine);
await initRustCrypto(
{} as MatrixClient["http"],
TEST_USER,
TEST_DEVICE_ID,
{} as ServerSideSecretStorage,
{} as CryptoCallbacks,
null,
"storePassphrase",
);
expect(OlmMachine.initialize).toHaveBeenCalledWith(expect.anything(), expect.anything(), undefined, undefined);
});
});
describe("RustCrypto", () => {
@@ -398,10 +448,6 @@ describe("RustCrypto", () => {
);
});
afterEach(() => {
jest.restoreAllMocks();
});
async function makeEncryptedEvent(): Promise<MatrixEvent> {
const encryptedEvent = mkEvent({
event: true,
@@ -812,5 +858,5 @@ async function makeTestRustCrypto(
secretStorage: ServerSideSecretStorage = {} as ServerSideSecretStorage,
cryptoCallbacks: CryptoCallbacks = {} as CryptoCallbacks,
): Promise<RustCrypto> {
return await initRustCrypto(http, userId, deviceId, secretStorage, cryptoCallbacks, null);
return await initRustCrypto(http, userId, deviceId, secretStorage, cryptoCallbacks, null, undefined);
}

View File

@@ -343,7 +343,14 @@ export interface ICreateClientOpts {
deviceToImport?: IExportedDevice;
/**
* Key used to pickle olm objects or other sensitive data.
* Encryption key used for encrypting sensitive data (such as e2ee keys) in storage.
*
* This must be set to the same value every time the client is initialised for the same device.
*
* If unset, either a hardcoded key or no encryption at all is used, depending on the Crypto implementation.
*
* No particular requirement is placed on the key data (it is fed into an HKDF to generate the actual encryption
* keys).
*/
pickleKey?: string;
@@ -1193,7 +1200,18 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
public store: Store;
public deviceId: string | null;
public credentials: { userId: string | null };
/**
* Encryption key used for encrypting sensitive data (such as e2ee keys) in storage.
*
* As supplied in the constructor via {@link IMatrixClientCreateOpts#pickleKey}.
*
* If unset, either a hardcoded key or no encryption at all is used, depending on the Crypto implementation.
*
* @deprecated this should be a private property.
*/
public pickleKey?: string;
public scheduler?: MatrixScheduler;
public clientRunning = false;
public timelineSupport = false;
@@ -2279,6 +2297,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
this.secretStorage,
this.cryptoCallbacks,
useIndexedDB ? RUST_SDK_STORE_PREFIX : null,
this.pickleKey,
);
rustCrypto.setSupportedVerificationMethods(this.verificationMethods);

View File

@@ -32,7 +32,10 @@ import { ICryptoCallbacks } from "../crypto";
* @param secretStorage - Interface to server-side secret storage.
* @param cryptoCallbacks - Crypto callbacks provided by the application
* @param storePrefix - the prefix to use on the indexeddbs created by rust-crypto.
* If unset, a memory store will be used.
* If `null`, a memory store will be used.
* @param storePassphrase - a passphrase to use to encrypt the indexeddbs created by rust-crypto.
* Ignored if `storePrefix` is null. If this is `undefined` (and `storePrefix` is not null), the indexeddbs
* will be unencrypted.
*
* @internal
*/
@@ -43,6 +46,7 @@ export async function initRustCrypto(
secretStorage: ServerSideSecretStorage,
cryptoCallbacks: ICryptoCallbacks,
storePrefix: string | null,
storePassphrase: string | undefined,
): Promise<RustCrypto> {
// initialise the rust matrix-sdk-crypto-wasm, if it hasn't already been done
await RustSdkCryptoJs.initAsync();
@@ -59,7 +63,7 @@ export async function initRustCrypto(
u,
d,
storePrefix ?? undefined,
(storePrefix && "test pass") ?? undefined,
(storePrefix && storePassphrase) ?? undefined,
);
const rustCrypto = new RustCrypto(olmMachine, http, userId, deviceId, secretStorage, cryptoCallbacks);
await olmMachine.registerRoomKeyUpdatedCallback((sessions: RustSdkCryptoJs.RoomKeyInfo[]) =>