simple-hpke 0.3.1 → 0.3.3
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/README.md +82 -14
- package/dist/constants.cjs +87 -28
- package/dist/constants.cjs.map +2 -2
- package/dist/constants.js +87 -28
- package/dist/constants.js.map +2 -2
- package/dist/constants.min.cjs +1 -1
- package/dist/constants.min.cjs.map +3 -3
- package/dist/constants.min.js +1 -1
- package/dist/constants.min.js.map +3 -3
- package/dist/index.cjs +99 -29
- package/dist/index.cjs.map +2 -2
- package/dist/index.d.ts +10 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +99 -29
- package/dist/index.js.map +2 -2
- package/dist/index.min.cjs +1 -1
- package/dist/index.min.cjs.map +3 -3
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +3 -3
- package/dist/meta.json +18 -16
- package/dist/util.cjs +99 -29
- package/dist/util.cjs.map +2 -2
- package/dist/util.d.ts +24 -2
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +99 -29
- package/dist/util.js.map +2 -2
- package/dist/util.min.cjs +1 -1
- package/dist/util.min.cjs.map +3 -3
- package/dist/util.min.js +1 -1
- package/dist/util.min.js.map +3 -3
- package/package.json +5 -4
package/dist/constants.js
CHANGED
|
@@ -1356,7 +1356,16 @@ async function decryptToString(keypair, message, opts) {
|
|
|
1356
1356
|
}
|
|
1357
1357
|
__name(decryptToString, "decryptToString");
|
|
1358
1358
|
async function decryptFromString(keypair, message, opts) {
|
|
1359
|
-
|
|
1359
|
+
let bytes;
|
|
1360
|
+
try {
|
|
1361
|
+
bytes = fromString2(message, "base64url");
|
|
1362
|
+
} catch (err) {
|
|
1363
|
+
throw new HpkeError(
|
|
1364
|
+
"ERR_MALFORMED_MESSAGE",
|
|
1365
|
+
"malformed message: not base64url",
|
|
1366
|
+
{ cause: err }
|
|
1367
|
+
);
|
|
1368
|
+
}
|
|
1360
1369
|
const plaintext = await decryptBytes(
|
|
1361
1370
|
keypair,
|
|
1362
1371
|
bytes,
|
|
@@ -1484,6 +1493,12 @@ async function encryptKey(recipient, aesKey, opts) {
|
|
|
1484
1493
|
validateRawKeyBytes(aesKey);
|
|
1485
1494
|
keyBytes = aesKey;
|
|
1486
1495
|
} else if (aesKey) {
|
|
1496
|
+
if (aesKey.algorithm.name !== "AES-GCM") {
|
|
1497
|
+
throw new HpkeError(
|
|
1498
|
+
"ERR_INVALID_AES_KEY",
|
|
1499
|
+
"aesKey must be an AES-GCM key, got " + aesKey.algorithm.name
|
|
1500
|
+
);
|
|
1501
|
+
}
|
|
1487
1502
|
keyBytes = await exportAesKeyBytes(aesKey);
|
|
1488
1503
|
validateRawKeyBytes(keyBytes);
|
|
1489
1504
|
} else {
|
|
@@ -1498,6 +1513,7 @@ async function encryptKey(recipient, aesKey, opts) {
|
|
|
1498
1513
|
const { key, baseNonce } = await keySchedule(sharedSecret, info);
|
|
1499
1514
|
const ciphertext = await aeadSeal(key, baseNonce, keyBytes);
|
|
1500
1515
|
const wrapped = concat2(enc, ciphertext);
|
|
1516
|
+
if (aesKey instanceof CryptoKey) return { wrapped, key: aesKey };
|
|
1501
1517
|
const aesGcmKey = await importAesKey(
|
|
1502
1518
|
keyBytes,
|
|
1503
1519
|
opts?.extractable ?? false
|
|
@@ -1550,6 +1566,12 @@ async function aeadOpen(key, nonce, ciphertext) {
|
|
|
1550
1566
|
}
|
|
1551
1567
|
__name(aeadOpen, "aeadOpen");
|
|
1552
1568
|
async function encryptBytes(recipient, message, aesKey, opts) {
|
|
1569
|
+
if (aesKey instanceof CryptoKey && !aesKey.usages.includes("encrypt")) {
|
|
1570
|
+
throw new HpkeError(
|
|
1571
|
+
"ERR_INVALID_AES_KEY",
|
|
1572
|
+
'aesKey is missing the "encrypt" usage, which encrypt needs to encrypt the message'
|
|
1573
|
+
);
|
|
1574
|
+
}
|
|
1553
1575
|
const plaintext = typeof message === "string" ? new TextEncoder().encode(message) : message;
|
|
1554
1576
|
const { wrapped, key } = await encryptKey(recipient, aesKey, opts);
|
|
1555
1577
|
const iv = globalThis.crypto.getRandomValues(new Uint8Array(NN));
|
|
@@ -1648,37 +1670,28 @@ async function resolveRecipientPublicKey(recipient) {
|
|
|
1648
1670
|
return importRawPublic(recipient);
|
|
1649
1671
|
}
|
|
1650
1672
|
if (recipient instanceof CryptoKey) {
|
|
1651
|
-
|
|
1652
|
-
throw new HpkeError(
|
|
1653
|
-
"ERR_INVALID_RECIPIENT_KEY",
|
|
1654
|
-
"recipient CryptoKey must be a public key"
|
|
1655
|
-
);
|
|
1656
|
-
}
|
|
1657
|
-
assertX25519Algorithm(
|
|
1658
|
-
recipient,
|
|
1659
|
-
"recipient CryptoKey",
|
|
1660
|
-
"ERR_INVALID_RECIPIENT_KEY"
|
|
1661
|
-
);
|
|
1662
|
-
return recipient;
|
|
1673
|
+
return assertRecipientPublicKey(recipient, "recipient CryptoKey");
|
|
1663
1674
|
}
|
|
1664
1675
|
if (typeof recipient.publicKey === "string") {
|
|
1665
1676
|
const { publicKey, encoding } = recipient;
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
if (pair.publicKey.type !== "public") {
|
|
1677
|
+
let decoded;
|
|
1678
|
+
try {
|
|
1679
|
+
decoded = fromString2(publicKey, encoding ?? "base64url");
|
|
1680
|
+
} catch (err) {
|
|
1671
1681
|
throw new HpkeError(
|
|
1672
1682
|
"ERR_INVALID_RECIPIENT_KEY",
|
|
1673
|
-
|
|
1683
|
+
`recipient publicKey string does not decode as ${encoding ?? "base64url"}`,
|
|
1684
|
+
{ cause: err }
|
|
1674
1685
|
);
|
|
1675
1686
|
}
|
|
1676
|
-
|
|
1687
|
+
return importRawPublic(decoded);
|
|
1688
|
+
}
|
|
1689
|
+
const pair = recipient;
|
|
1690
|
+
if (pair.publicKey instanceof CryptoKey) {
|
|
1691
|
+
return assertRecipientPublicKey(
|
|
1677
1692
|
pair.publicKey,
|
|
1678
|
-
"recipient keypair publicKey"
|
|
1679
|
-
"ERR_INVALID_RECIPIENT_KEY"
|
|
1693
|
+
"recipient keypair publicKey"
|
|
1680
1694
|
);
|
|
1681
|
-
return pair.publicKey;
|
|
1682
1695
|
}
|
|
1683
1696
|
throw new HpkeError(
|
|
1684
1697
|
"ERR_INVALID_RECIPIENT_KEY",
|
|
@@ -1686,6 +1699,23 @@ async function resolveRecipientPublicKey(recipient) {
|
|
|
1686
1699
|
);
|
|
1687
1700
|
}
|
|
1688
1701
|
__name(resolveRecipientPublicKey, "resolveRecipientPublicKey");
|
|
1702
|
+
function assertRecipientPublicKey(key, context) {
|
|
1703
|
+
if (key.type !== "public") {
|
|
1704
|
+
throw new HpkeError(
|
|
1705
|
+
"ERR_INVALID_RECIPIENT_KEY",
|
|
1706
|
+
`${context} must be a public key`
|
|
1707
|
+
);
|
|
1708
|
+
}
|
|
1709
|
+
assertX25519Algorithm(key, context, "ERR_INVALID_RECIPIENT_KEY");
|
|
1710
|
+
if (!key.extractable) {
|
|
1711
|
+
throw new HpkeError(
|
|
1712
|
+
"ERR_INVALID_RECIPIENT_KEY",
|
|
1713
|
+
`${context} must be extractable (the KEM exports it)`
|
|
1714
|
+
);
|
|
1715
|
+
}
|
|
1716
|
+
return key;
|
|
1717
|
+
}
|
|
1718
|
+
__name(assertRecipientPublicKey, "assertRecipientPublicKey");
|
|
1689
1719
|
function assertX25519Algorithm(key, context, code2) {
|
|
1690
1720
|
if (key.algorithm.name !== "X25519") {
|
|
1691
1721
|
throw new HpkeError(
|
|
@@ -1696,11 +1726,23 @@ function assertX25519Algorithm(key, context, code2) {
|
|
|
1696
1726
|
}
|
|
1697
1727
|
__name(assertX25519Algorithm, "assertX25519Algorithm");
|
|
1698
1728
|
async function dh(priv, pub) {
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1729
|
+
let bits;
|
|
1730
|
+
try {
|
|
1731
|
+
bits = await subtle2.deriveBits(
|
|
1732
|
+
{ name: "X25519", public: pub },
|
|
1733
|
+
priv,
|
|
1734
|
+
256
|
|
1735
|
+
);
|
|
1736
|
+
} catch (err) {
|
|
1737
|
+
if (err?.name === "OperationError") {
|
|
1738
|
+
throw new HpkeError(
|
|
1739
|
+
"ERR_SMALL_ORDER_KEY",
|
|
1740
|
+
"X25519 deriveBits rejected a small-order public key",
|
|
1741
|
+
{ cause: err }
|
|
1742
|
+
);
|
|
1743
|
+
}
|
|
1744
|
+
throw err;
|
|
1745
|
+
}
|
|
1704
1746
|
const bytes = new Uint8Array(bits);
|
|
1705
1747
|
if (bytes.every((b) => b === 0)) {
|
|
1706
1748
|
throw new HpkeError(
|
|
@@ -1753,6 +1795,23 @@ async function decap(enc, keypair) {
|
|
|
1753
1795
|
"keypair.privateKey",
|
|
1754
1796
|
"ERR_INVALID_KEYPAIR"
|
|
1755
1797
|
);
|
|
1798
|
+
if (!keypair.privateKey.usages.includes("deriveBits")) {
|
|
1799
|
+
throw new HpkeError(
|
|
1800
|
+
"ERR_INVALID_KEYPAIR",
|
|
1801
|
+
"keypair.privateKey must have the deriveBits usage"
|
|
1802
|
+
);
|
|
1803
|
+
}
|
|
1804
|
+
if (keypair.publicKey.type !== "public" || !keypair.publicKey.extractable) {
|
|
1805
|
+
throw new HpkeError(
|
|
1806
|
+
"ERR_INVALID_KEYPAIR",
|
|
1807
|
+
"keypair.publicKey must be an extractable public key"
|
|
1808
|
+
);
|
|
1809
|
+
}
|
|
1810
|
+
assertX25519Algorithm(
|
|
1811
|
+
keypair.publicKey,
|
|
1812
|
+
"keypair.publicKey",
|
|
1813
|
+
"ERR_INVALID_KEYPAIR"
|
|
1814
|
+
);
|
|
1756
1815
|
const pkE = await subtle2.importKey(
|
|
1757
1816
|
"raw",
|
|
1758
1817
|
enc,
|