@cloudpss/crypto 0.5.24 → 0.5.25
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.map +1 -1
- package/dist/encryption/common.d.ts +45 -16
- package/dist/encryption/common.js +57 -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/js/aes.d.ts +20 -0
- package/dist/encryption/js/aes.js +151 -0
- package/dist/encryption/js/aes.js.map +1 -0
- package/dist/encryption/js/gcm.d.ts +26 -0
- package/dist/encryption/js/gcm.js +226 -0
- package/dist/encryption/js/gcm.js.map +1 -0
- 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/pure-js.d.ts +3 -3
- package/dist/encryption/pure-js.js +70 -42
- package/dist/encryption/pure-js.js.map +1 -1
- 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/package.json +7 -4
- package/src/encryption/browser.ts +3 -3
- package/src/encryption/common.ts +79 -16
- package/src/encryption/index.ts +12 -71
- package/src/encryption/js/aes.ts +191 -0
- package/src/encryption/js/gcm.ts +258 -0
- package/src/encryption/module.ts +94 -0
- package/src/encryption/node.ts +24 -15
- package/src/encryption/pure-js.ts +89 -46
- package/src/encryption/web.ts +24 -15
- package/src/index.ts +1 -1
- package/tests/encryption.js +126 -49
package/tests/encryption.js
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
import { MAGIC_NUMBER } from '../dist/encryption/index.js';
|
|
2
|
-
import { isEncrypted, encrypt, decrypt } from '../dist/index.js';
|
|
2
|
+
import { isEncrypted, encrypt, decrypt, encryptAad, extractAad } from '../dist/index.js';
|
|
3
3
|
import { toUint8Array } from '../dist/utils.js';
|
|
4
|
+
import { createModule } from '../dist/encryption/module.js';
|
|
4
5
|
import * as nodeImpl from '../dist/encryption/node.js';
|
|
5
6
|
import * as browserImpl from '../dist/encryption/browser.js';
|
|
6
7
|
import * as webImpl from '../dist/encryption/web.js';
|
|
7
8
|
import * as jsImpl from '../dist/encryption/pure-js.js';
|
|
8
9
|
|
|
10
|
+
const data = [
|
|
11
|
+
Buffer.from(''),
|
|
12
|
+
Buffer.from('Hello, World!'),
|
|
13
|
+
Buffer.from('Hello, World!'.repeat(100)),
|
|
14
|
+
new Uint8Array(100),
|
|
15
|
+
Buffer.from('Hello, World!'.repeat(1000)).buffer,
|
|
16
|
+
].map((d) => ({ raw: d, length: d.byteLength, type: d.constructor.name }));
|
|
17
|
+
const passphrase = 'test';
|
|
18
|
+
|
|
9
19
|
describe('Encryption root export', () => {
|
|
10
20
|
it('has MAGIC_NUMBER', () => {
|
|
11
21
|
expect(MAGIC_NUMBER).toBeInstanceOf(Uint8Array);
|
|
@@ -16,8 +26,8 @@ describe('Encryption root export', () => {
|
|
|
16
26
|
// @ts-expect-error bad type
|
|
17
27
|
expect(() => isEncrypted({})).toThrow('Invalid data');
|
|
18
28
|
expect(isEncrypted(Buffer.from(MAGIC_NUMBER))).toBe(false);
|
|
19
|
-
expect(isEncrypted(Buffer.concat([MAGIC_NUMBER, Buffer.alloc(
|
|
20
|
-
expect(isEncrypted(Buffer.concat([MAGIC_NUMBER, Buffer.alloc(
|
|
29
|
+
expect(isEncrypted(Buffer.concat([MAGIC_NUMBER, Buffer.alloc(31)]))).toBe(false);
|
|
30
|
+
expect(isEncrypted(Buffer.concat([MAGIC_NUMBER, Buffer.alloc(32)]))).toBe(true);
|
|
21
31
|
expect(isEncrypted(Buffer.alloc(40))).toBe(false);
|
|
22
32
|
expect(isEncrypted(Buffer.alloc(41))).toBe(false);
|
|
23
33
|
});
|
|
@@ -40,71 +50,137 @@ describe('Encryption root export', () => {
|
|
|
40
50
|
await expect(() => decrypt(Buffer.alloc(100), 'xx')).rejects.toThrow('Invalid encrypted data');
|
|
41
51
|
});
|
|
42
52
|
|
|
43
|
-
it('
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
Buffer.from('Hello, World!'.repeat(1000)).buffer,
|
|
50
|
-
];
|
|
51
|
-
const passphrase = 'test';
|
|
52
|
-
for (const raw of data) {
|
|
53
|
-
const encrypted = await encrypt(raw, passphrase);
|
|
54
|
-
expect(encrypted).toBeInstanceOf(Uint8Array);
|
|
55
|
-
expect(encrypted.byteLength).toBeGreaterThan(raw.byteLength);
|
|
56
|
-
expect(isEncrypted(encrypted)).toBe(true);
|
|
53
|
+
it('accepts empty aad', async () => {
|
|
54
|
+
const encrypted = await encryptAad(Buffer.alloc(0), Buffer.alloc(0), passphrase);
|
|
55
|
+
expect(encrypted).toBeInstanceOf(Uint8Array);
|
|
56
|
+
const extractedAad = extractAad(encrypted);
|
|
57
|
+
expect(extractedAad).toBeUndefined();
|
|
58
|
+
});
|
|
57
59
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
it('accepts undefined aad', async () => {
|
|
61
|
+
const encrypted = await encryptAad(Buffer.alloc(0), undefined, passphrase);
|
|
62
|
+
expect(encrypted).toBeInstanceOf(Uint8Array);
|
|
63
|
+
const extractedAad = extractAad(encrypted);
|
|
64
|
+
expect(extractedAad).toBeUndefined();
|
|
65
|
+
});
|
|
62
66
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
it('rejects invalid aad size', async () => {
|
|
68
|
+
const aad2 = Buffer.alloc(1024 * 1024 * 1024 + 1);
|
|
69
|
+
await expect(async () => {
|
|
70
|
+
await encryptAad(Buffer.alloc(0), aad2, passphrase);
|
|
71
|
+
}).rejects.toThrow('Invalid AAD size');
|
|
67
72
|
});
|
|
73
|
+
|
|
74
|
+
checkModule({ encrypt, decrypt, encryptAad });
|
|
68
75
|
});
|
|
69
76
|
|
|
70
77
|
/**
|
|
71
|
-
*
|
|
72
|
-
* @param {any}
|
|
78
|
+
* 检查实现模块
|
|
79
|
+
* @param {any} module wrapped module
|
|
73
80
|
*/
|
|
74
|
-
function
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
81
|
+
function checkModule(module) {
|
|
82
|
+
it('has correct exports', () => {
|
|
83
|
+
expect(module).toMatchObject({
|
|
84
|
+
encrypt: expect.any(Function),
|
|
85
|
+
decrypt: expect.any(Function),
|
|
86
|
+
encryptAad: expect.any(Function),
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
91
|
+
const { encrypt, decrypt, encryptAad } = module;
|
|
92
|
+
|
|
93
|
+
it.each(data)('encrypt/decrypt $type[$length]', async ({ raw }) => {
|
|
94
|
+
const encrypted = await encrypt(raw, passphrase);
|
|
95
|
+
expect(encrypted).toBeInstanceOf(Uint8Array);
|
|
96
|
+
expect(encrypted.byteLength).toBeGreaterThan(raw.byteLength);
|
|
97
|
+
expect(isEncrypted(encrypted)).toBe(true);
|
|
98
|
+
|
|
99
|
+
await expect(async () => {
|
|
100
|
+
await decrypt(encrypted, 'xx');
|
|
101
|
+
}).rejects.toThrow();
|
|
102
|
+
|
|
103
|
+
const decrypted = await decrypt(encrypted, passphrase);
|
|
104
|
+
expect(decrypted).toBeInstanceOf(Uint8Array);
|
|
105
|
+
expect(decrypted).toEqual(toUint8Array(raw));
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it.each(data)('encrypt/decrypt $type[$length] with aad', async ({ raw }) => {
|
|
109
|
+
const aad = Buffer.from('Hello, AAD!');
|
|
110
|
+
const encrypted = await encryptAad(raw, aad, passphrase);
|
|
111
|
+
expect(encrypted).toBeInstanceOf(Uint8Array);
|
|
112
|
+
expect(encrypted.byteLength).toBeGreaterThan(raw.byteLength);
|
|
113
|
+
expect(isEncrypted(encrypted)).toBe(true);
|
|
114
|
+
|
|
115
|
+
const extractedAad = extractAad(encrypted);
|
|
116
|
+
expect(extractedAad).toBeInstanceOf(Uint8Array);
|
|
117
|
+
expect(extractedAad).toEqual(toUint8Array(aad));
|
|
118
|
+
|
|
119
|
+
await expect(async () => {
|
|
120
|
+
await decrypt(encrypted, 'xx');
|
|
121
|
+
}).rejects.toThrow();
|
|
122
|
+
|
|
123
|
+
const decrypted = await decrypt(encrypted, passphrase);
|
|
124
|
+
expect(decrypted).toBeInstanceOf(Uint8Array);
|
|
125
|
+
expect(decrypted).toEqual(toUint8Array(raw));
|
|
78
126
|
});
|
|
79
|
-
checkImplEncryption(impl.encrypt, impl.decrypt);
|
|
80
127
|
}
|
|
81
128
|
|
|
82
129
|
/**
|
|
83
130
|
* 检查实现
|
|
84
|
-
* @param {(
|
|
85
|
-
* @param {(
|
|
131
|
+
* @param {(data: import('../dist/encryption/common.js').PlainData, passphrase: string) => Promise<import('../dist/encryption/common.js').EncryptedData>} encrypt encrypt
|
|
132
|
+
* @param {(data: import('../dist/encryption/common.js').EncryptedData, passphrase: string) => Promise<import('../dist/encryption/common.js').PlainData>} decrypt decrypt
|
|
86
133
|
*/
|
|
87
134
|
function checkImplEncryption(encrypt, decrypt) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
expect(encrypted.
|
|
95
|
-
expect(encrypted.salt.byteLength).toBe(16);
|
|
96
|
-
expect(encrypted.iv).toBeInstanceOf(Uint8Array);
|
|
97
|
-
expect(encrypted.iv.byteLength).toBe(16);
|
|
135
|
+
it.each(data)(
|
|
136
|
+
`$type[$length]`,
|
|
137
|
+
async ({ raw }) => {
|
|
138
|
+
const encrypted = await encrypt({ data: toUint8Array(raw) }, passphrase);
|
|
139
|
+
expect(encrypted.nonce).toBeInstanceOf(Uint8Array);
|
|
140
|
+
expect(encrypted.nonce.byteLength).toBe(12);
|
|
141
|
+
expect(encrypted.aad).toBeUndefined();
|
|
98
142
|
expect(encrypted.data).toBeInstanceOf(Uint8Array);
|
|
99
143
|
|
|
100
144
|
await expect(async () => {
|
|
101
145
|
await decrypt(encrypted, 'xx');
|
|
102
|
-
throw new Error('This may not be thrown since cipher may not report error');
|
|
103
146
|
}).rejects.toThrow();
|
|
104
147
|
|
|
105
148
|
const decrypted = await decrypt(encrypted, passphrase);
|
|
106
|
-
expect(decrypted).toBeInstanceOf(Uint8Array);
|
|
107
|
-
expect(decrypted).toEqual(toUint8Array(raw));
|
|
149
|
+
expect(decrypted.data).toBeInstanceOf(Uint8Array);
|
|
150
|
+
expect(decrypted.data).toEqual(toUint8Array(raw));
|
|
151
|
+
expect(decrypted.aad).toBeUndefined();
|
|
152
|
+
},
|
|
153
|
+
100_000,
|
|
154
|
+
);
|
|
155
|
+
it.each(data)(
|
|
156
|
+
`(aad) $type[$length]`,
|
|
157
|
+
async ({ raw }) => {
|
|
158
|
+
const aad = Buffer.from('Hello, AAD!');
|
|
159
|
+
const encrypted = await encrypt({ data: toUint8Array(raw), aad }, passphrase);
|
|
160
|
+
expect(encrypted.nonce).toBeInstanceOf(Uint8Array);
|
|
161
|
+
expect(encrypted.nonce.byteLength).toBe(12);
|
|
162
|
+
expect(encrypted.data).toBeInstanceOf(Uint8Array);
|
|
163
|
+
|
|
164
|
+
await expect(async () => {
|
|
165
|
+
await decrypt(
|
|
166
|
+
{
|
|
167
|
+
nonce: encrypted.nonce,
|
|
168
|
+
data: encrypted.data,
|
|
169
|
+
},
|
|
170
|
+
passphrase,
|
|
171
|
+
);
|
|
172
|
+
}).rejects.toThrow();
|
|
173
|
+
|
|
174
|
+
const decrypted = await decrypt(
|
|
175
|
+
{
|
|
176
|
+
nonce: encrypted.nonce,
|
|
177
|
+
aad: toUint8Array(aad),
|
|
178
|
+
data: encrypted.data,
|
|
179
|
+
},
|
|
180
|
+
passphrase,
|
|
181
|
+
);
|
|
182
|
+
expect(decrypted.data).toBeInstanceOf(Uint8Array);
|
|
183
|
+
expect(decrypted.data).toEqual(toUint8Array(raw));
|
|
108
184
|
},
|
|
109
185
|
100_000,
|
|
110
186
|
);
|
|
@@ -118,7 +194,8 @@ describe('Encryption impl', () => {
|
|
|
118
194
|
js: jsImpl,
|
|
119
195
|
});
|
|
120
196
|
describe.each(impls)('impl %s', (name, impl) => {
|
|
121
|
-
|
|
197
|
+
const module = createModule(impl);
|
|
198
|
+
checkModule(module);
|
|
122
199
|
});
|
|
123
200
|
describe.each(impls.slice(1))(`cross impl %s/${impls[0][0]}`, (name, impl) => {
|
|
124
201
|
describe(`${impls[0][0]} -> ${name}`, () => {
|
|
@@ -140,6 +217,6 @@ describe('Encryption impl browser', () => {
|
|
|
140
217
|
afterAll(() => {
|
|
141
218
|
globalThis.crypto = crypto;
|
|
142
219
|
});
|
|
143
|
-
|
|
220
|
+
checkModule(createModule(browserImpl));
|
|
144
221
|
});
|
|
145
222
|
});
|