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/meta.json
CHANGED
|
@@ -702,7 +702,7 @@
|
|
|
702
702
|
"format": "esm"
|
|
703
703
|
},
|
|
704
704
|
"src/index.ts": {
|
|
705
|
-
"bytes":
|
|
705
|
+
"bytes": 15697,
|
|
706
706
|
"imports": [
|
|
707
707
|
{
|
|
708
708
|
"path": "node_modules/uint8arrays/dist/src/index.js",
|
|
@@ -738,7 +738,7 @@
|
|
|
738
738
|
"format": "esm"
|
|
739
739
|
},
|
|
740
740
|
"src/util.ts": {
|
|
741
|
-
"bytes":
|
|
741
|
+
"bytes": 22056,
|
|
742
742
|
"imports": [
|
|
743
743
|
{
|
|
744
744
|
"path": "node_modules/uint8arrays/dist/src/index.js",
|
|
@@ -785,7 +785,7 @@
|
|
|
785
785
|
"imports": [],
|
|
786
786
|
"exports": [],
|
|
787
787
|
"inputs": {},
|
|
788
|
-
"bytes":
|
|
788
|
+
"bytes": 128024
|
|
789
789
|
},
|
|
790
790
|
"dist/constants.js": {
|
|
791
791
|
"imports": [],
|
|
@@ -896,16 +896,16 @@
|
|
|
896
896
|
"bytesInOutput": 215
|
|
897
897
|
},
|
|
898
898
|
"src/index.ts": {
|
|
899
|
-
"bytesInOutput":
|
|
899
|
+
"bytesInOutput": 6418
|
|
900
900
|
},
|
|
901
901
|
"src/util.ts": {
|
|
902
|
-
"bytesInOutput":
|
|
902
|
+
"bytesInOutput": 8581
|
|
903
903
|
},
|
|
904
904
|
"src/constants.ts": {
|
|
905
905
|
"bytesInOutput": 551
|
|
906
906
|
}
|
|
907
907
|
},
|
|
908
|
-
"bytes":
|
|
908
|
+
"bytes": 54253
|
|
909
909
|
},
|
|
910
910
|
"dist/errors.js.map": {
|
|
911
911
|
"imports": [],
|
|
@@ -930,7 +930,7 @@
|
|
|
930
930
|
"imports": [],
|
|
931
931
|
"exports": [],
|
|
932
932
|
"inputs": {},
|
|
933
|
-
"bytes":
|
|
933
|
+
"bytes": 128969
|
|
934
934
|
},
|
|
935
935
|
"dist/index.js": {
|
|
936
936
|
"imports": [],
|
|
@@ -941,7 +941,8 @@
|
|
|
941
941
|
"encrypt",
|
|
942
942
|
"encryptKey",
|
|
943
943
|
"keyId",
|
|
944
|
-
"open"
|
|
944
|
+
"open",
|
|
945
|
+
"verifyKeyId"
|
|
945
946
|
],
|
|
946
947
|
"entryPoint": "src/index.ts",
|
|
947
948
|
"inputs": {
|
|
@@ -1036,19 +1037,19 @@
|
|
|
1036
1037
|
"bytesInOutput": 551
|
|
1037
1038
|
},
|
|
1038
1039
|
"src/util.ts": {
|
|
1039
|
-
"bytesInOutput":
|
|
1040
|
+
"bytesInOutput": 9693
|
|
1040
1041
|
},
|
|
1041
1042
|
"src/index.ts": {
|
|
1042
|
-
"bytesInOutput":
|
|
1043
|
+
"bytesInOutput": 6589
|
|
1043
1044
|
}
|
|
1044
1045
|
},
|
|
1045
|
-
"bytes":
|
|
1046
|
+
"bytes": 55429
|
|
1046
1047
|
},
|
|
1047
1048
|
"dist/util.js.map": {
|
|
1048
1049
|
"imports": [],
|
|
1049
1050
|
"exports": [],
|
|
1050
1051
|
"inputs": {},
|
|
1051
|
-
"bytes":
|
|
1052
|
+
"bytes": 128835
|
|
1052
1053
|
},
|
|
1053
1054
|
"dist/util.js": {
|
|
1054
1055
|
"imports": [],
|
|
@@ -1065,7 +1066,8 @@
|
|
|
1065
1066
|
"keyId",
|
|
1066
1067
|
"labeledExpand",
|
|
1067
1068
|
"labeledExtract",
|
|
1068
|
-
"resolveRecipientPublicKey"
|
|
1069
|
+
"resolveRecipientPublicKey",
|
|
1070
|
+
"verifyKeyId"
|
|
1069
1071
|
],
|
|
1070
1072
|
"entryPoint": "src/util.ts",
|
|
1071
1073
|
"inputs": {
|
|
@@ -1160,13 +1162,13 @@
|
|
|
1160
1162
|
"bytesInOutput": 551
|
|
1161
1163
|
},
|
|
1162
1164
|
"src/index.ts": {
|
|
1163
|
-
"bytesInOutput":
|
|
1165
|
+
"bytesInOutput": 6418
|
|
1164
1166
|
},
|
|
1165
1167
|
"src/util.ts": {
|
|
1166
|
-
"bytesInOutput":
|
|
1168
|
+
"bytesInOutput": 9709
|
|
1167
1169
|
}
|
|
1168
1170
|
},
|
|
1169
|
-
"bytes":
|
|
1171
|
+
"bytes": 55374
|
|
1170
1172
|
}
|
|
1171
1173
|
}
|
|
1172
1174
|
}
|
package/dist/util.cjs
CHANGED
|
@@ -33,7 +33,8 @@ __export(util_exports, {
|
|
|
33
33
|
keyId: () => keyId,
|
|
34
34
|
labeledExpand: () => labeledExpand,
|
|
35
35
|
labeledExtract: () => labeledExtract,
|
|
36
|
-
resolveRecipientPublicKey: () => resolveRecipientPublicKey
|
|
36
|
+
resolveRecipientPublicKey: () => resolveRecipientPublicKey,
|
|
37
|
+
verifyKeyId: () => verifyKeyId
|
|
37
38
|
});
|
|
38
39
|
module.exports = __toCommonJS(util_exports);
|
|
39
40
|
|
|
@@ -1413,7 +1414,16 @@ async function decryptToString(keypair, message, opts) {
|
|
|
1413
1414
|
}
|
|
1414
1415
|
__name(decryptToString, "decryptToString");
|
|
1415
1416
|
async function decryptFromString(keypair, message, opts) {
|
|
1416
|
-
|
|
1417
|
+
let bytes;
|
|
1418
|
+
try {
|
|
1419
|
+
bytes = fromString2(message, "base64url");
|
|
1420
|
+
} catch (err) {
|
|
1421
|
+
throw new HpkeError(
|
|
1422
|
+
"ERR_MALFORMED_MESSAGE",
|
|
1423
|
+
"malformed message: not base64url",
|
|
1424
|
+
{ cause: err }
|
|
1425
|
+
);
|
|
1426
|
+
}
|
|
1417
1427
|
const plaintext = await decryptBytes(
|
|
1418
1428
|
keypair,
|
|
1419
1429
|
bytes,
|
|
@@ -1541,6 +1551,12 @@ async function encryptKey(recipient, aesKey, opts) {
|
|
|
1541
1551
|
validateRawKeyBytes(aesKey);
|
|
1542
1552
|
keyBytes = aesKey;
|
|
1543
1553
|
} else if (aesKey) {
|
|
1554
|
+
if (aesKey.algorithm.name !== "AES-GCM") {
|
|
1555
|
+
throw new HpkeError(
|
|
1556
|
+
"ERR_INVALID_AES_KEY",
|
|
1557
|
+
"aesKey must be an AES-GCM key, got " + aesKey.algorithm.name
|
|
1558
|
+
);
|
|
1559
|
+
}
|
|
1544
1560
|
keyBytes = await exportAesKeyBytes(aesKey);
|
|
1545
1561
|
validateRawKeyBytes(keyBytes);
|
|
1546
1562
|
} else {
|
|
@@ -1555,6 +1571,7 @@ async function encryptKey(recipient, aesKey, opts) {
|
|
|
1555
1571
|
const { key, baseNonce } = await keySchedule(sharedSecret, info);
|
|
1556
1572
|
const ciphertext = await aeadSeal(key, baseNonce, keyBytes);
|
|
1557
1573
|
const wrapped = concat2(enc, ciphertext);
|
|
1574
|
+
if (aesKey instanceof CryptoKey) return { wrapped, key: aesKey };
|
|
1558
1575
|
const aesGcmKey = await importAesKey(
|
|
1559
1576
|
keyBytes,
|
|
1560
1577
|
opts?.extractable ?? false
|
|
@@ -1607,6 +1624,12 @@ async function aeadOpen(key, nonce, ciphertext) {
|
|
|
1607
1624
|
}
|
|
1608
1625
|
__name(aeadOpen, "aeadOpen");
|
|
1609
1626
|
async function encryptBytes(recipient, message, aesKey, opts) {
|
|
1627
|
+
if (aesKey instanceof CryptoKey && !aesKey.usages.includes("encrypt")) {
|
|
1628
|
+
throw new HpkeError(
|
|
1629
|
+
"ERR_INVALID_AES_KEY",
|
|
1630
|
+
'aesKey is missing the "encrypt" usage, which encrypt needs to encrypt the message'
|
|
1631
|
+
);
|
|
1632
|
+
}
|
|
1610
1633
|
const plaintext = typeof message === "string" ? new TextEncoder().encode(message) : message;
|
|
1611
1634
|
const { wrapped, key } = await encryptKey(recipient, aesKey, opts);
|
|
1612
1635
|
const iv = globalThis.crypto.getRandomValues(new Uint8Array(NN));
|
|
@@ -1705,37 +1728,28 @@ async function resolveRecipientPublicKey(recipient) {
|
|
|
1705
1728
|
return importRawPublic(recipient);
|
|
1706
1729
|
}
|
|
1707
1730
|
if (recipient instanceof CryptoKey) {
|
|
1708
|
-
|
|
1709
|
-
throw new HpkeError(
|
|
1710
|
-
"ERR_INVALID_RECIPIENT_KEY",
|
|
1711
|
-
"recipient CryptoKey must be a public key"
|
|
1712
|
-
);
|
|
1713
|
-
}
|
|
1714
|
-
assertX25519Algorithm(
|
|
1715
|
-
recipient,
|
|
1716
|
-
"recipient CryptoKey",
|
|
1717
|
-
"ERR_INVALID_RECIPIENT_KEY"
|
|
1718
|
-
);
|
|
1719
|
-
return recipient;
|
|
1731
|
+
return assertRecipientPublicKey(recipient, "recipient CryptoKey");
|
|
1720
1732
|
}
|
|
1721
1733
|
if (typeof recipient.publicKey === "string") {
|
|
1722
1734
|
const { publicKey, encoding } = recipient;
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
if (pair.publicKey.type !== "public") {
|
|
1735
|
+
let decoded;
|
|
1736
|
+
try {
|
|
1737
|
+
decoded = fromString2(publicKey, encoding ?? "base64url");
|
|
1738
|
+
} catch (err) {
|
|
1728
1739
|
throw new HpkeError(
|
|
1729
1740
|
"ERR_INVALID_RECIPIENT_KEY",
|
|
1730
|
-
|
|
1741
|
+
`recipient publicKey string does not decode as ${encoding ?? "base64url"}`,
|
|
1742
|
+
{ cause: err }
|
|
1731
1743
|
);
|
|
1732
1744
|
}
|
|
1733
|
-
|
|
1745
|
+
return importRawPublic(decoded);
|
|
1746
|
+
}
|
|
1747
|
+
const pair = recipient;
|
|
1748
|
+
if (pair.publicKey instanceof CryptoKey) {
|
|
1749
|
+
return assertRecipientPublicKey(
|
|
1734
1750
|
pair.publicKey,
|
|
1735
|
-
"recipient keypair publicKey"
|
|
1736
|
-
"ERR_INVALID_RECIPIENT_KEY"
|
|
1751
|
+
"recipient keypair publicKey"
|
|
1737
1752
|
);
|
|
1738
|
-
return pair.publicKey;
|
|
1739
1753
|
}
|
|
1740
1754
|
throw new HpkeError(
|
|
1741
1755
|
"ERR_INVALID_RECIPIENT_KEY",
|
|
@@ -1743,6 +1757,23 @@ async function resolveRecipientPublicKey(recipient) {
|
|
|
1743
1757
|
);
|
|
1744
1758
|
}
|
|
1745
1759
|
__name(resolveRecipientPublicKey, "resolveRecipientPublicKey");
|
|
1760
|
+
function assertRecipientPublicKey(key, context) {
|
|
1761
|
+
if (key.type !== "public") {
|
|
1762
|
+
throw new HpkeError(
|
|
1763
|
+
"ERR_INVALID_RECIPIENT_KEY",
|
|
1764
|
+
`${context} must be a public key`
|
|
1765
|
+
);
|
|
1766
|
+
}
|
|
1767
|
+
assertX25519Algorithm(key, context, "ERR_INVALID_RECIPIENT_KEY");
|
|
1768
|
+
if (!key.extractable) {
|
|
1769
|
+
throw new HpkeError(
|
|
1770
|
+
"ERR_INVALID_RECIPIENT_KEY",
|
|
1771
|
+
`${context} must be extractable (the KEM exports it)`
|
|
1772
|
+
);
|
|
1773
|
+
}
|
|
1774
|
+
return key;
|
|
1775
|
+
}
|
|
1776
|
+
__name(assertRecipientPublicKey, "assertRecipientPublicKey");
|
|
1746
1777
|
function assertX25519Algorithm(key, context, code2) {
|
|
1747
1778
|
if (key.algorithm.name !== "X25519") {
|
|
1748
1779
|
throw new HpkeError(
|
|
@@ -1753,11 +1784,23 @@ function assertX25519Algorithm(key, context, code2) {
|
|
|
1753
1784
|
}
|
|
1754
1785
|
__name(assertX25519Algorithm, "assertX25519Algorithm");
|
|
1755
1786
|
async function dh(priv, pub) {
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1787
|
+
let bits;
|
|
1788
|
+
try {
|
|
1789
|
+
bits = await subtle2.deriveBits(
|
|
1790
|
+
{ name: "X25519", public: pub },
|
|
1791
|
+
priv,
|
|
1792
|
+
256
|
|
1793
|
+
);
|
|
1794
|
+
} catch (err) {
|
|
1795
|
+
if (err?.name === "OperationError") {
|
|
1796
|
+
throw new HpkeError(
|
|
1797
|
+
"ERR_SMALL_ORDER_KEY",
|
|
1798
|
+
"X25519 deriveBits rejected a small-order public key",
|
|
1799
|
+
{ cause: err }
|
|
1800
|
+
);
|
|
1801
|
+
}
|
|
1802
|
+
throw err;
|
|
1803
|
+
}
|
|
1761
1804
|
const bytes = new Uint8Array(bits);
|
|
1762
1805
|
if (bytes.every((b) => b === 0)) {
|
|
1763
1806
|
throw new HpkeError(
|
|
@@ -1810,6 +1853,23 @@ async function decap(enc, keypair) {
|
|
|
1810
1853
|
"keypair.privateKey",
|
|
1811
1854
|
"ERR_INVALID_KEYPAIR"
|
|
1812
1855
|
);
|
|
1856
|
+
if (!keypair.privateKey.usages.includes("deriveBits")) {
|
|
1857
|
+
throw new HpkeError(
|
|
1858
|
+
"ERR_INVALID_KEYPAIR",
|
|
1859
|
+
"keypair.privateKey must have the deriveBits usage"
|
|
1860
|
+
);
|
|
1861
|
+
}
|
|
1862
|
+
if (keypair.publicKey.type !== "public" || !keypair.publicKey.extractable) {
|
|
1863
|
+
throw new HpkeError(
|
|
1864
|
+
"ERR_INVALID_KEYPAIR",
|
|
1865
|
+
"keypair.publicKey must be an extractable public key"
|
|
1866
|
+
);
|
|
1867
|
+
}
|
|
1868
|
+
assertX25519Algorithm(
|
|
1869
|
+
keypair.publicKey,
|
|
1870
|
+
"keypair.publicKey",
|
|
1871
|
+
"ERR_INVALID_KEYPAIR"
|
|
1872
|
+
);
|
|
1813
1873
|
const pkE = await subtle2.importKey(
|
|
1814
1874
|
"raw",
|
|
1815
1875
|
enc,
|
|
@@ -1852,6 +1912,16 @@ async function keyId(key) {
|
|
|
1852
1912
|
return toString2(new Uint8Array(digest2), "base64url");
|
|
1853
1913
|
}
|
|
1854
1914
|
__name(keyId, "keyId");
|
|
1915
|
+
async function verifyKeyId(key, expected) {
|
|
1916
|
+
const actual = await keyId(key);
|
|
1917
|
+
if (actual.length !== expected.length) return false;
|
|
1918
|
+
let diff = 0;
|
|
1919
|
+
for (let i = 0; i < actual.length; i++) {
|
|
1920
|
+
diff |= actual.charCodeAt(i) ^ expected.charCodeAt(i);
|
|
1921
|
+
}
|
|
1922
|
+
return diff === 0;
|
|
1923
|
+
}
|
|
1924
|
+
__name(verifyKeyId, "verifyKeyId");
|
|
1855
1925
|
function i2osp(n, len) {
|
|
1856
1926
|
const out = new Uint8Array(len);
|
|
1857
1927
|
let v = n;
|