@interop/minimal-cipher 7.0.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/LICENSE +27 -0
- package/README.md +220 -0
- package/dist/Cipher.d.ts +210 -0
- package/dist/Cipher.d.ts.map +1 -0
- package/dist/Cipher.js +313 -0
- package/dist/Cipher.js.map +1 -0
- package/dist/DecryptTransformer.d.ts +14 -0
- package/dist/DecryptTransformer.d.ts.map +1 -0
- package/dist/DecryptTransformer.js +125 -0
- package/dist/DecryptTransformer.js.map +1 -0
- package/dist/EncryptTransformer.d.ts +28 -0
- package/dist/EncryptTransformer.d.ts.map +1 -0
- package/dist/EncryptTransformer.js +94 -0
- package/dist/EncryptTransformer.js.map +1 -0
- package/dist/algorithms/a256gcm.d.ts +39 -0
- package/dist/algorithms/a256gcm.d.ts.map +1 -0
- package/dist/algorithms/a256gcm.js +101 -0
- package/dist/algorithms/a256gcm.js.map +1 -0
- package/dist/algorithms/aeskw.d.ts +5 -0
- package/dist/algorithms/aeskw.d.ts.map +1 -0
- package/dist/algorithms/aeskw.js +68 -0
- package/dist/algorithms/aeskw.js.map +1 -0
- package/dist/algorithms/c20p-browser.d.ts +51 -0
- package/dist/algorithms/c20p-browser.d.ts.map +1 -0
- package/dist/algorithms/c20p-browser.js +106 -0
- package/dist/algorithms/c20p-browser.js.map +1 -0
- package/dist/algorithms/c20p.d.ts +51 -0
- package/dist/algorithms/c20p.d.ts.map +1 -0
- package/dist/algorithms/c20p.js +110 -0
- package/dist/algorithms/c20p.js.map +1 -0
- package/dist/algorithms/ecdhkdf.d.ts +24 -0
- package/dist/algorithms/ecdhkdf.d.ts.map +1 -0
- package/dist/algorithms/ecdhkdf.js +76 -0
- package/dist/algorithms/ecdhkdf.js.map +1 -0
- package/dist/algorithms/fips.d.ts +8 -0
- package/dist/algorithms/fips.d.ts.map +1 -0
- package/dist/algorithms/fips.js +8 -0
- package/dist/algorithms/fips.js.map +1 -0
- package/dist/algorithms/p256.d.ts +24 -0
- package/dist/algorithms/p256.d.ts.map +1 -0
- package/dist/algorithms/p256.js +106 -0
- package/dist/algorithms/p256.js.map +1 -0
- package/dist/algorithms/recommended.d.ts +8 -0
- package/dist/algorithms/recommended.d.ts.map +1 -0
- package/dist/algorithms/recommended.js +8 -0
- package/dist/algorithms/recommended.js.map +1 -0
- package/dist/algorithms/x25519-helper-browser.d.ts +7 -0
- package/dist/algorithms/x25519-helper-browser.d.ts.map +1 -0
- package/dist/algorithms/x25519-helper-browser.js +25 -0
- package/dist/algorithms/x25519-helper-browser.js.map +1 -0
- package/dist/algorithms/x25519-helper.d.ts +7 -0
- package/dist/algorithms/x25519-helper.d.ts.map +1 -0
- package/dist/algorithms/x25519-helper.js +51 -0
- package/dist/algorithms/x25519-helper.js.map +1 -0
- package/dist/algorithms/x25519.d.ts +44 -0
- package/dist/algorithms/x25519.d.ts.map +1 -0
- package/dist/algorithms/x25519.js +112 -0
- package/dist/algorithms/x25519.js.map +1 -0
- package/dist/algorithms/xc20p.d.ts +40 -0
- package/dist/algorithms/xc20p.d.ts.map +1 -0
- package/dist/algorithms/xc20p.js +160 -0
- package/dist/algorithms/xc20p.js.map +1 -0
- package/dist/baseX.d.ts +7 -0
- package/dist/baseX.d.ts.map +1 -0
- package/dist/baseX.js +11 -0
- package/dist/baseX.js.map +1 -0
- package/dist/crypto.d.ts +3 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +3 -0
- package/dist/crypto.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +119 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/util.d.ts +2 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +11 -0
- package/dist/util.js.map +1 -0
- package/package.json +99 -0
package/dist/Cipher.js
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2019-2026 Digital Bazaar, Inc.
|
|
3
|
+
*/
|
|
4
|
+
import { base64url } from './baseX.js';
|
|
5
|
+
import * as fipsAlgorithm from './algorithms/fips.js';
|
|
6
|
+
import * as recAlgorithm from './algorithms/recommended.js';
|
|
7
|
+
import { DecryptTransformer } from './DecryptTransformer.js';
|
|
8
|
+
import { EncryptTransformer } from './EncryptTransformer.js';
|
|
9
|
+
import { stringToUint8Array } from './util.js';
|
|
10
|
+
const VERSIONS = ['recommended', 'fips'];
|
|
11
|
+
export class Cipher {
|
|
12
|
+
version;
|
|
13
|
+
cipher;
|
|
14
|
+
keyAgreement;
|
|
15
|
+
/**
|
|
16
|
+
* Creates a new Cipher instance that can be used to encrypt or decrypt
|
|
17
|
+
* data. A version must be supplied for encrypting data; the version
|
|
18
|
+
* indicates whether a FIPS-compliant algorithm or the latest recommended
|
|
19
|
+
* algorithm will be used.
|
|
20
|
+
*
|
|
21
|
+
* @param {string} [version='recommended'] - `fips` to use a FIPS-compliant
|
|
22
|
+
* algorithm, `recommended` to use the latest recommended algorithm when
|
|
23
|
+
* encrypting.
|
|
24
|
+
*
|
|
25
|
+
* @returns {Cipher} A Cipher used to encrypt and decrypt data.
|
|
26
|
+
*/
|
|
27
|
+
constructor({ version = 'recommended' } = {}) {
|
|
28
|
+
if (typeof version !== 'string') {
|
|
29
|
+
throw new TypeError('"version" must be a string.');
|
|
30
|
+
}
|
|
31
|
+
if (!VERSIONS.includes(version)) {
|
|
32
|
+
throw new Error(`Unsupported version "${version}".`);
|
|
33
|
+
}
|
|
34
|
+
this.version = version;
|
|
35
|
+
if (version === 'fips') {
|
|
36
|
+
this.cipher = fipsAlgorithm.cipher;
|
|
37
|
+
this.keyAgreement = fipsAlgorithm.keyAgreement;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
this.cipher = recAlgorithm.cipher;
|
|
41
|
+
this.keyAgreement = recAlgorithm.keyAgreement;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Creates a TransformStream that will encrypt some data for one or more
|
|
46
|
+
* recipients and output a stream of chunks, each containing an object
|
|
47
|
+
* with the property `jwe` with a JWE value.
|
|
48
|
+
*
|
|
49
|
+
* A list of recipients must be given in the `recipients` array, identified
|
|
50
|
+
* by key agreement keys. An ephemeral ECDH key will be generated and used to
|
|
51
|
+
* derive shared KEKs that will wrap a randomly generated CEK. Each recipient
|
|
52
|
+
* in the `recipients` array will be updated to include the generated
|
|
53
|
+
* ephemeral ECDH key.
|
|
54
|
+
*
|
|
55
|
+
* @param {object} options - The options for the stream.
|
|
56
|
+
* @param {Array} options.recipients - An array of recipients for the
|
|
57
|
+
* encrypted content.
|
|
58
|
+
* @param {Function} options.keyResolver - A function that returns a Promise
|
|
59
|
+
* that resolves a key ID to a DH public key.
|
|
60
|
+
* @param {number} [options.chunkSize=1048576] - The size, in bytes,
|
|
61
|
+
* of the chunks to break the incoming data into.
|
|
62
|
+
*
|
|
63
|
+
* @returns {Promise<TransformStream>} Resolves to a TransformStream.
|
|
64
|
+
*/
|
|
65
|
+
async createEncryptStream({ recipients, keyResolver, chunkSize }) {
|
|
66
|
+
const transformer = await this.createEncryptTransformer({
|
|
67
|
+
recipients,
|
|
68
|
+
keyResolver,
|
|
69
|
+
chunkSize
|
|
70
|
+
});
|
|
71
|
+
return new TransformStream(transformer);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Creates a TransformStream that will decrypt one or more chunks, each one
|
|
75
|
+
* that is an object with a `jwe` property that has a JWE as a value. The
|
|
76
|
+
* stream will output chunks of Uint8Arrays consisting of the decrypted
|
|
77
|
+
* data from each chunk.
|
|
78
|
+
*
|
|
79
|
+
* The only JWEs currently supported use an `alg` of `ECDH-ES+A256KW` and
|
|
80
|
+
* `enc` of `A256GCM` or `XC20P`. These parameters refer to data that has been
|
|
81
|
+
* encrypted using a 256-bit AES-GCM or XChaCha20Poly1305 content encryption
|
|
82
|
+
* key (CEK) that has been wrapped using a 256-bit AES-KW key encryption key
|
|
83
|
+
* (KEK) generated via a shared secret between an ephemeral ECDH key and a
|
|
84
|
+
* static ECDH key (ECDH-ES).
|
|
85
|
+
*
|
|
86
|
+
* @param {object} options - Options for createDecryptStream.
|
|
87
|
+
* @param {object} options.keyAgreementKey - A key agreement key API with
|
|
88
|
+
* `id` and deriveSecret`.
|
|
89
|
+
*
|
|
90
|
+
* @returns {Promise<TransformStream>} Resolves to the TransformStream.
|
|
91
|
+
*/
|
|
92
|
+
async createDecryptStream({ keyAgreementKey }) {
|
|
93
|
+
const transformer = await this.createDecryptTransformer({ keyAgreementKey });
|
|
94
|
+
return new TransformStream(transformer);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Encrypts some data for one or more recipients and outputs a JWE. The
|
|
98
|
+
* data to encrypt can be given as a Uint8Array or a string.
|
|
99
|
+
*
|
|
100
|
+
* A list of recipients must be given in the `recipients` array, identified
|
|
101
|
+
* by key agreement keys. An ephemeral ECDH key will be generated and used to
|
|
102
|
+
* derive shared KEKs that will wrap a randomly generated CEK. Each recipient
|
|
103
|
+
* in the `recipients` array will be updated to include the generated
|
|
104
|
+
* ephemeral ECDH key.
|
|
105
|
+
*
|
|
106
|
+
* @param {object} options - Options for encrypt.
|
|
107
|
+
* @param {Uint8Array|string} [options.data] - The data to encrypt.
|
|
108
|
+
* @param {Array} options.recipients - An array of recipients for the\
|
|
109
|
+
* encrypted content.
|
|
110
|
+
* @param {Function} options.keyResolver - A function that returns a Promise
|
|
111
|
+
* that resolves a key ID to a DH public key.
|
|
112
|
+
*
|
|
113
|
+
* @returns {Promise<object>} Resolves to a JWE.
|
|
114
|
+
*/
|
|
115
|
+
async encrypt({ data, recipients, keyResolver }) {
|
|
116
|
+
if (!(data instanceof Uint8Array) && typeof data !== 'string') {
|
|
117
|
+
throw new TypeError('"data" must be a Uint8Array or a string.');
|
|
118
|
+
}
|
|
119
|
+
let bytes = data;
|
|
120
|
+
if (data) {
|
|
121
|
+
bytes = stringToUint8Array(data);
|
|
122
|
+
}
|
|
123
|
+
const transformer = await this.createEncryptTransformer({
|
|
124
|
+
recipients,
|
|
125
|
+
keyResolver
|
|
126
|
+
});
|
|
127
|
+
return transformer.encrypt(bytes);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Encrypts an object. The object will be serialized to JSON and passed
|
|
131
|
+
* to `encrypt`. See `encrypt` for other parameters.
|
|
132
|
+
*
|
|
133
|
+
* @param {object} options - Options to use.
|
|
134
|
+
* @param {object} options.obj - The object to encrypt.
|
|
135
|
+
* @param {object} options.rest - The other options to be passed to encrypt.
|
|
136
|
+
*
|
|
137
|
+
* @returns {Promise<object>} Resolves to a JWE.
|
|
138
|
+
*/
|
|
139
|
+
async encryptObject({ obj, ...rest }) {
|
|
140
|
+
if (typeof obj !== 'object') {
|
|
141
|
+
throw new TypeError('"obj" must be an object.');
|
|
142
|
+
}
|
|
143
|
+
return this.encrypt({ data: JSON.stringify(obj), ...rest });
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Decrypts a single JWE.
|
|
147
|
+
*
|
|
148
|
+
* The only JWEs currently supported use an `alg` of `ECDH-ES+A256KW` and
|
|
149
|
+
* `enc` of `A256GCM` or `XC20P`. These parameters refer to data that has been
|
|
150
|
+
* encrypted using a 256-bit AES-GCM or XChaCha20Poly1305 content encryption
|
|
151
|
+
* key (CEK) that has been wrapped using a 256-bit AES-KW key encryption key
|
|
152
|
+
* (KEK) generated via a shared secret between an ephemeral ECDH key and a
|
|
153
|
+
* static ECDH key (ECDH-ES).
|
|
154
|
+
*
|
|
155
|
+
* Note: This version also supports decrypting data that was encrypted using
|
|
156
|
+
* `C20P` (ChaCha20Poly1305) for backwards compatibility.
|
|
157
|
+
*
|
|
158
|
+
* @param {object} options - Options for decrypt.
|
|
159
|
+
* @param {object} options.jwe - The JWE to decrypt.
|
|
160
|
+
* @param {object} options.keyAgreementKey - A key agreement key API with
|
|
161
|
+
* `id` and `deriveSecret`.
|
|
162
|
+
*
|
|
163
|
+
* @returns {Promise<Uint8Array>} - Resolves to the decrypted data
|
|
164
|
+
* or `null` if the decryption failed.
|
|
165
|
+
*/
|
|
166
|
+
async decrypt({ jwe, keyAgreementKey }) {
|
|
167
|
+
const transformer = await this.createDecryptTransformer({ keyAgreementKey });
|
|
168
|
+
return transformer.decrypt(jwe);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Decrypts a JWE that must contain an encrypted object. This method will
|
|
172
|
+
* call `decrypt` and then `JSON.parse` the resulting decrypted UTF-8 data.
|
|
173
|
+
*
|
|
174
|
+
* @param {object} options - Options.
|
|
175
|
+
* @param {object} options.jwe - The JWE to decrypt.
|
|
176
|
+
* @param {object} options.keyAgreementKey - A key agreement key API with
|
|
177
|
+
* `id` and `deriveSecret`.
|
|
178
|
+
*
|
|
179
|
+
* @returns {Promise<object>} - Resolves to the decrypted object or `null`
|
|
180
|
+
* if the decryption failed.
|
|
181
|
+
*/
|
|
182
|
+
async decryptObject({ jwe, keyAgreementKey }) {
|
|
183
|
+
const data = await this.decrypt({ jwe, keyAgreementKey });
|
|
184
|
+
if (!data) {
|
|
185
|
+
// decryption failed
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
return JSON.parse(new TextDecoder().decode(data));
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Creates an EncryptTransformer that can be used to encrypt one or more
|
|
192
|
+
* chunks of data.
|
|
193
|
+
*
|
|
194
|
+
* A list of recipients must be given in the `recipients` array, identified
|
|
195
|
+
* by key agreement keys. An ephemeral ECDH key will be generated and used to
|
|
196
|
+
* derive shared KEKs that will wrap a randomly generated CEK. Each recipient
|
|
197
|
+
* in the `recipients` array will be updated to include the generated
|
|
198
|
+
* ephemeral ECDH key.
|
|
199
|
+
*
|
|
200
|
+
* @param {object} options - Options for the transformer.
|
|
201
|
+
* @param {Array} options.recipients - An array of recipients for the
|
|
202
|
+
* encrypted content.
|
|
203
|
+
* @param {Function} options.keyResolver - A function that returns
|
|
204
|
+
* a Promise that resolves a key ID to a DH public key.
|
|
205
|
+
* @param {number} [options.chunkSize=1048576] - The size, in bytes, of the
|
|
206
|
+
* chunks to break the incoming data into (only applies if returning a
|
|
207
|
+
* stream).
|
|
208
|
+
*
|
|
209
|
+
* @returns {Promise<EncryptTransformer>} - Resolves to an EncryptTransformer.
|
|
210
|
+
*/
|
|
211
|
+
async createEncryptTransformer({ recipients, keyResolver, chunkSize }) {
|
|
212
|
+
if (!(Array.isArray(recipients) && recipients.length > 0)) {
|
|
213
|
+
throw new TypeError('"recipients" must be a non-empty array.');
|
|
214
|
+
}
|
|
215
|
+
// ensure all recipients use the supported key agreement algorithm
|
|
216
|
+
const { keyAgreement } = this;
|
|
217
|
+
const { JWE_ALG: alg } = keyAgreement;
|
|
218
|
+
if (!recipients.every(e => e.header && e.header.alg === alg)) {
|
|
219
|
+
throw new Error(`All recipients must use the algorithm "${alg}".`);
|
|
220
|
+
}
|
|
221
|
+
const { cipher } = this;
|
|
222
|
+
// generate a CEK for encrypting the content
|
|
223
|
+
const cek = await cipher.generateKey();
|
|
224
|
+
// derive ephemeral ECDH key pair to use with all recipients
|
|
225
|
+
const ephemeralKeyPair = await keyAgreement.generateEphemeralKeyPair();
|
|
226
|
+
recipients = await Promise.all(recipients.map(recipient => this._createRecipient({ recipient, cek, ephemeralKeyPair, keyResolver })));
|
|
227
|
+
// create shared protected header as associated authenticated data (aad)
|
|
228
|
+
// ASCII(BASE64URL(UTF8(JWE Protected Header)))
|
|
229
|
+
const enc = cipher.JWE_ENC;
|
|
230
|
+
const jweProtectedHeader = JSON.stringify({ enc });
|
|
231
|
+
const encodedProtectedHeader = base64url.encode(stringToUint8Array(jweProtectedHeader));
|
|
232
|
+
// UTF8-encoding a base64url-encoded string is the same as ASCII
|
|
233
|
+
const additionalData = stringToUint8Array(encodedProtectedHeader);
|
|
234
|
+
return new EncryptTransformer({
|
|
235
|
+
recipients,
|
|
236
|
+
encodedProtectedHeader,
|
|
237
|
+
cipher,
|
|
238
|
+
additionalData,
|
|
239
|
+
cek,
|
|
240
|
+
chunkSize
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Creates a DecryptTransformer.
|
|
245
|
+
*
|
|
246
|
+
* @param {object} options - Options to use.
|
|
247
|
+
* @param {object} options.keyAgreementKey - A key agreement key API with
|
|
248
|
+
* `id` and `deriveSecret`.
|
|
249
|
+
*
|
|
250
|
+
* @returns {Promise<DecryptTransformer>} - Resolves to a DecryptTransformer.
|
|
251
|
+
*/
|
|
252
|
+
async createDecryptTransformer({ keyAgreementKey }) {
|
|
253
|
+
return new DecryptTransformer({
|
|
254
|
+
keyAgreement: this.keyAgreement,
|
|
255
|
+
keyAgreementKey
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Creates a JWE recipient using the given inputs.
|
|
260
|
+
*
|
|
261
|
+
* @see https://tools.ietf.org/html/rfc7516#section-4
|
|
262
|
+
*
|
|
263
|
+
* @param {object} options - Options to use.
|
|
264
|
+
* @param {object} options.recipient - A recipient with a header with a
|
|
265
|
+
* kid and alg.
|
|
266
|
+
* @param {object} options.ephemeralKeyPair - An ephemeral key pair.
|
|
267
|
+
* @param {object} options.cek - A content encryption key.
|
|
268
|
+
* @param {Function} options.keyResolver - A function that can resolve keys.
|
|
269
|
+
*
|
|
270
|
+
* @returns {Promise<object>} A JWE recipient object.
|
|
271
|
+
*/
|
|
272
|
+
async _createRecipient({ recipient, ephemeralKeyPair, cek, keyResolver }) {
|
|
273
|
+
if (!recipient) {
|
|
274
|
+
throw new TypeError('"options.recipient" is required.');
|
|
275
|
+
}
|
|
276
|
+
if (!ephemeralKeyPair) {
|
|
277
|
+
throw new TypeError('"options.ephemeralKeyPair" is required.');
|
|
278
|
+
}
|
|
279
|
+
if (!cek) {
|
|
280
|
+
throw new TypeError('"options.cek" is required.');
|
|
281
|
+
}
|
|
282
|
+
if (!keyResolver) {
|
|
283
|
+
throw new TypeError('"options.keyResolver" is required.');
|
|
284
|
+
}
|
|
285
|
+
// resolve public DH key for recipient
|
|
286
|
+
const { keyAgreement } = this;
|
|
287
|
+
const staticPublicKey = await keyResolver({ id: recipient.header.kid });
|
|
288
|
+
// derive KEKs for each recipient
|
|
289
|
+
const derivedResult = await keyAgreement.kekFromStaticPeer({
|
|
290
|
+
ephemeralKeyPair,
|
|
291
|
+
staticPublicKey
|
|
292
|
+
});
|
|
293
|
+
const { kek, epk, apu, apv } = derivedResult;
|
|
294
|
+
const header = {
|
|
295
|
+
// contains the key id - kid
|
|
296
|
+
// contains the algorithm - alg
|
|
297
|
+
...recipient.header,
|
|
298
|
+
// the ephemeralKeyPair
|
|
299
|
+
epk,
|
|
300
|
+
// base64 encoded ephemeralKeyPair's publicKey
|
|
301
|
+
apu,
|
|
302
|
+
// base64 encoded staticPublicKey's id
|
|
303
|
+
apv
|
|
304
|
+
};
|
|
305
|
+
return {
|
|
306
|
+
...recipient,
|
|
307
|
+
header,
|
|
308
|
+
// the cek is wrapped so the recipient can use it to decrypt later
|
|
309
|
+
encrypted_key: await kek.wrapKey({ unwrappedKey: cek })
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
//# sourceMappingURL=Cipher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Cipher.js","sourceRoot":"","sources":["../src/Cipher.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,KAAK,aAAa,MAAM,sBAAsB,CAAA;AACrD,OAAO,KAAK,YAAY,MAAM,6BAA6B,CAAA;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAW9C,MAAM,QAAQ,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,CAAA;AAoBxC,MAAM,OAAO,MAAM;IACjB,OAAO,CAAQ;IACf,MAAM,CAAiB;IACvB,YAAY,CAAuB;IAEnC;;;;;;;;;;;OAWG;IACH,YAAY,EAAE,OAAO,GAAG,aAAa,KAA2B,EAAE;QAChE,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAChC,MAAM,IAAI,SAAS,CAAC,6BAA6B,CAAC,CAAA;QACpD,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,wBAAwB,OAAO,IAAI,CAAC,CAAA;QACtD,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;YACvB,IAAI,CAAC,MAAM,GAAG,aAAa,CAAC,MAAM,CAAA;YAClC,IAAI,CAAC,YAAY,GAAG,aAAa,CAAC,YAAY,CAAA;QAChD,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,GAAG,YAAY,CAAC,MAAM,CAAA;YACjC,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC,YAAY,CAAA;QAC/C,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,KAAK,CAAC,mBAAmB,CAAC,EACxB,UAAU,EACV,WAAW,EACX,SAAS,EACY;QACrB,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,wBAAwB,CAAC;YACtD,UAAU;YACV,WAAW;YACX,SAAS;SACV,CAAC,CAAA;QACF,OAAO,IAAI,eAAe,CAAC,WAAW,CAAC,CAAA;IACzC,CAAC;IAED;;;;;;;;;;;;;;;;;;OAkBG;IACH,KAAK,CAAC,mBAAmB,CAAC,EACxB,eAAe,EAGhB;QACC,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,wBAAwB,CAAC,EAAE,eAAe,EAAE,CAAC,CAAA;QAC5E,OAAO,IAAI,eAAe,CAAC,WAAW,CAAC,CAAA;IACzC,CAAC;IAED;;;;;;;;;;;;;;;;;;OAkBG;IACH,KAAK,CAAC,OAAO,CAAC,EACZ,IAAI,EACJ,UAAU,EACV,WAAW,EACI;QACf,IAAI,CAAC,CAAC,IAAI,YAAY,UAAU,CAAC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC9D,MAAM,IAAI,SAAS,CAAC,0CAA0C,CAAC,CAAA;QACjE,CAAC;QACD,IAAI,KAAK,GAAwB,IAAI,CAAA;QACrC,IAAI,IAAI,EAAE,CAAC;YACT,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAA;QAClC,CAAC;QACD,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,wBAAwB,CAAC;YACtD,UAAU;YACV,WAAW;SACZ,CAAC,CAAA;QACF,OAAO,WAAW,CAAC,OAAO,CAAC,KAAmB,CAAC,CAAA;IACjD,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,aAAa,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,EAAwB;QACxD,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;YAC5B,MAAM,IAAI,SAAS,CAAC,0BAA0B,CAAC,CAAA;QACjD,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,CAAA;IAC7D,CAAC;IAED;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,KAAK,CAAC,OAAO,CAAC,EACZ,GAAG,EACH,eAAe,EAIhB;QACC,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,wBAAwB,CAAC,EAAE,eAAe,EAAE,CAAC,CAAA;QAC5E,OAAO,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IACjC,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,aAAa,CAAC,EAClB,GAAG,EACH,eAAe,EAIhB;QACC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,eAAe,EAAE,CAAC,CAAA;QACzD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,oBAAoB;YACpB,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;IACnD,CAAC;IAED;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,KAAK,CAAC,wBAAwB,CAAC,EAC7B,UAAU,EACV,WAAW,EACX,SAAS,EACY;QACrB,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;YAC1D,MAAM,IAAI,SAAS,CAAC,yCAAyC,CAAC,CAAA;QAChE,CAAC;QACD,kEAAkE;QAClE,MAAM,EAAE,YAAY,EAAE,GAAG,IAAI,CAAA;QAC7B,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,YAAY,CAAA;QACrC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,KAAK,GAAG,CAAC,EAAE,CAAC;YAC7D,MAAM,IAAI,KAAK,CAAC,0CAA0C,GAAG,IAAI,CAAC,CAAA;QACpE,CAAC;QACD,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;QAEvB,4CAA4C;QAC5C,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAA;QAEtC,4DAA4D;QAC5D,MAAM,gBAAgB,GAAG,MAAM,YAAY,CAAC,wBAAwB,EAAE,CAAA;QAEtE,UAAU,GAAG,MAAM,OAAO,CAAC,GAAG,CAC5B,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CACzB,IAAI,CAAC,gBAAgB,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,gBAAgB,EAAE,WAAW,EAAE,CAAC,CACzE,CACF,CAAA;QAED,wEAAwE;QACxE,+CAA+C;QAC/C,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAA;QAC1B,MAAM,kBAAkB,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,CAAC,CAAA;QAClD,MAAM,sBAAsB,GAAG,SAAS,CAAC,MAAM,CAC7C,kBAAkB,CAAC,kBAAkB,CAAC,CACvC,CAAA;QACD,gEAAgE;QAChE,MAAM,cAAc,GAAG,kBAAkB,CAAC,sBAAsB,CAAC,CAAA;QAEjE,OAAO,IAAI,kBAAkB,CAAC;YAC5B,UAAU;YACV,sBAAsB;YACtB,MAAM;YACN,cAAc;YACd,GAAG;YACH,SAAS;SACV,CAAC,CAAA;IACJ,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,wBAAwB,CAAC,EAC7B,eAAe,EAGhB;QACC,OAAO,IAAI,kBAAkB,CAAC;YAC5B,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,eAAe;SAChB,CAAC,CAAA;IACJ,CAAC;IAED;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,gBAAgB,CAAC,EACrB,SAAS,EACT,gBAAgB,EAChB,GAAG,EACH,WAAW,EAMZ;QACC,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,SAAS,CAAC,kCAAkC,CAAC,CAAA;QACzD,CAAC;QACD,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACtB,MAAM,IAAI,SAAS,CAAC,yCAAyC,CAAC,CAAA;QAChE,CAAC;QACD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,SAAS,CAAC,4BAA4B,CAAC,CAAA;QACnD,CAAC;QACD,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,IAAI,SAAS,CAAC,oCAAoC,CAAC,CAAA;QAC3D,CAAC;QACD,sCAAsC;QACtC,MAAM,EAAE,YAAY,EAAE,GAAG,IAAI,CAAA;QAC7B,MAAM,eAAe,GAAG,MAAM,WAAW,CAAC,EAAE,EAAE,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAA;QACvE,iCAAiC;QACjC,MAAM,aAAa,GAAG,MAAM,YAAY,CAAC,iBAAiB,CAAC;YACzD,gBAAgB;YAChB,eAAe;SAChB,CAAC,CAAA;QACF,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,aAAa,CAAA;QAC5C,MAAM,MAAM,GAAG;YACb,4BAA4B;YAC5B,+BAA+B;YAC/B,GAAG,SAAS,CAAC,MAAM;YACnB,uBAAuB;YACvB,GAAG;YACH,8CAA8C;YAC9C,GAAG;YACH,sCAAsC;YACtC,GAAG;SACJ,CAAA;QACD,OAAO;YACL,GAAG,SAAS;YACZ,MAAM;YACN,kEAAkE;YAClE,aAAa,EAAE,MAAM,GAAG,CAAC,OAAO,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC;SACxD,CAAA;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { JWE, KeyAgreementAlgorithm, KeyAgreementKey } from './types.js';
|
|
2
|
+
export declare class DecryptTransformer {
|
|
3
|
+
keyAgreement: KeyAgreementAlgorithm;
|
|
4
|
+
keyAgreementKey: KeyAgreementKey;
|
|
5
|
+
constructor({ keyAgreement, keyAgreementKey }?: {
|
|
6
|
+
keyAgreement?: KeyAgreementAlgorithm;
|
|
7
|
+
keyAgreementKey?: KeyAgreementKey;
|
|
8
|
+
});
|
|
9
|
+
transform(chunk: {
|
|
10
|
+
jwe: JWE;
|
|
11
|
+
}, controller: TransformStreamDefaultController): Promise<void>;
|
|
12
|
+
decrypt(jwe: JWE): Promise<Uint8Array | null>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=DecryptTransformer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DecryptTransformer.d.ts","sourceRoot":"","sources":["../src/DecryptTransformer.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAGV,GAAG,EACH,qBAAqB,EACrB,eAAe,EAEhB,MAAM,YAAY,CAAA;AAenB,qBAAa,kBAAkB;IAC7B,YAAY,EAAE,qBAAqB,CAAA;IACnC,eAAe,EAAE,eAAe,CAAA;gBAEpB,EACV,YAAY,EACZ,eAAe,EAChB,GAAE;QACD,YAAY,CAAC,EAAE,qBAAqB,CAAA;QACpC,eAAe,CAAC,EAAE,eAAe,CAAA;KAC7B;IAWA,SAAS,CACb,KAAK,EAAE;QAAE,GAAG,EAAE,GAAG,CAAA;KAAE,EACnB,UAAU,EAAE,gCAAgC,GAC3C,OAAO,CAAC,IAAI,CAAC;IAiBV,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;CAgFpD"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2019-2026 Digital Bazaar, Inc.
|
|
3
|
+
*/
|
|
4
|
+
import { base64url } from './baseX.js';
|
|
5
|
+
import * as fipsAlgorithm from './algorithms/fips.js';
|
|
6
|
+
import * as recAlgorithm from './algorithms/recommended.js';
|
|
7
|
+
import { stringToUint8Array } from './util.js';
|
|
8
|
+
// support `C20P` for backwards compatibility
|
|
9
|
+
import * as c20p from './algorithms/c20p.js';
|
|
10
|
+
const CIPHER_ALGORITHMS = {
|
|
11
|
+
[fipsAlgorithm.cipher.JWE_ENC]: fipsAlgorithm.cipher,
|
|
12
|
+
[recAlgorithm.cipher.JWE_ENC]: recAlgorithm.cipher,
|
|
13
|
+
// backwards compatibility for decryption only (*not* encryption)
|
|
14
|
+
[c20p.JWE_ENC]: c20p
|
|
15
|
+
};
|
|
16
|
+
// only supported key algorithm
|
|
17
|
+
const KEY_ALGORITHM = 'ECDH-ES+A256KW';
|
|
18
|
+
export class DecryptTransformer {
|
|
19
|
+
keyAgreement;
|
|
20
|
+
keyAgreementKey;
|
|
21
|
+
constructor({ keyAgreement, keyAgreementKey } = {}) {
|
|
22
|
+
if (!keyAgreement) {
|
|
23
|
+
throw new TypeError('"keyAgreement" is a required parameter.');
|
|
24
|
+
}
|
|
25
|
+
if (!keyAgreementKey) {
|
|
26
|
+
throw new TypeError('"keyAgreementKey" is a required parameter.');
|
|
27
|
+
}
|
|
28
|
+
this.keyAgreement = keyAgreement;
|
|
29
|
+
this.keyAgreementKey = keyAgreementKey;
|
|
30
|
+
}
|
|
31
|
+
async transform(chunk, controller) {
|
|
32
|
+
// assumes `chunk` is an object with a JWE under the `jwe` property
|
|
33
|
+
if (!(chunk && typeof chunk === 'object')) {
|
|
34
|
+
throw new TypeError('"chunk" must be an object.');
|
|
35
|
+
}
|
|
36
|
+
const { jwe } = chunk;
|
|
37
|
+
const data = await this.decrypt(jwe);
|
|
38
|
+
if (data === null) {
|
|
39
|
+
const error = new Error('Invalid decryption key.');
|
|
40
|
+
error.name = 'DataError';
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
controller.enqueue(data);
|
|
44
|
+
}
|
|
45
|
+
async decrypt(jwe) {
|
|
46
|
+
// validate JWE
|
|
47
|
+
if (!(jwe && typeof jwe === 'object')) {
|
|
48
|
+
throw new TypeError('"jwe" must be an object.');
|
|
49
|
+
}
|
|
50
|
+
if (typeof jwe.protected !== 'string') {
|
|
51
|
+
throw new TypeError('"jwe.protected" is missing or not a string.');
|
|
52
|
+
}
|
|
53
|
+
if (typeof jwe.iv !== 'string') {
|
|
54
|
+
throw new Error('Invalid or missing "iv".');
|
|
55
|
+
}
|
|
56
|
+
if (typeof jwe.ciphertext !== 'string') {
|
|
57
|
+
throw new Error('Invalid or missing "ciphertext".');
|
|
58
|
+
}
|
|
59
|
+
if (typeof jwe.tag !== 'string') {
|
|
60
|
+
throw new Error('Invalid or missing "tag".');
|
|
61
|
+
}
|
|
62
|
+
// validate encryption header
|
|
63
|
+
let header;
|
|
64
|
+
let additionalData;
|
|
65
|
+
try {
|
|
66
|
+
// ASCII(BASE64URL(UTF8(JWE Protected Header)))
|
|
67
|
+
additionalData = stringToUint8Array(jwe.protected);
|
|
68
|
+
header = JSON.parse(new TextDecoder().decode(base64url.decode(jwe.protected)));
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
throw new Error('Invalid JWE "protected" header.');
|
|
72
|
+
}
|
|
73
|
+
if (!(header.enc && typeof header.enc === 'string')) {
|
|
74
|
+
throw new Error('Invalid JWE "enc" header.');
|
|
75
|
+
}
|
|
76
|
+
const cipher = CIPHER_ALGORITHMS[header.enc];
|
|
77
|
+
if (!cipher) {
|
|
78
|
+
throw new Error('Unsupported encryption algorithm "${header.enc}".');
|
|
79
|
+
}
|
|
80
|
+
if (!Array.isArray(jwe.recipients)) {
|
|
81
|
+
throw new TypeError('"jwe.recipients" must be an array.');
|
|
82
|
+
}
|
|
83
|
+
// find `keyAgreementKey` matching recipient
|
|
84
|
+
const { keyAgreementKey } = this;
|
|
85
|
+
const recipient = _findRecipient(jwe.recipients, keyAgreementKey);
|
|
86
|
+
if (!recipient) {
|
|
87
|
+
throw new Error('No matching recipient found for key agreement key.');
|
|
88
|
+
}
|
|
89
|
+
// get wrapped CEK
|
|
90
|
+
const { encrypted_key: wrappedKey } = recipient;
|
|
91
|
+
if (typeof wrappedKey !== 'string') {
|
|
92
|
+
throw new Error('Invalid or missing "encrypted_key".');
|
|
93
|
+
}
|
|
94
|
+
// TODO: consider a cache of encrypted_key => CEKs to reduce unwrapping
|
|
95
|
+
// calls which may even need to hit the network (e.g., Web KMS)
|
|
96
|
+
// derive KEK and unwrap CEK
|
|
97
|
+
const { epk } = recipient.header;
|
|
98
|
+
const { keyAgreement } = this;
|
|
99
|
+
const { kek } = await keyAgreement.kekFromEphemeralPeer({
|
|
100
|
+
keyAgreementKey,
|
|
101
|
+
epk: epk
|
|
102
|
+
});
|
|
103
|
+
const cek = await kek.unwrapKey({ wrappedKey });
|
|
104
|
+
if (!cek) {
|
|
105
|
+
// failed to unwrap key
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
// decrypt content
|
|
109
|
+
const { ciphertext, iv, tag } = jwe;
|
|
110
|
+
return cipher.decrypt({
|
|
111
|
+
ciphertext: base64url.decode(ciphertext),
|
|
112
|
+
iv: base64url.decode(iv),
|
|
113
|
+
tag: base64url.decode(tag),
|
|
114
|
+
additionalData,
|
|
115
|
+
cek
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function _findRecipient(recipients, key) {
|
|
120
|
+
return recipients.find(e => e.header &&
|
|
121
|
+
e.header.kid === key.id &&
|
|
122
|
+
!key.algorithm &&
|
|
123
|
+
e.header.alg === KEY_ALGORITHM);
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=DecryptTransformer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DecryptTransformer.js","sourceRoot":"","sources":["../src/DecryptTransformer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { CipherAlgorithm, JWE, Recipient } from './types.js';
|
|
2
|
+
interface EncryptTransformerOptions {
|
|
3
|
+
recipients: Recipient[];
|
|
4
|
+
encodedProtectedHeader: string;
|
|
5
|
+
cipher: CipherAlgorithm;
|
|
6
|
+
additionalData: Uint8Array;
|
|
7
|
+
cek: Uint8Array;
|
|
8
|
+
chunkSize?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class EncryptTransformer {
|
|
11
|
+
recipients: Recipient[];
|
|
12
|
+
encodedProtectedHeader: string;
|
|
13
|
+
cipher: CipherAlgorithm;
|
|
14
|
+
additionalData: Uint8Array;
|
|
15
|
+
cek: Uint8Array;
|
|
16
|
+
chunkSize: number;
|
|
17
|
+
offset: number;
|
|
18
|
+
totalOffset: number;
|
|
19
|
+
index: number;
|
|
20
|
+
buffer: Uint8Array;
|
|
21
|
+
constructor({ recipients, encodedProtectedHeader, cipher, additionalData, cek, chunkSize }: EncryptTransformerOptions);
|
|
22
|
+
start(): void;
|
|
23
|
+
transform(chunk: Uint8Array | null, controller: TransformStreamDefaultController): Promise<void>;
|
|
24
|
+
flush(controller: TransformStreamDefaultController): Promise<void>;
|
|
25
|
+
encrypt(data: Uint8Array): Promise<JWE>;
|
|
26
|
+
}
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=EncryptTransformer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EncryptTransformer.d.ts","sourceRoot":"","sources":["../src/EncryptTransformer.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAKjE,UAAU,yBAAyB;IACjC,UAAU,EAAE,SAAS,EAAE,CAAA;IACvB,sBAAsB,EAAE,MAAM,CAAA;IAC9B,MAAM,EAAE,eAAe,CAAA;IACvB,cAAc,EAAE,UAAU,CAAA;IAC1B,GAAG,EAAE,UAAU,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,qBAAa,kBAAkB;IAC7B,UAAU,EAAE,SAAS,EAAE,CAAA;IACvB,sBAAsB,EAAE,MAAM,CAAA;IAC9B,MAAM,EAAE,eAAe,CAAA;IACvB,cAAc,EAAE,UAAU,CAAA;IAC1B,GAAG,EAAE,UAAU,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAG,UAAU,CAAA;gBAEP,EACV,UAAU,EACV,sBAAsB,EACtB,MAAM,EACN,cAAc,EACd,GAAG,EACH,SAA8B,EAC/B,EAAE,yBAAyB;IAY5B,KAAK,IAAI,IAAI;IAIP,SAAS,CACb,KAAK,EAAE,UAAU,GAAG,IAAI,EACxB,UAAU,EAAE,gCAAgC,GAC3C,OAAO,CAAC,IAAI,CAAC;IAiCV,KAAK,CAAC,UAAU,EAAE,gCAAgC,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBlE,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC;CAkB9C"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2019-2022 Digital Bazaar, Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
import { base64url } from './baseX.js';
|
|
5
|
+
// 1 MiB = 1048576
|
|
6
|
+
const DEFAULT_CHUNK_SIZE = 1048576;
|
|
7
|
+
export class EncryptTransformer {
|
|
8
|
+
recipients;
|
|
9
|
+
encodedProtectedHeader;
|
|
10
|
+
cipher;
|
|
11
|
+
additionalData;
|
|
12
|
+
cek;
|
|
13
|
+
chunkSize;
|
|
14
|
+
offset;
|
|
15
|
+
totalOffset;
|
|
16
|
+
index;
|
|
17
|
+
buffer;
|
|
18
|
+
constructor({ recipients, encodedProtectedHeader, cipher, additionalData, cek, chunkSize = DEFAULT_CHUNK_SIZE }) {
|
|
19
|
+
this.recipients = recipients;
|
|
20
|
+
this.encodedProtectedHeader = encodedProtectedHeader;
|
|
21
|
+
this.cipher = cipher;
|
|
22
|
+
this.additionalData = additionalData;
|
|
23
|
+
this.cek = cek;
|
|
24
|
+
this.chunkSize = chunkSize;
|
|
25
|
+
this.offset = 0;
|
|
26
|
+
this.totalOffset = 0;
|
|
27
|
+
this.index = 0;
|
|
28
|
+
}
|
|
29
|
+
start() {
|
|
30
|
+
this.buffer = new Uint8Array(this.chunkSize);
|
|
31
|
+
}
|
|
32
|
+
async transform(chunk, controller) {
|
|
33
|
+
const { buffer } = this;
|
|
34
|
+
// assumes `chunk` is a Uint8Array...
|
|
35
|
+
if (!(chunk instanceof Uint8Array)) {
|
|
36
|
+
throw new TypeError('"chunk" must be an object.');
|
|
37
|
+
}
|
|
38
|
+
while (chunk) {
|
|
39
|
+
const space = buffer.length - this.offset;
|
|
40
|
+
if (chunk.length <= space) {
|
|
41
|
+
buffer.set(chunk, this.offset);
|
|
42
|
+
this.offset += chunk.byteLength;
|
|
43
|
+
this.totalOffset += chunk.byteLength;
|
|
44
|
+
chunk = null;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const partial = new Uint8Array(chunk.buffer, chunk.byteOffset, space);
|
|
48
|
+
chunk = new Uint8Array(chunk.buffer, chunk.byteOffset + space, chunk.length - space);
|
|
49
|
+
buffer.set(partial, this.offset);
|
|
50
|
+
this.offset += space;
|
|
51
|
+
this.totalOffset += space;
|
|
52
|
+
}
|
|
53
|
+
// flush if buffer is full and more data remains
|
|
54
|
+
if (chunk) {
|
|
55
|
+
await this.flush(controller);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async flush(controller) {
|
|
60
|
+
if (this.offset === 0) {
|
|
61
|
+
// nothing to flush
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
// encrypt data
|
|
65
|
+
const { buffer } = this;
|
|
66
|
+
const data = new Uint8Array(buffer.buffer, buffer.byteOffset, this.offset);
|
|
67
|
+
const jwe = await this.encrypt(data);
|
|
68
|
+
// clear buffer
|
|
69
|
+
this.offset = 0;
|
|
70
|
+
controller.enqueue({
|
|
71
|
+
index: this.index++,
|
|
72
|
+
offset: this.totalOffset,
|
|
73
|
+
jwe
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
async encrypt(data) {
|
|
77
|
+
const { cipher, additionalData, cek } = this;
|
|
78
|
+
const { ciphertext, iv, tag } = await cipher.encrypt({
|
|
79
|
+
data,
|
|
80
|
+
additionalData,
|
|
81
|
+
cek
|
|
82
|
+
});
|
|
83
|
+
// represent encrypted data as JWE
|
|
84
|
+
const jwe = {
|
|
85
|
+
protected: this.encodedProtectedHeader,
|
|
86
|
+
recipients: this.recipients,
|
|
87
|
+
iv: base64url.encode(iv),
|
|
88
|
+
ciphertext: base64url.encode(ciphertext),
|
|
89
|
+
tag: base64url.encode(tag)
|
|
90
|
+
};
|
|
91
|
+
return jwe;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=EncryptTransformer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EncryptTransformer.js","sourceRoot":"","sources":["../src/EncryptTransformer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { CipherDecryptOptions, CipherEncryptOptions, EncryptResult } from '../types.js';
|
|
2
|
+
export declare const JWE_ENC = "A256GCM";
|
|
3
|
+
/**
|
|
4
|
+
* Generates a content encryption key (CEK). The 256-bit key is intended to be
|
|
5
|
+
* used as an AES-GCM key.
|
|
6
|
+
*
|
|
7
|
+
* @returns {Promise<Uint8Array>} - Resolves to the generated key.
|
|
8
|
+
*/
|
|
9
|
+
export declare function generateKey(): Promise<Uint8Array>;
|
|
10
|
+
/**
|
|
11
|
+
* Encrypts some data. The data will be encrypted using the given 256-bit
|
|
12
|
+
* AES-GCM content encryption key (CEK).
|
|
13
|
+
*
|
|
14
|
+
* @param {object} options - The options to use.
|
|
15
|
+
* @param {Uint8Array} options.data - The data to encrypt.
|
|
16
|
+
* @param {Uint8Array} options.additionalData - Optional additional
|
|
17
|
+
* authentication data.
|
|
18
|
+
* @param {Uint8Array} options.cek - The content encryption key to use.
|
|
19
|
+
*
|
|
20
|
+
* @returns {Promise<object>} - A Promise that resolves to
|
|
21
|
+
* `{ciphertext, iv, tag}`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function encrypt({ data, additionalData, cek }: CipherEncryptOptions): Promise<EncryptResult>;
|
|
24
|
+
/**
|
|
25
|
+
* Decrypts some encrypted data. The data must have been encrypted using
|
|
26
|
+
* the given 256-bit AES-GCM content encryption key.
|
|
27
|
+
*
|
|
28
|
+
* @param {object} options - The options to use.
|
|
29
|
+
* @param {Uint8Array} options.ciphertext - The data to decrypt.
|
|
30
|
+
* @param {Uint8Array} options.iv - The initialization vector.
|
|
31
|
+
* @param {Uint8Array} options.tag - The authentication tag.
|
|
32
|
+
* @param {Uint8Array} options.additionalData - Optional additional
|
|
33
|
+
* authentication data.
|
|
34
|
+
* @param {Uint8Array} options.cek - The content encryption key to use.
|
|
35
|
+
*
|
|
36
|
+
* @returns {Promise<Uint8Array>} - The decrypted data.
|
|
37
|
+
*/
|
|
38
|
+
export declare function decrypt({ ciphertext, iv, tag, additionalData, cek }: CipherDecryptOptions): Promise<Uint8Array>;
|
|
39
|
+
//# sourceMappingURL=a256gcm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a256gcm.d.ts","sourceRoot":"","sources":["../../src/algorithms/a256gcm.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,oBAAoB,EACpB,oBAAoB,EACpB,aAAa,EACd,MAAM,aAAa,CAAA;AAEpB,eAAO,MAAM,OAAO,YAAY,CAAA;AAEhC;;;;;GAKG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,UAAU,CAAC,CASvD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,OAAO,CAAC,EAC5B,IAAI,EACJ,cAAc,EACd,GAAG,EACJ,EAAE,oBAAoB,GAAG,OAAO,CAAC,aAAa,CAAC,CAiC/C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,OAAO,CAAC,EAC5B,UAAU,EACV,EAAE,EACF,GAAG,EACH,cAAc,EACd,GAAG,EACJ,EAAE,oBAAoB,GAAG,OAAO,CAAC,UAAU,CAAC,CA+B5C"}
|