From 78851054bd1f66b3e3ad978b9628e4d0bd4025fb Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Tue, 2 May 2023 09:00:54 -0700 Subject: [PATCH] Remove unreliable webkit-linux useragent check --- src/ciphers/aes-gcm.browser.ts | 23 ++++++++++++++++------- test/workaround.spec.ts | 4 ++-- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/ciphers/aes-gcm.browser.ts b/src/ciphers/aes-gcm.browser.ts index 6466ca3..48e2b94 100644 --- a/src/ciphers/aes-gcm.browser.ts +++ b/src/ciphers/aes-gcm.browser.ts @@ -3,10 +3,6 @@ import { fromString } from 'uint8arrays/from-string' import webcrypto from '../webcrypto.js' import type { CreateOptions, AESCipher } from './interface.js' -export function isWebkitLinux (): boolean { - return typeof navigator !== 'undefined' && navigator.userAgent.includes('Safari') && navigator.userAgent.includes('Linux') && !navigator.userAgent.includes('Chrome') -} - // WebKit on Linux does not support deriving a key from an empty PBKDF2 key. // So, as a workaround, we provide the generated key as a constant. We test that // this generated key is accurate in test/workaround.spec.ts @@ -46,8 +42,15 @@ export function create (opts?: CreateOptions): AESCipher { } let cryptoKey: CryptoKey - if (password.length === 0 && isWebkitLinux()) { + if (password.length === 0) { cryptoKey = await crypto.subtle.importKey('jwk', derivedEmptyPasswordKey, { name: 'AES-GCM' }, true, ['encrypt']) + try { + const deriveParams = { name: 'PBKDF2', salt, iterations, hash: { name: digest } } + const runtimeDerivedEmptyPassword = await crypto.subtle.importKey('raw', password, { name: 'PBKDF2' }, false, ['deriveKey']) + cryptoKey = await crypto.subtle.deriveKey(deriveParams, runtimeDerivedEmptyPassword, { name: algorithm, length: keyLength }, true, ['encrypt']) + } catch { + cryptoKey = await crypto.subtle.importKey('jwk', derivedEmptyPasswordKey, { name: 'AES-GCM' }, true, ['encrypt']) + } } else { // Derive a key using PBKDF2. const deriveParams = { name: 'PBKDF2', salt, iterations, hash: { name: digest } } @@ -77,8 +80,14 @@ export function create (opts?: CreateOptions): AESCipher { } let cryptoKey: CryptoKey - if (password.length === 0 && isWebkitLinux()) { - cryptoKey = await crypto.subtle.importKey('jwk', derivedEmptyPasswordKey, { name: 'AES-GCM' }, true, ['decrypt']) + if (password.length === 0) { + try { + const deriveParams = { name: 'PBKDF2', salt, iterations, hash: { name: digest } } + const runtimeDerivedEmptyPassword = await crypto.subtle.importKey('raw', password, { name: 'PBKDF2' }, false, ['deriveKey']) + cryptoKey = await crypto.subtle.deriveKey(deriveParams, runtimeDerivedEmptyPassword, { name: algorithm, length: keyLength }, true, ['decrypt']) + } catch { + cryptoKey = await crypto.subtle.importKey('jwk', derivedEmptyPasswordKey, { name: 'AES-GCM' }, true, ['decrypt']) + } } else { // Derive the key using PBKDF2. const deriveParams = { name: 'PBKDF2', salt, iterations, hash: { name: digest } } diff --git a/test/workaround.spec.ts b/test/workaround.spec.ts index 86dcbd5..49322c6 100644 --- a/test/workaround.spec.ts +++ b/test/workaround.spec.ts @@ -1,11 +1,11 @@ /* eslint-env mocha */ -import { isWebkitLinux, derivedEmptyPasswordKey } from '../src/ciphers/aes-gcm.browser.js' +import { derivedEmptyPasswordKey } from '../src/ciphers/aes-gcm.browser.js' import { expect } from 'aegir/chai' describe('Constant derived key is generated correctly', () => { it('Generates correctly', async () => { - if (isWebkitLinux() || typeof crypto === 'undefined') { + if (navigator.userAgent.includes('Safari') || typeof crypto === 'undefined') { // WebKit Linux can't generate this. Hence the workaround. return }