simple-hpke 0.0.9 → 0.0.11

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/dist/index.cjs CHANGED
@@ -1306,8 +1306,7 @@ function toString2(array, encoding = "utf8") {
1306
1306
  }
1307
1307
  __name(toString2, "toString");
1308
1308
 
1309
- // src/index.ts
1310
- var subtle = globalThis.crypto.subtle;
1309
+ // src/constants.ts
1311
1310
  var KEM_ID = 32;
1312
1311
  var KDF_ID = 1;
1313
1312
  var AEAD_ID = 2;
@@ -1318,6 +1317,7 @@ var ENC_LENGTH = 32;
1318
1317
  var AEAD_TAG_LENGTH = 16;
1319
1318
  var MODE_BASE = 0;
1320
1319
  var HPKE_V1 = new TextEncoder().encode("HPKE-v1");
1320
+ var WRAPPED_LEN_PREFIX = 2;
1321
1321
  var KEM_SUITE_ID = concat2(
1322
1322
  new TextEncoder().encode("KEM"),
1323
1323
  i2osp(KEM_ID, 2)
@@ -1328,174 +1328,58 @@ var HPKE_SUITE_ID = concat2(
1328
1328
  i2osp(KDF_ID, 2),
1329
1329
  i2osp(AEAD_ID, 2)
1330
1330
  );
1331
- async function seal(recipient, aesKey, opts) {
1332
- const info = normalizeInfo(opts?.info);
1333
- let keyBytes;
1334
- if (aesKey instanceof Uint8Array) {
1335
- validateRawKeyBytes(aesKey);
1336
- keyBytes = aesKey;
1337
- } else if (aesKey) {
1338
- keyBytes = await exportAesKeyBytes(aesKey);
1339
- validateRawKeyBytes(keyBytes);
1340
- } else {
1341
- const keysize = opts?.keysize ?? 256;
1342
- validateKeysize(keysize);
1343
- keyBytes = globalThis.crypto.getRandomValues(
1344
- new Uint8Array(keysize / 8)
1345
- );
1346
- }
1347
- const publicKey = await resolveRecipientPublicKey(recipient);
1348
- const { sharedSecret, enc } = await encap(publicKey);
1349
- const { key, baseNonce } = await keySchedule(sharedSecret, info);
1350
- const ciphertext = await aeadSeal(key, baseNonce, keyBytes);
1351
- const wrapped = concat2(enc, ciphertext);
1352
- const aesGcmKey = await importAesKey(keyBytes);
1353
- return { wrapped, key: aesGcmKey };
1354
- }
1355
- __name(seal, "seal");
1356
- async function openBytes(keypair, wrapped, opts) {
1357
- const keyBytes = await openRawBytes(keypair, wrapped, opts);
1358
- return importAesKey(keyBytes);
1359
- }
1360
- __name(openBytes, "openBytes");
1361
- async function openRawBytes(keypair, wrapped, opts) {
1362
- if (wrapped.byteLength < ENC_LENGTH + AEAD_TAG_LENGTH) {
1363
- throw new Error("malformed envelope: too short");
1364
- }
1365
- const info = normalizeInfo(opts?.info);
1366
- const enc = wrapped.slice(0, ENC_LENGTH);
1367
- const ciphertext = wrapped.slice(ENC_LENGTH);
1368
- const sharedSecret = await decap(enc, keypair);
1369
- const { key, baseNonce } = await keySchedule(sharedSecret, info);
1370
- return aeadOpen(key, baseNonce, ciphertext);
1371
- }
1372
- __name(openRawBytes, "openRawBytes");
1373
- var open = Object.assign(openBytes, {
1374
- raw: openRawBytes
1375
- });
1376
- var WRAPPED_LEN_PREFIX = 2;
1377
- var encrypt = Object.assign(encryptBytes, {
1378
- asString: encryptToString
1379
- });
1380
- var decrypt = Object.assign(decryptBytes, {
1381
- asString: decryptToString,
1382
- fromString: decryptFromString
1383
- });
1384
- async function decryptBytes(keypair, message, opts) {
1385
- if (message.byteLength < WRAPPED_LEN_PREFIX) {
1386
- throw new Error("malformed message: too short");
1387
- }
1388
- const wrappedLen = message[0] << 8 | message[1];
1389
- const ivStart = WRAPPED_LEN_PREFIX + wrappedLen;
1390
- const ctStart = ivStart + NN;
1391
- if (message.byteLength < ctStart + AEAD_TAG_LENGTH) {
1392
- throw new Error("malformed message: too short");
1393
- }
1394
- const wrapped = message.slice(WRAPPED_LEN_PREFIX, ivStart);
1395
- const iv = message.slice(ivStart, ctStart);
1396
- const ciphertext = message.slice(ctStart);
1397
- const keyBytes = await openRawBytes(
1398
- keypair,
1399
- wrapped,
1400
- opts?.info !== void 0 ? { info: opts.info } : void 0
1401
- );
1402
- const key = await importAesKeyDecryptOnly(keyBytes);
1403
- const pt = await subtle.decrypt(
1404
- { name: "AES-GCM", iv },
1405
- key,
1406
- ciphertext
1407
- );
1408
- return new Uint8Array(pt);
1409
- }
1410
- __name(decryptBytes, "decryptBytes");
1411
- async function decryptToString(keypair, message, opts) {
1412
- const bytes = await decryptBytes(keypair, message, opts);
1413
- return new TextDecoder().decode(bytes);
1414
- }
1415
- __name(decryptToString, "decryptToString");
1416
- async function decryptFromString(keypair, message, opts) {
1417
- const bytes = fromString2(message, "base64url");
1418
- const plaintext = await decryptBytes(
1419
- keypair,
1420
- bytes,
1421
- opts?.info !== void 0 ? { info: opts.info } : void 0
1422
- );
1423
- return opts?.buffer ? plaintext : new TextDecoder().decode(plaintext);
1424
- }
1425
- __name(decryptFromString, "decryptFromString");
1426
- function validateKeysize(keysize) {
1427
- if (keysize !== 128 && keysize !== 256) {
1428
- throw new Error(
1429
- `invalid keysize: ${keysize} (expected 128 or 256)`
1430
- );
1431
- }
1432
- }
1433
- __name(validateKeysize, "validateKeysize");
1434
- function validateRawKeyBytes(raw) {
1435
- if (raw.length !== 16 && raw.length !== 32) {
1436
- throw new Error(
1437
- `invalid aesKey length: ${raw.length} bytes (expected 16 or 32)`
1438
- );
1439
- }
1440
- }
1441
- __name(validateRawKeyBytes, "validateRawKeyBytes");
1442
- function normalizeInfo(info) {
1443
- if (info === void 0 || info === null) return new Uint8Array(0);
1444
- if (typeof info === "string") return new TextEncoder().encode(info);
1445
- return info;
1446
- }
1447
- __name(normalizeInfo, "normalizeInfo");
1448
- async function exportAesKeyBytes(key) {
1449
- if (!key.extractable) {
1450
- throw new Error(
1451
- "aesKey must be extractable: its raw bytes are what get sealed"
1452
- );
1453
- }
1454
- return new Uint8Array(await subtle.exportKey("raw", key));
1455
- }
1456
- __name(exportAesKeyBytes, "exportAesKeyBytes");
1457
- async function importAesKey(raw) {
1458
- return subtle.importKey(
1331
+
1332
+ // src/util.ts
1333
+ var subtle = globalThis.crypto.subtle;
1334
+ async function aeadSeal(key, nonce, plaintext) {
1335
+ const k = await subtle.importKey(
1459
1336
  "raw",
1460
- raw,
1337
+ key,
1461
1338
  { name: "AES-GCM" },
1462
- true,
1463
- ["encrypt", "decrypt"]
1339
+ false,
1340
+ ["encrypt"]
1341
+ );
1342
+ const ct = await subtle.encrypt(
1343
+ { name: "AES-GCM", iv: nonce },
1344
+ k,
1345
+ plaintext
1464
1346
  );
1347
+ return new Uint8Array(ct);
1465
1348
  }
1466
- __name(importAesKey, "importAesKey");
1467
- async function importAesKeyDecryptOnly(raw) {
1468
- return subtle.importKey(
1349
+ __name(aeadSeal, "aeadSeal");
1350
+ async function aeadOpen(key, nonce, ciphertext) {
1351
+ const k = await subtle.importKey(
1469
1352
  "raw",
1470
- raw,
1353
+ key,
1471
1354
  { name: "AES-GCM" },
1472
1355
  false,
1473
1356
  ["decrypt"]
1474
1357
  );
1358
+ const pt = await subtle.decrypt(
1359
+ { name: "AES-GCM", iv: nonce },
1360
+ k,
1361
+ ciphertext
1362
+ );
1363
+ return new Uint8Array(pt);
1475
1364
  }
1476
- __name(importAesKeyDecryptOnly, "importAesKeyDecryptOnly");
1477
- function i2osp(n, len) {
1478
- const out = new Uint8Array(len);
1479
- let v = n;
1480
- for (let i = len - 1; i >= 0; i--) {
1481
- out[i] = v & 255;
1482
- v = Math.floor(v / 256);
1483
- }
1484
- return out;
1365
+ __name(aeadOpen, "aeadOpen");
1366
+ async function encryptBytes(recipient, message, aesKey, opts) {
1367
+ const plaintext = typeof message === "string" ? new TextEncoder().encode(message) : message;
1368
+ const { wrapped, key } = await seal(recipient, aesKey, opts);
1369
+ const iv = globalThis.crypto.getRandomValues(new Uint8Array(NN));
1370
+ const ct = new Uint8Array(await subtle.encrypt(
1371
+ { name: "AES-GCM", iv },
1372
+ key,
1373
+ plaintext
1374
+ ));
1375
+ return concat2(i2osp(wrapped.length, WRAPPED_LEN_PREFIX), wrapped, iv, ct);
1485
1376
  }
1486
- __name(i2osp, "i2osp");
1487
- function concat2(...arrays) {
1488
- let total = 0;
1489
- for (const a of arrays) total += a.length;
1490
- const out = new Uint8Array(total);
1491
- let offset = 0;
1492
- for (const a of arrays) {
1493
- out.set(a, offset);
1494
- offset += a.length;
1495
- }
1496
- return out;
1377
+ __name(encryptBytes, "encryptBytes");
1378
+ async function encryptToString(recipient, message, aesKey, opts) {
1379
+ const envelope = await encryptBytes(recipient, message, aesKey, opts);
1380
+ return toString2(envelope, opts?.encoding ?? "base64url");
1497
1381
  }
1498
- __name(concat2, "concat");
1382
+ __name(encryptToString, "encryptToString");
1499
1383
  async function hmac(key, data) {
1500
1384
  const k = await subtle.importKey(
1501
1385
  "raw",
@@ -1664,6 +1548,176 @@ async function decap(enc, keypair) {
1664
1548
  return extractAndExpand(dhBytes, kemContext);
1665
1549
  }
1666
1550
  __name(decap, "decap");
1551
+ function i2osp(n, len) {
1552
+ const out = new Uint8Array(len);
1553
+ let v = n;
1554
+ for (let i = len - 1; i >= 0; i--) {
1555
+ out[i] = v & 255;
1556
+ v = Math.floor(v / 256);
1557
+ }
1558
+ return out;
1559
+ }
1560
+ __name(i2osp, "i2osp");
1561
+ function concat2(...arrays) {
1562
+ let total = 0;
1563
+ for (const a of arrays) total += a.length;
1564
+ const out = new Uint8Array(total);
1565
+ let offset = 0;
1566
+ for (const a of arrays) {
1567
+ out.set(a, offset);
1568
+ offset += a.length;
1569
+ }
1570
+ return out;
1571
+ }
1572
+ __name(concat2, "concat");
1573
+
1574
+ // src/index.ts
1575
+ var subtle2 = globalThis.crypto.subtle;
1576
+ async function seal(recipient, aesKey, opts) {
1577
+ const info = normalizeInfo(opts?.info);
1578
+ let keyBytes;
1579
+ if (aesKey instanceof Uint8Array) {
1580
+ validateRawKeyBytes(aesKey);
1581
+ keyBytes = aesKey;
1582
+ } else if (aesKey) {
1583
+ keyBytes = await exportAesKeyBytes(aesKey);
1584
+ validateRawKeyBytes(keyBytes);
1585
+ } else {
1586
+ const keysize = opts?.keysize ?? 256;
1587
+ validateKeysize(keysize);
1588
+ keyBytes = globalThis.crypto.getRandomValues(
1589
+ new Uint8Array(keysize / 8)
1590
+ );
1591
+ }
1592
+ const publicKey = await resolveRecipientPublicKey(recipient);
1593
+ const { sharedSecret, enc } = await encap(publicKey);
1594
+ const { key, baseNonce } = await keySchedule(sharedSecret, info);
1595
+ const ciphertext = await aeadSeal(key, baseNonce, keyBytes);
1596
+ const wrapped = concat2(enc, ciphertext);
1597
+ const aesGcmKey = await importAesKey(keyBytes);
1598
+ return { wrapped, key: aesGcmKey };
1599
+ }
1600
+ __name(seal, "seal");
1601
+ var open = Object.assign(openBytes, {
1602
+ raw: openRawBytes
1603
+ });
1604
+ async function openBytes(keypair, wrapped, opts) {
1605
+ const keyBytes = await openRawBytes(keypair, wrapped, opts);
1606
+ return importAesKey(keyBytes);
1607
+ }
1608
+ __name(openBytes, "openBytes");
1609
+ async function openRawBytes(keypair, wrapped, opts) {
1610
+ if (wrapped.byteLength < ENC_LENGTH + AEAD_TAG_LENGTH) {
1611
+ throw new Error("malformed envelope: too short");
1612
+ }
1613
+ const info = normalizeInfo(opts?.info);
1614
+ const enc = wrapped.slice(0, ENC_LENGTH);
1615
+ const ciphertext = wrapped.slice(ENC_LENGTH);
1616
+ const sharedSecret = await decap(enc, keypair);
1617
+ const { key, baseNonce } = await keySchedule(sharedSecret, info);
1618
+ return aeadOpen(key, baseNonce, ciphertext);
1619
+ }
1620
+ __name(openRawBytes, "openRawBytes");
1621
+ var encrypt = Object.assign(encryptBytes, {
1622
+ asString: encryptToString
1623
+ });
1624
+ var decrypt = Object.assign(decryptBytes, {
1625
+ asString: decryptToString,
1626
+ fromString: decryptFromString
1627
+ });
1628
+ async function decryptBytes(keypair, message, opts) {
1629
+ if (message.byteLength < WRAPPED_LEN_PREFIX) {
1630
+ throw new Error("malformed message: too short");
1631
+ }
1632
+ const wrappedLen = message[0] << 8 | message[1];
1633
+ const ivStart = WRAPPED_LEN_PREFIX + wrappedLen;
1634
+ const ctStart = ivStart + NN;
1635
+ if (message.byteLength < ctStart + AEAD_TAG_LENGTH) {
1636
+ throw new Error("malformed message: too short");
1637
+ }
1638
+ const wrapped = message.slice(WRAPPED_LEN_PREFIX, ivStart);
1639
+ const iv = message.slice(ivStart, ctStart);
1640
+ const ciphertext = message.slice(ctStart);
1641
+ const keyBytes = await openRawBytes(
1642
+ keypair,
1643
+ wrapped,
1644
+ opts?.info !== void 0 ? { info: opts.info } : void 0
1645
+ );
1646
+ const key = await importAesKeyDecryptOnly(keyBytes);
1647
+ const pt = await subtle2.decrypt(
1648
+ { name: "AES-GCM", iv },
1649
+ key,
1650
+ ciphertext
1651
+ );
1652
+ return new Uint8Array(pt);
1653
+ }
1654
+ __name(decryptBytes, "decryptBytes");
1655
+ async function decryptToString(keypair, message, opts) {
1656
+ const bytes = await decryptBytes(keypair, message, opts);
1657
+ return new TextDecoder().decode(bytes);
1658
+ }
1659
+ __name(decryptToString, "decryptToString");
1660
+ async function decryptFromString(keypair, message, opts) {
1661
+ const bytes = fromString2(message, "base64url");
1662
+ const plaintext = await decryptBytes(
1663
+ keypair,
1664
+ bytes,
1665
+ opts?.info !== void 0 ? { info: opts.info } : void 0
1666
+ );
1667
+ return opts?.buffer ? plaintext : new TextDecoder().decode(plaintext);
1668
+ }
1669
+ __name(decryptFromString, "decryptFromString");
1670
+ function validateKeysize(keysize) {
1671
+ if (keysize !== 128 && keysize !== 256) {
1672
+ throw new Error(
1673
+ `invalid keysize: ${keysize} (expected 128 or 256)`
1674
+ );
1675
+ }
1676
+ }
1677
+ __name(validateKeysize, "validateKeysize");
1678
+ function validateRawKeyBytes(raw) {
1679
+ if (raw.length !== 16 && raw.length !== 32) {
1680
+ throw new Error(
1681
+ `invalid aesKey length: ${raw.length} bytes (expected 16 or 32)`
1682
+ );
1683
+ }
1684
+ }
1685
+ __name(validateRawKeyBytes, "validateRawKeyBytes");
1686
+ function normalizeInfo(info) {
1687
+ if (info === void 0 || info === null) return new Uint8Array(0);
1688
+ if (typeof info === "string") return new TextEncoder().encode(info);
1689
+ return info;
1690
+ }
1691
+ __name(normalizeInfo, "normalizeInfo");
1692
+ async function exportAesKeyBytes(key) {
1693
+ if (!key.extractable) {
1694
+ throw new Error(
1695
+ "aesKey must be extractable: its raw bytes are what get sealed"
1696
+ );
1697
+ }
1698
+ return new Uint8Array(await subtle2.exportKey("raw", key));
1699
+ }
1700
+ __name(exportAesKeyBytes, "exportAesKeyBytes");
1701
+ async function importAesKey(raw) {
1702
+ return subtle2.importKey(
1703
+ "raw",
1704
+ raw,
1705
+ { name: "AES-GCM" },
1706
+ true,
1707
+ ["encrypt", "decrypt"]
1708
+ );
1709
+ }
1710
+ __name(importAesKey, "importAesKey");
1711
+ async function importAesKeyDecryptOnly(raw) {
1712
+ return subtle2.importKey(
1713
+ "raw",
1714
+ raw,
1715
+ { name: "AES-GCM" },
1716
+ false,
1717
+ ["decrypt"]
1718
+ );
1719
+ }
1720
+ __name(importAesKeyDecryptOnly, "importAesKeyDecryptOnly");
1667
1721
  async function keySchedule(sharedSecret, info) {
1668
1722
  const empty2 = new Uint8Array(0);
1669
1723
  const pskIdHash = await labeledExtract(
@@ -1702,53 +1756,4 @@ async function keySchedule(sharedSecret, info) {
1702
1756
  return { key, baseNonce };
1703
1757
  }
1704
1758
  __name(keySchedule, "keySchedule");
1705
- async function aeadSeal(key, nonce, plaintext) {
1706
- const k = await subtle.importKey(
1707
- "raw",
1708
- key,
1709
- { name: "AES-GCM" },
1710
- false,
1711
- ["encrypt"]
1712
- );
1713
- const ct = await subtle.encrypt(
1714
- { name: "AES-GCM", iv: nonce },
1715
- k,
1716
- plaintext
1717
- );
1718
- return new Uint8Array(ct);
1719
- }
1720
- __name(aeadSeal, "aeadSeal");
1721
- async function aeadOpen(key, nonce, ciphertext) {
1722
- const k = await subtle.importKey(
1723
- "raw",
1724
- key,
1725
- { name: "AES-GCM" },
1726
- false,
1727
- ["decrypt"]
1728
- );
1729
- const pt = await subtle.decrypt(
1730
- { name: "AES-GCM", iv: nonce },
1731
- k,
1732
- ciphertext
1733
- );
1734
- return new Uint8Array(pt);
1735
- }
1736
- __name(aeadOpen, "aeadOpen");
1737
- async function encryptBytes(recipient, message, aesKey, opts) {
1738
- const plaintext = typeof message === "string" ? new TextEncoder().encode(message) : message;
1739
- const { wrapped, key } = await seal(recipient, aesKey, opts);
1740
- const iv = globalThis.crypto.getRandomValues(new Uint8Array(NN));
1741
- const ct = new Uint8Array(await subtle.encrypt(
1742
- { name: "AES-GCM", iv },
1743
- key,
1744
- plaintext
1745
- ));
1746
- return concat2(i2osp(wrapped.length, WRAPPED_LEN_PREFIX), wrapped, iv, ct);
1747
- }
1748
- __name(encryptBytes, "encryptBytes");
1749
- async function encryptToString(recipient, message, aesKey, opts) {
1750
- const envelope = await encryptBytes(recipient, message, aesKey, opts);
1751
- return toString2(envelope, opts?.encoding ?? "base64url");
1752
- }
1753
- __name(encryptToString, "encryptToString");
1754
1759
  //# sourceMappingURL=index.cjs.map