bitwarden-estensione-browser/src/services/nodeCryptoFunction.service.ts

105 lines
4.1 KiB
TypeScript
Raw Normal View History

2018-04-19 06:00:53 +02:00
import * as constants from 'constants';
2018-04-20 05:12:06 +02:00
import * as crypto from 'crypto';
import { CryptoFunctionService } from '../abstractions/cryptoFunction.service';
export class NodeCryptoFunctionService implements CryptoFunctionService {
2018-04-18 14:50:02 +02:00
pbkdf2(password: string | ArrayBuffer, salt: string | ArrayBuffer, algorithm: 'sha256' | 'sha512',
iterations: number): Promise<ArrayBuffer> {
const len = algorithm === 'sha256' ? 256 : 512;
const nodePassword = this.toNodeValue(password);
const nodeSalt = this.toNodeValue(salt);
return new Promise<ArrayBuffer>((resolve, reject) => {
2018-04-16 18:07:51 +02:00
crypto.pbkdf2(nodePassword, nodeSalt, iterations, length, algorithm, (error, key) => {
if (error != null) {
reject(error);
} else {
resolve(key.buffer);
}
});
});
}
2018-04-18 14:50:02 +02:00
hash(value: string | ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512'): Promise<ArrayBuffer> {
const nodeValue = this.toNodeValue(value);
const hash = crypto.createHash(algorithm);
hash.update(nodeValue);
2018-04-18 14:50:02 +02:00
return Promise.resolve(hash.digest().buffer);
}
2018-04-18 14:50:02 +02:00
hmac(value: ArrayBuffer, key: ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512'): Promise<ArrayBuffer> {
const nodeValue = this.toNodeBuffer(value);
const nodeKey = this.toNodeBuffer(value);
const hmac = crypto.createHmac(algorithm, nodeKey);
hmac.update(nodeValue);
return Promise.resolve(hmac.digest().buffer);
}
aesEncrypt(data: ArrayBuffer, iv: ArrayBuffer, key: ArrayBuffer): Promise<ArrayBuffer> {
const nodeData = this.toNodeBuffer(data);
const nodeIv = this.toNodeBuffer(iv);
const nodeKey = this.toNodeBuffer(key);
const cipher = crypto.createCipheriv('aes-256-cbc', nodeKey, nodeIv);
const encBuf = Buffer.concat([cipher.update(nodeData), cipher.final()]);
return Promise.resolve(encBuf.buffer);
}
aesDecryptSmall(data: ArrayBuffer, iv: ArrayBuffer, key: ArrayBuffer): Promise<ArrayBuffer> {
return this.aesDecryptLarge(data, iv, key);
}
aesDecryptLarge(data: ArrayBuffer, iv: ArrayBuffer, key: ArrayBuffer): Promise<ArrayBuffer> {
const nodeData = this.toNodeBuffer(data);
const nodeIv = this.toNodeBuffer(iv);
const nodeKey = this.toNodeBuffer(key);
const decipher = crypto.createDecipheriv('aes-256-cbc', nodeKey, nodeIv);
const decBuf = Buffer.concat([decipher.update(nodeData), decipher.final()]);
return Promise.resolve(decBuf.buffer);
}
2018-04-19 06:00:53 +02:00
rsaDecrypt(data: ArrayBuffer, key: ArrayBuffer, algorithm: 'sha1' | 'sha256'): Promise<ArrayBuffer> {
if (algorithm !== 'sha1') {
throw new Error('only sha1 is supported on this platform.');
}
const nodeData = this.toNodeBuffer(data);
const rsaKey: crypto.RsaPrivateKey = {
key: this.toPem(key),
padding: constants.RSA_PKCS1_OAEP_PADDING,
};
const decBuf = crypto.publicDecrypt(rsaKey, nodeData);
return Promise.resolve(decBuf.buffer);
}
2018-04-18 14:50:02 +02:00
randomBytes(length: number): Promise<ArrayBuffer> {
return new Promise<ArrayBuffer>((resolve, reject) => {
crypto.randomBytes(length, (error, bytes) => {
if (error != null) {
reject(error);
} else {
resolve(bytes.buffer);
}
});
});
2018-04-18 01:02:58 +02:00
}
private toNodeValue(value: string | ArrayBuffer): string | Buffer {
let nodeValue: string | Buffer;
if (typeof (value) === 'string') {
nodeValue = value;
} else {
2018-04-18 14:50:02 +02:00
nodeValue = this.toNodeBuffer(value);
}
return nodeValue;
}
2018-04-18 14:50:02 +02:00
private toNodeBuffer(value: ArrayBuffer): Buffer {
2018-04-18 19:43:42 +02:00
return Buffer.from(new Uint8Array(value) as any);
2018-04-18 14:50:02 +02:00
}
2018-04-19 06:00:53 +02:00
private toPem(key: ArrayBuffer): string {
const b64Key = ''; // TODO: key to b84
return '-----BEGIN PRIVATE KEY-----\n' + b64Key + '\n-----END PRIVATE KEY-----';
}
}