dignity.js 0.2.0 → 0.3.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dignity.js",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "P2P object API for decentralized JavaScript applications",
5
5
  "main": "dist/dignity.cjs.js",
6
6
  "module": "dist/dignity.esm.js",
@@ -39,7 +39,7 @@
39
39
  "rest",
40
40
  "objects"
41
41
  ],
42
- "license": "MIT",
42
+ "license": "Apache 2.0",
43
43
  "devDependencies": {
44
44
  "esbuild": "^0.28.0",
45
45
  "jest": "^29.7.0"
@@ -12,7 +12,8 @@ const DEFAULT_SECURITY_OPTIONS = {
12
12
  broadcastPasswords: {},
13
13
  resolveBroadcastPassword: null,
14
14
  powSteps: 22,
15
- trustedPeerKeys: {}
15
+ trustedPeerKeys: {},
16
+ kdfIterations: 100000
16
17
  };
17
18
 
18
19
  function stableStringify(value) {
@@ -47,6 +48,37 @@ function utf8ToBytes(value) {
47
48
  return naclUtil.decodeUTF8(value);
48
49
  }
49
50
 
51
+ async function deriveBroadcastKey(password, salt, iterations) {
52
+ const subtle = globalThis.crypto && globalThis.crypto.subtle;
53
+
54
+ if (subtle) {
55
+ const keyMaterial = await subtle.importKey(
56
+ 'raw',
57
+ utf8ToBytes(password),
58
+ 'PBKDF2',
59
+ false,
60
+ ['deriveBits']
61
+ );
62
+ const bits = await subtle.deriveBits(
63
+ { name: 'PBKDF2', salt, iterations, hash: 'SHA-256' },
64
+ keyMaterial,
65
+ 256
66
+ );
67
+ return new Uint8Array(bits);
68
+ }
69
+
70
+ try {
71
+ const { pbkdf2Sync } = require('crypto');
72
+ return new Uint8Array(pbkdf2Sync(password, Buffer.from(salt), iterations, 32, 'sha256'));
73
+ } catch (_ignored) {
74
+ return hash32(concatBytes(utf8ToBytes(password), salt));
75
+ }
76
+ }
77
+
78
+ function legacyBroadcastKey(password, salt) {
79
+ return hash32(concatBytes(utf8ToBytes(password), salt));
80
+ }
81
+
50
82
  function normalizePeerPublicKey(publicKey) {
51
83
  if (!publicKey || typeof publicKey !== 'object') {
52
84
  throw new Error('Public key must be an object with signingPublicKey and encryptionPublicKey');
@@ -240,7 +272,7 @@ class MessageSecurityService {
240
272
  this.verifySignature(envelope);
241
273
  }
242
274
 
243
- const payload = this.decryptPayload(envelope);
275
+ const payload = await this.decryptPayload(envelope);
244
276
 
245
277
  return {
246
278
  ignored: false,
@@ -320,7 +352,8 @@ class MessageSecurityService {
320
352
  const nonce = nacl.randomBytes(nacl.secretbox.nonceLength);
321
353
  const salt = nacl.randomBytes(16);
322
354
  const password = this.resolveBroadcastPassword(scope);
323
- const key = hash32(concatBytes(utf8ToBytes(password), salt));
355
+ const iterations = this.options.kdfIterations || DEFAULT_SECURITY_OPTIONS.kdfIterations;
356
+ const key = await deriveBroadcastKey(password, salt, iterations);
324
357
  const encrypted = nacl.secretbox(plainText, nonce, key);
325
358
 
326
359
  return {
@@ -330,12 +363,14 @@ class MessageSecurityService {
330
363
  mode: 'broadcast',
331
364
  scope,
332
365
  nonce: naclUtil.encodeBase64(nonce),
333
- salt: naclUtil.encodeBase64(salt)
366
+ salt: naclUtil.encodeBase64(salt),
367
+ kdf: 'pbkdf2',
368
+ kdfIterations: iterations
334
369
  }
335
370
  };
336
371
  }
337
372
 
338
- decryptPayload(envelope) {
373
+ async decryptPayload(envelope) {
339
374
  const encryption = envelope.security ? envelope.security.encryption : null;
340
375
 
341
376
  if (!encryption || !encryption.enabled || !this.options.encryptionEnabled) {
@@ -349,7 +384,15 @@ class MessageSecurityService {
349
384
  const password = this.resolveBroadcastPassword(scope);
350
385
  const salt = naclUtil.decodeBase64(encryption.salt);
351
386
  const nonce = naclUtil.decodeBase64(encryption.nonce);
352
- const key = hash32(concatBytes(utf8ToBytes(password), salt));
387
+
388
+ let key;
389
+ if (encryption.kdf === 'pbkdf2') {
390
+ const iterations = encryption.kdfIterations || DEFAULT_SECURITY_OPTIONS.kdfIterations;
391
+ key = await deriveBroadcastKey(password, salt, iterations);
392
+ } else {
393
+ key = legacyBroadcastKey(password, salt);
394
+ }
395
+
353
396
  const decrypted = nacl.secretbox.open(encryptedBuffer, nonce, key);
354
397
 
355
398
  if (!decrypted) {
@@ -470,5 +513,7 @@ class MessageSecurityService {
470
513
  module.exports = {
471
514
  MessageSecurityService,
472
515
  stableStringify,
516
+ deriveBroadcastKey,
517
+ legacyBroadcastKey,
473
518
  DEFAULT_SECURITY_OPTIONS
474
519
  };