mirror of
https://github.com/bitwarden/browser
synced 2025-01-14 03:19:54 +01:00
web crypto aes encryption and random bytes
This commit is contained in:
parent
2e58314759
commit
680fbff306
@ -65,6 +65,54 @@ describe('WebCrypto Function Service', () => {
|
||||
testHmac(true, 'sha256', sha256Mac);
|
||||
testHmac(true, 'sha512', sha512Mac);
|
||||
});
|
||||
|
||||
describe('aesEncrypt', () => {
|
||||
it('should successfully aes 256 encrypt data', async () => {
|
||||
const webCryptoFunctionService = getWebCryptoFunctionService();
|
||||
const iv = makeStaticByteArray(16);
|
||||
const key = makeStaticByteArray(32);
|
||||
const data = UtilsService.fromUtf8ToArray('EncryptMe!');
|
||||
const encValue = await webCryptoFunctionService.aesEncrypt(data.buffer, iv.buffer, key.buffer);
|
||||
expect(UtilsService.fromBufferToB64(encValue)).toBe('ByUF8vhyX4ddU9gcooznwA==');
|
||||
});
|
||||
});
|
||||
|
||||
describe('aesDecryptSmall', () => {
|
||||
it('should successfully aes 256 decrypt data', async () => {
|
||||
const webCryptoFunctionService = getWebCryptoFunctionService();
|
||||
const iv = makeStaticByteArray(16);
|
||||
const key = makeStaticByteArray(32);
|
||||
const data = UtilsService.fromB64ToArray('ByUF8vhyX4ddU9gcooznwA==');
|
||||
const decValue = await webCryptoFunctionService.aesDecryptSmall(data.buffer, iv.buffer, key.buffer);
|
||||
expect(UtilsService.fromBufferToUtf8(decValue)).toBe('EncryptMe!');
|
||||
});
|
||||
});
|
||||
|
||||
describe('aesDecryptLarge', () => {
|
||||
it('should successfully aes 256 decrypt data', async () => {
|
||||
const webCryptoFunctionService = getWebCryptoFunctionService();
|
||||
const iv = makeStaticByteArray(16);
|
||||
const key = makeStaticByteArray(32);
|
||||
const data = UtilsService.fromB64ToArray('ByUF8vhyX4ddU9gcooznwA==');
|
||||
const decValue = await webCryptoFunctionService.aesDecryptLarge(data.buffer, iv.buffer, key.buffer);
|
||||
expect(UtilsService.fromBufferToUtf8(decValue)).toBe('EncryptMe!');
|
||||
});
|
||||
});
|
||||
|
||||
describe('randomBytes', () => {
|
||||
it('should make a value of the correct length', async () => {
|
||||
const webCryptoFunctionService = getWebCryptoFunctionService();
|
||||
const randomData = await webCryptoFunctionService.randomBytes(16);
|
||||
expect(randomData.byteLength).toBe(16);
|
||||
});
|
||||
|
||||
it('should not make the same value twice', async () => {
|
||||
const webCryptoFunctionService = getWebCryptoFunctionService();
|
||||
const randomData = await webCryptoFunctionService.randomBytes(16);
|
||||
const randomData2 = await webCryptoFunctionService.randomBytes(16);
|
||||
expect(randomData.byteLength === randomData2.byteLength && randomData !== randomData2).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function testPbkdf2(edge: boolean, algorithm: 'sha256' | 'sha512', regularKey: string,
|
||||
@ -149,6 +197,14 @@ function getWebCryptoFunctionService(edge = false) {
|
||||
return new WebCryptoFunctionService(window, platformUtilsService);
|
||||
}
|
||||
|
||||
function makeStaticByteArray(length: number) {
|
||||
const arr = new Uint8Array(length);
|
||||
for (let i = 0; i < length; i++) {
|
||||
arr[i] = i;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
class BrowserPlatformUtilsService implements PlatformUtilsService {
|
||||
identityClientId: string;
|
||||
getDevice: () => DeviceType;
|
||||
|
@ -80,6 +80,34 @@ export class WebCryptoFunctionService implements CryptoFunctionService {
|
||||
return await this.subtle.sign(signingAlgorithm, impKey, value);
|
||||
}
|
||||
|
||||
async aesEncrypt(data: ArrayBuffer, iv: ArrayBuffer, key: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
const impKey = await this.subtle.importKey('raw', key, { name: 'AES-CBC' }, false, ['encrypt']);
|
||||
return await this.subtle.encrypt({ name: 'AES-CBC', iv: iv }, impKey, data);
|
||||
}
|
||||
|
||||
async aesDecryptSmall(data: ArrayBuffer, iv: ArrayBuffer, key: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
const dataBytes = this.toByteString(data);
|
||||
const ivBytes = this.toByteString(iv);
|
||||
const keyBytes = this.toByteString(key);
|
||||
const dataBuffer = (forge as any).util.createBuffer(dataBytes);
|
||||
const decipher = (forge as any).cipher.createDecipher('AES-CBC', keyBytes);
|
||||
decipher.start({ iv: ivBytes });
|
||||
decipher.update(dataBuffer);
|
||||
decipher.finish();
|
||||
return this.fromByteStringToBuf(decipher.output.getBytes());
|
||||
}
|
||||
|
||||
async aesDecryptLarge(data: ArrayBuffer, iv: ArrayBuffer, key: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
const impKey = await this.subtle.importKey('raw', key, { name: 'AES-CBC' }, false, ['decrypt']);
|
||||
return await this.subtle.decrypt({ name: 'AES-CBC', iv: iv }, impKey, data);
|
||||
}
|
||||
|
||||
randomBytes(length: number): ArrayBuffer {
|
||||
const arr = new Uint8Array(length);
|
||||
this.crypto.getRandomValues(arr);
|
||||
return arr.buffer;
|
||||
}
|
||||
|
||||
private toBuf(value: string | ArrayBuffer): ArrayBuffer {
|
||||
let buf: ArrayBuffer;
|
||||
if (typeof (value) === 'string') {
|
||||
|
Loading…
Reference in New Issue
Block a user