mirror of
https://github.com/bitwarden/browser
synced 2026-02-15 16:05:03 +00:00
Add necessary gcm decryption to encryptService
This is not added as an EncString and SymmetricCryptoKey because this is part of the transport layer, not vault encryption. TODO: This still probably needs better typing.
This commit is contained in:
@@ -14,6 +14,17 @@ export abstract class EncryptService {
|
||||
decryptContext?: string,
|
||||
): Promise<string>;
|
||||
abstract decryptToBytes(encThing: Encrypted, key: SymmetricCryptoKey): Promise<Uint8Array>;
|
||||
/**
|
||||
* Decrypts aes gcm encrypted data given a key.
|
||||
*
|
||||
* The data is expected to be a concatenation of cipherText, tag, and iv in that order.
|
||||
* Tag is required to be 16 bytes.
|
||||
* iv is required to be 12 bytes
|
||||
*
|
||||
* @param data The encrypted data + tag + iv
|
||||
* @param key The key to decrypt the data
|
||||
*/
|
||||
abstract aesGcmDecryptToBytes(data: Uint8Array, key: Uint8Array): Promise<Uint8Array>;
|
||||
abstract rsaEncrypt(data: Uint8Array, publicKey: Uint8Array): Promise<EncString>;
|
||||
abstract rsaDecrypt(data: EncString, privateKey: Uint8Array): Promise<Uint8Array>;
|
||||
abstract resolveLegacyKey(key: SymmetricCryptoKey, encThing: Encrypted): SymmetricCryptoKey;
|
||||
|
||||
@@ -126,6 +126,23 @@ export class EncryptServiceImplementation implements EncryptService {
|
||||
return await this.cryptoFunctionService.aesDecryptFast(fastParams, "cbc");
|
||||
}
|
||||
|
||||
async aesGcmDecryptToBytes(data: Uint8Array, key: Uint8Array): Promise<Uint8Array> {
|
||||
if (key == null) {
|
||||
throw new Error("No encryption key provided.");
|
||||
}
|
||||
|
||||
if (data == null) {
|
||||
throw new Error("Nothing provided for decryption.");
|
||||
}
|
||||
|
||||
// split data into cipherText + tag and iv
|
||||
const dataAndTag = data.slice(0, -12); // 12 bytes is the iv length
|
||||
const iv = data.slice(-12);
|
||||
|
||||
// aesDecrypt expects cipher + tag, but iv split
|
||||
return await this.cryptoFunctionService.aesDecrypt(dataAndTag, iv, key, "gcm");
|
||||
}
|
||||
|
||||
async decryptToBytes(encThing: Encrypted, key: SymmetricCryptoKey): Promise<Uint8Array> {
|
||||
if (key == null) {
|
||||
throw new Error("No encryption key provided.");
|
||||
|
||||
@@ -82,6 +82,41 @@ describe("EncryptService", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("aesGcmDecryptToBytes", () => {
|
||||
const data = makeStaticByteArray(10, 100);
|
||||
const key = makeStaticByteArray(32, 200);
|
||||
const encryptedData = new Uint8Array(1);
|
||||
|
||||
beforeEach(() => {
|
||||
cryptoFunctionService.aesDecrypt.mockResolvedValue(data);
|
||||
});
|
||||
|
||||
it("throws if no data is provided", () => {
|
||||
return expect(encryptService.aesGcmDecryptToBytes(null, key)).rejects.toThrow(
|
||||
"Nothing provided for decryption",
|
||||
);
|
||||
});
|
||||
|
||||
it("throws if no key is provided", () => {
|
||||
return expect(encryptService.aesGcmDecryptToBytes(encryptedData, null)).rejects.toThrow(
|
||||
"No encryption key",
|
||||
);
|
||||
});
|
||||
|
||||
it("strips off the tag and decrypts data with provided key and iv", async () => {
|
||||
const actual = await encryptService.aesGcmDecryptToBytes(encryptedData, key);
|
||||
|
||||
expect(cryptoFunctionService.aesDecrypt).toHaveBeenCalledWith(
|
||||
expect.toEqualBuffer(encryptedData.slice(0, -12)),
|
||||
expect.toEqualBuffer(encryptedData.slice(-12)),
|
||||
expect.toEqualBuffer(key),
|
||||
"gcm",
|
||||
);
|
||||
|
||||
expect(actual).toEqualBuffer(data);
|
||||
});
|
||||
});
|
||||
|
||||
describe("decryptToBytes", () => {
|
||||
const encType = EncryptionType.AesCbc256_HmacSha256_B64;
|
||||
const key = new SymmetricCryptoKey(makeStaticByteArray(64, 100), encType);
|
||||
|
||||
Reference in New Issue
Block a user