@digitaldefiance/ecies-lib 4.16.30 → 4.17.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.
Files changed (2) hide show
  1. package/README.md +287 -110
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -8,18 +8,6 @@ Production-ready, browser-compatible ECIES (Elliptic Curve Integrated Encryption
8
8
 
9
9
  Part of [Express Suite](https://github.com/Digital-Defiance/express-suite)
10
10
 
11
- **Current Version: v4.16.25**
12
-
13
- ## What's New in v4.16.x
14
-
15
- ✨ **Voting Key Derivation Security Improvements** - Enhanced voting key derivation to use both X and Y coordinates of the shared secret for improved security and cross-platform consistency.
16
-
17
- **Key Changes:**
18
- - **HKDF Salt Handling**: Per RFC 5869, when salt is not provided, it now uses a string of HashLen zeros (64 bytes for SHA-512, 32 bytes for SHA-256) instead of an empty array, ensuring consistency with Node.js implementation
19
- - **Private Key Normalization**: `deriveVotingKeysFromECDH` now handles 31-byte private keys (which can occur ~0.4% of the time when Node.js createECDH returns keys with leading zeros) by padding to 32 bytes
20
- - **Uncompressed Public Keys**: Voting key derivation now uses uncompressed format (65 bytes with 0x04 prefix) for maximum entropy in ECDH shared secret computation
21
- - **Simplified Prime Generation**: Removed constant-time padding in `generateDeterministicPrime` for cleaner implementation
22
-
23
11
  This library implements a modern, enterprise-grade ECIES protocol (v4.0) featuring HKDF key derivation, AAD binding, and optimized multi-recipient encryption. It includes a pluggable ID provider system with PlatformID support, memory-efficient streaming encryption, comprehensive internationalization, and a complete cryptographic voting system with 15+ voting methods.
24
12
 
25
13
  ## Features
@@ -36,9 +24,9 @@ This library implements a modern, enterprise-grade ECIES protocol (v4.0) featuri
36
24
  - **Symmetric**: `AES-256-GCM` for authenticated symmetric encryption.
37
25
  - **Hashing**: `SHA-256` and `SHA-512`.
38
26
  - **Modes**:
39
- - **Basic**: Minimal overhead (no length prefix).
40
- - **WithLength**: Includes data length prefix.
41
- - **Multiple**: Efficient encryption for up to 65,535 recipients.
27
+ - **Basic**: Minimal overhead (no length prefix) - Use for fixed-size data or when size is known
28
+ - **WithLength**: Includes data length prefix - Use for variable-size data or streaming
29
+ - **Multiple**: Efficient encryption for up to 65,535 recipients - Use for group messaging
42
30
 
43
31
  ### 🗳️ Cryptographic Voting System
44
32
 
@@ -217,53 +205,59 @@ import {
217
205
  AESGCMService
218
206
  } from '@digitaldefiance/ecies-lib';
219
207
 
220
- // 1. Initialize i18n (required once)
221
- getEciesI18nEngine();
222
-
223
- // 2. Configure (Optional - defaults to ObjectIdProvider)
224
- const config = createRuntimeConfiguration({
225
- idProvider: new ObjectIdProvider()
226
- });
227
-
228
- // 3. Initialize Service
229
- // The constructor accepts either IConstants (from createRuntimeConfiguration)
230
- // or Partial<IECIESConfig> for backward compatibility
231
- const ecies = new ECIESService(config);
232
-
233
- // 4. Generate Keys
234
- const mnemonic = ecies.generateNewMnemonic();
235
- const { privateKey, publicKey } = ecies.mnemonicToSimpleKeyPair(mnemonic);
236
-
237
- // 5. Encrypt & Decrypt
238
- const message = new TextEncoder().encode('Hello, Secure World!');
239
- const encrypted = await ecies.encryptWithLength(publicKey, message);
240
- const decrypted = await ecies.decryptWithLengthAndHeader(privateKey, encrypted);
241
-
242
- console.log(new TextDecoder().decode(decrypted)); // "Hello, Secure World!"
243
-
244
- // 6. Strong Typing for ID Operations (NEW!)
245
- const idProvider = getEnhancedIdProvider<ObjectId>();
246
- const objectId = idProvider.generateTyped(); // Returns ObjectId - strongly typed!
247
- const serialized = idProvider.serializeTyped(objectId); // Accepts ObjectId directly
248
- const deserialized = idProvider.deserializeTyped(serialized); // Returns ObjectId
249
-
250
- // 7. AES-GCM Service (Instance-based)
251
- const aesGcm = new AESGCMService(); // Now instance-based, not static
252
- const key = crypto.getRandomValues(new Uint8Array(32));
253
- const data = new TextEncoder().encode('Sensitive Data');
254
-
255
- // Encrypt with authentication tag
256
- const { encrypted: aesEncrypted, iv, tag } = await aesGcm.encrypt(data, key, true);
208
+ try {
209
+ // 1. Initialize i18n (required once)
210
+ getEciesI18nEngine();
257
211
 
258
- // Decrypt
259
- const combined = aesGcm.combineEncryptedDataAndTag(aesEncrypted, tag!);
260
- const aesDecrypted = await aesGcm.decrypt(iv, combined, key, true);
212
+ // 2. Configure (Optional - defaults to ObjectIdProvider)
213
+ const config = createRuntimeConfiguration({
214
+ idProvider: new ObjectIdProvider()
215
+ });
261
216
 
262
- // 8. JSON Encryption (NEW!)
263
- const userData = { name: 'Alice', email: 'alice@example.com', age: 30 };
264
- const encryptedJson = await aesGcm.encryptJson(userData, key);
265
- const decryptedJson = await aesGcm.decryptJson<typeof userData>(encryptedJson, key);
266
- console.log(decryptedJson); // { name: 'Alice', email: 'alice@example.com', age: 30 }
217
+ // 3. Initialize Service
218
+ const ecies = new ECIESService(config);
219
+
220
+ // 4. Generate Keys
221
+ const mnemonic = ecies.generateNewMnemonic();
222
+ const { privateKey, publicKey } = ecies.mnemonicToSimpleKeyPair(mnemonic);
223
+
224
+ // 5. Encrypt & Decrypt
225
+ const message = new TextEncoder().encode('Hello, Secure World!');
226
+ const encrypted = await ecies.encryptWithLength(publicKey, message);
227
+ const decrypted = await ecies.decryptWithLengthAndHeader(privateKey, encrypted);
228
+
229
+ console.log(new TextDecoder().decode(decrypted)); // "Hello, Secure World!"
230
+
231
+ // 6. Strong Typing for ID Operations
232
+ const idProvider = getEnhancedIdProvider<ObjectId>();
233
+ const objectId = idProvider.generateTyped(); // Returns ObjectId - strongly typed!
234
+ const serialized = idProvider.serializeTyped(objectId);
235
+ const deserialized = idProvider.deserializeTyped(serialized);
236
+
237
+ // 7. AES-GCM Service (Instance-based)
238
+ const aesGcm = new AESGCMService();
239
+ const key = crypto.getRandomValues(new Uint8Array(32));
240
+ const data = new TextEncoder().encode('Sensitive Data');
241
+
242
+ // Encrypt with authentication tag
243
+ const { encrypted: aesEncrypted, iv, tag } = await aesGcm.encrypt(data, key, true);
244
+
245
+ // Decrypt
246
+ const combined = aesGcm.combineEncryptedDataAndTag(aesEncrypted, tag!);
247
+ const aesDecrypted = await aesGcm.decrypt(iv, combined, key, true);
248
+
249
+ // 8. JSON Encryption
250
+ const userData = { name: 'Alice', email: 'alice@example.com', age: 30 };
251
+ const encryptedJson = await aesGcm.encryptJson(userData, key);
252
+ const decryptedJson = await aesGcm.decryptJson<typeof userData>(encryptedJson, key);
253
+ console.log(decryptedJson); // { name: 'Alice', email: 'alice@example.com', age: 30 }
254
+ } catch (error) {
255
+ console.error('Encryption error:', error.message);
256
+ // Handle specific error types
257
+ if (error.type === 'INVALID_KEY') {
258
+ console.error('Invalid key provided');
259
+ }
260
+ }
267
261
  ```
268
262
 
269
263
  ### 2. Internationalization (i18n)
@@ -305,12 +299,29 @@ const safeMessage = safeEciesTranslation(EciesStringKey.Error_ECIESError_Invalid
305
299
  const directTranslation = engine.translateStringKey(EciesStringKey.Error_ECIESError_InvalidIV);
306
300
  ```
307
301
 
302
+ **When to use each method:**
303
+ - `getEciesTranslation()`: Use for error messages and user-facing text (throws on failure)
304
+ - `safeEciesTranslation()`: Use when translation failure should not break execution
305
+ - `engine.translateStringKey()`: Use when you already have the engine instance
306
+
308
307
  **Supported Languages:** en-US, en-GB, fr, es, de, zh-CN, ja, uk
309
308
 
310
309
  ## Cryptographic Voting System
311
310
 
312
311
  The library includes a complete cryptographic voting system with government-grade security features, supporting 15+ voting methods from simple plurality to complex ranked choice voting.
313
312
 
313
+ **When to use the voting system:**
314
+ - Elections requiring verifiable, tamper-proof results
315
+ - Anonymous voting with receipt verification
316
+ - Multi-round elections (IRV, STAR, STV)
317
+ - Government or organizational voting with audit requirements
318
+ - Stakeholder voting with weighted votes
319
+
320
+ **When NOT to use:**
321
+ - Simple polls without privacy requirements (use regular encryption)
322
+ - Real-time voting displays (votes are encrypted until tally)
323
+ - Systems requiring instant results (multi-round methods need intermediate decryption)
324
+
314
325
  ### Quick Start - Voting
315
326
 
316
327
  ```typescript
@@ -327,46 +338,53 @@ import {
327
338
  VotingMethod
328
339
  } from '@digitaldefiance/ecies-lib/voting';
329
340
 
330
- // 1. Create authority with voting keys
331
- const ecies = new ECIESService();
332
- const { member: authority } = Member.newMember(
333
- ecies,
334
- MemberType.System,
335
- 'Election Authority',
336
- new EmailString('authority@example.com')
337
- );
338
- await authority.deriveVotingKeys();
339
-
340
- // 2. Create poll
341
- const poll = PollFactory.createPlurality(
342
- ['Alice', 'Bob', 'Charlie'],
343
- authority
344
- );
345
-
346
- // 3. Create voter and cast vote
347
- const { member: voter } = Member.newMember(
348
- ecies,
349
- MemberType.User,
350
- 'Voter',
351
- new EmailString('voter@example.com')
352
- );
353
- await voter.deriveVotingKeys();
354
-
355
- const encoder = new VoteEncoder(authority.votingPublicKey!);
356
- const vote = encoder.encodePlurality(0, 3); // Vote for Alice
357
- const receipt = poll.vote(voter, vote);
358
-
359
- // 4. Close and tally
360
- poll.close();
361
- const tallier = new PollTallier(
362
- authority,
363
- authority.votingPrivateKey!,
364
- authority.votingPublicKey!
365
- );
366
- const results = tallier.tally(poll);
367
-
368
- console.log('Winner:', results.choices[results.winner!]);
369
- console.log('Tallies:', results.tallies);
341
+ try {
342
+ // 1. Create authority with voting keys
343
+ const ecies = new ECIESService();
344
+ const { member: authority } = Member.newMember(
345
+ ecies,
346
+ MemberType.System,
347
+ 'Election Authority',
348
+ new EmailString('authority@example.com')
349
+ );
350
+ await authority.deriveVotingKeys();
351
+
352
+ // 2. Create poll
353
+ const poll = PollFactory.createPlurality(
354
+ ['Alice', 'Bob', 'Charlie'],
355
+ authority
356
+ );
357
+
358
+ // 3. Create voter and cast vote
359
+ const { member: voter } = Member.newMember(
360
+ ecies,
361
+ MemberType.User,
362
+ 'Voter',
363
+ new EmailString('voter@example.com')
364
+ );
365
+ await voter.deriveVotingKeys();
366
+
367
+ const encoder = new VoteEncoder(authority.votingPublicKey!);
368
+ const vote = encoder.encodePlurality(0, 3); // Vote for Alice
369
+ const receipt = poll.vote(voter, vote);
370
+
371
+ // 4. Close and tally
372
+ poll.close();
373
+ const tallier = new PollTallier(
374
+ authority,
375
+ authority.votingPrivateKey!,
376
+ authority.votingPublicKey!
377
+ );
378
+ const results = tallier.tally(poll);
379
+
380
+ console.log('Winner:', results.choices[results.winner!]);
381
+ console.log('Tallies:', results.tallies);
382
+ } catch (error) {
383
+ console.error('Voting error:', error.message);
384
+ if (error.message.includes('Already voted')) {
385
+ console.error('This voter has already cast a vote');
386
+ }
387
+ }
370
388
  ```
371
389
 
372
390
  ### Supported Voting Methods
@@ -657,6 +675,12 @@ public static fromJson(json: string, eciesService: ECIESService): Member {
657
675
 
658
676
  ### Available ID Providers
659
677
 
678
+ **Choosing an ID Provider:**
679
+ - **ObjectIdProvider**: Use for MongoDB integration, backward compatibility (12 bytes)
680
+ - **GuidV4Provider**: Use for Windows/.NET integration, compact serialization (16 bytes)
681
+ - **UuidProvider**: Use for standard UUID format, maximum compatibility (16 bytes, dash format)
682
+ - **CustomIdProvider**: Use for specialized requirements, legacy systems (1-255 bytes)
683
+
660
684
  #### ObjectIdProvider (Default)
661
685
 
662
686
  **Format**: 12-byte MongoDB-compatible ObjectID
@@ -1326,22 +1350,175 @@ The library maintains **100% test coverage** with over 1,200 tests, including:
1326
1350
  - **Vectors**: Validating against known test vectors.
1327
1351
  - **Property-based Tests**: Fuzzing inputs for robustness.
1328
1352
 
1353
+ ## Troubleshooting
1354
+
1355
+ ### Encryption/Decryption Errors
1356
+
1357
+ **Problem**: `ECIESError: Invalid IV length`
1358
+
1359
+ **Solutions**:
1360
+ 1. Ensure IV is exactly 12 bytes for AES-256-GCM
1361
+ 2. Don't reuse IVs - generate new one for each encryption
1362
+ 3. Check that encrypted data hasn't been corrupted
1363
+
1364
+ **Problem**: `ECIESError: Decryption failed`
1365
+
1366
+ **Solutions**:
1367
+ 1. Verify you're using the correct private key
1368
+ 2. Check that data wasn't modified in transit
1369
+ 3. Ensure using same encryption mode (Basic/WithLength/Multiple)
1370
+ 4. Verify recipient ID matches if using multi-recipient encryption
1371
+
1372
+ ### ID Provider Issues
1373
+
1374
+ **Problem**: `Member ID length mismatch`
1375
+
1376
+ **Solutions**:
1377
+ 1. Ensure same ID provider used for serialization and deserialization
1378
+ 2. Check configuration: `ecies.constants.idProvider.byteLength`
1379
+ 3. Don't mix ID providers in same application
1380
+
1381
+ ### Voting System Issues
1382
+
1383
+ **Problem**: `Already voted` error
1384
+
1385
+ **Solutions**:
1386
+ 1. Each voter can only vote once per poll
1387
+ 2. Check if voter already has a receipt
1388
+ 3. Use different Member instance for each voter
1389
+
1390
+ **Problem**: `Poll is closed` error
1391
+
1392
+ **Solutions**:
1393
+ 1. Cannot vote after `poll.close()` is called
1394
+ 2. Check poll status before voting
1395
+ 3. Create new poll if needed
1396
+
1397
+ ### Key Management Issues
1398
+
1399
+ **Problem**: `Invalid mnemonic phrase`
1400
+
1401
+ **Solutions**:
1402
+ 1. Ensure mnemonic is 12 or 24 words
1403
+ 2. Use `ecies.generateNewMnemonic()` to create valid mnemonics
1404
+ 3. Check for typos in mnemonic words
1405
+
1406
+ ### Cross-Platform Compatibility
1407
+
1408
+ **Problem**: Data encrypted in browser won't decrypt in Node.js
1409
+
1410
+ **Solutions**:
1411
+ 1. Ensure both use same protocol version (v4.0)
1412
+ 2. Use same ID provider configuration
1413
+ 3. Verify binary compatibility with `@digitaldefiance/node-ecies-lib`
1414
+
1415
+ ## FAQ
1416
+
1417
+ ### General Questions
1418
+
1419
+ **Q: What's the difference between ecies-lib and node-ecies-lib?**
1420
+
1421
+ A: `ecies-lib` is for browsers (Web Crypto API), `node-ecies-lib` is for Node.js (crypto module). They are binary compatible - data encrypted in one can be decrypted in the other.
1422
+
1423
+ **Q: Which encryption mode should I use?**
1424
+
1425
+ A:
1426
+ - **Basic**: Fixed-size data, minimal overhead
1427
+ - **WithLength**: Variable-size data, includes length prefix
1428
+ - **Multiple**: Encrypting for multiple recipients
1429
+
1430
+ **Q: Is this library production-ready?**
1431
+
1432
+ A: Yes. It has 1,200+ tests, 100% coverage on critical paths, and implements industry-standard protocols (ECIES v4.0, HKDF, AES-256-GCM).
1433
+
1434
+ ### ID Providers
1435
+
1436
+ **Q: Which ID provider should I use?**
1437
+
1438
+ A:
1439
+ - **MongoDB app**: ObjectIdProvider (12 bytes)
1440
+ - **Windows/.NET app**: GuidV4Provider (16 bytes, compact)
1441
+ - **Standard UUID**: UuidProvider (16 bytes, dashed format)
1442
+ - **Custom needs**: CustomIdProvider (1-255 bytes)
1443
+
1444
+ ### Voting System
1445
+
1446
+ **Q: Which voting method should I use?**
1447
+
1448
+ A:
1449
+ - **Simple elections**: Plurality (most votes wins)
1450
+ - **Multiple choices**: Approval voting
1451
+ - **Ranked preferences**: Ranked Choice (IRV)
1452
+ - **Score-based**: Score voting or STAR
1453
+ - **Proportional**: STV (Single Transferable Vote)
1454
+
1455
+ **Q: Are votes really private?**
1456
+
1457
+ A: Yes. Votes are encrypted with Paillier homomorphic encryption. The poll aggregator cannot decrypt individual votes - only the separate PollTallier with the private key can decrypt after poll closure.
1458
+
1459
+ **Q: How do I verify my vote was counted?**
1460
+
1461
+ A: Each voter receives a cryptographically signed receipt. Use `poll.verifyReceipt(voter, receipt)` to verify it's valid.
1462
+
1463
+ ### Security
1464
+
1465
+ **Q: How secure is the encryption?**
1466
+
1467
+ A: Uses industry-standard algorithms:
1468
+ - **Curve**: secp256k1 (same as Bitcoin)
1469
+ - **Key Derivation**: HKDF-SHA256 (RFC 5869)
1470
+ - **Symmetric**: AES-256-GCM (NIST approved)
1471
+ - **Hashing**: SHA-256/SHA-512
1472
+
1473
+ **Q: How do I securely store private keys?**
1474
+
1475
+ A:
1476
+ 1. Use `SecureString` for in-memory storage
1477
+ 2. Encrypt keys at rest with user password
1478
+ 3. Never log or transmit private keys
1479
+ 4. Call `dispose()` when done
1480
+
1481
+ ### Performance
1482
+
1483
+ **Q: How fast is encryption/decryption?**
1484
+
1485
+ A: Typical performance:
1486
+ - Small messages (<1KB): <1ms
1487
+ - Medium messages (1MB): ~50ms
1488
+ - Large files (1GB): ~5 seconds (streaming)
1489
+
1490
+ **Q: Can I encrypt large files?**
1491
+
1492
+ A: Yes. Use `EncryptionStream` for memory-efficient processing of files of any size (<10MB RAM usage).
1493
+
1329
1494
  ## ChangeLog
1330
1495
 
1331
- ### v4.16.x (v4.16.0 - v4.16.25)
1496
+ ### Recent Versions
1332
1497
 
1333
- **Voting Key Derivation Security Improvements**
1498
+ For detailed changelog, see [CHANGELOG.md](CHANGELOG.md) in the repository.
1334
1499
 
1335
- - **HKDF RFC 5869 Compliance**: When salt is not provided, now uses HashLen zeros (64 bytes for SHA-512) instead of empty array for consistency with Node.js
1336
- - **Private Key Normalization**: `deriveVotingKeysFromECDH` handles 31-byte private keys by padding to 32 bytes (occurs ~0.4% of the time with Node.js createECDH)
1337
- - **Uncompressed Public Keys**: Voting key derivation uses uncompressed format (65 bytes) for maximum entropy
1338
- - **Simplified Prime Generation**: Cleaner `generateDeterministicPrime` implementation
1339
- - **i18n Improvements**: Added `EciesComponentStrings` export with `BrandedPluralMasterStringsCollection` type for type-safe translations
1340
- - **String Key Enum Registration**: Added `registerStringKeyEnum(EciesStringKey)` for direct translation via `translateStringKey()`
1500
+ **v4.16.x** - Voting key derivation security improvements, HKDF RFC 5869 compliance
1501
+ **v4.13.0** - API naming improvements (SIMPLE→BASIC, SINGLE→WITH_LENGTH)
1502
+ **v4.12.0** - AESGCMService refactoring, JSON encryption
1503
+ **v4.10.7** - Strong typing for ID providers
1504
+ **v4.10.6** - Complete cryptographic voting system (15+ methods)
1505
+ **v4.0.0** - ECIES Protocol v4.0 (breaking changes)
1506
+ **v3.7.0** - Pluggable ID provider system
1507
+ **v3.0.0** - Streaming encryption
1341
1508
 
1342
- ### v4.13.0 - API Naming Improvements & Configuration Enhancements
1509
+ ### Breaking Changes Summary
1343
1510
 
1344
- **Breaking Changes:**
1511
+ **v4.13.0**: Encryption mode renaming, Guid class renamed
1512
+ **v4.12.0**: AESGCMService now instance-based
1513
+ **v4.0.0**: ECIES protocol v4.0, HKDF key derivation, compressed keys
1514
+
1515
+ See [CHANGELOG.md](CHANGELOG.md) for complete version history.
1516
+
1517
+ ## Testing
1518
+
1519
+ ### Testing Approach
1520
+
1521
+ The ecies-lib package employs a rigorous testing strategy with over 1,200 tests covering all cryptographic operations, protocol flows, and edge cases.
1345
1522
 
1346
1523
  - **Encryption Mode Renaming**:
1347
1524
  - `SIMPLE` → `BASIC` (constant)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digitaldefiance/ecies-lib",
3
- "version": "4.16.30",
3
+ "version": "4.17.0",
4
4
  "description": "Digital Defiance ECIES Library",
5
5
  "homepage": "https://github.com/Digital-Defiance/ecies-lib",
6
6
  "repository": {
@@ -62,7 +62,7 @@
62
62
  "license": "MIT",
63
63
  "packageManager": "yarn@4.11.0",
64
64
  "dependencies": {
65
- "@digitaldefiance/i18n-lib": "4.3.0",
65
+ "@digitaldefiance/i18n-lib": "4.3.1",
66
66
  "@ethereumjs/wallet": "^2.0.4",
67
67
  "@noble/curves": "^1.4.2",
68
68
  "@noble/hashes": "^1.4.0",