@cloudpss/crypto 0.5.24 → 0.5.26
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/benchmark.js +44 -0
- package/dist/encryption/browser.d.ts +3 -3
- package/dist/encryption/browser.js +1 -2
- package/dist/encryption/browser.js.map +1 -1
- package/dist/encryption/common.d.ts +45 -16
- package/dist/encryption/common.js +59 -9
- package/dist/encryption/common.js.map +1 -1
- package/dist/encryption/index.d.ts +4 -21
- package/dist/encryption/index.js +11 -63
- package/dist/encryption/index.js.map +1 -1
- package/dist/encryption/module.d.ts +22 -0
- package/dist/encryption/module.js +62 -0
- package/dist/encryption/module.js.map +1 -0
- package/dist/encryption/node.d.ts +3 -3
- package/dist/encryption/node.js +19 -15
- package/dist/encryption/node.js.map +1 -1
- package/dist/encryption/wasm.d.ts +5 -0
- package/dist/encryption/wasm.js +21 -0
- package/dist/encryption/wasm.js.map +1 -0
- package/dist/encryption/web.d.ts +3 -3
- package/dist/encryption/web.js +17 -15
- package/dist/encryption/web.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/lib/wasm.d.ts +26 -0
- package/lib/wasm.js +149 -0
- package/package.json +11 -10
- package/src/encryption/browser.ts +4 -5
- package/src/encryption/common.ts +83 -16
- package/src/encryption/index.ts +12 -71
- package/src/encryption/module.ts +94 -0
- package/src/encryption/node.ts +24 -15
- package/src/encryption/wasm.ts +46 -0
- package/src/encryption/web.ts +24 -15
- package/src/index.ts +1 -1
- package/tests/encryption.js +151 -55
- package/tsconfig.json +2 -1
- package/wasm-build.js +30 -0
- package/dist/encryption/pure-js.d.ts +0 -5
- package/dist/encryption/pure-js.js +0 -54
- package/dist/encryption/pure-js.js.map +0 -1
- package/src/encryption/pure-js.ts +0 -62
package/benchmark.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import prettyBytes from 'pretty-bytes';
|
|
3
|
+
import files from '../../benchmark-files/index.js';
|
|
4
|
+
import { createModule } from './dist/encryption/module.js';
|
|
5
|
+
import * as wasm from './dist/encryption/wasm.js';
|
|
6
|
+
import * as web from './dist/encryption/web.js';
|
|
7
|
+
import * as node from './dist/encryption/node.js';
|
|
8
|
+
|
|
9
|
+
const t = (/** @type {number} */ time) =>
|
|
10
|
+
Number.isFinite(time) ? (time.toFixed(2) + 'ms').padStart(10) : ' --------';
|
|
11
|
+
|
|
12
|
+
const pb = (/** @type {number} */ size) => prettyBytes(size, { binary: true });
|
|
13
|
+
|
|
14
|
+
/** 生成测试 */
|
|
15
|
+
function createTest(/** @type {string} */ name, { encrypt, decrypt }, /** @type {boolean} */ decompressOnly = false) {
|
|
16
|
+
/** 测试函数 */
|
|
17
|
+
async function fn(/** @type {Buffer} */ data) {
|
|
18
|
+
let start = performance.now();
|
|
19
|
+
const encrypted = await encrypt(data, 'pass').catch((e) => console.error(e.message));
|
|
20
|
+
const encryptTime = performance.now() - start;
|
|
21
|
+
start = performance.now();
|
|
22
|
+
const decrypted = await decrypt(encrypted, 'pass').catch((e) => console.error(e.message));
|
|
23
|
+
const decryptTime = performance.now() - start;
|
|
24
|
+
console.assert(data.equals(decrypted), name, `unmatched`);
|
|
25
|
+
return { encrypted, encryptTime, decryptTime };
|
|
26
|
+
}
|
|
27
|
+
Object.defineProperty(fn, 'name', { value: name });
|
|
28
|
+
return fn;
|
|
29
|
+
}
|
|
30
|
+
const tests = [
|
|
31
|
+
createTest('web', createModule(web)),
|
|
32
|
+
createTest('node', createModule(node)),
|
|
33
|
+
createTest('wasm', createModule(wasm)),
|
|
34
|
+
];
|
|
35
|
+
for await (const { file, data } of files()) {
|
|
36
|
+
console.log(`File: ${file} \tRaw: ${pb(data.length)}`);
|
|
37
|
+
for (const test of tests) {
|
|
38
|
+
const result = await test(data);
|
|
39
|
+
const diff = `+${result.encrypted.length - data.length}`;
|
|
40
|
+
console.log(
|
|
41
|
+
` ${test.name.padEnd(25)} ${diff.padStart(6)} ${t(result.encryptTime)} ${t(result.decryptTime)}`,
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { EncryptedData, PlainData } from './common.js';
|
|
2
2
|
/** browser encrypt */
|
|
3
|
-
export declare function encrypt(data:
|
|
3
|
+
export declare function encrypt(data: PlainData, passphrase: string): Promise<EncryptedData>;
|
|
4
4
|
/** browser decrypt */
|
|
5
|
-
export declare function decrypt(data:
|
|
5
|
+
export declare function decrypt(data: EncryptedData, passphrase: string): Promise<PlainData>;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
2
2
|
const module = () => {
|
|
3
3
|
if (typeof crypto == 'object' &&
|
|
4
|
-
typeof crypto.getRandomValues == 'function' &&
|
|
5
4
|
typeof crypto.subtle == 'object' &&
|
|
6
5
|
typeof crypto.subtle.importKey == 'function' &&
|
|
7
6
|
typeof crypto.subtle.deriveKey == 'function' &&
|
|
@@ -10,7 +9,7 @@ const module = () => {
|
|
|
10
9
|
return import('./web.js');
|
|
11
10
|
}
|
|
12
11
|
else {
|
|
13
|
-
return import('./
|
|
12
|
+
return import('./wasm.js');
|
|
14
13
|
}
|
|
15
14
|
};
|
|
16
15
|
/** browser encrypt */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/encryption/browser.ts"],"names":[],"mappings":"AAEA,4EAA4E;AAC5E,MAAM,MAAM,GAAG,GAAG,EAAE;IAChB,IACI,OAAO,MAAM,IAAI,QAAQ;QACzB,OAAO,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/encryption/browser.ts"],"names":[],"mappings":"AAEA,4EAA4E;AAC5E,MAAM,MAAM,GAAG,GAAG,EAAE;IAChB,IACI,OAAO,MAAM,IAAI,QAAQ;QACzB,OAAO,MAAM,CAAC,MAAM,IAAI,QAAQ;QAChC,OAAO,MAAM,CAAC,MAAM,CAAC,SAAS,IAAI,UAAU;QAC5C,OAAO,MAAM,CAAC,MAAM,CAAC,SAAS,IAAI,UAAU;QAC5C,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,IAAI,UAAU;QAC1C,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,IAAI,UAAU,EAC5C,CAAC;QACC,OAAO,MAAM,CAAC,UAAU,CAAC,CAAC;IAC9B,CAAC;SAAM,CAAC;QACJ,OAAO,MAAM,CAAC,WAAW,CAAC,CAAC;IAC/B,CAAC;AACL,CAAC,CAAC;AAEF,sBAAsB;AACtB,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAe,EAAE,UAAkB;IAC7D,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,EAAE,CAAC;IACnC,OAAO,MAAM,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;AAC3C,CAAC;AAED,sBAAsB;AACtB,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAmB,EAAE,UAAkB;IACjE,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,EAAE,CAAC;IACnC,OAAO,MAAM,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -1,21 +1,50 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PBKDF2 迭代次数
|
|
3
|
-
*/
|
|
1
|
+
/** PBKDF2 迭代次数 */
|
|
4
2
|
export declare const PBKDF2_ITERATIONS = 100000;
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
*/
|
|
8
|
-
export declare const
|
|
9
|
-
/**
|
|
10
|
-
export declare const
|
|
3
|
+
/** NONCE 长度(byte) */
|
|
4
|
+
export declare const NONCE_SIZE: number;
|
|
5
|
+
/** AAD 最大长度(byte) */
|
|
6
|
+
export declare const AAD_MAX_SIZE: number;
|
|
7
|
+
/** AAD 长度字段长度(byte) */
|
|
8
|
+
export declare const AAD_LEN_SIZE = 4;
|
|
9
|
+
/** AAD padding */
|
|
10
|
+
export declare const AAD_PADDING: number;
|
|
11
11
|
/** KEY 长度(byte) */
|
|
12
12
|
export declare const AES_KEY_SIZE: number;
|
|
13
|
-
/**
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
|
|
19
|
-
/**
|
|
13
|
+
/** Auth tag 长度(byte) */
|
|
14
|
+
export declare const AES_TAG_SIZE: number;
|
|
15
|
+
/** 加密输入/解密结果 */
|
|
16
|
+
export interface PlainData {
|
|
17
|
+
/** 附加数据 */
|
|
18
|
+
aad?: Uint8Array;
|
|
19
|
+
/** 明文数据 */
|
|
20
20
|
data: Uint8Array;
|
|
21
21
|
}
|
|
22
|
+
/** 解密输入/加密结果 */
|
|
23
|
+
export interface EncryptedData {
|
|
24
|
+
/** NONCE */
|
|
25
|
+
nonce: Uint8Array;
|
|
26
|
+
/** 附加数据 */
|
|
27
|
+
aad?: Uint8Array;
|
|
28
|
+
/** 加密后的数据和 tag */
|
|
29
|
+
data: Uint8Array;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* CloudPSS 数据加密
|
|
33
|
+
* - 密钥生成算法:PBKDF2-HMAC-SHA256,盐长度 96,迭代 100,000 次
|
|
34
|
+
* - 加密算法:AES-256-GCM,使用与密钥生成算法的盐作为 NONCE,TAG 长度 128
|
|
35
|
+
* - 附加数据:最大长度 0x7fff_ffff
|
|
36
|
+
*
|
|
37
|
+
* - 文件格式:
|
|
38
|
+
* - Magic Number: 0e 02 49 29 3f 07 7b 0a
|
|
39
|
+
* - Nonce: 96 bits
|
|
40
|
+
* - Length of AAD: 4 bytes
|
|
41
|
+
* - AAD (if exists)
|
|
42
|
+
* - Encrypted Data
|
|
43
|
+
* - Auth Tag: 128 bits
|
|
44
|
+
*/
|
|
45
|
+
/** CloudPSS 数据加密 */
|
|
46
|
+
export declare const MAGIC_NUMBER: Uint8Array;
|
|
47
|
+
/** 计算对齐后的长度 */
|
|
48
|
+
export declare function padding(size: number, padding: number): number;
|
|
49
|
+
/** 解析 CloudPSS 加密数据 */
|
|
50
|
+
export declare function parseEncrypted(data: BinaryData): EncryptedData | undefined;
|
|
@@ -1,13 +1,63 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*/
|
|
1
|
+
import { toUint8Array } from '../utils.js';
|
|
2
|
+
/** PBKDF2 迭代次数 */
|
|
4
3
|
export const PBKDF2_ITERATIONS = 100_000;
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
*/
|
|
8
|
-
export const
|
|
9
|
-
/**
|
|
10
|
-
export const
|
|
4
|
+
/** NONCE 长度(byte) */
|
|
5
|
+
export const NONCE_SIZE = 96 / 8;
|
|
6
|
+
/** AAD 最大长度(byte) */
|
|
7
|
+
export const AAD_MAX_SIZE = 1024 * 1024 * 1024; // 1GiB
|
|
8
|
+
/** AAD 长度字段长度(byte) */
|
|
9
|
+
export const AAD_LEN_SIZE = 4;
|
|
10
|
+
// 与 AES 一致对齐
|
|
11
|
+
/** AAD padding */
|
|
12
|
+
export const AAD_PADDING = 128 / 8;
|
|
11
13
|
/** KEY 长度(byte) */
|
|
12
14
|
export const AES_KEY_SIZE = 256 / 8;
|
|
15
|
+
/** Auth tag 长度(byte) */
|
|
16
|
+
export const AES_TAG_SIZE = 128 / 8;
|
|
17
|
+
/**
|
|
18
|
+
* CloudPSS 数据加密
|
|
19
|
+
* - 密钥生成算法:PBKDF2-HMAC-SHA256,盐长度 96,迭代 100,000 次
|
|
20
|
+
* - 加密算法:AES-256-GCM,使用与密钥生成算法的盐作为 NONCE,TAG 长度 128
|
|
21
|
+
* - 附加数据:最大长度 0x7fff_ffff
|
|
22
|
+
*
|
|
23
|
+
* - 文件格式:
|
|
24
|
+
* - Magic Number: 0e 02 49 29 3f 07 7b 0a
|
|
25
|
+
* - Nonce: 96 bits
|
|
26
|
+
* - Length of AAD: 4 bytes
|
|
27
|
+
* - AAD (if exists)
|
|
28
|
+
* - Encrypted Data
|
|
29
|
+
* - Auth Tag: 128 bits
|
|
30
|
+
*/
|
|
31
|
+
/** CloudPSS 数据加密 */
|
|
32
|
+
export const MAGIC_NUMBER = Uint8Array.from([0x0e, 0x02, 0x49, 0x29, 0x3f, 0x07, 0x7b, 0x0a]);
|
|
33
|
+
const MIN_ENCRYPTED_SIZE = MAGIC_NUMBER.length + NONCE_SIZE + AAD_LEN_SIZE + AES_TAG_SIZE;
|
|
34
|
+
/** 计算对齐后的长度 */
|
|
35
|
+
export function padding(size, padding) {
|
|
36
|
+
return (size + padding - 1) & ~(padding - 1);
|
|
37
|
+
}
|
|
38
|
+
/** 解析 CloudPSS 加密数据 */
|
|
39
|
+
export function parseEncrypted(data) {
|
|
40
|
+
const buffer = toUint8Array(data);
|
|
41
|
+
if (buffer.byteLength < MIN_ENCRYPTED_SIZE)
|
|
42
|
+
return undefined;
|
|
43
|
+
if (!MAGIC_NUMBER.every((v, i) => buffer[i] === v))
|
|
44
|
+
return undefined;
|
|
45
|
+
const nonce = buffer.subarray(MAGIC_NUMBER.length, MAGIC_NUMBER.length + NONCE_SIZE);
|
|
46
|
+
const aadSize = (buffer[MAGIC_NUMBER.length + NONCE_SIZE] << 24) |
|
|
47
|
+
(buffer[MAGIC_NUMBER.length + NONCE_SIZE + 1] << 16) |
|
|
48
|
+
(buffer[MAGIC_NUMBER.length + NONCE_SIZE + 2] << 8) |
|
|
49
|
+
buffer[MAGIC_NUMBER.length + NONCE_SIZE + 3];
|
|
50
|
+
if (aadSize > AAD_MAX_SIZE || aadSize < 0) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
const paddingAadSize = padding(aadSize, AAD_PADDING);
|
|
54
|
+
if (buffer.byteLength < paddingAadSize + MIN_ENCRYPTED_SIZE) {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
const aad = aadSize
|
|
58
|
+
? buffer.subarray(MAGIC_NUMBER.length + NONCE_SIZE + AAD_LEN_SIZE, MAGIC_NUMBER.length + NONCE_SIZE + AAD_LEN_SIZE + aadSize)
|
|
59
|
+
: undefined;
|
|
60
|
+
const encrypted = buffer.subarray(MAGIC_NUMBER.length + NONCE_SIZE + AAD_LEN_SIZE + paddingAadSize);
|
|
61
|
+
return { nonce, aad, data: encrypted };
|
|
62
|
+
}
|
|
13
63
|
//# sourceMappingURL=common.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/encryption/common.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/encryption/common.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,26 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
* CloudPSS 数据加密
|
|
3
|
-
* - 密钥生成算法:PBKDF2-HMAC-SHA256,盐长度 128,迭代 100,000 次
|
|
4
|
-
* - 加密算法:AES-256-CBC
|
|
5
|
-
*
|
|
6
|
-
* - 文件格式:
|
|
7
|
-
* - Magic Number: 0e 02 49 29 3f 07 7b 0a
|
|
8
|
-
* - Salt: 128 bits
|
|
9
|
-
* - IV: 128 bits
|
|
10
|
-
* - Encrypted Data
|
|
11
|
-
*/
|
|
12
|
-
/** CloudPSS 数据加密 */
|
|
13
|
-
export declare const MAGIC_NUMBER: Uint8Array;
|
|
1
|
+
export { MAGIC_NUMBER } from './common.js';
|
|
14
2
|
/** 检查是否为 CloudPSS 加密数据 */
|
|
15
3
|
export declare function isEncrypted(data: BinaryData): boolean;
|
|
16
4
|
/**
|
|
17
|
-
*
|
|
18
|
-
* @throws {TypeError} 如果密码无效
|
|
19
|
-
*/
|
|
20
|
-
export declare function encrypt(data: BinaryData, passphrase: string): Promise<Uint8Array>;
|
|
21
|
-
/**
|
|
22
|
-
* 解密数据
|
|
5
|
+
* 从加密数据中提取附加数据
|
|
23
6
|
* @throws {TypeError} 如果数据不是有效的加密数据
|
|
24
|
-
* @throws {TypeError} 如果密码无效
|
|
25
7
|
*/
|
|
26
|
-
export declare function
|
|
8
|
+
export declare function extractAad(data: BinaryData): Uint8Array | undefined;
|
|
9
|
+
export declare const encrypt: (data: BinaryData, passphrase: string) => Promise<Uint8Array>, decrypt: (data: BinaryData, passphrase: string) => Promise<Uint8Array>, encryptAad: (data: BinaryData, aad: BinaryData | undefined, passphrase: string) => Promise<Uint8Array>;
|
package/dist/encryption/index.js
CHANGED
|
@@ -1,74 +1,22 @@
|
|
|
1
1
|
import * as impl from '#encryption';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
* CloudPSS 数据加密
|
|
6
|
-
* - 密钥生成算法:PBKDF2-HMAC-SHA256,盐长度 128,迭代 100,000 次
|
|
7
|
-
* - 加密算法:AES-256-CBC
|
|
8
|
-
*
|
|
9
|
-
* - 文件格式:
|
|
10
|
-
* - Magic Number: 0e 02 49 29 3f 07 7b 0a
|
|
11
|
-
* - Salt: 128 bits
|
|
12
|
-
* - IV: 128 bits
|
|
13
|
-
* - Encrypted Data
|
|
14
|
-
*/
|
|
15
|
-
/** CloudPSS 数据加密 */
|
|
16
|
-
export const MAGIC_NUMBER = Uint8Array.from([0x0e, 0x02, 0x49, 0x29, 0x3f, 0x07, 0x7b, 0x0a]);
|
|
17
|
-
/** 检查是否为 CloudPSS 加密数据 */
|
|
18
|
-
function isEncryptedImpl(data) {
|
|
19
|
-
return (data.length > MAGIC_NUMBER.length + PBKDF2_SALT_SIZE + AES_IV_SIZE &&
|
|
20
|
-
MAGIC_NUMBER.every((v, i) => data[i] === v));
|
|
21
|
-
}
|
|
2
|
+
import { parseEncrypted } from './common.js';
|
|
3
|
+
import { createModule } from './module.js';
|
|
4
|
+
export { MAGIC_NUMBER } from './common.js';
|
|
22
5
|
/** 检查是否为 CloudPSS 加密数据 */
|
|
23
6
|
export function isEncrypted(data) {
|
|
24
|
-
|
|
25
|
-
return isEncryptedImpl(buffer);
|
|
26
|
-
}
|
|
27
|
-
/** 检查密码 */
|
|
28
|
-
function assertPassphrase(passphrase) {
|
|
29
|
-
if (typeof passphrase !== 'string') {
|
|
30
|
-
throw new TypeError('Invalid passphrase, must be a string');
|
|
31
|
-
}
|
|
32
|
-
if (passphrase.length === 0) {
|
|
33
|
-
throw new TypeError('Invalid passphrase, must not be empty');
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* 加密数据
|
|
38
|
-
* @throws {TypeError} 如果密码无效
|
|
39
|
-
*/
|
|
40
|
-
export async function encrypt(data, passphrase) {
|
|
41
|
-
assertPassphrase(passphrase);
|
|
42
|
-
const buffer = toUint8Array(data);
|
|
43
|
-
const encrypted = await impl.encrypt(buffer, passphrase);
|
|
44
|
-
const result = new Uint8Array(MAGIC_NUMBER.length + PBKDF2_SALT_SIZE + AES_IV_SIZE + encrypted.data.length);
|
|
45
|
-
result.set(MAGIC_NUMBER);
|
|
46
|
-
result.set(encrypted.salt, MAGIC_NUMBER.length);
|
|
47
|
-
result.set(encrypted.iv, MAGIC_NUMBER.length + PBKDF2_SALT_SIZE);
|
|
48
|
-
result.set(encrypted.data, MAGIC_NUMBER.length + PBKDF2_SALT_SIZE + AES_IV_SIZE);
|
|
49
|
-
return result;
|
|
7
|
+
return parseEncrypted(data) != null;
|
|
50
8
|
}
|
|
51
9
|
/**
|
|
52
|
-
*
|
|
10
|
+
* 从加密数据中提取附加数据
|
|
53
11
|
* @throws {TypeError} 如果数据不是有效的加密数据
|
|
54
|
-
* @throws {TypeError} 如果密码无效
|
|
55
12
|
*/
|
|
56
|
-
export
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (!isEncryptedImpl(buffer)) {
|
|
13
|
+
export function extractAad(data) {
|
|
14
|
+
const encrypted = parseEncrypted(data);
|
|
15
|
+
if (encrypted == null) {
|
|
60
16
|
throw new TypeError('Invalid encrypted data');
|
|
61
17
|
}
|
|
62
|
-
|
|
63
|
-
salt: buffer.subarray(MAGIC_NUMBER.length, MAGIC_NUMBER.length + PBKDF2_SALT_SIZE),
|
|
64
|
-
iv: buffer.subarray(MAGIC_NUMBER.length + PBKDF2_SALT_SIZE, MAGIC_NUMBER.length + PBKDF2_SALT_SIZE + AES_IV_SIZE),
|
|
65
|
-
data: buffer.subarray(MAGIC_NUMBER.length + PBKDF2_SALT_SIZE + AES_IV_SIZE),
|
|
66
|
-
};
|
|
67
|
-
try {
|
|
68
|
-
return await impl.decrypt(encrypted, passphrase);
|
|
69
|
-
}
|
|
70
|
-
catch (ex) {
|
|
71
|
-
throw new Error('Wrong passphrase', { cause: ex });
|
|
72
|
-
}
|
|
18
|
+
return encrypted.aad;
|
|
73
19
|
}
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
21
|
+
export const { encrypt, decrypt, encryptAad } = createModule(impl);
|
|
74
22
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/encryption/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/encryption/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,0BAA0B;AAC1B,MAAM,UAAU,WAAW,CAAC,IAAgB;IACxC,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,IAAgB;IACvC,MAAM,SAAS,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;QACpB,MAAM,IAAI,SAAS,CAAC,wBAAwB,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,SAAS,CAAC,GAAG,CAAC;AACzB,CAAC;AAED,6DAA6D;AAC7D,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** 模块 */
|
|
2
|
+
interface Module {
|
|
3
|
+
/**
|
|
4
|
+
* 加密数据
|
|
5
|
+
* @throws {TypeError} 如果密码无效
|
|
6
|
+
*/
|
|
7
|
+
encrypt(data: BinaryData, passphrase: string): Promise<Uint8Array>;
|
|
8
|
+
/**
|
|
9
|
+
* 加密数据,包含不加密的附加数据
|
|
10
|
+
* @throws {TypeError} 如果密码无效
|
|
11
|
+
*/
|
|
12
|
+
encryptAad(data: BinaryData, aad: BinaryData | undefined, passphrase: string): Promise<Uint8Array>;
|
|
13
|
+
/**
|
|
14
|
+
* 解密数据
|
|
15
|
+
* @throws {TypeError} 如果数据不是有效的加密数据
|
|
16
|
+
* @throws {TypeError} 如果密码无效
|
|
17
|
+
*/
|
|
18
|
+
decrypt(data: BinaryData, passphrase: string): Promise<Uint8Array>;
|
|
19
|
+
}
|
|
20
|
+
/** 创建模块 */
|
|
21
|
+
export declare function createModule(impl: typeof import('#encryption') | typeof import('./wasm.js')): Module;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { toUint8Array } from '../utils.js';
|
|
2
|
+
import { AAD_LEN_SIZE, AAD_MAX_SIZE, AAD_PADDING, MAGIC_NUMBER, NONCE_SIZE, padding, parseEncrypted, } from './common.js';
|
|
3
|
+
/** 检查密码 */
|
|
4
|
+
function assertPassphrase(passphrase) {
|
|
5
|
+
if (typeof passphrase !== 'string') {
|
|
6
|
+
throw new TypeError('Invalid passphrase, must be a string');
|
|
7
|
+
}
|
|
8
|
+
if (passphrase.length === 0) {
|
|
9
|
+
throw new TypeError('Invalid passphrase, must not be empty');
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/** 创建模块 */
|
|
13
|
+
export function createModule(impl) {
|
|
14
|
+
const encryptAad = async (data, aad, passphrase) => {
|
|
15
|
+
assertPassphrase(passphrase);
|
|
16
|
+
const aadSize = aad?.byteLength ?? 0;
|
|
17
|
+
if (aadSize > AAD_MAX_SIZE) {
|
|
18
|
+
throw new TypeError('Invalid AAD size');
|
|
19
|
+
}
|
|
20
|
+
const paddedAddSize = padding(aadSize, AAD_PADDING);
|
|
21
|
+
const plain = {
|
|
22
|
+
aad: aadSize ? toUint8Array(aad) : undefined,
|
|
23
|
+
data: toUint8Array(data),
|
|
24
|
+
};
|
|
25
|
+
const encrypted = await impl.encrypt(plain, passphrase);
|
|
26
|
+
const result = new Uint8Array(MAGIC_NUMBER.length + NONCE_SIZE + AAD_LEN_SIZE + paddedAddSize + encrypted.data.length);
|
|
27
|
+
result.set(MAGIC_NUMBER);
|
|
28
|
+
result.set(encrypted.nonce, MAGIC_NUMBER.length);
|
|
29
|
+
if (aadSize) {
|
|
30
|
+
result[MAGIC_NUMBER.length + NONCE_SIZE] = aadSize >>> 24;
|
|
31
|
+
result[MAGIC_NUMBER.length + NONCE_SIZE + 1] = aadSize >>> 16;
|
|
32
|
+
result[MAGIC_NUMBER.length + NONCE_SIZE + 2] = aadSize >>> 8;
|
|
33
|
+
result[MAGIC_NUMBER.length + NONCE_SIZE + 3] = aadSize;
|
|
34
|
+
result.set(plain.aad, MAGIC_NUMBER.length + NONCE_SIZE + AAD_LEN_SIZE);
|
|
35
|
+
}
|
|
36
|
+
result.set(encrypted.data, MAGIC_NUMBER.length + NONCE_SIZE + AAD_LEN_SIZE + paddedAddSize);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
const encrypt = async (data, passphrase) => {
|
|
40
|
+
return await encryptAad(data, undefined, passphrase);
|
|
41
|
+
};
|
|
42
|
+
const decrypt = async (data, passphrase) => {
|
|
43
|
+
assertPassphrase(passphrase);
|
|
44
|
+
const encrypted = parseEncrypted(data);
|
|
45
|
+
if (encrypted == null) {
|
|
46
|
+
throw new TypeError('Invalid encrypted data');
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const result = await impl.decrypt(encrypted, passphrase);
|
|
50
|
+
return result.data;
|
|
51
|
+
}
|
|
52
|
+
catch (ex) {
|
|
53
|
+
throw new Error('Wrong passphrase', { cause: ex });
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
return {
|
|
57
|
+
encrypt,
|
|
58
|
+
encryptAad,
|
|
59
|
+
decrypt,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.js","sourceRoot":"","sources":["../../src/encryption/module.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type EncryptedData, type PlainData } from './common.js';
|
|
2
2
|
/** nodejs encrypt */
|
|
3
|
-
export declare function encrypt(data:
|
|
3
|
+
export declare function encrypt({ data, aad }: PlainData, passphrase: string): Promise<EncryptedData>;
|
|
4
4
|
/** nodejs decrypt */
|
|
5
|
-
export declare function decrypt({
|
|
5
|
+
export declare function decrypt({ nonce, aad, data }: EncryptedData, passphrase: string): Promise<PlainData>;
|
package/dist/encryption/node.js
CHANGED
|
@@ -1,28 +1,32 @@
|
|
|
1
1
|
import { pbkdf2 as _pbkdf2, createCipheriv, createDecipheriv, randomBytes } from 'node:crypto';
|
|
2
|
-
import { PBKDF2_ITERATIONS,
|
|
2
|
+
import { PBKDF2_ITERATIONS, NONCE_SIZE, AES_TAG_SIZE, AES_KEY_SIZE, } from './common.js';
|
|
3
3
|
import { promisify } from 'node:util';
|
|
4
4
|
import { toUint8Array } from '../utils.js';
|
|
5
|
+
const pbkdf2 = promisify(_pbkdf2);
|
|
5
6
|
const aesKdf = (passphrase, salt) => {
|
|
6
|
-
return
|
|
7
|
+
return pbkdf2(passphrase, salt, PBKDF2_ITERATIONS, AES_KEY_SIZE, 'sha256');
|
|
7
8
|
};
|
|
8
9
|
/** nodejs encrypt */
|
|
9
|
-
export async function encrypt(data, passphrase) {
|
|
10
|
-
const
|
|
11
|
-
const key = await aesKdf(passphrase,
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
export async function encrypt({ data, aad }, passphrase) {
|
|
11
|
+
const nonce = randomBytes(NONCE_SIZE);
|
|
12
|
+
const key = await aesKdf(passphrase, nonce);
|
|
13
|
+
const cipher = createCipheriv('aes-256-gcm', key, nonce, { authTagLength: AES_TAG_SIZE });
|
|
14
|
+
if (aad)
|
|
15
|
+
cipher.setAAD(aad);
|
|
16
|
+
const encrypted = Buffer.concat([cipher.update(data), cipher.final(), cipher.getAuthTag()]);
|
|
15
17
|
return {
|
|
16
|
-
|
|
17
|
-
iv: toUint8Array(iv),
|
|
18
|
+
nonce: toUint8Array(nonce),
|
|
18
19
|
data: toUint8Array(encrypted),
|
|
19
20
|
};
|
|
20
21
|
}
|
|
21
22
|
/** nodejs decrypt */
|
|
22
|
-
export async function decrypt({
|
|
23
|
-
const key = await aesKdf(passphrase,
|
|
24
|
-
const decipher = createDecipheriv('aes-256-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
export async function decrypt({ nonce, aad, data }, passphrase) {
|
|
24
|
+
const key = await aesKdf(passphrase, nonce);
|
|
25
|
+
const decipher = createDecipheriv('aes-256-gcm', key, nonce, { authTagLength: AES_TAG_SIZE });
|
|
26
|
+
decipher.setAuthTag(data.subarray(data.length - AES_TAG_SIZE));
|
|
27
|
+
if (aad)
|
|
28
|
+
decipher.setAAD(aad);
|
|
29
|
+
const decrypted = Buffer.concat([decipher.update(data.subarray(0, data.length - AES_TAG_SIZE)), decipher.final()]);
|
|
30
|
+
return { data: toUint8Array(decrypted) };
|
|
27
31
|
}
|
|
28
32
|
//# sourceMappingURL=node.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/encryption/node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/F,OAAO,
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/encryption/node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/F,OAAO,EACH,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,YAAY,GAGf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;AAClC,MAAM,MAAM,GAAG,CAAC,UAAkB,EAAE,IAAgB,EAAmB,EAAE;IACrE,OAAO,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,iBAAiB,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;AAC/E,CAAC,CAAC;AAEF,qBAAqB;AACrB,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,EAAE,IAAI,EAAE,GAAG,EAAa,EAAE,UAAkB;IACtE,MAAM,KAAK,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,cAAc,CAAC,aAAa,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,aAAa,EAAE,YAAY,EAAE,CAAC,CAAC;IAC1F,IAAI,GAAG;QAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IAC5F,OAAO;QACH,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC;QAC1B,IAAI,EAAE,YAAY,CAAC,SAAS,CAAC;KAChC,CAAC;AACN,CAAC;AAED,qBAAqB;AACrB,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAiB,EAAE,UAAkB;IACjF,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,aAAa,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,aAAa,EAAE,YAAY,EAAE,CAAC,CAAC;IAC9F,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC;IAC/D,IAAI,GAAG;QAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC9B,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,YAAY,CAAC,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACnH,OAAO,EAAE,IAAI,EAAE,YAAY,CAAC,SAAS,CAAC,EAAE,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type EncryptedData, type PlainData } from './common.js';
|
|
2
|
+
/** crypto-js encrypt */
|
|
3
|
+
export declare function encrypt({ data, aad }: PlainData, passphrase: string): EncryptedData;
|
|
4
|
+
/** crypto-js decrypt */
|
|
5
|
+
export declare function decrypt({ data, aad, nonce }: EncryptedData, passphrase: string): PlainData;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { NONCE_SIZE, AES_KEY_SIZE, AES_TAG_SIZE, PBKDF2_ITERATIONS, } from './common.js';
|
|
2
|
+
import * as mod from '#lib-wasm';
|
|
3
|
+
const EMPTY = new Uint8Array(0);
|
|
4
|
+
const encoder = new TextEncoder();
|
|
5
|
+
/** crypto-js encrypt */
|
|
6
|
+
export function encrypt({ data, aad }, passphrase) {
|
|
7
|
+
const nonce = crypto.getRandomValues(new Uint8Array(NONCE_SIZE));
|
|
8
|
+
const result = mod.encrypt(encoder.encode(passphrase), data, aad ?? EMPTY, nonce, PBKDF2_ITERATIONS, AES_KEY_SIZE, AES_TAG_SIZE);
|
|
9
|
+
return {
|
|
10
|
+
nonce,
|
|
11
|
+
data: result,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/** crypto-js decrypt */
|
|
15
|
+
export function decrypt({ data, aad, nonce }, passphrase) {
|
|
16
|
+
const decrypted = mod.decrypt(encoder.encode(passphrase), data, aad ?? EMPTY, nonce, PBKDF2_ITERATIONS, AES_KEY_SIZE, AES_TAG_SIZE);
|
|
17
|
+
return {
|
|
18
|
+
data: decrypted,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=wasm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wasm.js","sourceRoot":"","sources":["../../src/encryption/wasm.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,UAAU,EACV,YAAY,EACZ,YAAY,EAEZ,iBAAiB,GAEpB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,GAAG,MAAM,WAAW,CAAC;AAEjC,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;AAChC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;AAElC,wBAAwB;AACxB,MAAM,UAAU,OAAO,CAAC,EAAE,IAAI,EAAE,GAAG,EAAa,EAAE,UAAkB;IAChE,MAAM,KAAK,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC;IACjE,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CACtB,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,EAC1B,IAAI,EACJ,GAAG,IAAI,KAAK,EACZ,KAAK,EACL,iBAAiB,EACjB,YAAY,EACZ,YAAY,CACf,CAAC;IACF,OAAO;QACH,KAAK;QACL,IAAI,EAAE,MAAM;KACf,CAAC;AACN,CAAC;AAED,wBAAwB;AACxB,MAAM,UAAU,OAAO,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAiB,EAAE,UAAkB;IAC3E,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CACzB,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,EAC1B,IAAI,EACJ,GAAG,IAAI,KAAK,EACZ,KAAK,EACL,iBAAiB,EACjB,YAAY,EACZ,YAAY,CACf,CAAC;IACF,OAAO;QACH,IAAI,EAAE,SAAS;KAClB,CAAC;AACN,CAAC"}
|
package/dist/encryption/web.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type EncryptedData, type PlainData } from './common.js';
|
|
2
2
|
/** webcrypto encrypt */
|
|
3
|
-
export declare function encrypt(data:
|
|
3
|
+
export declare function encrypt({ data, aad }: PlainData, passphrase: string): Promise<EncryptedData>;
|
|
4
4
|
/** webcrypto decrypt */
|
|
5
|
-
export declare function decrypt({ data,
|
|
5
|
+
export declare function decrypt({ data, nonce, aad }: EncryptedData, passphrase: string): Promise<PlainData>;
|
package/dist/encryption/web.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NONCE_SIZE, AES_TAG_SIZE, AES_KEY_SIZE, PBKDF2_ITERATIONS, } from './common.js';
|
|
2
2
|
const encoder = new TextEncoder();
|
|
3
3
|
/** Create aes params */
|
|
4
4
|
async function aesKdfWeb(passphrase, salt) {
|
|
@@ -9,33 +9,35 @@ async function aesKdfWeb(passphrase, salt) {
|
|
|
9
9
|
iterations: PBKDF2_ITERATIONS,
|
|
10
10
|
hash: 'SHA-256',
|
|
11
11
|
};
|
|
12
|
-
return await crypto.subtle.deriveKey(pbkdf2Params, pass, { name: 'AES-
|
|
12
|
+
return await crypto.subtle.deriveKey(pbkdf2Params, pass, { name: 'AES-GCM', length: AES_KEY_SIZE * 8 }, false, [
|
|
13
13
|
'encrypt',
|
|
14
14
|
'decrypt',
|
|
15
15
|
]);
|
|
16
16
|
}
|
|
17
17
|
/** webcrypto encrypt */
|
|
18
|
-
export async function encrypt(data, passphrase) {
|
|
19
|
-
const
|
|
20
|
-
const key = await aesKdfWeb(passphrase,
|
|
21
|
-
const iv = crypto.getRandomValues(new Uint8Array(AES_IV_SIZE));
|
|
18
|
+
export async function encrypt({ data, aad }, passphrase) {
|
|
19
|
+
const nonce = crypto.getRandomValues(new Uint8Array(NONCE_SIZE));
|
|
20
|
+
const key = await aesKdfWeb(passphrase, nonce);
|
|
22
21
|
const encrypted = await crypto.subtle.encrypt({
|
|
23
|
-
name: 'AES-
|
|
24
|
-
iv,
|
|
22
|
+
name: 'AES-GCM',
|
|
23
|
+
iv: nonce,
|
|
24
|
+
tagLength: AES_TAG_SIZE * 8,
|
|
25
|
+
additionalData: aad,
|
|
25
26
|
}, key, data);
|
|
26
27
|
return {
|
|
27
|
-
|
|
28
|
-
iv: iv,
|
|
28
|
+
nonce,
|
|
29
29
|
data: new Uint8Array(encrypted),
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
32
|
/** webcrypto decrypt */
|
|
33
|
-
export async function decrypt({ data,
|
|
34
|
-
const key = await aesKdfWeb(passphrase,
|
|
33
|
+
export async function decrypt({ data, nonce, aad }, passphrase) {
|
|
34
|
+
const key = await aesKdfWeb(passphrase, nonce);
|
|
35
35
|
const decrypted = await crypto.subtle.decrypt({
|
|
36
|
-
name: 'AES-
|
|
37
|
-
iv,
|
|
36
|
+
name: 'AES-GCM',
|
|
37
|
+
iv: nonce,
|
|
38
|
+
tagLength: AES_TAG_SIZE * 8,
|
|
39
|
+
additionalData: aad,
|
|
38
40
|
}, key, data);
|
|
39
|
-
return new Uint8Array(decrypted);
|
|
41
|
+
return { data: new Uint8Array(decrypted) };
|
|
40
42
|
}
|
|
41
43
|
//# sourceMappingURL=web.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/encryption/web.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/encryption/web.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,UAAU,EACV,YAAY,EACZ,YAAY,EAGZ,iBAAiB,GACpB,MAAM,aAAa,CAAC;AAErB,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;AAElC,wBAAwB;AACxB,KAAK,UAAU,SAAS,CAAC,UAAkB,EAAE,IAAgB;IACzD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;IAC9G,MAAM,YAAY,GAAiB;QAC/B,IAAI,EAAE,QAAQ;QACd,IAAI;QACJ,UAAU,EAAE,iBAAiB;QAC7B,IAAI,EAAE,SAAS;KAClB,CAAC;IACF,OAAO,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE;QAC3G,SAAS;QACT,SAAS;KACZ,CAAC,CAAC;AACP,CAAC;AAED,wBAAwB;AACxB,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,EAAE,IAAI,EAAE,GAAG,EAAa,EAAE,UAAkB;IACtE,MAAM,KAAK,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC;IACjE,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAC/C,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CACzC;QACI,IAAI,EAAE,SAAS;QACf,EAAE,EAAE,KAAK;QACT,SAAS,EAAE,YAAY,GAAG,CAAC;QAC3B,cAAc,EAAE,GAAG;KACtB,EACD,GAAG,EACH,IAAI,CACP,CAAC;IACF,OAAO;QACH,KAAK;QACL,IAAI,EAAE,IAAI,UAAU,CAAC,SAAS,CAAC;KAClC,CAAC;AACN,CAAC;AAED,wBAAwB;AACxB,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAiB,EAAE,UAAkB;IACjF,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAC/C,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CACzC;QACI,IAAI,EAAE,SAAS;QACf,EAAE,EAAE,KAAK;QACT,SAAS,EAAE,YAAY,GAAG,CAAC;QAC3B,cAAc,EAAE,GAAG;KACtB,EACD,GAAG,EACH,IAAI,CACP,CAAC;IACF,OAAO,EAAE,IAAI,EAAE,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;AAC/C,CAAC"}
|