You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-11-25 05:23:13 +03:00
Split up, rename, and move ISecretStorageKeyInfo (#3242)
* Move SecretStorageKeyInfo interfaces out to a new module * Replace usages of ISecretStorageKeyInfo with SecretStorageKeyDescription
This commit is contained in:
committed by
GitHub
parent
78aa6cb62b
commit
41d3ffdab9
@@ -25,10 +25,10 @@ import { encryptAES } from "../../../src/crypto/aes";
|
||||
import { createSecretStorageKey, resetCrossSigningKeys } from "./crypto-utils";
|
||||
import { logger } from "../../../src/logger";
|
||||
import { ClientEvent, ICreateClientOpts, ICrossSigningKey, MatrixClient } from "../../../src/client";
|
||||
import { ISecretStorageKeyInfo } from "../../../src/crypto/api";
|
||||
import { DeviceInfo } from "../../../src/crypto/deviceinfo";
|
||||
import { ISignatures } from "../../../src/@types/signed";
|
||||
import { ICurve25519AuthData } from "../../../src/crypto/keybackup";
|
||||
import { SecretStorageKeyDescription } from "../../../src/secret-storage";
|
||||
|
||||
async function makeTestClient(
|
||||
userInfo: { userId: string; deviceId: string },
|
||||
@@ -541,7 +541,9 @@ describe("Secrets", function () {
|
||||
await alice.bootstrapSecretStorage({});
|
||||
|
||||
expect(alice.getAccountData("m.secret_storage.default_key")!.getContent()).toEqual({ key: "key_id" });
|
||||
const keyInfo = alice.getAccountData("m.secret_storage.key.key_id")!.getContent<ISecretStorageKeyInfo>();
|
||||
const keyInfo = alice
|
||||
.getAccountData("m.secret_storage.key.key_id")!
|
||||
.getContent<SecretStorageKeyDescription>();
|
||||
expect(keyInfo.algorithm).toEqual("m.secret_storage.v1.aes-hmac-sha2");
|
||||
expect(keyInfo.passphrase).toEqual({
|
||||
algorithm: "m.pbkdf2",
|
||||
|
||||
@@ -106,7 +106,6 @@ import {
|
||||
IEncryptedEventInfo,
|
||||
IImportRoomKeysOpts,
|
||||
IRecoveryKey,
|
||||
ISecretStorageKeyInfo,
|
||||
} from "./crypto/api";
|
||||
import { EventTimelineSet } from "./models/event-timeline-set";
|
||||
import { VerificationRequest } from "./crypto/verification/request/VerificationRequest";
|
||||
@@ -208,6 +207,7 @@ import { CryptoBackend } from "./common-crypto/CryptoBackend";
|
||||
import { RUST_SDK_STORE_PREFIX } from "./rust-crypto/constants";
|
||||
import { CryptoApi } from "./crypto-api";
|
||||
import { DeviceInfoMap } from "./crypto/DeviceList";
|
||||
import { SecretStorageKeyDescription } from "./secret-storage";
|
||||
|
||||
export type Store = IStore;
|
||||
|
||||
@@ -2463,7 +2463,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
||||
return this.crypto.beginKeyVerification(method, userId, deviceId);
|
||||
}
|
||||
|
||||
public checkSecretStorageKey(key: Uint8Array, info: ISecretStorageKeyInfo): Promise<boolean> {
|
||||
public checkSecretStorageKey(key: Uint8Array, info: SecretStorageKeyDescription): Promise<boolean> {
|
||||
if (!this.crypto) {
|
||||
throw new Error("End-to-end encryption disabled");
|
||||
}
|
||||
@@ -2863,7 +2863,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
||||
algorithm: string,
|
||||
opts: IAddSecretStorageKeyOpts,
|
||||
keyName?: string,
|
||||
): Promise<{ keyId: string; keyInfo: ISecretStorageKeyInfo }> {
|
||||
): Promise<{ keyId: string; keyInfo: SecretStorageKeyDescription }> {
|
||||
if (!this.crypto) {
|
||||
throw new Error("End-to-end encryption disabled");
|
||||
}
|
||||
@@ -2929,7 +2929,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
||||
* with, or null if it is not present or not encrypted with a trusted
|
||||
* key
|
||||
*/
|
||||
public isSecretStored(name: string): Promise<Record<string, ISecretStorageKeyInfo> | null> {
|
||||
public isSecretStored(name: string): Promise<Record<string, SecretStorageKeyDescription> | null> {
|
||||
if (!this.crypto) {
|
||||
throw new Error("End-to-end encryption disabled");
|
||||
}
|
||||
@@ -3306,7 +3306,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
||||
* encrypted with, or null if it is not present or not encrypted with a
|
||||
* trusted key
|
||||
*/
|
||||
public isKeyBackupKeyStored(): Promise<Record<string, ISecretStorageKeyInfo> | null> {
|
||||
public isKeyBackupKeyStored(): Promise<Record<string, SecretStorageKeyDescription> | null> {
|
||||
return Promise.resolve(this.isSecretStored("m.megolm_backup.v1"));
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ import { OlmDevice } from "./OlmDevice";
|
||||
import { ICryptoCallbacks } from ".";
|
||||
import { ISignatures } from "../@types/signed";
|
||||
import { CryptoStore, SecretStorePrivateKeys } from "./store/base";
|
||||
import { ISecretStorageKeyInfo } from "./api";
|
||||
import { SecretStorageKeyDescription } from "../secret-storage";
|
||||
|
||||
const KEY_REQUEST_TIMEOUT_MS = 1000 * 60;
|
||||
|
||||
@@ -169,7 +169,7 @@ export class CrossSigningInfo {
|
||||
// check what SSSS keys have encrypted the master key (if any)
|
||||
const stored = (await secretStorage.isStored("m.cross_signing.master")) || {};
|
||||
// then check which of those SSSS keys have also encrypted the SSK and USK
|
||||
function intersect(s: Record<string, ISecretStorageKeyInfo>): void {
|
||||
function intersect(s: Record<string, SecretStorageKeyDescription>): void {
|
||||
for (const k of Object.keys(stored)) {
|
||||
if (!s[k]) {
|
||||
delete stored[k];
|
||||
|
||||
@@ -28,10 +28,10 @@ import {
|
||||
ISignedKey,
|
||||
KeySignatures,
|
||||
} from "../client";
|
||||
import { ISecretStorageKeyInfo } from "./api";
|
||||
import { IKeyBackupInfo } from "./keybackup";
|
||||
import { TypedEventEmitter } from "../models/typed-event-emitter";
|
||||
import { IAccountDataClient } from "./SecretStorage";
|
||||
import { SecretStorageKeyDescription } from "../secret-storage";
|
||||
|
||||
interface ICrossSigningKeys {
|
||||
authUpload: IBootstrapCrossSigningOpts["authUploadDeviceSigningKeys"];
|
||||
@@ -326,7 +326,7 @@ class SSSSCryptoCallbacks {
|
||||
public constructor(private readonly delegateCryptoCallbacks?: ICryptoCallbacks) {}
|
||||
|
||||
public async getSecretStorageKey(
|
||||
{ keys }: { keys: Record<string, ISecretStorageKeyInfo> },
|
||||
{ keys }: { keys: Record<string, SecretStorageKeyDescription> },
|
||||
name: string,
|
||||
): Promise<[string, Uint8Array] | null> {
|
||||
for (const keyId of Object.keys(keys)) {
|
||||
@@ -348,7 +348,7 @@ class SSSSCryptoCallbacks {
|
||||
return null;
|
||||
}
|
||||
|
||||
public addPrivateKey(keyId: string, keyInfo: ISecretStorageKeyInfo, privKey: Uint8Array): void {
|
||||
public addPrivateKey(keyId: string, keyInfo: SecretStorageKeyDescription, privKey: Uint8Array): void {
|
||||
this.privateKeys.set(keyId, privKey);
|
||||
// Also pass along to application to cache if it wishes
|
||||
this.delegateCryptoCallbacks?.cacheSecretStorageKey?.(keyId, keyInfo, privKey);
|
||||
|
||||
@@ -23,16 +23,17 @@ import { calculateKeyCheck, decryptAES, encryptAES, IEncryptedPayload } from "./
|
||||
import { ICryptoCallbacks, IEncryptedContent } from ".";
|
||||
import { IContent, MatrixEvent } from "../models/event";
|
||||
import { ClientEvent, ClientEventHandlerMap, MatrixClient } from "../client";
|
||||
import { IAddSecretStorageKeyOpts, ISecretStorageKeyInfo } from "./api";
|
||||
import { IAddSecretStorageKeyOpts } from "./api";
|
||||
import { TypedEventEmitter } from "../models/typed-event-emitter";
|
||||
import { defer, IDeferred } from "../utils";
|
||||
import { ToDeviceMessageId } from "../@types/event";
|
||||
import { SecretStorageKeyDescription, SecretStorageKeyDescriptionAesV1 } from "../secret-storage";
|
||||
|
||||
export const SECRET_STORAGE_ALGORITHM_V1_AES = "m.secret_storage.v1.aes-hmac-sha2";
|
||||
|
||||
// Some of the key functions use a tuple and some use an object...
|
||||
export type SecretStorageKeyTuple = [keyId: string, keyInfo: ISecretStorageKeyInfo];
|
||||
export type SecretStorageKeyObject = { keyId: string; keyInfo: ISecretStorageKeyInfo };
|
||||
export type SecretStorageKeyTuple = [keyId: string, keyInfo: SecretStorageKeyDescription];
|
||||
export type SecretStorageKeyObject = { keyId: string; keyInfo: SecretStorageKeyDescription };
|
||||
|
||||
export interface ISecretRequest {
|
||||
requestId: string;
|
||||
@@ -127,30 +128,30 @@ export class SecretStorage<B extends MatrixClient | undefined = MatrixClient> {
|
||||
opts: IAddSecretStorageKeyOpts = {},
|
||||
keyId?: string,
|
||||
): Promise<SecretStorageKeyObject> {
|
||||
const keyInfo = { algorithm } as ISecretStorageKeyInfo;
|
||||
if (algorithm !== SECRET_STORAGE_ALGORITHM_V1_AES) {
|
||||
throw new Error(`Unknown key algorithm ${algorithm}`);
|
||||
}
|
||||
|
||||
const keyInfo = { algorithm } as SecretStorageKeyDescriptionAesV1;
|
||||
|
||||
if (opts.name) {
|
||||
keyInfo.name = opts.name;
|
||||
}
|
||||
|
||||
if (algorithm === SECRET_STORAGE_ALGORITHM_V1_AES) {
|
||||
if (opts.passphrase) {
|
||||
keyInfo.passphrase = opts.passphrase;
|
||||
}
|
||||
if (opts.key) {
|
||||
const { iv, mac } = await calculateKeyCheck(opts.key);
|
||||
keyInfo.iv = iv;
|
||||
keyInfo.mac = mac;
|
||||
}
|
||||
} else {
|
||||
throw new Error(`Unknown key algorithm ${algorithm}`);
|
||||
if (opts.passphrase) {
|
||||
keyInfo.passphrase = opts.passphrase;
|
||||
}
|
||||
if (opts.key) {
|
||||
const { iv, mac } = await calculateKeyCheck(opts.key);
|
||||
keyInfo.iv = iv;
|
||||
keyInfo.mac = mac;
|
||||
}
|
||||
|
||||
if (!keyId) {
|
||||
do {
|
||||
keyId = randomString(32);
|
||||
} while (
|
||||
await this.accountDataAdapter.getAccountDataFromServer<ISecretStorageKeyInfo>(
|
||||
await this.accountDataAdapter.getAccountDataFromServer<SecretStorageKeyDescription>(
|
||||
`m.secret_storage.key.${keyId}`,
|
||||
)
|
||||
);
|
||||
@@ -181,7 +182,7 @@ export class SecretStorage<B extends MatrixClient | undefined = MatrixClient> {
|
||||
return null;
|
||||
}
|
||||
|
||||
const keyInfo = await this.accountDataAdapter.getAccountDataFromServer<ISecretStorageKeyInfo>(
|
||||
const keyInfo = await this.accountDataAdapter.getAccountDataFromServer<SecretStorageKeyDescription>(
|
||||
"m.secret_storage.key." + keyId,
|
||||
);
|
||||
return keyInfo ? [keyId, keyInfo] : null;
|
||||
@@ -206,7 +207,7 @@ export class SecretStorage<B extends MatrixClient | undefined = MatrixClient> {
|
||||
*
|
||||
* @returns whether or not the key matches
|
||||
*/
|
||||
public async checkKey(key: Uint8Array, info: ISecretStorageKeyInfo): Promise<boolean> {
|
||||
public async checkKey(key: Uint8Array, info: SecretStorageKeyDescription): Promise<boolean> {
|
||||
if (info.algorithm === SECRET_STORAGE_ALGORITHM_V1_AES) {
|
||||
if (info.mac) {
|
||||
const { mac } = await calculateKeyCheck(key, info.iv);
|
||||
@@ -245,7 +246,7 @@ export class SecretStorage<B extends MatrixClient | undefined = MatrixClient> {
|
||||
|
||||
for (const keyId of keys) {
|
||||
// get key information from key storage
|
||||
const keyInfo = await this.accountDataAdapter.getAccountDataFromServer<ISecretStorageKeyInfo>(
|
||||
const keyInfo = await this.accountDataAdapter.getAccountDataFromServer<SecretStorageKeyDescription>(
|
||||
"m.secret_storage.key." + keyId,
|
||||
);
|
||||
if (!keyInfo) {
|
||||
@@ -284,10 +285,10 @@ export class SecretStorage<B extends MatrixClient | undefined = MatrixClient> {
|
||||
}
|
||||
|
||||
// get possible keys to decrypt
|
||||
const keys: Record<string, ISecretStorageKeyInfo> = {};
|
||||
const keys: Record<string, SecretStorageKeyDescription> = {};
|
||||
for (const keyId of Object.keys(secretInfo.encrypted)) {
|
||||
// get key information from key storage
|
||||
const keyInfo = await this.accountDataAdapter.getAccountDataFromServer<ISecretStorageKeyInfo>(
|
||||
const keyInfo = await this.accountDataAdapter.getAccountDataFromServer<SecretStorageKeyDescription>(
|
||||
"m.secret_storage.key." + keyId,
|
||||
);
|
||||
const encInfo = secretInfo.encrypted[keyId];
|
||||
@@ -322,17 +323,17 @@ export class SecretStorage<B extends MatrixClient | undefined = MatrixClient> {
|
||||
* with, or null if it is not present or not encrypted with a trusted
|
||||
* key
|
||||
*/
|
||||
public async isStored(name: string): Promise<Record<string, ISecretStorageKeyInfo> | null> {
|
||||
public async isStored(name: string): Promise<Record<string, SecretStorageKeyDescription> | null> {
|
||||
// check if secret exists
|
||||
const secretInfo = await this.accountDataAdapter.getAccountDataFromServer<ISecretInfo>(name);
|
||||
if (!secretInfo?.encrypted) return null;
|
||||
|
||||
const ret: Record<string, ISecretStorageKeyInfo> = {};
|
||||
const ret: Record<string, SecretStorageKeyDescription> = {};
|
||||
|
||||
// filter secret encryption keys with supported algorithm
|
||||
for (const keyId of Object.keys(secretInfo.encrypted)) {
|
||||
// get key information from key storage
|
||||
const keyInfo = await this.accountDataAdapter.getAccountDataFromServer<ISecretStorageKeyInfo>(
|
||||
const keyInfo = await this.accountDataAdapter.getAccountDataFromServer<SecretStorageKeyDescription>(
|
||||
"m.secret_storage.key." + keyId,
|
||||
);
|
||||
if (!keyInfo) continue;
|
||||
@@ -544,7 +545,7 @@ export class SecretStorage<B extends MatrixClient | undefined = MatrixClient> {
|
||||
}
|
||||
|
||||
private async getSecretStorageKey(
|
||||
keys: Record<string, ISecretStorageKeyInfo>,
|
||||
keys: Record<string, SecretStorageKeyDescription>,
|
||||
name: string,
|
||||
): Promise<[string, IDecryptors]> {
|
||||
if (!this.cryptoCallbacks.getSecretStorageKey) {
|
||||
|
||||
@@ -16,6 +16,13 @@ limitations under the License.
|
||||
|
||||
import { DeviceInfo } from "./deviceinfo";
|
||||
import { IKeyBackupInfo } from "./keybackup";
|
||||
import { PassphraseInfo } from "../secret-storage";
|
||||
|
||||
/* re-exports for backwards compatibility. */
|
||||
export {
|
||||
PassphraseInfo as IPassphraseInfo,
|
||||
SecretStorageKeyDescription as ISecretStorageKeyInfo,
|
||||
} from "../secret-storage";
|
||||
|
||||
// TODO: Merge this with crypto.js once converted
|
||||
|
||||
@@ -98,26 +105,9 @@ export interface ICreateSecretStorageOpts {
|
||||
getKeyBackupPassphrase?: () => Promise<Uint8Array>;
|
||||
}
|
||||
|
||||
export interface ISecretStorageKeyInfo {
|
||||
name: string;
|
||||
algorithm: string;
|
||||
// technically the below are specific to AES keys. If we ever introduce another type,
|
||||
// we can split into separate interfaces.
|
||||
iv: string;
|
||||
mac: string;
|
||||
passphrase: IPassphraseInfo;
|
||||
}
|
||||
|
||||
export interface IPassphraseInfo {
|
||||
algorithm: "m.pbkdf2";
|
||||
iterations: number;
|
||||
salt: string;
|
||||
bits?: number;
|
||||
}
|
||||
|
||||
export interface IAddSecretStorageKeyOpts {
|
||||
pubkey?: string;
|
||||
passphrase?: IPassphraseInfo;
|
||||
passphrase?: PassphraseInfo;
|
||||
name?: string;
|
||||
key?: Uint8Array;
|
||||
}
|
||||
|
||||
@@ -21,13 +21,13 @@ import { decodeBase64, encodeBase64 } from "./olmlib";
|
||||
import { IndexedDBCryptoStore } from "../crypto/store/indexeddb-crypto-store";
|
||||
import { decryptAES, encryptAES } from "./aes";
|
||||
import { logger } from "../logger";
|
||||
import { ISecretStorageKeyInfo } from "./api";
|
||||
import { Crypto } from "./index";
|
||||
import { Method } from "../http-api";
|
||||
import { SecretStorageKeyDescription } from "../secret-storage";
|
||||
|
||||
export interface IDehydratedDevice {
|
||||
device_id: string; // eslint-disable-line camelcase
|
||||
device_data: ISecretStorageKeyInfo & {
|
||||
device_data: SecretStorageKeyDescription & {
|
||||
// eslint-disable-line camelcase
|
||||
algorithm: string;
|
||||
account: string; // pickle
|
||||
|
||||
@@ -48,7 +48,6 @@ import {
|
||||
IEncryptedEventInfo,
|
||||
IImportRoomKeysOpts,
|
||||
IRecoveryKey,
|
||||
ISecretStorageKeyInfo,
|
||||
} from "./api";
|
||||
import { OutgoingRoomKeyRequestManager } from "./OutgoingRoomKeyRequestManager";
|
||||
import { IndexedDBCryptoStore } from "./store/indexeddb-crypto-store";
|
||||
@@ -91,6 +90,7 @@ import { IMessage } from "./algorithms/olm";
|
||||
import { CryptoBackend, OnSyncCompletedData } from "../common-crypto/CryptoBackend";
|
||||
import { RoomState, RoomStateEvent } from "../models/room-state";
|
||||
import { MapWithDefault, recursiveMapToObject } from "../utils";
|
||||
import { SecretStorageKeyDescription } from "../secret-storage";
|
||||
|
||||
const DeviceVerification = DeviceInfo.DeviceVerification;
|
||||
|
||||
@@ -142,10 +142,10 @@ export interface ICryptoCallbacks {
|
||||
saveCrossSigningKeys?: (keys: Record<string, Uint8Array>) => void;
|
||||
shouldUpgradeDeviceVerifications?: (users: Record<string, any>) => Promise<string[]>;
|
||||
getSecretStorageKey?: (
|
||||
keys: { keys: Record<string, ISecretStorageKeyInfo> },
|
||||
keys: { keys: Record<string, SecretStorageKeyDescription> },
|
||||
name: string,
|
||||
) => Promise<[string, Uint8Array] | null>;
|
||||
cacheSecretStorageKey?: (keyId: string, keyInfo: ISecretStorageKeyInfo, key: Uint8Array) => void;
|
||||
cacheSecretStorageKey?: (keyId: string, keyInfo: SecretStorageKeyDescription, key: Uint8Array) => void;
|
||||
onSecretRequested?: (
|
||||
userId: string,
|
||||
deviceId: string,
|
||||
@@ -153,7 +153,10 @@ export interface ICryptoCallbacks {
|
||||
secretName: string,
|
||||
deviceTrust: DeviceTrustLevel,
|
||||
) => Promise<string | undefined>;
|
||||
getDehydrationKey?: (keyInfo: ISecretStorageKeyInfo, checkFunc: (key: Uint8Array) => void) => Promise<Uint8Array>;
|
||||
getDehydrationKey?: (
|
||||
keyInfo: SecretStorageKeyDescription,
|
||||
checkFunc: (key: Uint8Array) => void,
|
||||
) => Promise<Uint8Array>;
|
||||
getBackupKey?: () => Promise<Uint8Array>;
|
||||
}
|
||||
|
||||
@@ -923,7 +926,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
|
||||
return keyId;
|
||||
};
|
||||
|
||||
const ensureCanCheckPassphrase = async (keyId: string, keyInfo: ISecretStorageKeyInfo): Promise<void> => {
|
||||
const ensureCanCheckPassphrase = async (keyId: string, keyInfo: SecretStorageKeyDescription): Promise<void> => {
|
||||
if (!keyInfo.mac) {
|
||||
const key = await this.baseApis.cryptoCallbacks.getSecretStorageKey?.(
|
||||
{ keys: { [keyId]: keyInfo } },
|
||||
@@ -1130,7 +1133,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
|
||||
return this.secretStorage.get(name);
|
||||
}
|
||||
|
||||
public isSecretStored(name: string): Promise<Record<string, ISecretStorageKeyInfo> | null> {
|
||||
public isSecretStored(name: string): Promise<Record<string, SecretStorageKeyDescription> | null> {
|
||||
return this.secretStorage.isStored(name);
|
||||
}
|
||||
|
||||
@@ -1149,7 +1152,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
|
||||
return this.secretStorage.setDefaultKeyId(k);
|
||||
}
|
||||
|
||||
public checkSecretStorageKey(key: Uint8Array, info: ISecretStorageKeyInfo): Promise<boolean> {
|
||||
public checkSecretStorageKey(key: Uint8Array, info: SecretStorageKeyDescription): Promise<boolean> {
|
||||
return this.secretStorage.checkKey(key, info);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ export * from "./@types/requests";
|
||||
export * from "./@types/search";
|
||||
export * from "./models/room-summary";
|
||||
export * as ContentHelpers from "./content-helpers";
|
||||
export * as SecretStorage from "./secret-storage";
|
||||
export type { ICryptoCallbacks } from "./crypto"; // used to be located here
|
||||
export { createNewMatrixCall } from "./webrtc/call";
|
||||
export type { MatrixCall } from "./webrtc/call";
|
||||
|
||||
88
src/secret-storage.ts
Normal file
88
src/secret-storage.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Copyright 2021-2023 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of server-side secret storage
|
||||
*
|
||||
* @see https://spec.matrix.org/v1.6/client-server-api/#storage
|
||||
*/
|
||||
|
||||
/**
|
||||
* Common base interface for Secret Storage Keys.
|
||||
*
|
||||
* The common properties for all encryption keys used in server-side secret storage.
|
||||
*
|
||||
* @see https://spec.matrix.org/v1.6/client-server-api/#key-storage
|
||||
*/
|
||||
export interface SecretStorageKeyDescriptionCommon {
|
||||
/** A human-readable name for this key. */
|
||||
// XXX: according to the spec, this is optional
|
||||
name: string;
|
||||
|
||||
/** The encryption algorithm used with this key. */
|
||||
algorithm: string;
|
||||
|
||||
/** Information for deriving this key from a passphrase. */
|
||||
// XXX: according to the spec, this is optional
|
||||
passphrase: PassphraseInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties for a SSSS key using the `m.secret_storage.v1.aes-hmac-sha2` algorithm.
|
||||
*
|
||||
* Corresponds to `AesHmacSha2KeyDescription` in the specification.
|
||||
*
|
||||
* @see https://spec.matrix.org/v1.6/client-server-api/#msecret_storagev1aes-hmac-sha2
|
||||
*/
|
||||
export interface SecretStorageKeyDescriptionAesV1 extends SecretStorageKeyDescriptionCommon {
|
||||
// XXX: strictly speaking, we should be able to enforce the algorithm here. But
|
||||
// this interface ends up being incorrectly used where other algorithms are in use (notably
|
||||
// in device-dehydration support), and unpicking that is too much like hard work
|
||||
// at the moment.
|
||||
// algorithm: "m.secret_storage.v1.aes-hmac-sha2";
|
||||
|
||||
/** The 16-byte AES initialization vector, encoded as base64. */
|
||||
iv: string;
|
||||
|
||||
/** The MAC of the result of encrypting 32 bytes of 0, encoded as base64. */
|
||||
mac: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Union type for secret storage keys.
|
||||
*
|
||||
* For now, this is only {@link SecretStorageKeyDescriptionAesV1}, but other interfaces may be added in future.
|
||||
*/
|
||||
export type SecretStorageKeyDescription = SecretStorageKeyDescriptionAesV1;
|
||||
|
||||
/**
|
||||
* Information on how to generate the key from a passphrase.
|
||||
*
|
||||
* @see https://spec.matrix.org/v1.6/client-server-api/#deriving-keys-from-passphrases
|
||||
*/
|
||||
export interface PassphraseInfo {
|
||||
/** The algorithm to be used to derive the key. */
|
||||
algorithm: "m.pbkdf2";
|
||||
|
||||
/** The number of PBKDF2 iterations to use. */
|
||||
iterations: number;
|
||||
|
||||
/** The salt to be used for PBKDF2. */
|
||||
salt: string;
|
||||
|
||||
/** The number of bits to generate. Defaults to 256. */
|
||||
bits?: number;
|
||||
}
|
||||
Reference in New Issue
Block a user