this.listen()
}
- static async work (data: NamedData<ArrayBuffer>): Promise<NamedData<CryptoKey>> {
- this.#validate(data)
+ static async work (data: NamedData | unknown): Promise<NamedData> {
+ let method, password, salt
+ if (data == null) {
+ throw new TypeError('Worker received no data')
+ }
+ if (typeof data !== 'object') {
+ throw new Error('Invalid data')
+ }
+ const dataObject = data as { [key: string]: unknown }
+ 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')
+ }
+ if (dataObject.method !== 'encrypt' && dataObject.method !== 'decrypt') {
+ throw new TypeError('Invalid method')
+ }
+ 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
+ }
try {
- const salt = (method === 'decrypt')
- ? data.salt
- : (await Entropy.create()).buffer
+ salt ??= (await Entropy.create()).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()
- }
+ }
}
-
+
static async #createAesKey (purpose: 'encrypt' | 'decrypt', password: ArrayBuffer, salt: ArrayBuffer): Promise<CryptoKey> {
const derivationKey = await globalThis.crypto.subtle.importKey('raw', password, 'PBKDF2', false, ['deriveBits', 'deriveKey'])
const derivationAlgorithm: Pbkdf2Params = {
}
return await globalThis.crypto.subtle.deriveKey(derivationAlgorithm, derivationKey, derivedKeyType, false, [purpose])
}
-
- static #validate (data: unknown): asserts data is NamedData<ArrayBuffer> } {
- if (data == null) {
- throw new TypeError('Worker received no data')
- }
- if (typeof data !== 'object') {
- throw new Error('Invalid data')
- }
- const dataObject = data as { [key: string]: unknown }
- if (!(data.password instanceof ArrayBuffer)) {
- throw new TypeError('Password must be ArrayBuffer')
- }
- if (data.method !== 'encrypt' && data.method !== 'decrypt') {
- throw new TypeError('Invalid method')
- }
- if (data.method === 'decrypt' && !(data.salt instanceof ArrayBuffer)) {
- throw new TypeError('Salt required for decryption key')
- }
}
let importWorkerThreads = ''