this.listen()
}
- static async work (data: NamedData | unknown): Promise<NamedData> {
- let method, password, salt
+ static async work (data: NamedData | unknown): Promise<NamedData<ArrayBuffer | CryptoKey>> {
+ const { purpose, password, salt } = this.#extractData(data)
+ try {
+ const key = await this.#createAesKey(purpose, password, salt)
+ return { salt, key }
+ } catch (err) {
+ throw new Error('Failed to derive key from password', { cause: err })
+ } finally {
+ password.transfer()
+ }
+ }
+
+ static #extractData (data: unknown) {
if (data == null) {
throw new TypeError('Worker received no data')
}
if (!('password' in dataObject) || !(dataObject.password instanceof ArrayBuffer)) {
throw new TypeError('Password must be ArrayBuffer')
}
- password = dataObject.password
- if (!('method' in dataObject)) {
- throw new TypeError('Method is required')
+ const password: ArrayBuffer = dataObject.password
+ if (!('purpose' in dataObject)) {
+ throw new TypeError('Key purpose is required')
}
- if (dataObject.method !== 'encrypt' && dataObject.method !== 'decrypt') {
- throw new TypeError('Invalid method')
+ if (dataObject.purpose !== 'encrypt' && dataObject.purpose !== 'decrypt') {
+ throw new TypeError('Invalid key purpose')
}
- method = dataObject.method as typeof dataObject.method
- if (method === 'decrypt') {
- if (!('salt' in dataObject) || !(dataObject.salt instanceof ArrayBuffer)) {
- throw new TypeError('Salt required for decryption key')
- }
- salt = dataObject.salt
+ const purpose: 'encrypt' | 'decrypt' = dataObject.purpose
+ if (purpose === 'decrypt' && !('salt' in dataObject)) {
+ throw new TypeError('Salt required for decryption key')
}
- try {
- salt ??= globalThis.crypto.getRandomValues(new Uint8Array(32)).buffer
- const key = await this.#createAesKey(method, password, salt)
- return { salt, key }
- } catch (err) {
- throw new Error('Failed to derive key from password', { cause: err })
- } finally {
- password.transfer()
+ if (dataObject.salt != null && !(dataObject.salt instanceof ArrayBuffer)) {
+ throw new TypeError('Salt must be ArrayBuffer')
}
+ const salt: ArrayBuffer = dataObject.salt ?? globalThis.crypto.getRandomValues(new Uint8Array(32)).buffer
+ return { purpose, password, salt }
}
static async #createAesKey (purpose: 'encrypt' | 'decrypt', password: ArrayBuffer, salt: ArrayBuffer): Promise<CryptoKey> {