simple-hpke 0.1.3 → 0.2.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/README.md +27 -16
- package/dist/constants.cjs +2 -22
- package/dist/constants.cjs.map +3 -3
- package/dist/constants.js +2 -22
- package/dist/constants.js.map +3 -3
- 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 +6 -21
- package/dist/index.cjs.map +3 -3
- package/dist/index.d.ts +33 -22
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -21
- package/dist/index.js.map +3 -3
- 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 +16 -16
- package/dist/util.cjs +2 -22
- package/dist/util.cjs.map +3 -3
- package/dist/util.d.ts +7 -7
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +2 -22
- package/dist/util.js.map +3 -3
- 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 +1 -1
package/README.md
CHANGED
|
@@ -14,12 +14,22 @@ Hybrid Public Key Encryption
|
|
|
14
14
|
|
|
15
15
|
1 dependency -- `uint8arrays`.
|
|
16
16
|
|
|
17
|
+
On every `create`/`encrypt` call, we generate a fresh ephemeral X25519 keypair,
|
|
18
|
+
do Diffie-Hellman against the recipient public key, and the key schedule derives
|
|
19
|
+
an AES-256-GCM key from that shared secret.
|
|
20
|
+
|
|
21
|
+
That DH-derived key is the wrapping key. The AES key the API hands back is a
|
|
22
|
+
second, independently random key, and the wrapping key encrypts its raw
|
|
23
|
+
bytes. *Key wrapping* here just means "HPKE seal where the plaintext
|
|
24
|
+
happens to be 16 or 32 bytes of key material." The RFC doesn't care what
|
|
25
|
+
the plaintext is.
|
|
26
|
+
|
|
17
27
|
<details><summary><h2>Contents</h2></summary>
|
|
18
28
|
|
|
19
29
|
<!-- toc -->
|
|
20
30
|
|
|
21
31
|
- [Install](#install)
|
|
22
|
-
- [
|
|
32
|
+
- [Examples](#examples)
|
|
23
33
|
* [Key Wrapping](#key-wrapping)
|
|
24
34
|
* [Hybrid Encryption](#hybrid-encryption)
|
|
25
35
|
+ [Encrypt / Decrypt](#encrypt--decrypt)
|
|
@@ -45,46 +55,47 @@ Hybrid Public Key Encryption
|
|
|
45
55
|
npm i -S simple-hpke
|
|
46
56
|
```
|
|
47
57
|
|
|
48
|
-
##
|
|
58
|
+
## Examples
|
|
49
59
|
|
|
50
|
-
|
|
60
|
+
Create an AES key, or encrypt a message.
|
|
51
61
|
|
|
52
62
|
### Key Wrapping
|
|
53
63
|
|
|
54
|
-
Encrypt an AES key
|
|
64
|
+
Encrypt an AES key, then recover it later.
|
|
55
65
|
|
|
56
66
|
```ts
|
|
57
|
-
import { create,
|
|
67
|
+
import { create, encryptKey, open } from 'simple-hpke'
|
|
58
68
|
|
|
59
69
|
// An X25519 keypair. (asymmetric keypair).
|
|
60
70
|
// The private key can be non-extractable.
|
|
61
71
|
// HPKE only needs `deriveBits`.
|
|
62
72
|
const keypair = await crypto.subtle.generateKey(
|
|
63
73
|
{ name: 'X25519' },
|
|
64
|
-
false, // extractable
|
|
74
|
+
false, // not extractable
|
|
65
75
|
['deriveBits']
|
|
66
76
|
)
|
|
67
77
|
|
|
68
78
|
// Create a new AES key and encrypt it to your public key.
|
|
69
|
-
|
|
79
|
+
// `key` is the unencrypted new AES key
|
|
80
|
+
// `enc` is the AES key encrypted to the given public key
|
|
81
|
+
const { enc, key } = await create(keypair.publicKey) // or a buffer or string
|
|
70
82
|
|
|
71
83
|
//
|
|
72
84
|
// Or wrap an existing AES key. The supplied AES key must be extractable.
|
|
73
85
|
//
|
|
74
|
-
|
|
75
86
|
const aesKey = await crypto.subtle.generateKey(
|
|
76
87
|
{ name: 'AES-GCM', length: 256 },
|
|
77
|
-
true, // extractable
|
|
88
|
+
true, // not extractable
|
|
78
89
|
['encrypt', 'decrypt']
|
|
79
90
|
)
|
|
80
91
|
|
|
81
92
|
// Wrap the existing key.
|
|
82
|
-
const { enc:
|
|
93
|
+
const { enc: wrappedKey } = await encryptKey(keypair, aesKey)
|
|
83
94
|
|
|
84
95
|
// or pass in just a public key
|
|
85
96
|
|
|
86
97
|
// Later, recover the same key with your private key.
|
|
87
|
-
const recoveredKey = await open(keypair,
|
|
98
|
+
const recoveredKey = await open(keypair, wrappedKey)
|
|
88
99
|
|
|
89
100
|
// `recoveredKey` is equal to `aesKey`
|
|
90
101
|
```
|
|
@@ -96,7 +107,7 @@ const recoveredKey = await open(keypair, sealedKey)
|
|
|
96
107
|
### Hybrid Encryption
|
|
97
108
|
|
|
98
109
|
Encrypt a message with AES-GCM, then encrypt the AES key to a given
|
|
99
|
-
public key. The
|
|
110
|
+
public key. The encrypted key is concattenated with the cipher text,
|
|
100
111
|
along with the IV. The recipient uses their private key to open the AES key and
|
|
101
112
|
decrypt the message.
|
|
102
113
|
|
|
@@ -151,7 +162,7 @@ new TextDecoder().decode(plaintext) // => 'attack at dawn'
|
|
|
151
162
|
So that was a lot of code to encrypt and decrypt a message...
|
|
152
163
|
This package exposes functions `encrypt` and `decrypt` that do the same thing.
|
|
153
164
|
|
|
154
|
-
`encrypt`
|
|
165
|
+
`encrypt` wraps an AES key to the recipient, encrypts the message under
|
|
155
166
|
that key, and returns a single envelope:
|
|
156
167
|
`wrappedLen + wrappedKey + iv + ciphertext`
|
|
157
168
|
(a 2-byte length prefix, the wrapped key, the 12-byte AES-GCM IV, and the
|
|
@@ -179,7 +190,7 @@ import { encrypt, decrypt } from 'simple-hpke'
|
|
|
179
190
|
// need a public key for the recipient
|
|
180
191
|
const recipient = await crypto.subtle.generateKey(
|
|
181
192
|
{ name: 'X25519' },
|
|
182
|
-
false, // extractable
|
|
193
|
+
false, // not extractable
|
|
183
194
|
['deriveBits']
|
|
184
195
|
)
|
|
185
196
|
|
|
@@ -249,7 +260,7 @@ async function encrypt (
|
|
|
249
260
|
message:Uint8Array|string,
|
|
250
261
|
aesKey?:CryptoKey|Uint8Array|null,
|
|
251
262
|
opts?:{
|
|
252
|
-
|
|
263
|
+
size?:128|256
|
|
253
264
|
info?:Uint8Array|string
|
|
254
265
|
}
|
|
255
266
|
):Promise<Uint8Array>
|
|
@@ -330,7 +341,7 @@ This exposes ESM and common JS via
|
|
|
330
341
|
|
|
331
342
|
### ESM
|
|
332
343
|
```js
|
|
333
|
-
import { create,
|
|
344
|
+
import { create, encryptKey, open, encrypt, decrypt } from 'simple-hpke'
|
|
334
345
|
```
|
|
335
346
|
|
|
336
347
|
### Common JS
|
package/dist/constants.cjs
CHANGED
|
@@ -1317,16 +1317,6 @@ __name(toString2, "toString");
|
|
|
1317
1317
|
|
|
1318
1318
|
// src/index.ts
|
|
1319
1319
|
var subtle = globalThis.crypto.subtle;
|
|
1320
|
-
async function create2(recipient, opts) {
|
|
1321
|
-
const { wrapped, key } = await encryptKey(recipient, null, opts);
|
|
1322
|
-
return { enc: wrapped, key };
|
|
1323
|
-
}
|
|
1324
|
-
__name(create2, "create");
|
|
1325
|
-
async function seal(recipient, aesKey, opts) {
|
|
1326
|
-
const { wrapped, key } = await encryptKey(recipient, aesKey, opts);
|
|
1327
|
-
return { enc: wrapped, key };
|
|
1328
|
-
}
|
|
1329
|
-
__name(seal, "seal");
|
|
1330
1320
|
var open = Object.assign(openBytes, {
|
|
1331
1321
|
raw: openRawBytes
|
|
1332
1322
|
});
|
|
@@ -1507,7 +1497,7 @@ async function encryptKey(recipient, aesKey, opts) {
|
|
|
1507
1497
|
const ciphertext = await aeadSeal(key, baseNonce, keyBytes);
|
|
1508
1498
|
const wrapped = concat2(enc, ciphertext);
|
|
1509
1499
|
const aesGcmKey = await importAesKey(keyBytes);
|
|
1510
|
-
return { wrapped, key: aesGcmKey };
|
|
1500
|
+
return { enc: wrapped, key: aesGcmKey };
|
|
1511
1501
|
}
|
|
1512
1502
|
__name(encryptKey, "encryptKey");
|
|
1513
1503
|
|
|
@@ -1547,17 +1537,7 @@ async function aeadOpen(key, nonce, ciphertext) {
|
|
|
1547
1537
|
__name(aeadOpen, "aeadOpen");
|
|
1548
1538
|
async function encryptBytes(recipient, message, aesKey, opts) {
|
|
1549
1539
|
const plaintext = typeof message === "string" ? new TextEncoder().encode(message) : message;
|
|
1550
|
-
|
|
1551
|
-
let key;
|
|
1552
|
-
if (!aesKey) {
|
|
1553
|
-
const keys = await create2(recipient, opts);
|
|
1554
|
-
enc = keys.enc;
|
|
1555
|
-
key = keys.key;
|
|
1556
|
-
} else {
|
|
1557
|
-
const keys = await seal(recipient, aesKey, opts);
|
|
1558
|
-
enc = keys.enc;
|
|
1559
|
-
key = keys.key;
|
|
1560
|
-
}
|
|
1540
|
+
const { enc, key } = await encryptKey(recipient, aesKey, opts);
|
|
1561
1541
|
const iv = globalThis.crypto.getRandomValues(new Uint8Array(NN));
|
|
1562
1542
|
const ct = new Uint8Array(await subtle2.encrypt(
|
|
1563
1543
|
{ name: "AES-GCM", iv },
|