From 2b482bf3858c74b1af727a1b1cf7c4514859eaca Mon Sep 17 00:00:00 2001 From: Katherine Reynolds <7054971+reynoldskr@users.noreply.github.com> Date: Thu, 20 Nov 2025 15:54:28 -0800 Subject: [PATCH] Use new SDK interface --- .../popup/settings/noise-protocol.service.ts | 105 ++++++-------- .../src/tools/popup/settings/rust_noise.d.ts | 129 ------------------ .../popup/settings/tunnel-client.service.ts | 1 - 3 files changed, 42 insertions(+), 193 deletions(-) delete mode 100644 apps/browser/src/tools/popup/settings/rust_noise.d.ts diff --git a/apps/browser/src/tools/popup/settings/noise-protocol.service.ts b/apps/browser/src/tools/popup/settings/noise-protocol.service.ts index a723f2d3a32..f6982425390 100644 --- a/apps/browser/src/tools/popup/settings/noise-protocol.service.ts +++ b/apps/browser/src/tools/popup/settings/noise-protocol.service.ts @@ -1,63 +1,25 @@ import { Injectable } from "@angular/core"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import * as sdk from "@bitwarden/sdk-internal"; type KeyPair = { publicKey: Uint8Array; secretKey: Uint8Array }; /** - * Noise Protocol WASM adapter for browser extension - * Wraps the Rust/WASM implementation to provide secure Noise_XXpsk3_25519_AESGCM_SHA256 handshakes + * Noise Protocol service using Bitwarden SDK + * Wraps the SDK's Noise Protocol implementation to provide secure Noise_XXpsk3_25519_AESGCM_SHA256 handshakes */ @Injectable({ providedIn: "root", }) export class NoiseProtocolService { - private wasmModule: any = null; - private isInitialized = false; - constructor(private logService: LogService) {} - /** - * Initialize the WASM module - * Must be called before using any other methods - */ - async initialize(): Promise { - if (this.isInitialized) { - return; - } - - try { - // Import the WASM module - hardcoded path for demo - // The WASM file will be in the build output directory alongside other assets - const wasmModule = await import("./rust_noise.js"); - - // Initialize WASM - for --target web, the default export is the init function - if (typeof wasmModule.default === "function") { - // Pass the WASM file path explicitly to avoid import.meta.url issues in bundled code - await wasmModule.default("./rust_noise_bg.wasm"); - } else if (typeof wasmModule.init === "function") { - // Fallback for other targets - await wasmModule.init(); - } - - this.wasmModule = wasmModule; - this.isInitialized = true; - this.logService.info("[NoiseProtocol] WASM module initialized"); - } catch (error) { - this.logService.error("[NoiseProtocol] Failed to initialize WASM module:", error); - throw new Error(`Failed to initialize Noise Protocol WASM: ${error}`); - } - } - /** * Create a new Noise Protocol instance */ createProtocol(isInitiator: boolean, staticKeypair?: KeyPair, psk?: Uint8Array): NoiseProtocol { - if (!this.isInitialized || !this.wasmModule) { - throw new Error("NoiseProtocolService not initialized. Call initialize() first."); - } - - return new NoiseProtocol(this.wasmModule, isInitiator, staticKeypair, psk, this.logService); + return new NoiseProtocol(isInitiator, staticKeypair, psk, this.logService); } /** @@ -69,8 +31,6 @@ export class NoiseProtocolService { staticKeypair?: KeyPair, psk?: Uint8Array, ): Promise { - await this.initialize(); - const noise = this.createProtocol(isInitiator, staticKeypair, psk); if (isInitiator) { @@ -98,35 +58,42 @@ export class NoiseProtocolService { } /** - * Noise Protocol wrapper using Rust/WASM implementation + * Noise Protocol wrapper using Bitwarden SDK * Implements Noise_XXpsk3_25519_AESGCM_SHA256 pattern */ export class NoiseProtocol { - private wasmProtocol: any; - private isInitiator: boolean; + private handle: number; constructor( - wasmModule: any, isInitiator: boolean, staticKeypair?: KeyPair, psk?: Uint8Array, private logService?: LogService, ) { - this.isInitiator = isInitiator; - try { // Convert optional parameters const staticSecretKey = staticKeypair ? staticKeypair.secretKey : null; const pskBytes = psk ? psk : null; - // Create WASM protocol instance - this.wasmProtocol = new wasmModule.NoiseProtocol(isInitiator, staticSecretKey, pskBytes); - this.log( - `Noise XX handshake initialized (${isInitiator ? "initiator" : "responder"}, PSK: ${psk ? "yes" : "no"})`, + `Creating Noise protocol instance (${isInitiator ? "initiator" : "responder"}, ` + + `staticKey: ${staticSecretKey ? staticSecretKey.length : "none"} bytes, ` + + `PSK: ${pskBytes ? pskBytes.length : "none"} bytes)`, ); + + // Create SDK protocol instance using the built-in noise functions + this.handle = sdk.create_noise_protocol(isInitiator, staticSecretKey, pskBytes); + + if (this.handle === undefined || this.handle === null) { + throw new Error("Failed to create NoiseProtocol - SDK returned invalid handle"); + } + + this.log(`Noise XX handshake initialized successfully (handle: ${this.handle})`); } catch (error) { - this.logError("Failed to create WASM NoiseProtocol:", error); + this.logError("Failed to create SDK NoiseProtocol:", error); + if (error instanceof Error) { + this.logError("Error stack:", error.stack); + } throw error; } } @@ -137,7 +104,7 @@ export class NoiseProtocol { writeMessage(payload?: Uint8Array): Uint8Array { try { const payloadArray = payload && payload.length > 0 ? payload : null; - const message = this.wasmProtocol.writeMessage(payloadArray); + const message = sdk.noise_write_message(this.handle, payloadArray); this.log(`Sent handshake message (length: ${message.length})`); return message; @@ -152,7 +119,7 @@ export class NoiseProtocol { */ readMessage(message: Uint8Array): Uint8Array { try { - const payload = this.wasmProtocol.readMessage(message); + const payload = sdk.noise_read_message(this.handle, message); this.log( `Received handshake message (length: ${message.length}, payload: ${payload.length})`, @@ -169,7 +136,7 @@ export class NoiseProtocol { */ split(): void { try { - this.wasmProtocol.split(); + sdk.noise_split(this.handle); this.log("Handshake complete - transport keys derived"); } catch (error) { this.logError("Failed to split:", error); @@ -182,7 +149,7 @@ export class NoiseProtocol { */ encryptMessage(plaintext: Uint8Array): Uint8Array { try { - const ciphertext = this.wasmProtocol.encryptMessage(plaintext); + const ciphertext = sdk.noise_encrypt_message(this.handle, plaintext); this.log(`Message encrypted (length: ${ciphertext.length})`); return ciphertext; @@ -197,7 +164,7 @@ export class NoiseProtocol { */ decryptMessage(ciphertext: Uint8Array): Uint8Array { try { - const plaintext = this.wasmProtocol.decryptMessage(ciphertext); + const plaintext = sdk.noise_decrypt_message(this.handle, ciphertext); this.log(`Message decrypted (length: ${plaintext.length})`); return plaintext; @@ -211,15 +178,27 @@ export class NoiseProtocol { * Check if handshake is complete */ isHandshakeComplete(): boolean { - return this.wasmProtocol.isHandshakeComplete(); + return sdk.noise_is_handshake_complete(this.handle); } /** * Get static public key - * Note: WASM implementation doesn't expose this directly + * Note: SDK implementation doesn't expose this directly */ getStaticPublicKey(): Uint8Array { - throw new Error("getStaticPublicKey not yet implemented for WASM"); + throw new Error("getStaticPublicKey not yet implemented for SDK Noise"); + } + + /** + * Destroy the protocol instance and free resources + */ + destroy(): void { + try { + sdk.destroy_noise_protocol(this.handle); + this.log("Noise protocol instance destroyed"); + } catch (error) { + this.logError("Failed to destroy noise protocol:", error); + } } private log(message: string) { diff --git a/apps/browser/src/tools/popup/settings/rust_noise.d.ts b/apps/browser/src/tools/popup/settings/rust_noise.d.ts deleted file mode 100644 index 0173e4e515a..00000000000 --- a/apps/browser/src/tools/popup/settings/rust_noise.d.ts +++ /dev/null @@ -1,129 +0,0 @@ -/* tslint:disable */ - -/** - * Generate a new Curve25519 keypair - */ -export function generate_keypair(): Keypair; -/** - * Initialize the WASM module - */ -export function init(): void; -/** - * Keypair structure - */ -export class Keypair { - free(): void; - [Symbol.dispose](): void; - constructor(public_key: Uint8Array, secret_key: Uint8Array); - readonly public_key: Uint8Array; - readonly secret_key: Uint8Array; -} -/** - * Noise Protocol state machine - */ -export class NoiseProtocol { - free(): void; - [Symbol.dispose](): void; - /** - * Read a handshake message from the peer - * Returns the payload contained in the message - */ - readMessage(message: Uint8Array): Uint8Array; - /** - * Write a handshake message - * Returns the message to send to the peer - */ - writeMessage(payload?: Uint8Array | null): Uint8Array; - /** - * Decrypt a message (after handshake is complete) - */ - decryptMessage(ciphertext: Uint8Array): Uint8Array; - /** - * Encrypt a message (after handshake is complete) - */ - encryptMessage(plaintext: Uint8Array): Uint8Array; - /** - * Check if handshake is complete - */ - isHandshakeComplete(): boolean; - /** - * Get the remote static public key (available after handshake) - */ - getRemoteStaticPublicKey(): Uint8Array; - /** - * Create a new Noise protocol instance - * - * # Arguments - * * `is_initiator` - Whether this is the initiator (true) or responder (false) - * * `static_keypair` - Optional static keypair (if None, generates new one) - * * `psk` - Optional pre-shared key for additional authentication - */ - constructor( - is_initiator: boolean, - static_secret_key?: Uint8Array | null, - psk?: Uint8Array | null, - ); - /** - * Complete the handshake and derive transport keys - */ - split(): void; -} - -export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module; - -export interface InitOutput { - readonly memory: WebAssembly.Memory; - readonly __wbg_keypair_free: (a: number, b: number) => void; - readonly __wbg_noiseprotocol_free: (a: number, b: number) => void; - readonly generate_keypair: (a: number) => void; - readonly init: () => void; - readonly keypair_new: (a: number, b: number, c: number, d: number) => number; - readonly keypair_public_key: (a: number, b: number) => void; - readonly keypair_secret_key: (a: number, b: number) => void; - readonly noiseprotocol_decryptMessage: (a: number, b: number, c: number, d: number) => void; - readonly noiseprotocol_encryptMessage: (a: number, b: number, c: number, d: number) => void; - readonly noiseprotocol_getRemoteStaticPublicKey: (a: number, b: number) => void; - readonly noiseprotocol_isHandshakeComplete: (a: number) => number; - readonly noiseprotocol_new: ( - a: number, - b: number, - c: number, - d: number, - e: number, - f: number, - ) => void; - readonly noiseprotocol_readMessage: (a: number, b: number, c: number, d: number) => void; - readonly noiseprotocol_split: (a: number, b: number) => void; - readonly noiseprotocol_writeMessage: (a: number, b: number, c: number, d: number) => void; - readonly __wbindgen_export: (a: number) => void; - readonly __wbindgen_add_to_stack_pointer: (a: number) => number; - readonly __wbindgen_export2: (a: number, b: number) => number; - readonly __wbindgen_export3: (a: number, b: number, c: number) => void; - readonly __wbindgen_start: () => void; -} - -export type SyncInitInput = BufferSource | WebAssembly.Module; -/** - * Instantiates the given `module`, which can either be bytes or - * a precompiled `WebAssembly.Module`. - * - * @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated. - * - * @returns {InitOutput} - */ -export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput; - -/** - * If `module_or_path` is {RequestInfo} or {URL}, makes a request and - * for everything else, calls `WebAssembly.instantiate` directly. - * - * @param {{ module_or_path: InitInput | Promise }} module_or_path - Passing `InitInput` directly is deprecated. - * - * @returns {Promise} - */ -export default function __wbg_init( - module_or_path?: - | { module_or_path: InitInput | Promise } - | InitInput - | Promise, -): Promise; diff --git a/apps/browser/src/tools/popup/settings/tunnel-client.service.ts b/apps/browser/src/tools/popup/settings/tunnel-client.service.ts index f7c5b85f8b2..7246e025bf2 100644 --- a/apps/browser/src/tools/popup/settings/tunnel-client.service.ts +++ b/apps/browser/src/tools/popup/settings/tunnel-client.service.ts @@ -336,7 +336,6 @@ export class TunnelClientService { }); // Initialize Noise Protocol as responder - await this.noiseProtocolService.initialize(); this.noiseProtocol = this.noiseProtocolService.createProtocol( false, this.staticKeypair,