diff --git a/src/abstractions/cryptoFunction.service.ts b/src/abstractions/cryptoFunction.service.ts index 1012090bb0e..cb755573ba7 100644 --- a/src/abstractions/cryptoFunction.service.ts +++ b/src/abstractions/cryptoFunction.service.ts @@ -1,6 +1,6 @@ export abstract class CryptoFunctionService { pbkdf2: (password: string | ArrayBuffer, salt: string | ArrayBuffer, algorithm: 'sha256' | 'sha512', - iterations: number, length: number) => Promise; + iterations: number) => Promise; hash: (value: string | ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512') => Promise; hmac: (value: ArrayBuffer, key: ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512') => Promise; } diff --git a/src/index.ts b/src/index.ts index 5d4c096cc3d..36346148dab 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,11 @@ import * as Abstractions from './abstractions'; import * as Enums from './enums'; +import * as Misc from './misc'; import * as Data from './models/data'; import * as Domain from './models/domain'; -import * as Misc from './misc'; import * as Request from './models/request'; import * as Response from './models/response'; -import * as Services from './services'; import * as View from './models/view'; +import * as Services from './services'; export { Abstractions, Enums, Data, Domain, Misc, Request, Response, Services, View }; diff --git a/src/services/nodeCryptoFunction.service.ts b/src/services/nodeCryptoFunction.service.ts index d9a54774e73..7c6e6e11f01 100644 --- a/src/services/nodeCryptoFunction.service.ts +++ b/src/services/nodeCryptoFunction.service.ts @@ -4,7 +4,8 @@ import { CryptoFunctionService } from '../abstractions/cryptoFunction.service'; export class NodeCryptoFunctionService implements CryptoFunctionService { async pbkdf2(password: string | ArrayBuffer, salt: string | ArrayBuffer, algorithm: 'sha256' | 'sha512', - iterations: number, length: number): Promise { + iterations: number): Promise { + const len = algorithm === 'sha256' ? 256 : 512; const nodePassword = this.toNodeValue(password); const nodeSalt = this.toNodeValue(salt); return new Promise((resolve, reject) => { diff --git a/src/services/webCryptoFunction.service.spec.ts b/src/services/webCryptoFunction.service.spec.ts index 4da6ae5865d..498aa17b0fa 100644 --- a/src/services/webCryptoFunction.service.spec.ts +++ b/src/services/webCryptoFunction.service.spec.ts @@ -12,15 +12,18 @@ describe('WebCrypto Function Service', () => { const utf8256Key = 'yqvoFXgMRmHR3QPYr5pyR4uVuoHkltv9aHUP63p8n7I='; const unicode256Key = 'ZdeOata6xoRpB4DLp8zHhXz5kLmkWtX5pd+TdRH8w8w='; - const regular512Key = 'liTi/Ke8LPU1Qv+Vl7NGEVt/XMbsBVJ2kQxtVG/Z1/I='; - const utf8512Key = 'df0KdvIBeCzD/kyXptwQohaqUa4e7IyFUyhFQjXCANs='; - const unicode512Key = 'FE+AnUJaxv8jh+zUDtZz4mjjcYk0/PZDZm+SLJe3Xtw='; + const regular512Key = 'liTi/Ke8LPU1Qv+Vl7NGEVt/XMbsBVJ2kQxtVG/Z1/JFHFKQW3ZkI81qVlwTiCpb+cFXzs+57' + + 'eyhhx5wfKo5Cg=='; + const utf8512Key = 'df0KdvIBeCzD/kyXptwQohaqUa4e7IyFUyhFQjXCANu5T+scq55hCcE4dG4T/MhAk2exw8j7ixRN' + + 'zXANiVZpnw=='; + const unicode512Key = 'FE+AnUJaxv8jh+zUDtZz4mjjcYk0/PZDZm+SLJe3XtxtnpdqqpblX6JjuMZt/dYYNMOrb2+mD' + + 'L3FiQDTROh1lg=='; - testPbkdf2ValidKey(false, 'sha256', regular256Key, utf8256Key, unicode256Key); - testPbkdf2ValidKey(false, 'sha512', regular512Key, utf8512Key, unicode512Key); + testPbkdf2(false, 'sha256', regular256Key, utf8256Key, unicode256Key); + testPbkdf2(false, 'sha512', regular512Key, utf8512Key, unicode512Key); - testPbkdf2ValidKey(true, 'sha256', regular256Key, utf8256Key, unicode256Key); - testPbkdf2ValidKey(true, 'sha512', regular512Key, utf8512Key, unicode512Key); + testPbkdf2(true, 'sha256', regular256Key, utf8256Key, unicode256Key); + testPbkdf2(true, 'sha512', regular512Key, utf8512Key, unicode512Key); }); describe('hash', () => { @@ -64,7 +67,7 @@ describe('WebCrypto Function Service', () => { }); }); -function testPbkdf2ValidKey(edge: boolean, algorithm: 'sha256' | 'sha512', regularKey: string, +function testPbkdf2(edge: boolean, algorithm: 'sha256' | 'sha512', regularKey: string, utf8Key: string, unicodeKey: string) { const forEdge = edge ? ' for edge' : ''; const regularEmail = 'user@example.com'; @@ -76,26 +79,26 @@ function testPbkdf2ValidKey(edge: boolean, algorithm: 'sha256' | 'sha512', regul it('should create valid ' + algorithm + ' key from regular input' + forEdge, async () => { const webCryptoFunctionService = getWebCryptoFunctionService(edge); - const key = await webCryptoFunctionService.pbkdf2(regularPassword, regularEmail, algorithm, 5000, 256); + const key = await webCryptoFunctionService.pbkdf2(regularPassword, regularEmail, algorithm, 5000); expect(UtilsService.fromBufferToB64(key)).toBe(regularKey); }); it('should create valid ' + algorithm + ' key from utf8 input' + forEdge, async () => { const webCryptoFunctionService = getWebCryptoFunctionService(edge); - const key = await webCryptoFunctionService.pbkdf2(utf8Password, utf8Email, algorithm, 5000, 256); + const key = await webCryptoFunctionService.pbkdf2(utf8Password, utf8Email, algorithm, 5000); expect(UtilsService.fromBufferToB64(key)).toBe(utf8Key); }); it('should create valid ' + algorithm + ' key from unicode input' + forEdge, async () => { const webCryptoFunctionService = getWebCryptoFunctionService(edge); - const key = await webCryptoFunctionService.pbkdf2(unicodePassword, regularEmail, algorithm, 5000, 256); + const key = await webCryptoFunctionService.pbkdf2(unicodePassword, regularEmail, algorithm, 5000); expect(UtilsService.fromBufferToB64(key)).toBe(unicodeKey); }); it('should create valid ' + algorithm + ' key from array buffer input' + forEdge, async () => { const webCryptoFunctionService = getWebCryptoFunctionService(edge); const key = await webCryptoFunctionService.pbkdf2(UtilsService.fromUtf8ToArray(regularPassword).buffer, - UtilsService.fromUtf8ToArray(regularEmail).buffer, algorithm, 5000, 256); + UtilsService.fromUtf8ToArray(regularEmail).buffer, algorithm, 5000); expect(UtilsService.fromBufferToB64(key)).toBe(regularKey); }); } @@ -147,12 +150,6 @@ function getWebCryptoFunctionService(edge = false) { } class BrowserPlatformUtilsService implements PlatformUtilsService { - constructor(private edge: boolean) { } - - isEdge() { - return this.edge; - } - identityClientId: string; getDevice: () => DeviceType; getDeviceString: () => string; @@ -173,4 +170,10 @@ class BrowserPlatformUtilsService implements PlatformUtilsService { type?: string) => Promise; isDev: () => boolean; copyToClipboard: (text: string, options?: any) => void; + + constructor(private edge: boolean) { } + + isEdge() { + return this.edge; + } } diff --git a/src/services/webCryptoFunction.service.ts b/src/services/webCryptoFunction.service.ts index 639a191f6db..41b24479868 100644 --- a/src/services/webCryptoFunction.service.ts +++ b/src/services/webCryptoFunction.service.ts @@ -17,20 +17,19 @@ export class WebCryptoFunctionService implements CryptoFunctionService { } async pbkdf2(password: string | ArrayBuffer, salt: string | ArrayBuffer, algorithm: 'sha256' | 'sha512', - iterations: number, length: number): Promise { + iterations: number): Promise { if (this.isEdge) { + const len = algorithm === 'sha256' ? 32 : 64; const passwordBytes = this.toForgeBytes(password); const saltBytes = this.toForgeBytes(salt); - const derivedKeyBytes = (forge as any).pbkdf2(passwordBytes, saltBytes, iterations, length / 8, algorithm); + const derivedKeyBytes = (forge as any).pbkdf2(passwordBytes, saltBytes, iterations, len, algorithm); return this.fromForgeBytesToBuf(derivedKeyBytes); } + const len = algorithm === 'sha256' ? 256 : 512; const passwordBuf = this.toBuf(password); const saltBuf = this.toBuf(salt); - const importedKey = await this.subtle.importKey('raw', passwordBuf, { name: 'PBKDF2' }, - false, ['deriveKey', 'deriveBits']); - const alg: Pbkdf2Params = { name: 'PBKDF2', salt: saltBuf, @@ -38,13 +37,8 @@ export class WebCryptoFunctionService implements CryptoFunctionService { hash: { name: this.toWebCryptoAlgorithm(algorithm) }, }; - const keyType: AesDerivedKeyParams = { - name: 'AES-CBC', - length: length, - }; - - const derivedKey = await this.subtle.deriveKey(alg, importedKey, keyType, true, ['encrypt', 'decrypt']); - return await this.subtle.exportKey('raw', derivedKey); + const impKey = await this.subtle.importKey('raw', passwordBuf, { name: 'PBKDF2' }, false, ['deriveBits']); + return await window.crypto.subtle.deriveBits(alg, impKey, len); } async hash(value: string | ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512'): Promise { @@ -64,9 +58,7 @@ export class WebCryptoFunctionService implements CryptoFunctionService { } const valueBuf = this.toBuf(value); - return await this.subtle.digest({ - name: this.toWebCryptoAlgorithm(algorithm) - }, valueBuf); + return await this.subtle.digest({ name: this.toWebCryptoAlgorithm(algorithm) }, valueBuf); } async hmac(value: ArrayBuffer, key: ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512'): Promise { @@ -84,8 +76,8 @@ export class WebCryptoFunctionService implements CryptoFunctionService { hash: { name: this.toWebCryptoAlgorithm(algorithm) }, }; - const importedKey = await this.subtle.importKey('raw', key, signingAlgorithm, false, ['sign']); - return await this.subtle.sign(signingAlgorithm, importedKey, value); + const impKey = await this.subtle.importKey('raw', key, signingAlgorithm, false, ['sign']); + return await this.subtle.sign(signingAlgorithm, impKey, value); } private toBuf(value: string | ArrayBuffer): ArrayBuffer {