mirror of
https://github.com/bitwarden/browser
synced 2025-12-22 19:23:52 +00:00
[PM-20492] Refactor symmetric keys - remove key buffer representation, migrate consumers to .toEncoded() (#14371)
* Refactor encrypt service to expose key wrapping * Fix build * Undo ts strict removal * Fix wrong method being used to encrypt key material * Rename parameters and remove todo * Add summary to encrypt * Update libs/common/src/key-management/crypto/services/encrypt.service.implementation.ts Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update libs/common/src/key-management/crypto/services/encrypt.service.implementation.ts Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update libs/common/src/key-management/crypto/services/encrypt.service.implementation.ts Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update libs/common/src/key-management/crypto/services/encrypt.service.implementation.ts Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update libs/common/src/key-management/crypto/abstractions/encrypt.service.ts Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update libs/common/src/key-management/crypto/services/encrypt.service.implementation.ts Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Add tests for unhappy paths * Add test coverage * Add links * Remove direct buffer access * Fix build on cli --------- Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>
This commit is contained in:
@@ -47,7 +47,7 @@ export class EncryptServiceImplementation implements EncryptService {
|
||||
}
|
||||
|
||||
if (this.blockType0) {
|
||||
if (key.inner().type === EncryptionType.AesCbc256_B64 || key.key.byteLength < 64) {
|
||||
if (key.inner().type === EncryptionType.AesCbc256_B64) {
|
||||
throw new Error("Type 0 encryption is not supported.");
|
||||
}
|
||||
}
|
||||
@@ -105,7 +105,7 @@ export class EncryptServiceImplementation implements EncryptService {
|
||||
throw new Error("No wrappingKey provided for wrapping.");
|
||||
}
|
||||
|
||||
return await this.encryptUint8Array(keyToBeWrapped.key, wrappingKey);
|
||||
return await this.encryptUint8Array(keyToBeWrapped.toEncoded(), wrappingKey);
|
||||
}
|
||||
|
||||
private async encryptUint8Array(
|
||||
@@ -147,7 +147,7 @@ export class EncryptServiceImplementation implements EncryptService {
|
||||
}
|
||||
|
||||
if (this.blockType0) {
|
||||
if (key.inner().type === EncryptionType.AesCbc256_B64 || key.key.byteLength < 64) {
|
||||
if (key.inner().type === EncryptionType.AesCbc256_B64) {
|
||||
throw new Error("Type 0 encryption is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,10 +184,9 @@ describe("EncryptService", () => {
|
||||
(encryptService as any).blockType0 = true;
|
||||
const key = new SymmetricCryptoKey(makeStaticByteArray(32));
|
||||
const mock32Key = mock<SymmetricCryptoKey>();
|
||||
mock32Key.key = makeStaticByteArray(32);
|
||||
mock32Key.inner.mockReturnValue({
|
||||
type: 0,
|
||||
encryptionKey: mock32Key.key,
|
||||
encryptionKey: makeStaticByteArray(32),
|
||||
});
|
||||
|
||||
await expect(encryptService.encrypt(null!, key)).rejects.toThrow(
|
||||
@@ -270,10 +269,9 @@ describe("EncryptService", () => {
|
||||
(encryptService as any).blockType0 = true;
|
||||
const key = new SymmetricCryptoKey(makeStaticByteArray(32));
|
||||
const mock32Key = mock<SymmetricCryptoKey>();
|
||||
mock32Key.key = makeStaticByteArray(32);
|
||||
mock32Key.inner.mockReturnValue({
|
||||
type: 0,
|
||||
encryptionKey: mock32Key.key,
|
||||
encryptionKey: makeStaticByteArray(32),
|
||||
});
|
||||
|
||||
await expect(encryptService.encryptToBytes(plainValue, key)).rejects.toThrow(
|
||||
@@ -571,7 +569,7 @@ describe("EncryptService", () => {
|
||||
const actual = await encryptService.encapsulateKeyUnsigned(testKey, publicKey);
|
||||
|
||||
expect(cryptoFunctionService.rsaEncrypt).toBeCalledWith(
|
||||
expect.toEqualBuffer(testKey.key),
|
||||
expect.toEqualBuffer(testKey.toEncoded()),
|
||||
expect.toEqualBuffer(publicKey),
|
||||
"sha1",
|
||||
);
|
||||
@@ -622,7 +620,7 @@ describe("EncryptService", () => {
|
||||
"sha1",
|
||||
);
|
||||
|
||||
expect(actual.key).toEqualBuffer(data);
|
||||
expect(actual.toEncoded()).toEqualBuffer(data);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -221,8 +221,8 @@ export class DeviceTrustService implements DeviceTrustServiceAbstraction {
|
||||
}
|
||||
|
||||
const newEncryptedPublicKey = await this.encryptService.encrypt(publicKey, newUserKey);
|
||||
const newEncryptedUserKey = await this.encryptService.rsaEncrypt(
|
||||
newUserKey.key,
|
||||
const newEncryptedUserKey = await this.encryptService.encapsulateKeyUnsigned(
|
||||
newUserKey,
|
||||
publicKey,
|
||||
);
|
||||
|
||||
|
||||
@@ -450,7 +450,7 @@ describe("deviceTrustService", () => {
|
||||
|
||||
// RsaEncrypt must be called w/ a user key array buffer of 64 bytes
|
||||
const userKey = cryptoSvcRsaEncryptSpy.mock.calls[0][0];
|
||||
expect(userKey.key.byteLength).toBe(64);
|
||||
expect(userKey.inner().type).toBe(EncryptionType.AesCbc256_HmacSha256_B64);
|
||||
|
||||
expect(encryptServiceWrapDecapsulationKeySpy).toHaveBeenCalledTimes(1);
|
||||
expect(encryptServiceWrapEncapsulationKeySpy).toHaveBeenCalledTimes(1);
|
||||
@@ -706,7 +706,9 @@ describe("deviceTrustService", () => {
|
||||
);
|
||||
encryptService.decryptToBytes.mockResolvedValue(null);
|
||||
encryptService.encrypt.mockResolvedValue(new EncString("test_encrypted_data"));
|
||||
encryptService.rsaEncrypt.mockResolvedValue(new EncString("test_encrypted_data"));
|
||||
encryptService.encapsulateKeyUnsigned.mockResolvedValue(
|
||||
new EncString("test_encrypted_data"),
|
||||
);
|
||||
|
||||
const protectedDeviceResponse = new ProtectedDeviceResponse({
|
||||
id: "id",
|
||||
@@ -861,8 +863,8 @@ describe("deviceTrustService", () => {
|
||||
|
||||
// Mock the decryption of the public key with the old user key
|
||||
encryptService.decryptToBytes.mockImplementationOnce((_encValue, privateKeyValue) => {
|
||||
expect(privateKeyValue.key.byteLength).toBe(64);
|
||||
expect(new Uint8Array(privateKeyValue.key)[0]).toBe(FakeOldUserKeyMarker);
|
||||
expect(privateKeyValue.inner().type).toBe(EncryptionType.AesCbc256_HmacSha256_B64);
|
||||
expect(new Uint8Array(privateKeyValue.toEncoded())[0]).toBe(FakeOldUserKeyMarker);
|
||||
const data = new Uint8Array(250);
|
||||
data.fill(FakeDecryptedPublicKeyMarker, 0, 1);
|
||||
return Promise.resolve(data);
|
||||
@@ -870,8 +872,8 @@ describe("deviceTrustService", () => {
|
||||
|
||||
// Mock the encryption of the new user key with the decrypted public key
|
||||
encryptService.encapsulateKeyUnsigned.mockImplementationOnce((data, publicKey) => {
|
||||
expect(data.key.byteLength).toBe(64); // New key should also be 64 bytes
|
||||
expect(new Uint8Array(data.key)[0]).toBe(FakeNewUserKeyMarker); // New key should have the first byte be '1';
|
||||
expect(data.inner().type).toBe(EncryptionType.AesCbc256_HmacSha256_B64); // New key should also be 64 bytes
|
||||
expect(new Uint8Array(data.toEncoded())[0]).toBe(FakeNewUserKeyMarker); // New key should have the first byte be '1';
|
||||
|
||||
expect(new Uint8Array(publicKey)[0]).toBe(FakeDecryptedPublicKeyMarker);
|
||||
return Promise.resolve(new EncString("4.ZW5jcnlwdGVkdXNlcg=="));
|
||||
@@ -882,7 +884,7 @@ describe("deviceTrustService", () => {
|
||||
expect(plainValue).toBeInstanceOf(Uint8Array);
|
||||
expect(new Uint8Array(plainValue as Uint8Array)[0]).toBe(FakeDecryptedPublicKeyMarker);
|
||||
|
||||
expect(new Uint8Array(key.key)[0]).toBe(FakeNewUserKeyMarker);
|
||||
expect(new Uint8Array(key.toEncoded())[0]).toBe(FakeNewUserKeyMarker);
|
||||
return Promise.resolve(
|
||||
new EncString("2.ZW5jcnlwdGVkcHVibGlj|ZW5jcnlwdGVkcHVibGlj|ZW5jcnlwdGVkcHVibGlj"),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user