mirror of
https://github.com/bitwarden/browser
synced 2026-02-10 05:30:01 +00:00
Update apis
This commit is contained in:
@@ -226,7 +226,10 @@ export class ChangePasswordComponent
|
||||
this.formPromise = this.apiService.postPassword(request);
|
||||
}
|
||||
|
||||
await this.opaqueService.Register(this.masterPassword, newUserKey[0]);
|
||||
await this.opaqueService.register(this.masterPassword, newUserKey[0], {
|
||||
algorithm: "argon2id",
|
||||
parameters: { memory: 256 * 1024, iterations: 3, parallelism: 4 },
|
||||
});
|
||||
await this.formPromise;
|
||||
|
||||
this.toastService.showToast({
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { KdfType } from "@bitwarden/key-management";
|
||||
|
||||
import { BaseResponse } from "../../../models/response/base.response";
|
||||
import { CipherConfiguration } from "../../opaque/models/cipher-configuration";
|
||||
|
||||
export class PreloginResponse extends BaseResponse {
|
||||
kdf: KdfType;
|
||||
@@ -8,11 +9,14 @@ export class PreloginResponse extends BaseResponse {
|
||||
kdfMemory?: number;
|
||||
kdfParallelism?: number;
|
||||
|
||||
opaqueConfiguration?: CipherConfiguration;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
this.kdf = this.getResponseProperty("Kdf");
|
||||
this.kdfIterations = this.getResponseProperty("KdfIterations");
|
||||
this.kdfMemory = this.getResponseProperty("KdfMemory");
|
||||
this.kdfParallelism = this.getResponseProperty("KdfParallelism");
|
||||
this.opaqueConfiguration = this.getResponseProperty("OpaqueConfiguration");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,6 @@ import { firstValueFrom } from "rxjs";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
|
||||
import { OpaqueSessionId } from "../../types/guid";
|
||||
|
||||
import { RegistrationFinishRequest } from "./models/registration-finish.request";
|
||||
import { RegistrationFinishResponse } from "./models/registration-finish.response";
|
||||
import { RegistrationStartRequest } from "./models/registration-start.request";
|
||||
@@ -17,7 +15,7 @@ export class DefaultOpaqueApiService implements OpaqueApiService {
|
||||
private environmentService: EnvironmentService,
|
||||
) {}
|
||||
|
||||
async RegistrationStart(request: RegistrationStartRequest): Promise<RegistrationStartResponse> {
|
||||
async registrationStart(request: RegistrationStartRequest): Promise<RegistrationStartResponse> {
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
const response = await this.apiService.send(
|
||||
"POST",
|
||||
@@ -30,8 +28,7 @@ export class DefaultOpaqueApiService implements OpaqueApiService {
|
||||
return new RegistrationStartResponse(response);
|
||||
}
|
||||
|
||||
async RegistrationFinish(
|
||||
credentialId: OpaqueSessionId,
|
||||
async registrationFinish(
|
||||
request: RegistrationFinishRequest,
|
||||
): Promise<RegistrationFinishResponse> {
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
@@ -46,10 +43,10 @@ export class DefaultOpaqueApiService implements OpaqueApiService {
|
||||
return new RegistrationFinishResponse(response);
|
||||
}
|
||||
|
||||
LoginStart(): any {
|
||||
loginStart(): any {
|
||||
throw new Error("Method not implemented");
|
||||
}
|
||||
LoginFinish(): any {
|
||||
loginFinish(): any {
|
||||
throw new Error("Method not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,72 +4,63 @@ import { RotateableKeySet } from "@bitwarden/auth/common";
|
||||
import { SdkService } from "@bitwarden/common/platform/abstractions/sdk/sdk.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||
import { Argon2KdfConfig } from "@bitwarden/key-management";
|
||||
import { Argon2Id, KeGroup, KeyExchange, OprfCS } from "@bitwarden/sdk-internal";
|
||||
|
||||
import { UserKey } from "../../types/key";
|
||||
|
||||
import { CipherConfiguration } from "./models/cipher-configuration";
|
||||
import { CipherConfiguration, KsfConfig } from "./models/cipher-configuration";
|
||||
import { RegistrationFinishRequest } from "./models/registration-finish.request";
|
||||
import { RegistrationStartRequest } from "./models/registration-start.request";
|
||||
import { OpaqueApiService } from "./opaque-api.service";
|
||||
import { OpaqueService } from "./opaque.service";
|
||||
|
||||
// static argon2 config for now
|
||||
const cipherConfiguration = {
|
||||
oprf: "ristretto255" as OprfCS,
|
||||
ke_group: "ristretto255" as KeGroup,
|
||||
key_exchange: "triple-dh" as KeyExchange,
|
||||
ksf: {
|
||||
t_cost: 3,
|
||||
m_cost: 256 * 1024,
|
||||
p_cost: 4,
|
||||
} as Argon2Id,
|
||||
};
|
||||
const kdfConfig = new Argon2KdfConfig(3, 256, 4);
|
||||
|
||||
export class DefaultOpaqueService implements OpaqueService {
|
||||
constructor(
|
||||
private opaqueApiService: OpaqueApiService,
|
||||
private sdkService: SdkService,
|
||||
) {}
|
||||
|
||||
async Register(masterPassword: string, userKey: UserKey) {
|
||||
async register(masterPassword: string, userKey: UserKey, ksfConfig: KsfConfig): Promise<void> {
|
||||
const config = new CipherConfiguration(ksfConfig);
|
||||
const cryptoClient = (await firstValueFrom(this.sdkService.client$)).crypto();
|
||||
|
||||
const registrationStart = cryptoClient.opaque_register_start(
|
||||
Utils.fromUtf8ToArray(masterPassword),
|
||||
masterPassword,
|
||||
config.toSdkConfig(),
|
||||
);
|
||||
const registrationStartResponse = await this.opaqueApiService.RegistrationStart(
|
||||
const registrationStartResponse = await this.opaqueApiService.registrationStart(
|
||||
new RegistrationStartRequest(
|
||||
Utils.fromBufferToB64(new Uint8Array(registrationStart.registration_start_message)),
|
||||
new CipherConfiguration(kdfConfig),
|
||||
Utils.fromBufferToB64(registrationStart.registration_request),
|
||||
config,
|
||||
),
|
||||
);
|
||||
|
||||
const registrationFinish = cryptoClient.opaque_register_finish(
|
||||
new Uint8Array(registrationStart.registration_start_state),
|
||||
Utils.fromB64ToArray(registrationStartResponse.serverRegistrationStartResult),
|
||||
Utils.fromUtf8ToArray(masterPassword),
|
||||
cipherConfiguration,
|
||||
masterPassword,
|
||||
config.toSdkConfig(),
|
||||
registrationStart.state,
|
||||
Utils.fromB64ToArray(registrationStartResponse.registrationResponse),
|
||||
);
|
||||
|
||||
const sdkKeyset = cryptoClient.create_rotateablekeyset_from_exportkey(
|
||||
registrationFinish.export_key,
|
||||
userKey.key,
|
||||
);
|
||||
const keyset = new RotateableKeySet(
|
||||
new EncString(registrationFinish.keyset.encapsulated_key),
|
||||
new EncString(registrationFinish.keyset.public_key),
|
||||
new EncString(registrationFinish.keyset.private_key),
|
||||
new EncString(sdkKeyset.encapsulated_key),
|
||||
new EncString(sdkKeyset.public_key),
|
||||
new EncString(sdkKeyset.private_key),
|
||||
);
|
||||
|
||||
await this.opaqueApiService.RegistrationFinish(
|
||||
registrationStartResponse.sessionId,
|
||||
await this.opaqueApiService.registrationFinish(
|
||||
new RegistrationFinishRequest(
|
||||
Utils.fromBufferToB64(new Uint8Array(registrationFinish.registration_finish_message)),
|
||||
registrationStartResponse.sessionId,
|
||||
Utils.fromBufferToB64(registrationFinish.registration_upload),
|
||||
keyset,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
async Login(masterPassword: string): Promise<UserKey> {
|
||||
async login(masterPassword: string, ksfConfig: KsfConfig): Promise<Uint8Array> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,59 @@
|
||||
import { KdfConfig } from "../../../../../key-management/src";
|
||||
import { CipherConfiguration as CipherConfigurationSdk } from "@bitwarden/sdk-internal";
|
||||
|
||||
export type OpaqueKeVersion = 3;
|
||||
|
||||
export class CipherConfiguration {
|
||||
opaqueVersion = 1; // TODO: what's the current version?
|
||||
kdf: KdfConfig;
|
||||
oprf = "ristretto-255";
|
||||
ke = "ristretto-255";
|
||||
keyExchange = "triple-diffie-helmen";
|
||||
opaqueVersion: OpaqueKeVersion;
|
||||
|
||||
constructor(kdf: KdfConfig) {
|
||||
this.kdf = kdf;
|
||||
oprfCs: OprfCs;
|
||||
keGroup: KeGroup;
|
||||
keyExchange: KeyExchange;
|
||||
ksf: KsfConfig;
|
||||
|
||||
constructor(ksf: KsfConfig) {
|
||||
this.opaqueVersion = 3;
|
||||
this.oprfCs = "ristretto255";
|
||||
this.keGroup = "ristretto255";
|
||||
this.keyExchange = "triple-dh";
|
||||
this.ksf = ksf;
|
||||
}
|
||||
|
||||
toSdkConfig(): CipherConfigurationSdk {
|
||||
if (this.ksf.algorithm !== "argon2id") {
|
||||
throw new Error("Unsupported KSF algorithm");
|
||||
} else {
|
||||
return {
|
||||
oprf_cs: this.oprfCs,
|
||||
ke_group: this.keGroup,
|
||||
key_exchange: this.keyExchange,
|
||||
ksf: {
|
||||
argon2id: [
|
||||
this.ksf.parameters.memory,
|
||||
this.ksf.parameters.iterations,
|
||||
this.ksf.parameters.parallelism,
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type OprfCs = "ristretto255";
|
||||
export type KeGroup = "ristretto255";
|
||||
export type KeyExchange = "triple-dh";
|
||||
|
||||
export type Argon2IdParameters = {
|
||||
// Memory in KiB
|
||||
memory: number;
|
||||
iterations: number;
|
||||
parallelism: number;
|
||||
};
|
||||
|
||||
export type KsfParameters = Argon2IdParameters;
|
||||
|
||||
type KsfAlgorithm = "argon2id";
|
||||
|
||||
export type KsfConfig = {
|
||||
algorithm: KsfAlgorithm;
|
||||
parameters: KsfParameters;
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import { OpaqueSessionId } from "@bitwarden/common/types/guid";
|
||||
|
||||
export class LoginFinishRequest {
|
||||
constructor(
|
||||
readonly loginSessionId: OpaqueSessionId,
|
||||
readonly clientLoginFinishResult: string,
|
||||
readonly sessionId: OpaqueSessionId,
|
||||
readonly credentialFinalization: string,
|
||||
) {}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export class LoginStartRequest {
|
||||
constructor(
|
||||
readonly email: string,
|
||||
readonly clientLoginStartRequest: string,
|
||||
readonly credentialRequest: string,
|
||||
) {}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { BaseResponse } from "../../../models/response/base.response";
|
||||
|
||||
export class LoginStartResponse extends BaseResponse {
|
||||
loginSessionId: string;
|
||||
serverLoginStartResult: string;
|
||||
sessionId: string;
|
||||
credentialResponse: string;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
this.loginSessionId = this.getResponseProperty("LoginSessionId");
|
||||
this.serverLoginStartResult = this.getResponseProperty("ServerRegistrationStartResult");
|
||||
this.sessionId = this.getResponseProperty("SessionId");
|
||||
this.credentialResponse = this.getResponseProperty("CredentialResponse");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { RotateableKeySet } from "@bitwarden/auth/common";
|
||||
import { OpaqueSessionId } from "@bitwarden/common/types/guid";
|
||||
|
||||
export class RegistrationFinishRequest {
|
||||
constructor(
|
||||
readonly clientRegistrationFinishResult: string,
|
||||
readonly sessionId: OpaqueSessionId,
|
||||
readonly registrationUpload: string,
|
||||
readonly keySet: RotateableKeySet,
|
||||
) {}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { CipherConfiguration } from "./cipher-configuration";
|
||||
|
||||
export class RegistrationStartRequest {
|
||||
constructor(
|
||||
readonly clientRegistrationStartResult: string,
|
||||
readonly registrationRequest: string,
|
||||
readonly cipherConfiguration: CipherConfiguration,
|
||||
) {}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@ import { OpaqueSessionId } from "../../../types/guid";
|
||||
|
||||
export class RegistrationStartResponse extends BaseResponse {
|
||||
sessionId: OpaqueSessionId;
|
||||
serverRegistrationStartResult: string;
|
||||
registrationResponse: string;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
|
||||
this.sessionId = this.getResponseProperty("SessionId");
|
||||
this.serverRegistrationStartResult = this.getResponseProperty("ServerRegistrationStartResult");
|
||||
this.registrationResponse = this.getResponseProperty("RegistrationResponse");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
import { OpaqueSessionId } from "../../types/guid";
|
||||
|
||||
import { RegistrationFinishRequest } from "./models/registration-finish.request";
|
||||
import { RegistrationFinishResponse } from "./models/registration-finish.response";
|
||||
import { RegistrationStartRequest } from "./models/registration-start.request";
|
||||
import { RegistrationStartResponse } from "./models/registration-start.response";
|
||||
|
||||
export abstract class OpaqueApiService {
|
||||
abstract RegistrationStart(request: RegistrationStartRequest): Promise<RegistrationStartResponse>;
|
||||
abstract RegistrationFinish(
|
||||
sessionId: OpaqueSessionId,
|
||||
abstract registrationStart(request: RegistrationStartRequest): Promise<RegistrationStartResponse>;
|
||||
abstract registrationFinish(
|
||||
request: RegistrationFinishRequest,
|
||||
): Promise<RegistrationFinishResponse>;
|
||||
abstract LoginStart(): any;
|
||||
abstract LoginFinish(): any;
|
||||
abstract loginStart(): any;
|
||||
abstract loginFinish(): any;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
import { UserKey } from "../../types/key";
|
||||
|
||||
import { KsfConfig } from "./models/cipher-configuration";
|
||||
|
||||
export abstract class OpaqueService {
|
||||
/**
|
||||
* Register a user to use the Opaque login method.
|
||||
*/
|
||||
abstract Register(masterPassword: string, userKey: UserKey): Promise<void>;
|
||||
abstract register(masterPassword: string, userKey: UserKey, ksfConfig: KsfConfig): Promise<void>;
|
||||
|
||||
/**
|
||||
* Authenticate using the Opaque login method.
|
||||
* @returns The UserKey obtained during the Opaque login flow.
|
||||
* Authenticate using the Opaque login method. Returns the export key, which must be used
|
||||
* in combination with the rotateable keyset returned from the token endpoint.
|
||||
* @returns The ExportKey obtained during the Opaque login flow.
|
||||
*/
|
||||
abstract Login(masterPassword: string): Promise<UserKey>;
|
||||
abstract login(masterPassword: string, ksfConfig: KsfConfig): Promise<Uint8Array>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user