From d6474aee0e84c933c5a36aa2fa20b209be18d74c Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Mon, 16 Apr 2018 12:07:51 -0400 Subject: [PATCH] crypto function implementations --- src/abstractions/cryptoFunction.service.ts | 3 +- src/services/nodeCryptoFunction.service.ts | 19 ++++++++- src/services/webCryptoFunction.service.ts | 48 ++++++++++++++++++---- 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/src/abstractions/cryptoFunction.service.ts b/src/abstractions/cryptoFunction.service.ts index 5daffbd4f2..2385977b5e 100644 --- a/src/abstractions/cryptoFunction.service.ts +++ b/src/abstractions/cryptoFunction.service.ts @@ -1,3 +1,4 @@ export abstract class CryptoFunctionService { - pbkdf2: (password: Buffer, salt: Buffer, iterations: number, length: number) => Promise + pbkdf2: (password: string | ArrayBuffer, salt: string | ArrayBuffer, algorithm: 'sha256' | 'sha512', + iterations: number, length: number) => Promise; } diff --git a/src/services/nodeCryptoFunction.service.ts b/src/services/nodeCryptoFunction.service.ts index 750b18a78d..ed53e8d5c3 100644 --- a/src/services/nodeCryptoFunction.service.ts +++ b/src/services/nodeCryptoFunction.service.ts @@ -3,9 +3,24 @@ import * as crypto from 'crypto'; import { CryptoFunctionService } from '../abstractions/cryptoFunction.service'; export class NodeCryptoFunctionService implements CryptoFunctionService { - async pbkdf2(password: Buffer, salt: Buffer, iterations: number, length: number): Promise { + 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); + } + return new Promise((resolve, reject) => { - crypto.pbkdf2(password, salt, iterations, length, 'sha256', (error, key) => { + crypto.pbkdf2(nodePassword, nodeSalt, iterations, length, algorithm, (error, key) => { if (error != null) { reject(error); } else { diff --git a/src/services/webCryptoFunction.service.ts b/src/services/webCryptoFunction.service.ts index ea563b32c8..91e3d7d90f 100644 --- a/src/services/webCryptoFunction.service.ts +++ b/src/services/webCryptoFunction.service.ts @@ -3,6 +3,8 @@ import * as forge from 'node-forge'; import { CryptoFunctionService } from '../abstractions/cryptoFunction.service'; import { PlatformUtilsService } from '../abstractions/platformUtils.service'; +import { UtilsService } from '../services/utils.service'; + export class WebCryptoFunctionService implements CryptoFunctionService { private crypto: Crypto; private subtle: SubtleCrypto; @@ -12,15 +14,35 @@ export class WebCryptoFunctionService implements CryptoFunctionService { this.subtle = win.crypto.subtle; } - async pbkdf2(password: Buffer, salt: Buffer, iterations: number, length: number): Promise { - const importedKey = await this.subtle.importKey('raw', password, { name: 'PBKDF2' }, + 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; + } + + 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 importedKey = await this.subtle.importKey('raw', passwordBuf, { name: 'PBKDF2' }, false, ['deriveKey', 'deriveBits']); const alg: Pbkdf2Params = { name: 'PBKDF2', - salt: salt, + salt: saltBuf, iterations: iterations, - hash: { name: 'SHA-256' }, + hash: { name: algorithm === 'sha256' ? 'SHA-256' : 'SHA-512' }, }; const keyType: AesDerivedKeyParams = { @@ -32,11 +54,21 @@ export class WebCryptoFunctionService implements CryptoFunctionService { return await this.subtle.exportKey('raw', derivedKey); } - async sha1(value: Buffer): Promise { + async hash(value: string | ArrayBuffer, algorithm: 'sha1' | 'sha256'): Promise { if (this.platformUtilsService.isEdge()) { - return new Uint8Array([1]).buffer; // TODO: sha1 with forge - } else { - return await this.subtle.digest({ name: 'SHA-1' }, value); + // TODO + return new Uint8Array([]).buffer; } + + let valueBuf: ArrayBuffer; + if (typeof (value) === 'string') { + valueBuf = UtilsService.fromUtf8ToArray(value).buffer; + } else { + valueBuf = value; + } + + return await this.subtle.digest({ + name: algorithm === 'sha256' ? 'SHA-256' : 'SHA-1' + }, valueBuf); } }