@pryv/encryption 3.11.0 → 3.12.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/package.json
CHANGED
package/src/EventsCipher.js
CHANGED
|
@@ -46,7 +46,7 @@ class EventsCipher {
|
|
|
46
46
|
* `encrypt` is optional (a decrypt-only method supports reading existing
|
|
47
47
|
* encrypted events but cannot produce new ones).
|
|
48
48
|
* @param {string} name
|
|
49
|
-
* @param {{ decrypt: Function, encrypt?: Function }} method
|
|
49
|
+
* @param {{ decrypt: Function, encrypt?: Function, encryptBytes?: Function, decryptBytes?: Function }} method
|
|
50
50
|
* @returns {EventsCipher} this, for chaining.
|
|
51
51
|
*/
|
|
52
52
|
registerMethod (name, method) {
|
|
@@ -72,7 +72,7 @@ class EventsCipher {
|
|
|
72
72
|
* @param {*} [params.hint]
|
|
73
73
|
* @returns {Promise<{ type: string, content: { payload: string, keyRef?: string, hint?: * } }>}
|
|
74
74
|
*/
|
|
75
|
-
async encryptEventContent (material, params = {}) {
|
|
75
|
+
async encryptEventContent (material, params = /** @type {any} */ ({})) {
|
|
76
76
|
const { method: methodName, keyRef, hint } = params;
|
|
77
77
|
const method = this._methods[methodName];
|
|
78
78
|
if (!method) {
|
|
@@ -103,7 +103,7 @@ class EventsCipher {
|
|
|
103
103
|
* @param {*} [params.hint]
|
|
104
104
|
* @returns {Promise<Object>} a new encrypted event (input is not mutated).
|
|
105
105
|
*/
|
|
106
|
-
async encryptEvent (plainEvent, params = {}) {
|
|
106
|
+
async encryptEvent (plainEvent, params = /** @type {any} */ ({})) {
|
|
107
107
|
const { type, content } = await this.encryptEventContent(plainEvent, params);
|
|
108
108
|
const encrypted = Object.assign({}, plainEvent);
|
|
109
109
|
encrypted.type = type;
|
|
@@ -180,7 +180,7 @@ class EventsCipher {
|
|
|
180
180
|
* @param {*} [params.hint]
|
|
181
181
|
* @returns {Promise<Uint8Array>} raw payload-layout bytes.
|
|
182
182
|
*/
|
|
183
|
-
async encryptAttachmentData (bytes, params = {}) {
|
|
183
|
+
async encryptAttachmentData (bytes, params = /** @type {any} */ ({})) {
|
|
184
184
|
const { method: methodName, keyRef, hint } = params;
|
|
185
185
|
const method = this._methods[methodName];
|
|
186
186
|
if (!method) {
|
|
@@ -43,7 +43,11 @@ async function importKey (key) {
|
|
|
43
43
|
if (raw.length !== KEY_LENGTH) {
|
|
44
44
|
throw new Error(`aes-256-gcm: key must be ${KEY_LENGTH} bytes, got ${raw.length}`);
|
|
45
45
|
}
|
|
46
|
-
|
|
46
|
+
// Cast at the Web Crypto boundary: since TypeScript 5.7 a bare
|
|
47
|
+
// `Uint8Array` is `Uint8Array<ArrayBufferLike>`, which admits
|
|
48
|
+
// SharedArrayBuffer and so is not a `BufferSource`. These bytes never
|
|
49
|
+
// come from shared memory, and Web Crypto rejects it regardless.
|
|
50
|
+
return globalThis.crypto.subtle.importKey('raw', /** @type {BufferSource} */ (raw), ALGORITHM, false, ['encrypt', 'decrypt']);
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
/**
|
|
@@ -58,7 +62,7 @@ async function importKey (key) {
|
|
|
58
62
|
async function encryptBytes (bytes, key) {
|
|
59
63
|
const cryptoKey = await importKey(key);
|
|
60
64
|
const iv = globalThis.crypto.getRandomValues(new Uint8Array(IV_LENGTH));
|
|
61
|
-
const cipherBuffer = await globalThis.crypto.subtle.encrypt({ name: ALGORITHM, iv }, cryptoKey, bytes);
|
|
65
|
+
const cipherBuffer = await globalThis.crypto.subtle.encrypt({ name: ALGORITHM, iv }, cryptoKey, /** @type {BufferSource} */ (bytes));
|
|
62
66
|
const cipherBytes = new Uint8Array(cipherBuffer);
|
|
63
67
|
|
|
64
68
|
const out = new Uint8Array(iv.length + cipherBytes.length);
|
|
@@ -45,7 +45,7 @@ function evpBytesToKey (passphrase, salt) {
|
|
|
45
45
|
input.set(block, 0);
|
|
46
46
|
input.set(passphrase, block.length);
|
|
47
47
|
input.set(salt, block.length + passphrase.length);
|
|
48
|
-
block = md5(input);
|
|
48
|
+
block = /** @type {Uint8Array<ArrayBuffer>} */ (md5(input));
|
|
49
49
|
const take = Math.min(block.length, needed - filled);
|
|
50
50
|
derived.set(block.subarray(0, take), filled);
|
|
51
51
|
filled += take;
|
|
@@ -85,8 +85,13 @@ async function decrypt (content, key) {
|
|
|
85
85
|
const passphrase = new TextEncoder().encode(key);
|
|
86
86
|
const { key: keyBytes, iv } = evpBytesToKey(passphrase, salt);
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
const
|
|
88
|
+
// See the boundary note in aes-256-gcm.js.
|
|
89
|
+
const cryptoKey = await globalThis.crypto.subtle.importKey('raw', /** @type {BufferSource} */ (keyBytes), 'AES-CBC', false, ['decrypt']);
|
|
90
|
+
const plainBuffer = await globalThis.crypto.subtle.decrypt(
|
|
91
|
+
{ name: 'AES-CBC', iv: /** @type {BufferSource} */ (iv) },
|
|
92
|
+
cryptoKey,
|
|
93
|
+
/** @type {BufferSource} */ (ciphertext)
|
|
94
|
+
);
|
|
90
95
|
return JSON.parse(new TextDecoder().decode(plainBuffer));
|
|
91
96
|
}
|
|
92
97
|
|
|
@@ -106,29 +106,30 @@ async function normalizeKey (material, usage) {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
if (wantPrivate) {
|
|
109
|
-
|
|
109
|
+
// See the boundary note in aes-256-gcm.js.
|
|
110
|
+
return subtle.importKey('pkcs8', /** @type {BufferSource} */ (bytes), ALGORITHM, false, ['deriveBits']);
|
|
110
111
|
}
|
|
111
112
|
if (bytes.length !== EPH_PUB_LENGTH || bytes[0] !== 0x04) {
|
|
112
113
|
throw new Error('ecies-aes-256-gcm: public key must be a 65-byte SEC1 uncompressed point (0x04 || X || Y)');
|
|
113
114
|
}
|
|
114
|
-
return subtle.importKey('raw', bytes, ALGORITHM, false, []);
|
|
115
|
+
return subtle.importKey('raw', /** @type {BufferSource} */ (bytes), ALGORITHM, false, []);
|
|
115
116
|
}
|
|
116
117
|
|
|
117
118
|
/**
|
|
118
119
|
* Derive the AES-256-GCM key from an ECDH shared secret via HKDF-SHA-256.
|
|
119
120
|
* @param {Uint8Array} secret - the 32-byte ECDH shared secret.
|
|
120
|
-
* @param {
|
|
121
|
+
* @param {KeyUsage[]} usages
|
|
121
122
|
* @returns {Promise<CryptoKey>}
|
|
122
123
|
*/
|
|
123
124
|
async function deriveAesKey (secret, usages) {
|
|
124
125
|
const subtle = globalThis.crypto.subtle;
|
|
125
|
-
const hkdfKey = await subtle.importKey('raw', secret, 'HKDF', false, ['deriveBits']);
|
|
126
|
+
const hkdfKey = await subtle.importKey('raw', /** @type {BufferSource} */ (secret), 'HKDF', false, ['deriveBits']);
|
|
126
127
|
const aesBits = await subtle.deriveBits(
|
|
127
128
|
{ name: 'HKDF', hash: 'SHA-256', salt: new Uint8Array(0), info: new TextEncoder().encode(INFO) },
|
|
128
129
|
hkdfKey,
|
|
129
130
|
256
|
|
130
131
|
);
|
|
131
|
-
return subtle.importKey('raw', new Uint8Array(aesBits), 'AES-GCM', false, usages);
|
|
132
|
+
return subtle.importKey('raw', /** @type {BufferSource} */ (new Uint8Array(aesBits)), 'AES-GCM', false, usages);
|
|
132
133
|
}
|
|
133
134
|
|
|
134
135
|
/**
|
|
@@ -150,7 +151,7 @@ async function encryptBytes (bytes, key) {
|
|
|
150
151
|
const aesKey = await deriveAesKey(new Uint8Array(secretBits), ['encrypt']);
|
|
151
152
|
|
|
152
153
|
const iv = globalThis.crypto.getRandomValues(new Uint8Array(IV_LENGTH));
|
|
153
|
-
const cipherBuffer = await subtle.encrypt({ name: 'AES-GCM', iv }, aesKey, bytes);
|
|
154
|
+
const cipherBuffer = await subtle.encrypt({ name: 'AES-GCM', iv }, aesKey, /** @type {BufferSource} */ (bytes));
|
|
154
155
|
const cipherBytes = new Uint8Array(cipherBuffer);
|
|
155
156
|
|
|
156
157
|
const ephRaw = new Uint8Array(await subtle.exportKey('raw', ephemeral.publicKey));
|