From 71b4c0f2cffc85e7dcdcd31fa3d70b4aaf32a681 Mon Sep 17 00:00:00 2001 From: Maycon Date: Thu, 12 Feb 2026 10:44:13 -0300 Subject: [PATCH 1/2] Move crypto functions from cloud-wallet core to edv service --- package-lock.json | 4 +- packages/core/src/cloud-wallet.ts | 60 +----- packages/react-native/bundler/index.js | 5 +- packages/wasm/package.json | 31 +-- packages/wasm/src/services/edv/index.test.js | 176 ++++++++++++++++++ packages/wasm/src/services/edv/service-rpc.js | 16 ++ packages/wasm/src/services/edv/service.ts | 119 ++++++++++++ 7 files changed, 337 insertions(+), 74 deletions(-) diff --git a/package-lock.json b/package-lock.json index e562911c..80867ae7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18477,7 +18477,6 @@ "version": "1.5.3", "resolved": "https://registry.npmjs.org/futoin-hkdf/-/futoin-hkdf-1.5.3.tgz", "integrity": "sha512-SewY5KdMpaoCeh7jachEWFsh1nNlaDjNHZXWqL5IGwtpEYHTgkr2+AMCgNwKWkcc0wpSYrZfR7he4WdmHFtDxQ==", - "license": "Apache-2.0", "engines": { "node": ">=8" } @@ -37552,6 +37551,7 @@ "axios-retry": "^3.2.5", "base64url": "^3.0.1", "cwait": "1.1.2", + "futoin-hkdf": "^1.5.3", "json-rpc-2.0": "^0.2.16", "jsonld": "^6.0.0", "p-limit": "2.3.0", @@ -37601,7 +37601,7 @@ }, "packages/web": { "name": "@docknetwork/wallet-sdk-web", - "version": "0.0.8", + "version": "0.0.10", "license": "https://github.com/docknetwork/wallet-sdk/LICENSE", "devDependencies": { "@docknetwork/wallet-sdk-core": "^1.7.0", diff --git a/packages/core/src/cloud-wallet.ts b/packages/core/src/cloud-wallet.ts index a83d60af..1ba117ec 100644 --- a/packages/core/src/cloud-wallet.ts +++ b/packages/core/src/cloud-wallet.ts @@ -10,15 +10,11 @@ import { } from '@docknetwork/wallet-sdk-data-store/src/types'; import { logger } from '@docknetwork/wallet-sdk-data-store/src/logger'; import { edvService, EDVService } from '@docknetwork/wallet-sdk-wasm/src/services/edv/service'; -import hkdf from 'futoin-hkdf'; -import crypto from '@docknetwork/universal-wallet/crypto'; import { utilCryptoService } from '@docknetwork/wallet-sdk-wasm/src/services/util-crypto'; export const SYNC_MARKER_TYPE = 'SyncMarkerDocument'; export const MNEMONIC_WORD_COUNT = 12; export const KEY_MAPPING_TYPE = 'KeyMappingDocument'; -export const HKDF_LENGTH = 32; -export const HKDF_HASH = 'SHA-256'; const MASTER_KEY_SUFFIX = 'master-key'; /** @@ -31,9 +27,7 @@ export function deriveBiometricKey( biometricData: Buffer, identifier: string, ): Buffer { - const salt = identifier; - - return hkdf(biometricData, HKDF_LENGTH, { salt, hash: HKDF_HASH }); + return edvService.deriveBiometricKey(biometricData, identifier); } /** @@ -61,15 +55,7 @@ export async function deriveBiometricEncryptionKey( biometricData: Buffer, identifier: string ): Promise<{ key: Buffer; iv: Buffer }> { - const key = deriveBiometricKey(biometricData, identifier); - - const randomBytes = crypto.getRandomValues(new Uint8Array(16)); - const iv = Buffer.from(randomBytes); - - return { - key, - iv - }; + return edvService.deriveBiometricEncryptionKey(biometricData, identifier); } /** @@ -84,24 +70,7 @@ export async function encryptMasterKey( encryptionKey: Buffer, iv: Buffer ): Promise { - const keyData = new Uint8Array(encryptionKey); - const ivData = new Uint8Array(iv); - - const key = await crypto.subtle.importKey( - 'raw', - keyData, - { name: 'AES-GCM' }, - false, - ['encrypt'] - ); - - const encryptedBuffer = await crypto.subtle.encrypt( - { name: 'AES-GCM', iv: ivData }, - key, - masterKey - ); - - return new Uint8Array(encryptedBuffer); + return edvService.encryptMasterKey(masterKey, encryptionKey, iv); } /** @@ -116,28 +85,7 @@ export async function decryptMasterKey( decryptionKey: Buffer, iv: Buffer ): Promise { - try { - const keyData = new Uint8Array(decryptionKey); - const ivData = new Uint8Array(iv); - - const key = await crypto.subtle.importKey( - 'raw', - keyData, - { name: 'AES-GCM' }, - false, - ['decrypt'] - ); - - const decryptedBuffer = await crypto.subtle.decrypt( - { name: 'AES-GCM', iv: ivData }, - key, - encryptedKey - ); - - return new Uint8Array(decryptedBuffer); - } catch (error) { - throw new Error('Decryption failed: Invalid key or corrupted data'); - } + return edvService.decryptMasterKey(encryptedKey, decryptionKey, iv); } /** diff --git a/packages/react-native/bundler/index.js b/packages/react-native/bundler/index.js index a9cf16c9..aa4e30fd 100644 --- a/packages/react-native/bundler/index.js +++ b/packages/react-native/bundler/index.js @@ -10,6 +10,9 @@ const getWebpackConfig = ({entry, path, filename}) => ({ }, resolve: { extensions: ['.tsx', '.ts', '.js', '.json', '.mjs', '.cjs'], + alias: { + '@cheqd/ts-proto': '@cheqd/ts-proto-cjs', + }, fallback: { crypto: require.resolve('crypto-browserify'), stream: require.resolve('stream-browserify'), @@ -28,7 +31,7 @@ const getWebpackConfig = ({entry, path, filename}) => ({ rules: [ { test: /\.(m|c)?(j|t)s$/, - exclude: [/\/node_modules\/(?!@docknetwork|@digitalbazaar|@cheqd)/], + exclude: [/\/node_modules\/(?!@docknetwork|@digitalbazaar|@cheqd\/ts-proto)/], use: { loader: require.resolve('babel-loader'), options: { diff --git a/packages/wasm/package.json b/packages/wasm/package.json index bbfd0084..70e6e24e 100644 --- a/packages/wasm/package.json +++ b/packages/wasm/package.json @@ -18,36 +18,37 @@ "p-limit": "2.3.0" }, "dependencies": { - "p-limit": "2.3.0", "@astronautlabs/jsonpath": "^1.1.2", - "@docknetwork/universal-wallet": "^2.0.1", - "@docknetwork/wallet-sdk-dids": "^1.7.0", "@cedar-policy/cedar-wasm": "^4.5.0", - "jsonld": "^6.0.0", - "@docknetwork/vc-delegation-engine": "1.0.3", "@cosmjs/proto-signing": "^0.32.4", "@docknetwork/cheqd-blockchain-api": "4.1.1", "@docknetwork/cheqd-blockchain-modules": "4.0.8", - "@scure/bip39": "^1.6.0", - "@noble/hashes": "1.8.0", "@docknetwork/credential-sdk": "0.54.16", - "@sphereon/oid4vci-client": "^0.16.0", - "@sphereon/oid4vci-common": "^0.16.0", + "@docknetwork/universal-wallet": "^2.0.1", + "@docknetwork/vc-delegation-engine": "1.0.3", + "@docknetwork/wallet-sdk-dids": "^1.7.0", + "@noble/hashes": "1.8.0", + "@scure/bip39": "^1.6.0", "@sd-jwt/crypto-nodejs": "^0.15.0", "@sd-jwt/sd-jwt-vc": "^0.15.1", - "base64url": "^3.0.1", + "@sphereon/oid4vci-client": "^0.16.0", + "@sphereon/oid4vci-common": "^0.16.0", + "@sphereon/pex": "^1.1.4", "axios": "^0.25.0", + "axios-retry": "^3.2.5", + "base64url": "^3.0.1", + "cwait": "1.1.2", + "futoin-hkdf": "^1.5.3", "json-rpc-2.0": "^0.2.16", + "jsonld": "^6.0.0", + "p-limit": "2.3.0", "uuid": "^8.3.2", - "winston": "^3.3.3", - "cwait": "1.1.2", - "axios-retry": "^3.2.5", - "@sphereon/pex": "^1.1.4" + "winston": "^3.3.3" }, "devDependencies": { "@babel/node": "^7.16.0", - "sinon": "^12.0.1", "jest": "29.6.1", + "sinon": "^12.0.1", "ts-jest": "29.1.0", "typescript": "^5.0.4" } diff --git a/packages/wasm/src/services/edv/index.test.js b/packages/wasm/src/services/edv/index.test.js index 1d1683b4..bbb017da 100644 --- a/packages/wasm/src/services/edv/index.test.js +++ b/packages/wasm/src/services/edv/index.test.js @@ -47,5 +47,181 @@ describe('EDVService', () => { expect(JSON.stringify(agreementKey)).toBe(derivedTestAgreementKey); }); }); + + describe('deriveBiometricKey', () => { + it('should derive a key from biometric data', () => { + const biometricData = Buffer.from('mock-biometric-data'); + const identifier = 'user@example.com'; + + const key = service.deriveBiometricKey(biometricData, identifier); + + expect(key).toBeDefined(); + expect(Buffer.isBuffer(key)).toBe(true); + expect(key.length).toBe(32); // HKDF_LENGTH + }); + + it('should produce consistent keys for same inputs', () => { + const biometricData = Buffer.from('mock-biometric-data'); + const identifier = 'user@example.com'; + + const key1 = service.deriveBiometricKey(biometricData, identifier); + const key2 = service.deriveBiometricKey(biometricData, identifier); + + expect(key1.equals(key2)).toBe(true); + }); + + it('should produce different keys for different identifiers', () => { + const biometricData = Buffer.from('mock-biometric-data'); + const identifier1 = 'user1@example.com'; + const identifier2 = 'user2@example.com'; + + const key1 = service.deriveBiometricKey(biometricData, identifier1); + const key2 = service.deriveBiometricKey(biometricData, identifier2); + + expect(key1.equals(key2)).toBe(false); + }); + + it('should produce different keys for different biometric data', () => { + const biometricData1 = Buffer.from('mock-biometric-data-1'); + const biometricData2 = Buffer.from('mock-biometric-data-2'); + const identifier = 'user@example.com'; + + const key1 = service.deriveBiometricKey(biometricData1, identifier); + const key2 = service.deriveBiometricKey(biometricData2, identifier); + + expect(key1.equals(key2)).toBe(false); + }); + }); + + describe('deriveBiometricEncryptionKey', () => { + it('should derive encryption key and IV', async () => { + const biometricData = Buffer.from('mock-biometric-data'); + const identifier = 'user@example.com'; + + const result = await service.deriveBiometricEncryptionKey(biometricData, identifier); + + expect(result).toBeDefined(); + expect(result.key).toBeDefined(); + expect(result.iv).toBeDefined(); + expect(Buffer.isBuffer(result.key)).toBe(true); + expect(Buffer.isBuffer(result.iv)).toBe(true); + expect(result.key.length).toBe(32); // HKDF_LENGTH + expect(result.iv.length).toBe(16); // AES-GCM IV length + }); + + it('should produce consistent keys but different IVs for same inputs', async () => { + const biometricData = Buffer.from('mock-biometric-data'); + const identifier = 'user@example.com'; + + const result1 = await service.deriveBiometricEncryptionKey(biometricData, identifier); + const result2 = await service.deriveBiometricEncryptionKey(biometricData, identifier); + + expect(result1.key.equals(result2.key)).toBe(true); + // IVs should be different (random) + expect(result1.iv.equals(result2.iv)).toBe(false); + }); + }); + + describe('encryptMasterKey and decryptMasterKey', () => { + it('should encrypt and decrypt master key successfully', async () => { + const masterKey = new Uint8Array(32).fill(42); + const encryptionKey = Buffer.from(new Uint8Array(32).fill(1)); + const iv = Buffer.from(new Uint8Array(16).fill(2)); + + const encrypted = await service.encryptMasterKey(masterKey, encryptionKey, iv); + expect(encrypted).toBeDefined(); + expect(encrypted instanceof Uint8Array).toBe(true); + expect(encrypted.length).toBeGreaterThan(0); + + const decrypted = await service.decryptMasterKey(encrypted, encryptionKey, iv); + expect(decrypted).toBeDefined(); + expect(decrypted instanceof Uint8Array).toBe(true); + expect(new Uint8Array(decrypted)).toEqual(masterKey); + }); + + it('should fail to decrypt with wrong key', async () => { + const masterKey = new Uint8Array(32).fill(42); + const encryptionKey = Buffer.from(new Uint8Array(32).fill(1)); + const wrongKey = Buffer.from(new Uint8Array(32).fill(99)); + const iv = Buffer.from(new Uint8Array(16).fill(2)); + + const encrypted = await service.encryptMasterKey(masterKey, encryptionKey, iv); + + await expect(service.decryptMasterKey(encrypted, wrongKey, iv)) + .rejects.toThrow('Decryption failed: Invalid key or corrupted data'); + }); + + it('should fail to decrypt with wrong IV', async () => { + const masterKey = new Uint8Array(32).fill(42); + const encryptionKey = Buffer.from(new Uint8Array(32).fill(1)); + const iv = Buffer.from(new Uint8Array(16).fill(2)); + const wrongIv = Buffer.from(new Uint8Array(16).fill(99)); + + const encrypted = await service.encryptMasterKey(masterKey, encryptionKey, iv); + + await expect(service.decryptMasterKey(encrypted, encryptionKey, wrongIv)) + .rejects.toThrow('Decryption failed: Invalid key or corrupted data'); + }); + + it('should produce different ciphertext for same plaintext with different IVs', async () => { + const masterKey = new Uint8Array(32).fill(42); + const encryptionKey = Buffer.from(new Uint8Array(32).fill(1)); + const iv1 = Buffer.from(new Uint8Array(16).fill(2)); + const iv2 = Buffer.from(new Uint8Array(16).fill(3)); + + const encrypted1 = await service.encryptMasterKey(masterKey, encryptionKey, iv1); + const encrypted2 = await service.encryptMasterKey(masterKey, encryptionKey, iv2); + + expect(encrypted1).not.toEqual(encrypted2); + }); + + it('should handle empty master key', async () => { + const masterKey = new Uint8Array(0); + const encryptionKey = Buffer.from(new Uint8Array(32).fill(1)); + const iv = Buffer.from(new Uint8Array(16).fill(2)); + + const encrypted = await service.encryptMasterKey(masterKey, encryptionKey, iv); + const decrypted = await service.decryptMasterKey(encrypted, encryptionKey, iv); + + expect(new Uint8Array(decrypted)).toEqual(masterKey); + }); + }); + + describe('integration: biometric encryption workflow', () => { + it('should complete full encryption workflow', async () => { + const biometricData = Buffer.from('mock-biometric-data'); + const identifier = 'user@example.com'; + const masterKey = new Uint8Array(32).fill(123); + + // Derive encryption key and IV from biometric data + const { key, iv } = await service.deriveBiometricEncryptionKey(biometricData, identifier); + + // Encrypt master key + const encrypted = await service.encryptMasterKey(masterKey, key, iv); + + // Decrypt master key + const decrypted = await service.decryptMasterKey(encrypted, key, iv); + + // Verify decrypted matches original + expect(new Uint8Array(decrypted)).toEqual(masterKey); + }); + + it('should fail workflow with different biometric data', async () => { + const biometricData1 = Buffer.from('mock-biometric-data-1'); + const biometricData2 = Buffer.from('mock-biometric-data-2'); + const identifier = 'user@example.com'; + const masterKey = new Uint8Array(32).fill(123); + + // Encrypt with first biometric data + const { key: key1, iv } = await service.deriveBiometricEncryptionKey(biometricData1, identifier); + const encrypted = await service.encryptMasterKey(masterKey, key1, iv); + + // Try to decrypt with second biometric data (should fail) + const { key: key2 } = await service.deriveBiometricEncryptionKey(biometricData2, identifier); + + await expect(service.decryptMasterKey(encrypted, key2, iv)) + .rejects.toThrow('Decryption failed: Invalid key or corrupted data'); + }); + }); }); }); diff --git a/packages/wasm/src/services/edv/service-rpc.js b/packages/wasm/src/services/edv/service-rpc.js index 7d42f4f6..8672b624 100644 --- a/packages/wasm/src/services/edv/service-rpc.js +++ b/packages/wasm/src/services/edv/service-rpc.js @@ -38,4 +38,20 @@ export class EDVServiceRpc extends RpcService { delete(params: any) { return this.call('delete', params); } + + deriveBiometricKey(biometricData: Buffer, identifier: string) { + return this.call('deriveBiometricKey', { biometricData, identifier }); + } + + deriveBiometricEncryptionKey(biometricData: Buffer, identifier: string) { + return this.call('deriveBiometricEncryptionKey', { biometricData, identifier }); + } + + encryptMasterKey(masterKey: Uint8Array, encryptionKey: Buffer, iv: Buffer) { + return this.call('encryptMasterKey', { masterKey, encryptionKey, iv }); + } + + decryptMasterKey(encryptedKey: Uint8Array, decryptionKey: Buffer, iv: Buffer) { + return this.call('decryptMasterKey', { encryptedKey, decryptionKey, iv }); + } } diff --git a/packages/wasm/src/services/edv/service.ts b/packages/wasm/src/services/edv/service.ts index 65e55d5a..15523e77 100644 --- a/packages/wasm/src/services/edv/service.ts +++ b/packages/wasm/src/services/edv/service.ts @@ -17,6 +17,11 @@ import {getKeypairFromDoc} from '@docknetwork/universal-wallet/methods/keypairs' import {logger} from '@docknetwork/wallet-sdk-data-store/src/logger'; import {didService} from '@docknetwork/wallet-sdk-wasm/src/services/dids/service'; import {Ed25519Keypair} from '@docknetwork/credential-sdk/keypairs'; +import hkdf from 'futoin-hkdf'; +import crypto from '@docknetwork/universal-wallet/crypto'; + +export const HKDF_LENGTH = 32; +export const HKDF_HASH = 'SHA-256'; /** * Service class for managing Encrypted Data Vaults @@ -39,6 +44,10 @@ export class EDVService { EDVService.prototype.update, EDVService.prototype.insert, EDVService.prototype.delete, + EDVService.prototype.deriveBiometricKey, + EDVService.prototype.deriveBiometricEncryptionKey, + EDVService.prototype.encryptMasterKey, + EDVService.prototype.decryptMasterKey, ]; /** @@ -269,6 +278,116 @@ export class EDVService { delete(params: any) { return this.storageInterface.delete(params); } + + /** + * Derives a key from biometric data using HKDF + * @param {Buffer} biometricData - Biometric data from provider + * @param {string} identifier - User's identifier as salt (email, phone number, etc.) + * @returns {Buffer} Derived key + * @example + * const key = edvService.deriveBiometricKey(biometricData, 'user@example.com'); + */ + deriveBiometricKey(biometricData: Buffer, identifier: string): Buffer { + const salt = identifier; + return hkdf(biometricData, HKDF_LENGTH, { salt, hash: HKDF_HASH }); + } + + /** + * Generates a key for encrypting/decrypting the master key + * @param {Buffer} biometricData - Biometric data from provider + * @param {string} identifier - User's identifier as salt (email, phone number, etc.) + * @returns {Promise} Encryption key and IV for AES encryption + * @returns {Buffer} returns.key - Encryption key + * @returns {Buffer} returns.iv - Initialization vector + * @example + * const { key, iv } = await edvService.deriveBiometricEncryptionKey(biometricData, 'user@example.com'); + */ + async deriveBiometricEncryptionKey( + biometricData: Buffer, + identifier: string + ): Promise<{ key: Buffer; iv: Buffer }> { + const key = this.deriveBiometricKey(biometricData, identifier); + const randomBytes = crypto.getRandomValues(new Uint8Array(16)); + const iv = Buffer.from(randomBytes); + + return { + key, + iv + }; + } + + /** + * Encrypts the master key using a key derived from biometric data + * @param {Uint8Array} masterKey - The CloudWalletVault master key to encrypt + * @param {Buffer} encryptionKey - Key derived from biometric data + * @param {Buffer} iv - Initialization vector + * @returns {Promise} Encrypted master key + * @example + * const encrypted = await edvService.encryptMasterKey(masterKey, encryptionKey, iv); + */ + async encryptMasterKey( + masterKey: Uint8Array, + encryptionKey: Buffer, + iv: Buffer + ): Promise { + const keyData = new Uint8Array(encryptionKey); + const ivData = new Uint8Array(iv); + + const key = await crypto.subtle.importKey( + 'raw', + keyData, + { name: 'AES-GCM' }, + false, + ['encrypt'] + ); + + const encryptedBuffer = await crypto.subtle.encrypt( + { name: 'AES-GCM', iv: ivData }, + key, + masterKey + ); + + return new Uint8Array(encryptedBuffer); + } + + /** + * Decrypts the master key using biometric-derived key + * @param {Uint8Array} encryptedKey - The encrypted master key + * @param {Buffer} decryptionKey - Key derived from biometric data + * @param {Buffer} iv - Initialization vector + * @returns {Promise} The decrypted master key + * @throws {Error} If decryption fails + * @example + * const masterKey = await edvService.decryptMasterKey(encryptedKey, decryptionKey, iv); + */ + async decryptMasterKey( + encryptedKey: Uint8Array, + decryptionKey: Buffer, + iv: Buffer + ): Promise { + try { + const keyData = new Uint8Array(decryptionKey); + const ivData = new Uint8Array(iv); + + const key = await crypto.subtle.importKey( + 'raw', + keyData, + { name: 'AES-GCM' }, + false, + ['decrypt'] + ); + + const decryptedBuffer = await crypto.subtle.decrypt( + { name: 'AES-GCM', iv: ivData }, + key, + encryptedKey + ); + + return new Uint8Array(decryptedBuffer); + } catch (error) { + throw new Error('Decryption failed: Invalid key or corrupted data'); + } + } } /** From 2b2c2d07df766b63ee4962a4752c3ac5e840459f Mon Sep 17 00:00:00 2001 From: Maycon Date: Thu, 12 Feb 2026 11:05:55 -0300 Subject: [PATCH 2/2] fixing lint issues --- packages/react-native/bundler/index.js | 4 +- packages/wasm/src/services/edv/index.test.js | 93 +++++++++++++++---- packages/wasm/src/services/edv/service-rpc.js | 17 +++- 3 files changed, 88 insertions(+), 26 deletions(-) diff --git a/packages/react-native/bundler/index.js b/packages/react-native/bundler/index.js index aa4e30fd..115c07bd 100644 --- a/packages/react-native/bundler/index.js +++ b/packages/react-native/bundler/index.js @@ -31,7 +31,9 @@ const getWebpackConfig = ({entry, path, filename}) => ({ rules: [ { test: /\.(m|c)?(j|t)s$/, - exclude: [/\/node_modules\/(?!@docknetwork|@digitalbazaar|@cheqd\/ts-proto)/], + exclude: [ + /\/node_modules\/(?!@docknetwork|@digitalbazaar|@cheqd\/ts-proto)/, + ], use: { loader: require.resolve('babel-loader'), options: { diff --git a/packages/wasm/src/services/edv/index.test.js b/packages/wasm/src/services/edv/index.test.js index bbb017da..c8fe3ec8 100644 --- a/packages/wasm/src/services/edv/index.test.js +++ b/packages/wasm/src/services/edv/index.test.js @@ -98,7 +98,10 @@ describe('EDVService', () => { const biometricData = Buffer.from('mock-biometric-data'); const identifier = 'user@example.com'; - const result = await service.deriveBiometricEncryptionKey(biometricData, identifier); + const result = await service.deriveBiometricEncryptionKey( + biometricData, + identifier, + ); expect(result).toBeDefined(); expect(result.key).toBeDefined(); @@ -113,8 +116,14 @@ describe('EDVService', () => { const biometricData = Buffer.from('mock-biometric-data'); const identifier = 'user@example.com'; - const result1 = await service.deriveBiometricEncryptionKey(biometricData, identifier); - const result2 = await service.deriveBiometricEncryptionKey(biometricData, identifier); + const result1 = await service.deriveBiometricEncryptionKey( + biometricData, + identifier, + ); + const result2 = await service.deriveBiometricEncryptionKey( + biometricData, + identifier, + ); expect(result1.key.equals(result2.key)).toBe(true); // IVs should be different (random) @@ -128,12 +137,20 @@ describe('EDVService', () => { const encryptionKey = Buffer.from(new Uint8Array(32).fill(1)); const iv = Buffer.from(new Uint8Array(16).fill(2)); - const encrypted = await service.encryptMasterKey(masterKey, encryptionKey, iv); + const encrypted = await service.encryptMasterKey( + masterKey, + encryptionKey, + iv, + ); expect(encrypted).toBeDefined(); expect(encrypted instanceof Uint8Array).toBe(true); expect(encrypted.length).toBeGreaterThan(0); - const decrypted = await service.decryptMasterKey(encrypted, encryptionKey, iv); + const decrypted = await service.decryptMasterKey( + encrypted, + encryptionKey, + iv, + ); expect(decrypted).toBeDefined(); expect(decrypted instanceof Uint8Array).toBe(true); expect(new Uint8Array(decrypted)).toEqual(masterKey); @@ -145,10 +162,15 @@ describe('EDVService', () => { const wrongKey = Buffer.from(new Uint8Array(32).fill(99)); const iv = Buffer.from(new Uint8Array(16).fill(2)); - const encrypted = await service.encryptMasterKey(masterKey, encryptionKey, iv); + const encrypted = await service.encryptMasterKey( + masterKey, + encryptionKey, + iv, + ); - await expect(service.decryptMasterKey(encrypted, wrongKey, iv)) - .rejects.toThrow('Decryption failed: Invalid key or corrupted data'); + await expect( + service.decryptMasterKey(encrypted, wrongKey, iv), + ).rejects.toThrow('Decryption failed: Invalid key or corrupted data'); }); it('should fail to decrypt with wrong IV', async () => { @@ -157,10 +179,15 @@ describe('EDVService', () => { const iv = Buffer.from(new Uint8Array(16).fill(2)); const wrongIv = Buffer.from(new Uint8Array(16).fill(99)); - const encrypted = await service.encryptMasterKey(masterKey, encryptionKey, iv); + const encrypted = await service.encryptMasterKey( + masterKey, + encryptionKey, + iv, + ); - await expect(service.decryptMasterKey(encrypted, encryptionKey, wrongIv)) - .rejects.toThrow('Decryption failed: Invalid key or corrupted data'); + await expect( + service.decryptMasterKey(encrypted, encryptionKey, wrongIv), + ).rejects.toThrow('Decryption failed: Invalid key or corrupted data'); }); it('should produce different ciphertext for same plaintext with different IVs', async () => { @@ -169,8 +196,16 @@ describe('EDVService', () => { const iv1 = Buffer.from(new Uint8Array(16).fill(2)); const iv2 = Buffer.from(new Uint8Array(16).fill(3)); - const encrypted1 = await service.encryptMasterKey(masterKey, encryptionKey, iv1); - const encrypted2 = await service.encryptMasterKey(masterKey, encryptionKey, iv2); + const encrypted1 = await service.encryptMasterKey( + masterKey, + encryptionKey, + iv1, + ); + const encrypted2 = await service.encryptMasterKey( + masterKey, + encryptionKey, + iv2, + ); expect(encrypted1).not.toEqual(encrypted2); }); @@ -180,8 +215,16 @@ describe('EDVService', () => { const encryptionKey = Buffer.from(new Uint8Array(32).fill(1)); const iv = Buffer.from(new Uint8Array(16).fill(2)); - const encrypted = await service.encryptMasterKey(masterKey, encryptionKey, iv); - const decrypted = await service.decryptMasterKey(encrypted, encryptionKey, iv); + const encrypted = await service.encryptMasterKey( + masterKey, + encryptionKey, + iv, + ); + const decrypted = await service.decryptMasterKey( + encrypted, + encryptionKey, + iv, + ); expect(new Uint8Array(decrypted)).toEqual(masterKey); }); @@ -194,7 +237,10 @@ describe('EDVService', () => { const masterKey = new Uint8Array(32).fill(123); // Derive encryption key and IV from biometric data - const { key, iv } = await service.deriveBiometricEncryptionKey(biometricData, identifier); + const {key, iv} = await service.deriveBiometricEncryptionKey( + biometricData, + identifier, + ); // Encrypt master key const encrypted = await service.encryptMasterKey(masterKey, key, iv); @@ -213,14 +259,21 @@ describe('EDVService', () => { const masterKey = new Uint8Array(32).fill(123); // Encrypt with first biometric data - const { key: key1, iv } = await service.deriveBiometricEncryptionKey(biometricData1, identifier); + const {key: key1, iv} = await service.deriveBiometricEncryptionKey( + biometricData1, + identifier, + ); const encrypted = await service.encryptMasterKey(masterKey, key1, iv); // Try to decrypt with second biometric data (should fail) - const { key: key2 } = await service.deriveBiometricEncryptionKey(biometricData2, identifier); + const {key: key2} = await service.deriveBiometricEncryptionKey( + biometricData2, + identifier, + ); - await expect(service.decryptMasterKey(encrypted, key2, iv)) - .rejects.toThrow('Decryption failed: Invalid key or corrupted data'); + await expect( + service.decryptMasterKey(encrypted, key2, iv), + ).rejects.toThrow('Decryption failed: Invalid key or corrupted data'); }); }); }); diff --git a/packages/wasm/src/services/edv/service-rpc.js b/packages/wasm/src/services/edv/service-rpc.js index 8672b624..ac6ec6a6 100644 --- a/packages/wasm/src/services/edv/service-rpc.js +++ b/packages/wasm/src/services/edv/service-rpc.js @@ -40,18 +40,25 @@ export class EDVServiceRpc extends RpcService { } deriveBiometricKey(biometricData: Buffer, identifier: string) { - return this.call('deriveBiometricKey', { biometricData, identifier }); + return this.call('deriveBiometricKey', {biometricData, identifier}); } deriveBiometricEncryptionKey(biometricData: Buffer, identifier: string) { - return this.call('deriveBiometricEncryptionKey', { biometricData, identifier }); + return this.call('deriveBiometricEncryptionKey', { + biometricData, + identifier, + }); } encryptMasterKey(masterKey: Uint8Array, encryptionKey: Buffer, iv: Buffer) { - return this.call('encryptMasterKey', { masterKey, encryptionKey, iv }); + return this.call('encryptMasterKey', {masterKey, encryptionKey, iv}); } - decryptMasterKey(encryptedKey: Uint8Array, decryptionKey: Buffer, iv: Buffer) { - return this.call('decryptMasterKey', { encryptedKey, decryptionKey, iv }); + decryptMasterKey( + encryptedKey: Uint8Array, + decryptionKey: Buffer, + iv: Buffer, + ) { + return this.call('decryptMasterKey', {encryptedKey, decryptionKey, iv}); } }