@docknetwork/wallet-sdk-wasm 1.5.14 → 1.7.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/generate-docs.js +49 -0
- package/jsdoc.conf.json +29 -6
- package/lib/index.js +9 -1
- package/lib/index.mjs +9 -1
- package/lib/modules/network-manager.js +15 -12
- package/lib/modules/network-manager.mjs +15 -12
- package/lib/rpc-server.js +11 -1
- package/lib/rpc-server.mjs +11 -1
- package/lib/services/blockchain/cached-did-resolver.js +113 -0
- package/lib/services/blockchain/cached-did-resolver.mjs +109 -0
- package/lib/services/blockchain/index.js +11 -0
- package/lib/services/blockchain/index.mjs +11 -0
- package/lib/services/blockchain/service-rpc.js +12 -0
- package/lib/services/blockchain/service-rpc.mjs +12 -0
- package/lib/services/blockchain/service.js +161 -19
- package/lib/services/blockchain/service.mjs +162 -20
- package/lib/services/credential/bbs-revocation.js +11 -0
- package/lib/services/credential/bbs-revocation.mjs +11 -0
- package/lib/services/credential/bound-check.js +1 -1
- package/lib/services/credential/bound-check.mjs +1 -1
- package/lib/services/credential/config.js +4 -1
- package/lib/services/credential/config.mjs +4 -1
- package/lib/services/credential/delegatable-credentials.js +300 -0
- package/lib/services/credential/delegatable-credentials.mjs +263 -0
- package/lib/services/credential/index.js +53 -0
- package/lib/services/credential/index.mjs +18 -0
- package/lib/services/credential/pex-helpers.js +4 -4
- package/lib/services/credential/pex-helpers.mjs +4 -4
- package/lib/services/credential/sd-jwt.js +214 -0
- package/lib/services/credential/sd-jwt.mjs +200 -0
- package/lib/services/credential/service-rpc.js +9 -0
- package/lib/services/credential/service-rpc.mjs +9 -0
- package/lib/services/credential/service.js +324 -7
- package/lib/services/credential/service.mjs +324 -7
- package/lib/services/edv/index.js +1 -0
- package/lib/services/edv/index.mjs +1 -0
- package/lib/services/edv/service-rpc.js +23 -0
- package/lib/services/edv/service-rpc.mjs +23 -0
- package/lib/services/edv/service.js +226 -2
- package/lib/services/edv/service.mjs +223 -3
- package/lib/services/index.js +14 -0
- package/lib/services/index.mjs +14 -0
- package/lib/services/pex/config.js +4 -0
- package/lib/services/pex/config.mjs +4 -0
- package/lib/services/pex/service-rpc.js +4 -0
- package/lib/services/pex/service-rpc.mjs +4 -0
- package/lib/services/pex/service.js +7 -0
- package/lib/services/pex/service.mjs +7 -0
- package/lib/services/relay-service/service.js +124 -1
- package/lib/services/relay-service/service.mjs +124 -1
- package/lib/services/rpc-service-client.js +0 -3
- package/lib/services/rpc-service-client.mjs +0 -3
- package/lib/services/storage/index.js +19 -2
- package/lib/services/storage/index.mjs +24 -1
- package/lib/services/storage/service-rpc.js +7 -3
- package/lib/services/storage/service-rpc.mjs +7 -3
- package/lib/services/storage/service.js +4 -0
- package/lib/services/storage/service.mjs +4 -0
- package/lib/setup-nodejs.js +9 -1
- package/lib/setup-nodejs.mjs +9 -1
- package/lib/setup-tests.js +9 -1
- package/lib/setup-tests.mjs +9 -1
- package/lib/src/modules/event-manager.d.ts +0 -1
- package/lib/src/modules/event-manager.d.ts.map +1 -1
- package/lib/src/modules/network-manager.d.ts +2 -4
- package/lib/src/modules/network-manager.d.ts.map +1 -1
- package/lib/src/services/blockchain/cached-did-resolver.d.ts +28 -0
- package/lib/src/services/blockchain/cached-did-resolver.d.ts.map +1 -0
- package/lib/src/services/blockchain/cached-did-resolver.test.d.ts +2 -0
- package/lib/src/services/blockchain/cached-did-resolver.test.d.ts.map +1 -0
- package/lib/src/services/blockchain/configs.d.ts +1 -2
- package/lib/src/services/blockchain/configs.d.ts.map +1 -1
- package/lib/src/services/blockchain/service.d.ts +117 -19
- package/lib/src/services/blockchain/service.d.ts.map +1 -1
- package/lib/src/services/credential/bbs-revocation.d.ts +1 -1
- package/lib/src/services/credential/bbs-revocation.d.ts.map +1 -1
- package/lib/src/services/credential/bound-check.d.ts.map +1 -1
- package/lib/src/services/credential/config.d.ts.map +1 -1
- package/lib/src/services/credential/delegatable-credentials.d.ts +272 -0
- package/lib/src/services/credential/delegatable-credentials.d.ts.map +1 -0
- package/lib/src/services/credential/index.d.ts +4 -0
- package/lib/src/services/credential/index.d.ts.map +1 -1
- package/lib/src/services/credential/pex-helpers.d.ts +2 -2
- package/lib/src/services/credential/pex-helpers.d.ts.map +1 -1
- package/lib/src/services/credential/sd-jwt.test.d.ts +2 -0
- package/lib/src/services/credential/sd-jwt.test.d.ts.map +1 -0
- package/lib/src/services/credential/service.d.ts +274 -4
- package/lib/src/services/credential/service.d.ts.map +1 -1
- package/lib/src/services/dids/keypair-utils.d.ts +2 -2
- package/lib/src/services/dids/keypair-utils.d.ts.map +1 -1
- package/lib/src/services/dids/service.d.ts +35 -3
- package/lib/src/services/dids/service.d.ts.map +1 -1
- package/lib/src/services/edv/service.d.ts +201 -2
- package/lib/src/services/edv/service.d.ts.map +1 -1
- package/lib/src/services/pex/config.d.ts +1 -0
- package/lib/src/services/pex/config.d.ts.map +1 -1
- package/lib/src/services/pex/service.d.ts +1 -0
- package/lib/src/services/pex/service.d.ts.map +1 -1
- package/lib/src/services/relay-service/service.d.ts +148 -8
- package/lib/src/services/relay-service/service.d.ts.map +1 -1
- package/lib/src/services/rpc-service-client.d.ts +2 -2
- package/lib/src/services/rpc-service-client.d.ts.map +1 -1
- package/lib/src/services/storage/index.d.ts +1 -1
- package/lib/src/services/storage/index.d.ts.map +1 -1
- package/lib/src/services/storage/service-rpc.d.ts +9 -0
- package/lib/src/services/storage/service-rpc.d.ts.map +1 -0
- package/lib/src/services/storage/service.d.ts +1 -0
- package/lib/src/services/storage/service.d.ts.map +1 -1
- package/lib/src/services/util-crypto/service.d.ts +2 -2
- package/lib/src/services/util-crypto/service.d.ts.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/wallet/rpc-storage-interface.js +13 -3
- package/lib/wallet/rpc-storage-interface.mjs +11 -1
- package/lib/wallet/rpc-storage-wallet.js +10 -0
- package/lib/wallet/rpc-storage-wallet.mjs +10 -0
- package/package.json +29 -16
- package/rollup.config.mjs +5 -3
- package/src/globals.d.ts +3 -0
- package/src/modules/network-manager.ts +15 -14
- package/src/services/blockchain/cached-did-resolver.test.ts +288 -0
- package/src/services/blockchain/cached-did-resolver.ts +126 -0
- package/src/services/blockchain/configs.ts +1 -2
- package/src/services/blockchain/service-rpc.js +12 -0
- package/src/services/blockchain/service.ts +167 -20
- package/src/services/credential/bound-check.ts +1 -1
- package/src/services/credential/config.ts +7 -1
- package/src/services/credential/delegatable-credentials.ts +409 -0
- package/src/services/credential/index.ts +16 -0
- package/src/services/credential/pex-helpers.js +4 -4
- package/src/services/credential/pex-helpers.test.js +2 -2
- package/src/services/credential/sd-jwt.test.ts +718 -0
- package/src/services/credential/sd-jwt.ts +231 -0
- package/src/services/credential/service-rpc.js +9 -0
- package/src/services/credential/service.ts +328 -7
- package/src/services/edv/index.test.js +229 -0
- package/src/services/edv/service-rpc.js +23 -0
- package/src/services/edv/service.ts +272 -1
- package/src/services/pex/config.ts +4 -0
- package/src/services/pex/service-rpc.js +4 -0
- package/src/services/pex/service.ts +13 -0
- package/src/services/pex/tests/pex-service.test.js +210 -0
- package/src/services/relay-service/service.ts +130 -1
- package/src/services/rpc-service-client.js +0 -3
- package/src/services/storage/index.js +15 -1
- package/src/services/storage/service-rpc.js +7 -3
- package/src/services/storage/service.ts +5 -0
|
@@ -47,5 +47,234 @@ describe('EDVService', () => {
|
|
|
47
47
|
expect(JSON.stringify(agreementKey)).toBe(derivedTestAgreementKey);
|
|
48
48
|
});
|
|
49
49
|
});
|
|
50
|
+
|
|
51
|
+
describe('deriveBiometricKey', () => {
|
|
52
|
+
it('should derive a key from biometric data', () => {
|
|
53
|
+
const biometricData = Buffer.from('mock-biometric-data');
|
|
54
|
+
const identifier = 'user@example.com';
|
|
55
|
+
|
|
56
|
+
const key = service.deriveBiometricKey(biometricData, identifier);
|
|
57
|
+
|
|
58
|
+
expect(key).toBeDefined();
|
|
59
|
+
expect(Buffer.isBuffer(key)).toBe(true);
|
|
60
|
+
expect(key.length).toBe(32); // HKDF_LENGTH
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should produce consistent keys for same inputs', () => {
|
|
64
|
+
const biometricData = Buffer.from('mock-biometric-data');
|
|
65
|
+
const identifier = 'user@example.com';
|
|
66
|
+
|
|
67
|
+
const key1 = service.deriveBiometricKey(biometricData, identifier);
|
|
68
|
+
const key2 = service.deriveBiometricKey(biometricData, identifier);
|
|
69
|
+
|
|
70
|
+
expect(key1.equals(key2)).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should produce different keys for different identifiers', () => {
|
|
74
|
+
const biometricData = Buffer.from('mock-biometric-data');
|
|
75
|
+
const identifier1 = 'user1@example.com';
|
|
76
|
+
const identifier2 = 'user2@example.com';
|
|
77
|
+
|
|
78
|
+
const key1 = service.deriveBiometricKey(biometricData, identifier1);
|
|
79
|
+
const key2 = service.deriveBiometricKey(biometricData, identifier2);
|
|
80
|
+
|
|
81
|
+
expect(key1.equals(key2)).toBe(false);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should produce different keys for different biometric data', () => {
|
|
85
|
+
const biometricData1 = Buffer.from('mock-biometric-data-1');
|
|
86
|
+
const biometricData2 = Buffer.from('mock-biometric-data-2');
|
|
87
|
+
const identifier = 'user@example.com';
|
|
88
|
+
|
|
89
|
+
const key1 = service.deriveBiometricKey(biometricData1, identifier);
|
|
90
|
+
const key2 = service.deriveBiometricKey(biometricData2, identifier);
|
|
91
|
+
|
|
92
|
+
expect(key1.equals(key2)).toBe(false);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe('deriveBiometricEncryptionKey', () => {
|
|
97
|
+
it('should derive encryption key and IV', async () => {
|
|
98
|
+
const biometricData = Buffer.from('mock-biometric-data');
|
|
99
|
+
const identifier = 'user@example.com';
|
|
100
|
+
|
|
101
|
+
const result = await service.deriveBiometricEncryptionKey(
|
|
102
|
+
biometricData,
|
|
103
|
+
identifier,
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
expect(result).toBeDefined();
|
|
107
|
+
expect(result.key).toBeDefined();
|
|
108
|
+
expect(result.iv).toBeDefined();
|
|
109
|
+
expect(Buffer.isBuffer(result.key)).toBe(true);
|
|
110
|
+
expect(Buffer.isBuffer(result.iv)).toBe(true);
|
|
111
|
+
expect(result.key.length).toBe(32); // HKDF_LENGTH
|
|
112
|
+
expect(result.iv.length).toBe(16); // AES-GCM IV length
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should produce consistent keys but different IVs for same inputs', async () => {
|
|
116
|
+
const biometricData = Buffer.from('mock-biometric-data');
|
|
117
|
+
const identifier = 'user@example.com';
|
|
118
|
+
|
|
119
|
+
const result1 = await service.deriveBiometricEncryptionKey(
|
|
120
|
+
biometricData,
|
|
121
|
+
identifier,
|
|
122
|
+
);
|
|
123
|
+
const result2 = await service.deriveBiometricEncryptionKey(
|
|
124
|
+
biometricData,
|
|
125
|
+
identifier,
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
expect(result1.key.equals(result2.key)).toBe(true);
|
|
129
|
+
// IVs should be different (random)
|
|
130
|
+
expect(result1.iv.equals(result2.iv)).toBe(false);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
describe('encryptMasterKey and decryptMasterKey', () => {
|
|
135
|
+
it('should encrypt and decrypt master key successfully', async () => {
|
|
136
|
+
const masterKey = new Uint8Array(32).fill(42);
|
|
137
|
+
const encryptionKey = Buffer.from(new Uint8Array(32).fill(1));
|
|
138
|
+
const iv = Buffer.from(new Uint8Array(16).fill(2));
|
|
139
|
+
|
|
140
|
+
const encrypted = await service.encryptMasterKey(
|
|
141
|
+
masterKey,
|
|
142
|
+
encryptionKey,
|
|
143
|
+
iv,
|
|
144
|
+
);
|
|
145
|
+
expect(encrypted).toBeDefined();
|
|
146
|
+
expect(encrypted instanceof Uint8Array).toBe(true);
|
|
147
|
+
expect(encrypted.length).toBeGreaterThan(0);
|
|
148
|
+
|
|
149
|
+
const decrypted = await service.decryptMasterKey(
|
|
150
|
+
encrypted,
|
|
151
|
+
encryptionKey,
|
|
152
|
+
iv,
|
|
153
|
+
);
|
|
154
|
+
expect(decrypted).toBeDefined();
|
|
155
|
+
expect(decrypted instanceof Uint8Array).toBe(true);
|
|
156
|
+
expect(new Uint8Array(decrypted)).toEqual(masterKey);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('should fail to decrypt with wrong key', async () => {
|
|
160
|
+
const masterKey = new Uint8Array(32).fill(42);
|
|
161
|
+
const encryptionKey = Buffer.from(new Uint8Array(32).fill(1));
|
|
162
|
+
const wrongKey = Buffer.from(new Uint8Array(32).fill(99));
|
|
163
|
+
const iv = Buffer.from(new Uint8Array(16).fill(2));
|
|
164
|
+
|
|
165
|
+
const encrypted = await service.encryptMasterKey(
|
|
166
|
+
masterKey,
|
|
167
|
+
encryptionKey,
|
|
168
|
+
iv,
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
await expect(
|
|
172
|
+
service.decryptMasterKey(encrypted, wrongKey, iv),
|
|
173
|
+
).rejects.toThrow('Decryption failed: Invalid key or corrupted data');
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('should fail to decrypt with wrong IV', async () => {
|
|
177
|
+
const masterKey = new Uint8Array(32).fill(42);
|
|
178
|
+
const encryptionKey = Buffer.from(new Uint8Array(32).fill(1));
|
|
179
|
+
const iv = Buffer.from(new Uint8Array(16).fill(2));
|
|
180
|
+
const wrongIv = Buffer.from(new Uint8Array(16).fill(99));
|
|
181
|
+
|
|
182
|
+
const encrypted = await service.encryptMasterKey(
|
|
183
|
+
masterKey,
|
|
184
|
+
encryptionKey,
|
|
185
|
+
iv,
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
await expect(
|
|
189
|
+
service.decryptMasterKey(encrypted, encryptionKey, wrongIv),
|
|
190
|
+
).rejects.toThrow('Decryption failed: Invalid key or corrupted data');
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('should produce different ciphertext for same plaintext with different IVs', async () => {
|
|
194
|
+
const masterKey = new Uint8Array(32).fill(42);
|
|
195
|
+
const encryptionKey = Buffer.from(new Uint8Array(32).fill(1));
|
|
196
|
+
const iv1 = Buffer.from(new Uint8Array(16).fill(2));
|
|
197
|
+
const iv2 = Buffer.from(new Uint8Array(16).fill(3));
|
|
198
|
+
|
|
199
|
+
const encrypted1 = await service.encryptMasterKey(
|
|
200
|
+
masterKey,
|
|
201
|
+
encryptionKey,
|
|
202
|
+
iv1,
|
|
203
|
+
);
|
|
204
|
+
const encrypted2 = await service.encryptMasterKey(
|
|
205
|
+
masterKey,
|
|
206
|
+
encryptionKey,
|
|
207
|
+
iv2,
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
expect(encrypted1).not.toEqual(encrypted2);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it('should handle empty master key', async () => {
|
|
214
|
+
const masterKey = new Uint8Array(0);
|
|
215
|
+
const encryptionKey = Buffer.from(new Uint8Array(32).fill(1));
|
|
216
|
+
const iv = Buffer.from(new Uint8Array(16).fill(2));
|
|
217
|
+
|
|
218
|
+
const encrypted = await service.encryptMasterKey(
|
|
219
|
+
masterKey,
|
|
220
|
+
encryptionKey,
|
|
221
|
+
iv,
|
|
222
|
+
);
|
|
223
|
+
const decrypted = await service.decryptMasterKey(
|
|
224
|
+
encrypted,
|
|
225
|
+
encryptionKey,
|
|
226
|
+
iv,
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
expect(new Uint8Array(decrypted)).toEqual(masterKey);
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
describe('integration: biometric encryption workflow', () => {
|
|
234
|
+
it('should complete full encryption workflow', async () => {
|
|
235
|
+
const biometricData = Buffer.from('mock-biometric-data');
|
|
236
|
+
const identifier = 'user@example.com';
|
|
237
|
+
const masterKey = new Uint8Array(32).fill(123);
|
|
238
|
+
|
|
239
|
+
// Derive encryption key and IV from biometric data
|
|
240
|
+
const {key, iv} = await service.deriveBiometricEncryptionKey(
|
|
241
|
+
biometricData,
|
|
242
|
+
identifier,
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
// Encrypt master key
|
|
246
|
+
const encrypted = await service.encryptMasterKey(masterKey, key, iv);
|
|
247
|
+
|
|
248
|
+
// Decrypt master key
|
|
249
|
+
const decrypted = await service.decryptMasterKey(encrypted, key, iv);
|
|
250
|
+
|
|
251
|
+
// Verify decrypted matches original
|
|
252
|
+
expect(new Uint8Array(decrypted)).toEqual(masterKey);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it('should fail workflow with different biometric data', async () => {
|
|
256
|
+
const biometricData1 = Buffer.from('mock-biometric-data-1');
|
|
257
|
+
const biometricData2 = Buffer.from('mock-biometric-data-2');
|
|
258
|
+
const identifier = 'user@example.com';
|
|
259
|
+
const masterKey = new Uint8Array(32).fill(123);
|
|
260
|
+
|
|
261
|
+
// Encrypt with first biometric data
|
|
262
|
+
const {key: key1, iv} = await service.deriveBiometricEncryptionKey(
|
|
263
|
+
biometricData1,
|
|
264
|
+
identifier,
|
|
265
|
+
);
|
|
266
|
+
const encrypted = await service.encryptMasterKey(masterKey, key1, iv);
|
|
267
|
+
|
|
268
|
+
// Try to decrypt with second biometric data (should fail)
|
|
269
|
+
const {key: key2} = await service.deriveBiometricEncryptionKey(
|
|
270
|
+
biometricData2,
|
|
271
|
+
identifier,
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
await expect(
|
|
275
|
+
service.decryptMasterKey(encrypted, key2, iv),
|
|
276
|
+
).rejects.toThrow('Decryption failed: Invalid key or corrupted data');
|
|
277
|
+
});
|
|
278
|
+
});
|
|
50
279
|
});
|
|
51
280
|
});
|
|
@@ -38,4 +38,27 @@ export class EDVServiceRpc extends RpcService {
|
|
|
38
38
|
delete(params: any) {
|
|
39
39
|
return this.call('delete', params);
|
|
40
40
|
}
|
|
41
|
+
|
|
42
|
+
deriveBiometricKey(biometricData: Buffer, identifier: string) {
|
|
43
|
+
return this.call('deriveBiometricKey', {biometricData, identifier});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
deriveBiometricEncryptionKey(biometricData: Buffer, identifier: string) {
|
|
47
|
+
return this.call('deriveBiometricEncryptionKey', {
|
|
48
|
+
biometricData,
|
|
49
|
+
identifier,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
encryptMasterKey(masterKey: Uint8Array, encryptionKey: Buffer, iv: Buffer) {
|
|
54
|
+
return this.call('encryptMasterKey', {masterKey, encryptionKey, iv});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
decryptMasterKey(
|
|
58
|
+
encryptedKey: Uint8Array,
|
|
59
|
+
decryptionKey: Buffer,
|
|
60
|
+
iv: Buffer,
|
|
61
|
+
) {
|
|
62
|
+
return this.call('decryptMasterKey', {encryptedKey, decryptionKey, iv});
|
|
63
|
+
}
|
|
41
64
|
}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @module edv-service
|
|
5
|
+
* @description Encrypted Data Vault (EDV) service for the Wallet SDK.
|
|
6
|
+
* This module provides secure, encrypted storage functionality using EDV protocol,
|
|
7
|
+
* enabling privacy-preserving data storage with client-side encryption.
|
|
8
|
+
*/
|
|
9
|
+
|
|
2
10
|
import {InitializeEDVParams, serviceName} from './configs';
|
|
3
11
|
import EDVHTTPStorageInterface from '@docknetwork/universal-wallet/storage/edv-http-storage';
|
|
4
12
|
import HMAC from './hmac';
|
|
@@ -9,9 +17,17 @@ import {getKeypairFromDoc} from '@docknetwork/universal-wallet/methods/keypairs'
|
|
|
9
17
|
import {logger} from '@docknetwork/wallet-sdk-data-store/src/logger';
|
|
10
18
|
import {didService} from '@docknetwork/wallet-sdk-wasm/src/services/dids/service';
|
|
11
19
|
import {Ed25519Keypair} from '@docknetwork/credential-sdk/keypairs';
|
|
20
|
+
import hkdf from 'futoin-hkdf';
|
|
21
|
+
import crypto from '@docknetwork/universal-wallet/crypto';
|
|
22
|
+
|
|
23
|
+
export const HKDF_LENGTH = 32;
|
|
24
|
+
export const HKDF_HASH = 'SHA-256';
|
|
12
25
|
|
|
13
26
|
/**
|
|
14
|
-
*
|
|
27
|
+
* Service class for managing Encrypted Data Vaults
|
|
28
|
+
* @class
|
|
29
|
+
* @description Provides methods for creating, managing, and interacting with
|
|
30
|
+
* encrypted data vaults for secure storage of sensitive wallet data
|
|
15
31
|
*/
|
|
16
32
|
export class EDVService {
|
|
17
33
|
storageInterface: EDVHTTPStorageInterface;
|
|
@@ -28,12 +44,39 @@ export class EDVService {
|
|
|
28
44
|
EDVService.prototype.update,
|
|
29
45
|
EDVService.prototype.insert,
|
|
30
46
|
EDVService.prototype.delete,
|
|
47
|
+
EDVService.prototype.deriveBiometricKey,
|
|
48
|
+
EDVService.prototype.deriveBiometricEncryptionKey,
|
|
49
|
+
EDVService.prototype.encryptMasterKey,
|
|
50
|
+
EDVService.prototype.decryptMasterKey,
|
|
31
51
|
];
|
|
32
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Creates a new EDVService instance
|
|
55
|
+
* @constructor
|
|
56
|
+
*/
|
|
33
57
|
constructor() {
|
|
34
58
|
this.name = serviceName;
|
|
35
59
|
}
|
|
36
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Initializes the EDV service with encryption keys and connection parameters
|
|
63
|
+
* @param {InitializeEDVParams} params - Initialization parameters
|
|
64
|
+
* @param {Object} params.hmacKey - HMAC key for document indexing
|
|
65
|
+
* @param {Object} params.agreementKey - Key agreement key for encryption
|
|
66
|
+
* @param {Object} params.verificationKey - Verification key for authentication
|
|
67
|
+
* @param {string} params.edvUrl - URL of the EDV server
|
|
68
|
+
* @param {string} params.authKey - Authentication key for the EDV server
|
|
69
|
+
* @returns {Promise<void>}
|
|
70
|
+
* @throws {Error} If unable to create or connect to EDV
|
|
71
|
+
* @example
|
|
72
|
+
* await edvService.initialize({
|
|
73
|
+
* hmacKey: hmacKeyData,
|
|
74
|
+
* agreementKey: agreementKeyData,
|
|
75
|
+
* verificationKey: verificationKeyData,
|
|
76
|
+
* edvUrl: 'https://edv.example.com',
|
|
77
|
+
* authKey: 'auth-token-123'
|
|
78
|
+
* });
|
|
79
|
+
*/
|
|
37
80
|
async initialize({
|
|
38
81
|
hmacKey,
|
|
39
82
|
agreementKey,
|
|
@@ -95,6 +138,21 @@ export class EDVService {
|
|
|
95
138
|
});
|
|
96
139
|
}
|
|
97
140
|
|
|
141
|
+
/**
|
|
142
|
+
* Generates new cryptographic keys for EDV operations
|
|
143
|
+
* @returns {Promise<Object>} Generated keys
|
|
144
|
+
* @returns {Object} returns.verificationKey - Ed25519 verification key for authentication
|
|
145
|
+
* @returns {Object} returns.agreementKey - X25519 key agreement key for encryption
|
|
146
|
+
* @returns {Object} returns.hmacKey - HMAC key for indexing
|
|
147
|
+
* @example
|
|
148
|
+
* const keys = await edvService.generateKeys();
|
|
149
|
+
* // Use keys for EDV initialization
|
|
150
|
+
* await edvService.initialize({
|
|
151
|
+
* ...keys,
|
|
152
|
+
* edvUrl: 'https://edv.example.com',
|
|
153
|
+
* authKey: 'auth-token'
|
|
154
|
+
* });
|
|
155
|
+
*/
|
|
98
156
|
async generateKeys() {
|
|
99
157
|
const keyPair = await didService.generateKeyDoc({});
|
|
100
158
|
|
|
@@ -111,6 +169,17 @@ export class EDVService {
|
|
|
111
169
|
return {verificationKey, agreementKey, hmacKey};
|
|
112
170
|
}
|
|
113
171
|
|
|
172
|
+
/**
|
|
173
|
+
* Derives cryptographic keys from a master key
|
|
174
|
+
* @param {Uint8Array} masterKey - Master key for derivation
|
|
175
|
+
* @returns {Promise<Object>} Derived keys
|
|
176
|
+
* @returns {Object} returns.verificationKey - Derived Ed25519 verification key
|
|
177
|
+
* @returns {Object} returns.agreementKey - Derived X25519 key agreement key
|
|
178
|
+
* @returns {Object} returns.hmacKey - Derived HMAC key
|
|
179
|
+
* @example
|
|
180
|
+
* const masterKey = new Uint8Array(32); // Your master key
|
|
181
|
+
* const keys = await edvService.deriveKeys(masterKey);
|
|
182
|
+
*/
|
|
114
183
|
async deriveKeys(masterKey: Uint8Array) {
|
|
115
184
|
const {keyPair: pair} = new Ed25519Keypair(masterKey, 'seed');
|
|
116
185
|
|
|
@@ -126,18 +195,66 @@ export class EDVService {
|
|
|
126
195
|
return { verificationKey, agreementKey, hmacKey };
|
|
127
196
|
}
|
|
128
197
|
|
|
198
|
+
/**
|
|
199
|
+
* Gets the controller identifier for the current EDV
|
|
200
|
+
* @returns {Promise<string>} The controller DID or identifier
|
|
201
|
+
* @example
|
|
202
|
+
* const controller = await edvService.getController();
|
|
203
|
+
* console.log('EDV Controller:', controller);
|
|
204
|
+
*/
|
|
129
205
|
async getController() {
|
|
130
206
|
return this.controller;
|
|
131
207
|
}
|
|
132
208
|
|
|
209
|
+
/**
|
|
210
|
+
* Finds documents in the EDV based on query parameters
|
|
211
|
+
* @param {Object} params - Query parameters
|
|
212
|
+
* @param {Object} [params.equals] - Equality-based query conditions
|
|
213
|
+
* @param {boolean} [params.has] - Existence-based query conditions
|
|
214
|
+
* @param {number} [params.limit] - Maximum number of results
|
|
215
|
+
* @returns {Promise<Array>} Array of matching documents
|
|
216
|
+
* @example
|
|
217
|
+
* const documents = await edvService.find({
|
|
218
|
+
* equals: { 'content.type': 'VerifiableCredential' },
|
|
219
|
+
* limit: 10
|
|
220
|
+
* });
|
|
221
|
+
*/
|
|
133
222
|
find(params: any) {
|
|
134
223
|
return this.storageInterface.find(params);
|
|
135
224
|
}
|
|
136
225
|
|
|
226
|
+
/**
|
|
227
|
+
* Updates a document in the EDV
|
|
228
|
+
* @param {Object} params - Update parameters
|
|
229
|
+
* @param {string} params.id - Document ID to update
|
|
230
|
+
* @param {Object} params.content - New document content
|
|
231
|
+
* @returns {Promise<Object>} Updated document
|
|
232
|
+
* @example
|
|
233
|
+
* const updated = await edvService.update({
|
|
234
|
+
* id: 'doc-123',
|
|
235
|
+
* content: { ...existingContent, updated: true }
|
|
236
|
+
* });
|
|
237
|
+
*/
|
|
137
238
|
update(params: any) {
|
|
138
239
|
return this.storageInterface.update(params);
|
|
139
240
|
}
|
|
140
241
|
|
|
242
|
+
/**
|
|
243
|
+
* Inserts a new document into the EDV
|
|
244
|
+
* @param {Object} params - Insert parameters
|
|
245
|
+
* @param {string} params.id - Document ID
|
|
246
|
+
* @param {Object} params.content - Document content to store
|
|
247
|
+
* @returns {Promise<Object>} The inserted document
|
|
248
|
+
* @throws {Error} If insertion fails
|
|
249
|
+
* @example
|
|
250
|
+
* const document = await edvService.insert({
|
|
251
|
+
* id: 'doc-456',
|
|
252
|
+
* content: {
|
|
253
|
+
* type: 'VerifiableCredential',
|
|
254
|
+
* data: credentialData
|
|
255
|
+
* }
|
|
256
|
+
* });
|
|
257
|
+
*/
|
|
141
258
|
insert(params: any) {
|
|
142
259
|
this.insertQueue = this.insertQueue.then(() => {
|
|
143
260
|
return this.storageInterface.insert(params).catch(error => {
|
|
@@ -148,9 +265,163 @@ export class EDVService {
|
|
|
148
265
|
return this.insertQueue;
|
|
149
266
|
}
|
|
150
267
|
|
|
268
|
+
/**
|
|
269
|
+
* Deletes a document from the EDV
|
|
270
|
+
* @param {Object} params - Deletion parameters
|
|
271
|
+
* @param {string} params.id - Document ID to delete
|
|
272
|
+
* @returns {Promise<boolean>} True if deletion successful
|
|
273
|
+
* @example
|
|
274
|
+
* const deleted = await edvService.delete({
|
|
275
|
+
* id: 'doc-123'
|
|
276
|
+
* });
|
|
277
|
+
*/
|
|
151
278
|
delete(params: any) {
|
|
152
279
|
return this.storageInterface.delete(params);
|
|
153
280
|
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Derives a key from biometric data using HKDF
|
|
284
|
+
* @param {Buffer} biometricData - Biometric data from provider
|
|
285
|
+
* @param {string} identifier - User's identifier as salt (email, phone number, etc.)
|
|
286
|
+
* @returns {Buffer} Derived key
|
|
287
|
+
* @example
|
|
288
|
+
* const key = edvService.deriveBiometricKey(biometricData, 'user@example.com');
|
|
289
|
+
*/
|
|
290
|
+
deriveBiometricKey(biometricData: Buffer, identifier: string): Buffer {
|
|
291
|
+
const salt = identifier;
|
|
292
|
+
return hkdf(biometricData, HKDF_LENGTH, { salt, hash: HKDF_HASH });
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Generates a key for encrypting/decrypting the master key
|
|
297
|
+
* @param {Buffer} biometricData - Biometric data from provider
|
|
298
|
+
* @param {string} identifier - User's identifier as salt (email, phone number, etc.)
|
|
299
|
+
* @returns {Promise<Object>} Encryption key and IV for AES encryption
|
|
300
|
+
* @returns {Buffer} returns.key - Encryption key
|
|
301
|
+
* @returns {Buffer} returns.iv - Initialization vector
|
|
302
|
+
* @example
|
|
303
|
+
* const { key, iv } = await edvService.deriveBiometricEncryptionKey(biometricData, 'user@example.com');
|
|
304
|
+
*/
|
|
305
|
+
async deriveBiometricEncryptionKey(
|
|
306
|
+
biometricData: Buffer,
|
|
307
|
+
identifier: string
|
|
308
|
+
): Promise<{ key: Buffer; iv: Buffer }> {
|
|
309
|
+
const key = this.deriveBiometricKey(biometricData, identifier);
|
|
310
|
+
const randomBytes = crypto.getRandomValues(new Uint8Array(16));
|
|
311
|
+
const iv = Buffer.from(randomBytes);
|
|
312
|
+
|
|
313
|
+
return {
|
|
314
|
+
key,
|
|
315
|
+
iv
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Encrypts the master key using a key derived from biometric data
|
|
321
|
+
* @param {Uint8Array} masterKey - The CloudWalletVault master key to encrypt
|
|
322
|
+
* @param {Buffer} encryptionKey - Key derived from biometric data
|
|
323
|
+
* @param {Buffer} iv - Initialization vector
|
|
324
|
+
* @returns {Promise<Uint8Array>} Encrypted master key
|
|
325
|
+
* @example
|
|
326
|
+
* const encrypted = await edvService.encryptMasterKey(masterKey, encryptionKey, iv);
|
|
327
|
+
*/
|
|
328
|
+
async encryptMasterKey(
|
|
329
|
+
masterKey: Uint8Array,
|
|
330
|
+
encryptionKey: Buffer,
|
|
331
|
+
iv: Buffer
|
|
332
|
+
): Promise<Uint8Array> {
|
|
333
|
+
const keyData = new Uint8Array(encryptionKey);
|
|
334
|
+
const ivData = new Uint8Array(iv);
|
|
335
|
+
|
|
336
|
+
const key = await crypto.subtle.importKey(
|
|
337
|
+
'raw',
|
|
338
|
+
keyData,
|
|
339
|
+
{ name: 'AES-GCM' },
|
|
340
|
+
false,
|
|
341
|
+
['encrypt']
|
|
342
|
+
);
|
|
343
|
+
|
|
344
|
+
const encryptedBuffer = await crypto.subtle.encrypt(
|
|
345
|
+
{ name: 'AES-GCM', iv: ivData },
|
|
346
|
+
key,
|
|
347
|
+
masterKey
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
return new Uint8Array(encryptedBuffer);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Decrypts the master key using biometric-derived key
|
|
355
|
+
* @param {Uint8Array} encryptedKey - The encrypted master key
|
|
356
|
+
* @param {Buffer} decryptionKey - Key derived from biometric data
|
|
357
|
+
* @param {Buffer} iv - Initialization vector
|
|
358
|
+
* @returns {Promise<Uint8Array>} The decrypted master key
|
|
359
|
+
* @throws {Error} If decryption fails
|
|
360
|
+
* @example
|
|
361
|
+
* const masterKey = await edvService.decryptMasterKey(encryptedKey, decryptionKey, iv);
|
|
362
|
+
*/
|
|
363
|
+
async decryptMasterKey(
|
|
364
|
+
encryptedKey: Uint8Array,
|
|
365
|
+
decryptionKey: Buffer,
|
|
366
|
+
iv: Buffer
|
|
367
|
+
): Promise<Uint8Array> {
|
|
368
|
+
try {
|
|
369
|
+
const keyData = new Uint8Array(decryptionKey);
|
|
370
|
+
const ivData = new Uint8Array(iv);
|
|
371
|
+
|
|
372
|
+
const key = await crypto.subtle.importKey(
|
|
373
|
+
'raw',
|
|
374
|
+
keyData,
|
|
375
|
+
{ name: 'AES-GCM' },
|
|
376
|
+
false,
|
|
377
|
+
['decrypt']
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
const decryptedBuffer = await crypto.subtle.decrypt(
|
|
381
|
+
{ name: 'AES-GCM', iv: ivData },
|
|
382
|
+
key,
|
|
383
|
+
encryptedKey
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
return new Uint8Array(decryptedBuffer);
|
|
387
|
+
} catch (error) {
|
|
388
|
+
throw new Error('Decryption failed: Invalid key or corrupted data');
|
|
389
|
+
}
|
|
390
|
+
}
|
|
154
391
|
}
|
|
155
392
|
|
|
393
|
+
/**
|
|
394
|
+
* Singleton instance of the EDV service
|
|
395
|
+
* @type {EDVService}
|
|
396
|
+
* @example
|
|
397
|
+
* import { edvService } from '@docknetwork/wallet-sdk-wasm/services/edv';
|
|
398
|
+
*
|
|
399
|
+
* // Generate keys and initialize
|
|
400
|
+
* const keys = await edvService.generateKeys();
|
|
401
|
+
* await edvService.initialize({
|
|
402
|
+
* ...keys,
|
|
403
|
+
* edvUrl: 'https://edv.example.com',
|
|
404
|
+
* authKey: 'auth-token'
|
|
405
|
+
* });
|
|
406
|
+
*
|
|
407
|
+
* // Store encrypted data
|
|
408
|
+
* await edvService.insert({
|
|
409
|
+
* id: 'credential-1',
|
|
410
|
+
* content: {
|
|
411
|
+
* type: 'VerifiableCredential',
|
|
412
|
+
* data: credentialData
|
|
413
|
+
* }
|
|
414
|
+
* });
|
|
415
|
+
*
|
|
416
|
+
* // Query encrypted data
|
|
417
|
+
* const credentials = await edvService.find({
|
|
418
|
+
* equals: { 'content.type': 'VerifiableCredential' }
|
|
419
|
+
* });
|
|
420
|
+
*
|
|
421
|
+
* // Update encrypted data
|
|
422
|
+
* await edvService.update({
|
|
423
|
+
* id: 'credential-1',
|
|
424
|
+
* content: updatedData
|
|
425
|
+
* });
|
|
426
|
+
*/
|
|
156
427
|
export const edvService: EDVService = new EDVService();
|
|
@@ -7,6 +7,10 @@ export const validation = {
|
|
|
7
7
|
assert(params.credentials, 'credentials is required');
|
|
8
8
|
assert(params.presentationDefinition, 'presentationDefinition is required');
|
|
9
9
|
},
|
|
10
|
+
evaluateCredentials: (params: EvaluateCredentialsParams) => {
|
|
11
|
+
assert(params.credentials, 'credentials is required');
|
|
12
|
+
assert(params.presentationDefinition, 'presentationDefinition is required');
|
|
13
|
+
},
|
|
10
14
|
evaluatePresentation: (params: EvaluatePresentationParams) => {
|
|
11
15
|
assert(params.presentation, 'presentation is required');
|
|
12
16
|
assert(params.presentationDefinition, 'presentationDefinition is required');
|
|
@@ -24,4 +24,8 @@ export class PEXServiceRPC extends RpcService {
|
|
|
24
24
|
async presentationFrom(params: CreatePresentationParams) {
|
|
25
25
|
return this.call('presentationFrom', params);
|
|
26
26
|
}
|
|
27
|
+
|
|
28
|
+
async isCredentialSelectionValid(params: EvaluateCredentialsParams) {
|
|
29
|
+
return this.call('isCredentialSelectionValid', params);
|
|
30
|
+
}
|
|
27
31
|
}
|
|
@@ -78,6 +78,7 @@ class PEXService {
|
|
|
78
78
|
PEXService.prototype.filterCredentials,
|
|
79
79
|
PEXService.prototype.evaluatePresentation,
|
|
80
80
|
PEXService.prototype.presentationFrom,
|
|
81
|
+
PEXService.prototype.isCredentialSelectionValid,
|
|
81
82
|
];
|
|
82
83
|
|
|
83
84
|
filterCredentials(params: FilterCredentialsParams) {
|
|
@@ -92,6 +93,18 @@ class PEXService {
|
|
|
92
93
|
return result;
|
|
93
94
|
}
|
|
94
95
|
|
|
96
|
+
isCredentialSelectionValid(params: EvaluateCredentialsParams) {
|
|
97
|
+
validation.evaluateCredentials(params);
|
|
98
|
+
const {credentials, presentationDefinition, holderDIDs} = params;
|
|
99
|
+
const result = pex.selectFrom(
|
|
100
|
+
removeOptionalAttribute(presentationDefinition),
|
|
101
|
+
credentials,
|
|
102
|
+
holderDIDs,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
return result.errors.length === 0;
|
|
106
|
+
}
|
|
107
|
+
|
|
95
108
|
evaluatePresentation(params: EvaluatePresentationParams) {
|
|
96
109
|
validation.evaluatePresentation(params);
|
|
97
110
|
const {presentation, presentationDefinition} = params;
|