@cloudpss/crypto 0.5.23 → 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.
Files changed (42) hide show
  1. package/benchmark.js +44 -0
  2. package/dist/encryption/browser.d.ts +3 -3
  3. package/dist/encryption/browser.js.map +1 -1
  4. package/dist/encryption/common.d.ts +45 -16
  5. package/dist/encryption/common.js +57 -9
  6. package/dist/encryption/common.js.map +1 -1
  7. package/dist/encryption/index.d.ts +4 -21
  8. package/dist/encryption/index.js +11 -63
  9. package/dist/encryption/index.js.map +1 -1
  10. package/dist/encryption/js/aes.d.ts +20 -0
  11. package/dist/encryption/js/aes.js +151 -0
  12. package/dist/encryption/js/aes.js.map +1 -0
  13. package/dist/encryption/js/gcm.d.ts +26 -0
  14. package/dist/encryption/js/gcm.js +226 -0
  15. package/dist/encryption/js/gcm.js.map +1 -0
  16. package/dist/encryption/module.d.ts +22 -0
  17. package/dist/encryption/module.js +62 -0
  18. package/dist/encryption/module.js.map +1 -0
  19. package/dist/encryption/node.d.ts +3 -3
  20. package/dist/encryption/node.js +19 -15
  21. package/dist/encryption/node.js.map +1 -1
  22. package/dist/encryption/pure-js.d.ts +3 -3
  23. package/dist/encryption/pure-js.js +70 -42
  24. package/dist/encryption/pure-js.js.map +1 -1
  25. package/dist/encryption/web.d.ts +3 -3
  26. package/dist/encryption/web.js +17 -15
  27. package/dist/encryption/web.js.map +1 -1
  28. package/dist/index.d.ts +1 -1
  29. package/dist/index.js +1 -1
  30. package/dist/index.js.map +1 -1
  31. package/package.json +7 -4
  32. package/src/encryption/browser.ts +3 -3
  33. package/src/encryption/common.ts +79 -16
  34. package/src/encryption/index.ts +12 -71
  35. package/src/encryption/js/aes.ts +191 -0
  36. package/src/encryption/js/gcm.ts +258 -0
  37. package/src/encryption/module.ts +94 -0
  38. package/src/encryption/node.ts +24 -15
  39. package/src/encryption/pure-js.ts +89 -46
  40. package/src/encryption/web.ts +24 -15
  41. package/src/index.ts +1 -1
  42. package/tests/encryption.js +126 -49
@@ -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(32)]))).toBe(false);
20
- expect(isEncrypted(Buffer.concat([MAGIC_NUMBER, Buffer.alloc(33)]))).toBe(true);
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('encrypt/decrypt', async () => {
44
- const data = [
45
- Buffer.from(''),
46
- Buffer.from('Hello, World!'),
47
- Buffer.from('Hello, World!'.repeat(100)),
48
- new Uint8Array(100),
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
- await expect(async () => {
59
- await decrypt(encrypted, 'xx');
60
- throw new Error('This may not be thrown since cipher may not report error');
61
- }).rejects.toThrow();
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
- const decrypted = await decrypt(encrypted, passphrase);
64
- expect(decrypted).toBeInstanceOf(Uint8Array);
65
- expect(decrypted).toEqual(toUint8Array(raw));
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} impl impl module
78
+ * 检查实现模块
79
+ * @param {any} module wrapped module
73
80
  */
74
- function checkImpl(impl) {
75
- expect(impl).toMatchObject({
76
- encrypt: expect.any(Function),
77
- decrypt: expect.any(Function),
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 {(arg0: Buffer, arg1: string) => any} encrypt encrypt
85
- * @param {(arg0: any, arg1: string) => any} decrypt decrypt
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
- const data = [Buffer.alloc(0), Buffer.from('Hello, World!'), Buffer.from('Hello, World!'.repeat(100))];
89
- const passphrase = 'test';
90
- it.each(data.map((v) => ({ length: v.byteLength, buffer: v })))(
91
- `len=$length`,
92
- async ({ buffer: raw }) => {
93
- const encrypted = await encrypt(raw, passphrase);
94
- expect(encrypted.salt).toBeInstanceOf(Uint8Array);
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
- checkImpl(impl);
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
- checkImpl(browserImpl);
220
+ checkModule(createModule(browserImpl));
144
221
  });
145
222
  });