diff --git a/src/abstractions/cryptoFunction.service.ts b/src/abstractions/cryptoFunction.service.ts index 2385977b5e..a992da8379 100644 --- a/src/abstractions/cryptoFunction.service.ts +++ b/src/abstractions/cryptoFunction.service.ts @@ -1,4 +1,5 @@ export abstract class CryptoFunctionService { pbkdf2: (password: string | ArrayBuffer, salt: string | ArrayBuffer, algorithm: 'sha256' | 'sha512', iterations: number, length: number) => Promise; + hash: (value: string | ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512') => Promise; } diff --git a/src/services/nodeCryptoFunction.service.ts b/src/services/nodeCryptoFunction.service.ts index ed53e8d5c3..0c0d4aaf00 100644 --- a/src/services/nodeCryptoFunction.service.ts +++ b/src/services/nodeCryptoFunction.service.ts @@ -5,20 +5,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 { - let nodePassword: string | Buffer; - if (typeof (password) === 'string') { - nodePassword = password; - } else { - nodePassword = Buffer.from(new Uint8Array(password) as any); - } - - let nodeSalt: string | Buffer; - if (typeof (salt) === 'string') { - nodeSalt = salt; - } else { - nodeSalt = Buffer.from(new Uint8Array(salt) as any); - } - + const nodePassword = this.toNodeValue(password); + const nodeSalt = this.toNodeValue(salt); return new Promise((resolve, reject) => { crypto.pbkdf2(nodePassword, nodeSalt, iterations, length, algorithm, (error, key) => { if (error != null) { @@ -29,4 +17,21 @@ export class NodeCryptoFunctionService implements CryptoFunctionService { }); }); } + + async hash(value: string | ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512'): Promise { + const nodeValue = this.toNodeValue(value); + const hash = crypto.createHash(algorithm); + hash.update(nodeValue); + return hash.digest().buffer; + } + + private toNodeValue(value: string | ArrayBuffer): string | Buffer { + let nodeValue: string | Buffer; + if (typeof (value) === 'string') { + nodeValue = value; + } else { + nodeValue = Buffer.from(new Uint8Array(value) as any); + } + return nodeValue; + } } diff --git a/src/services/webCryptoFunction.service.ts b/src/services/webCryptoFunction.service.ts index 91e3d7d90f..2eb4e68a03 100644 --- a/src/services/webCryptoFunction.service.ts +++ b/src/services/webCryptoFunction.service.ts @@ -17,23 +17,14 @@ export class WebCryptoFunctionService implements CryptoFunctionService { async pbkdf2(password: string | ArrayBuffer, salt: string | ArrayBuffer, algorithm: 'sha256' | 'sha512', iterations: number, length: number): Promise { if (this.platformUtilsService.isEdge()) { - // TODO - return new Uint8Array([]).buffer; + const passwordBytes = this.toForgeBytes(password); + const saltBytes = this.toForgeBytes(salt); + const derivedKeyBytes = (forge as any).pbkdf2(passwordBytes, saltBytes, iterations, length / 8, algorithm); + return this.fromForgeBytesToBuf(derivedKeyBytes); } - let passwordBuf: ArrayBuffer; - if (typeof (password) === 'string') { - passwordBuf = UtilsService.fromUtf8ToArray(password).buffer; - } else { - passwordBuf = password; - } - - let saltBuf: ArrayBuffer; - if (typeof (salt) === 'string') { - saltBuf = UtilsService.fromUtf8ToArray(salt).buffer; - } else { - saltBuf = salt; - } + const passwordBuf = this.toBuf(password); + const saltBuf = this.toBuf(salt); const importedKey = await this.subtle.importKey('raw', passwordBuf, { name: 'PBKDF2' }, false, ['deriveKey', 'deriveBits']); @@ -54,21 +45,51 @@ export class WebCryptoFunctionService implements CryptoFunctionService { return await this.subtle.exportKey('raw', derivedKey); } - async hash(value: string | ArrayBuffer, algorithm: 'sha1' | 'sha256'): Promise { + async hash(value: string | ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512'): Promise { if (this.platformUtilsService.isEdge()) { - // TODO - return new Uint8Array([]).buffer; - } - - let valueBuf: ArrayBuffer; - if (typeof (value) === 'string') { - valueBuf = UtilsService.fromUtf8ToArray(value).buffer; - } else { - valueBuf = value; + let md: forge.md.MessageDigest; + if (algorithm === 'sha1') { + md = forge.md.sha1.create(); + } else if (algorithm === 'sha256') { + md = forge.md.sha256.create(); + } else { + md = (forge as any).md.sha512.create(); + } + + const valueBytes = this.toForgeBytes(value); + md.update(valueBytes, 'raw'); + return this.fromForgeBytesToBuf(md.digest().data); } + const valueBuf = this.toBuf(value); return await this.subtle.digest({ - name: algorithm === 'sha256' ? 'SHA-256' : 'SHA-1' + name: algorithm === 'sha1' ? 'SHA-1' : algorithm === 'sha256' ? 'SHA-256' : 'SHA-512' }, valueBuf); } + + private toBuf(value: string | ArrayBuffer): ArrayBuffer { + let buf: ArrayBuffer; + if (typeof (value) === 'string') { + buf = UtilsService.fromUtf8ToArray(value).buffer; + } else { + buf = value; + } + return buf; + } + + private toForgeBytes(value: string | ArrayBuffer): string { + let bytes: string; + if (typeof (value) === 'string') { + bytes = forge.util.encodeUtf8(value); + } else { + const value64 = UtilsService.fromBufferToB64(value); + bytes = forge.util.encode64(value64); + } + return bytes; + } + + private fromForgeBytesToBuf(byteString: string): ArrayBuffer { + const b64 = forge.util.decode64(byteString); + return UtilsService.fromB64ToArray(b64).buffer; + } }