1 |
|
2 |
|
3 |
|
4 |
|
5 | import * as encoding from '../encoding.js'
|
6 | import * as decoding from '../decoding.js'
|
7 | import * as webcrypto from 'lib0/webcrypto'
|
8 | import * as string from '../string.js'
|
9 | export { exportKeyJwk, exportKeyRaw } from './common.js'
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | const defaultUsages = ['encrypt', 'decrypt']
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 | export const encrypt = (key, data) => {
|
25 | const iv = webcrypto.getRandomValues(new Uint8Array(16))
|
26 | return webcrypto.subtle.encrypt(
|
27 | {
|
28 | name: 'AES-GCM',
|
29 | iv
|
30 | },
|
31 | key,
|
32 | data
|
33 | ).then(cipher => {
|
34 | const encryptedDataEncoder = encoding.createEncoder()
|
35 |
|
36 | encoding.writeUint8Array(encryptedDataEncoder, iv)
|
37 | encoding.writeVarUint8Array(encryptedDataEncoder, new Uint8Array(cipher))
|
38 | return encoding.toUint8Array(encryptedDataEncoder)
|
39 | })
|
40 | }
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 | export const decrypt = (key, data) => {
|
52 | const dataDecoder = decoding.createDecoder(data)
|
53 | const iv = decoding.readUint8Array(dataDecoder, 16)
|
54 | const cipher = decoding.readVarUint8Array(dataDecoder)
|
55 | return webcrypto.subtle.decrypt(
|
56 | {
|
57 | name: 'AES-GCM',
|
58 | iv
|
59 | },
|
60 | key,
|
61 | cipher
|
62 | ).then(data => new Uint8Array(data))
|
63 | }
|
64 |
|
65 | const aesAlgDef = {
|
66 | name: 'AES-GCM',
|
67 | length: 256
|
68 | }
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 | export const importKeyJwk = (jwk, { usages, extractable = false } = {}) => {
|
77 | if (usages == null) {
|
78 |
|
79 | usages = jwk.key_ops || defaultUsages
|
80 | }
|
81 | return webcrypto.subtle.importKey('jwk', jwk, 'AES-GCM', extractable, (usages))
|
82 | }
|
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 | export const importKeyRaw = (raw, { usages = defaultUsages, extractable = false } = {}) =>
|
93 | webcrypto.subtle.importKey('raw', raw, aesAlgDef, extractable, (usages))
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 | const toBinary = data => typeof data === 'string' ? string.encodeUtf8(data) : data
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 | export const deriveKey = (secret, salt, { extractable = false, usages = defaultUsages } = {}) =>
|
113 | webcrypto.subtle.importKey(
|
114 | 'raw',
|
115 | toBinary(secret),
|
116 | 'PBKDF2',
|
117 | false,
|
118 | ['deriveKey']
|
119 | ).then(keyMaterial =>
|
120 | webcrypto.subtle.deriveKey(
|
121 | {
|
122 | name: 'PBKDF2',
|
123 | salt: toBinary(salt),
|
124 | iterations: 600000,
|
125 | hash: 'SHA-256'
|
126 | },
|
127 | keyMaterial,
|
128 | aesAlgDef,
|
129 | extractable,
|
130 | usages
|
131 | )
|
132 | )
|