1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-17 08:43:33 +00:00

Fix failing crypto tests (#5948)

* Change everything to Uint8Array

related to https://github.com/jestjs/jest/issues/14379

* Work on failing type tests

* Revert changes to custom matcher setup

* Remove last BufferArrays from tests

* Fix custom matcher type errors in vscode

* Remove errant `.buffer` calls on Uint8Arrays

* Encryption Pair should serialize Array Buffer and Uint8Array

* Fix EncArrayBuffer encryption

---------

Co-authored-by: Thomas Rittson <trittson@bitwarden.com>
This commit is contained in:
Matt Gibson
2023-08-03 22:13:33 -04:00
committed by GitHub
parent efb26e3e27
commit 36b7d30804
62 changed files with 401 additions and 424 deletions

View File

@@ -8,7 +8,7 @@ describe("AccountKeys", () => {
describe("toJSON", () => {
it("should serialize itself", () => {
const keys = new AccountKeys();
const buffer = makeStaticByteArray(64).buffer;
const buffer = makeStaticByteArray(64);
keys.publicKey = buffer;
const bufferSpy = jest.spyOn(Utils, "fromBufferToByteString");
@@ -18,7 +18,7 @@ describe("AccountKeys", () => {
it("should serialize public key as a string", () => {
const keys = new AccountKeys();
keys.publicKey = Utils.fromByteStringToArray("hello").buffer;
keys.publicKey = Utils.fromByteStringToArray("hello");
const json = JSON.stringify(keys);
expect(json).toContain('"publicKey":"hello"');
});
@@ -29,7 +29,7 @@ describe("AccountKeys", () => {
const keys = AccountKeys.fromJSON({
publicKey: "hello",
});
expect(keys.publicKey).toEqual(Utils.fromByteStringToArray("hello").buffer);
expect(keys.publicKey).toEqual(Utils.fromByteStringToArray("hello"));
});
it("should deserialize cryptoMasterKey", () => {

View File

@@ -119,8 +119,8 @@ export class AccountKeys {
any,
Record<string, SymmetricCryptoKey>
>();
privateKey?: EncryptionPair<string, ArrayBuffer> = new EncryptionPair<string, ArrayBuffer>();
publicKey?: ArrayBuffer;
privateKey?: EncryptionPair<string, Uint8Array> = new EncryptionPair<string, Uint8Array>();
publicKey?: Uint8Array;
apiKeyClientSecret?: string;
toJSON() {
@@ -142,11 +142,10 @@ export class AccountKeys {
),
organizationKeys: AccountKeys.initRecordEncryptionPairsFromJSON(obj?.organizationKeys),
providerKeys: AccountKeys.initRecordEncryptionPairsFromJSON(obj?.providerKeys),
privateKey: EncryptionPair.fromJSON<string, ArrayBuffer>(
obj?.privateKey,
(decObj: string) => Utils.fromByteStringToArray(decObj).buffer
privateKey: EncryptionPair.fromJSON<string, Uint8Array>(obj?.privateKey, (decObj: string) =>
Utils.fromByteStringToArray(decObj)
),
publicKey: Utils.fromByteStringToArray(obj?.publicKey)?.buffer,
publicKey: Utils.fromByteStringToArray(obj?.publicKey),
});
}

View File

@@ -20,7 +20,7 @@ describe("encArrayBuffer", () => {
array.set(mac, 1 + iv.byteLength);
array.set(data, 1 + iv.byteLength + mac.byteLength);
const actual = new EncArrayBuffer(array.buffer);
const actual = new EncArrayBuffer(array);
expect(actual.encryptionType).toEqual(encType);
expect(actual.ivBytes).toEqualBuffer(iv);
@@ -39,11 +39,11 @@ describe("encArrayBuffer", () => {
array.set(iv, 1);
array.set(data, 1 + iv.byteLength);
const actual = new EncArrayBuffer(array.buffer);
const actual = new EncArrayBuffer(array);
expect(actual.encryptionType).toEqual(encType);
expect(actual.ivBytes).toEqualBuffer(iv);
expect(actual.dataBytes).toEqualBuffer(data);
expect(actual.ivBytes).toEqual(iv);
expect(actual.dataBytes).toEqual(data);
expect(actual.macBytes).toBeNull();
});
});
@@ -58,13 +58,11 @@ describe("encArrayBuffer", () => {
// Minus 1 to leave room for the encType, minus 1 to make it invalid
const invalidBytes = makeStaticByteArray(minLength - 2);
const invalidArray = new Uint8Array(1 + invalidBytes.buffer.byteLength);
const invalidArray = new Uint8Array(1 + invalidBytes.byteLength);
invalidArray.set([encType]);
invalidArray.set(invalidBytes, 1);
expect(() => new EncArrayBuffer(invalidArray.buffer)).toThrow(
"Error parsing encrypted ArrayBuffer"
);
expect(() => new EncArrayBuffer(invalidArray)).toThrow("Error parsing encrypted ArrayBuffer");
});
});

View File

@@ -9,12 +9,12 @@ const MIN_DATA_LENGTH = 1;
export class EncArrayBuffer implements Encrypted {
readonly encryptionType: EncryptionType = null;
readonly dataBytes: ArrayBuffer = null;
readonly ivBytes: ArrayBuffer = null;
readonly macBytes: ArrayBuffer = null;
readonly dataBytes: Uint8Array = null;
readonly ivBytes: Uint8Array = null;
readonly macBytes: Uint8Array = null;
constructor(readonly buffer: ArrayBuffer) {
const encBytes = new Uint8Array(buffer);
constructor(readonly buffer: Uint8Array) {
const encBytes = buffer;
const encType = encBytes[0];
switch (encType) {
@@ -25,12 +25,12 @@ export class EncArrayBuffer implements Encrypted {
this.throwDecryptionError();
}
this.ivBytes = encBytes.slice(ENC_TYPE_LENGTH, ENC_TYPE_LENGTH + IV_LENGTH).buffer;
this.ivBytes = encBytes.slice(ENC_TYPE_LENGTH, ENC_TYPE_LENGTH + IV_LENGTH);
this.macBytes = encBytes.slice(
ENC_TYPE_LENGTH + IV_LENGTH,
ENC_TYPE_LENGTH + IV_LENGTH + MAC_LENGTH
).buffer;
this.dataBytes = encBytes.slice(ENC_TYPE_LENGTH + IV_LENGTH + MAC_LENGTH).buffer;
);
this.dataBytes = encBytes.slice(ENC_TYPE_LENGTH + IV_LENGTH + MAC_LENGTH);
break;
}
case EncryptionType.AesCbc256_B64: {
@@ -39,8 +39,8 @@ export class EncArrayBuffer implements Encrypted {
this.throwDecryptionError();
}
this.ivBytes = encBytes.slice(ENC_TYPE_LENGTH, ENC_TYPE_LENGTH + IV_LENGTH).buffer;
this.dataBytes = encBytes.slice(ENC_TYPE_LENGTH + IV_LENGTH).buffer;
this.ivBytes = encBytes.slice(ENC_TYPE_LENGTH, ENC_TYPE_LENGTH + IV_LENGTH);
this.dataBytes = encBytes.slice(ENC_TYPE_LENGTH + IV_LENGTH);
break;
}
default:
@@ -63,11 +63,11 @@ export class EncArrayBuffer implements Encrypted {
if (buffer == null) {
throw new Error("Cannot create EncArrayBuffer from Response - Response is empty");
}
return new EncArrayBuffer(buffer);
return new EncArrayBuffer(new Uint8Array(buffer));
}
static fromB64(b64: string) {
const buffer = Utils.fromB64ToArray(b64).buffer;
const buffer = Utils.fromB64ToArray(b64);
return new EncArrayBuffer(buffer);
}
}

View File

@@ -27,16 +27,16 @@ export class EncString implements Encrypted {
}
}
get ivBytes(): ArrayBuffer {
return this.iv == null ? null : Utils.fromB64ToArray(this.iv).buffer;
get ivBytes(): Uint8Array {
return this.iv == null ? null : Utils.fromB64ToArray(this.iv);
}
get macBytes(): ArrayBuffer {
return this.mac == null ? null : Utils.fromB64ToArray(this.mac).buffer;
get macBytes(): Uint8Array {
return this.mac == null ? null : Utils.fromB64ToArray(this.mac);
}
get dataBytes(): ArrayBuffer {
return this.data == null ? null : Utils.fromB64ToArray(this.data).buffer;
get dataBytes(): Uint8Array {
return this.data == null ? null : Utils.fromB64ToArray(this.data);
}
toJSON() {

View File

@@ -1,8 +1,8 @@
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
export class EncryptedObject {
iv: ArrayBuffer;
data: ArrayBuffer;
mac: ArrayBuffer;
iv: Uint8Array;
data: Uint8Array;
mac: Uint8Array;
key: SymmetricCryptoKey;
}

View File

@@ -11,6 +11,13 @@ describe("EncryptionPair", () => {
expect(json.decrypted).toEqual("hello");
});
it("should populate decryptedSerialized for TypesArrays", () => {
const pair = new EncryptionPair<string, Uint8Array>();
pair.decrypted = Utils.fromByteStringToArray("hello");
const json = pair.toJSON();
expect(json.decrypted).toEqual(new Uint8Array([104, 101, 108, 108, 111]));
});
it("should serialize encrypted and decrypted", () => {
const pair = new EncryptionPair<string, string>();
pair.encrypted = "hello";

View File

@@ -68,7 +68,7 @@ describe("SymmetricCryptoKey", () => {
});
it("toJSON creates object for serialization", () => {
const key = new SymmetricCryptoKey(makeStaticByteArray(64).buffer);
const key = new SymmetricCryptoKey(makeStaticByteArray(64));
const actual = key.toJSON();
const expected = { keyB64: key.keyB64 };
@@ -77,7 +77,7 @@ describe("SymmetricCryptoKey", () => {
});
it("fromJSON hydrates new object", () => {
const expected = new SymmetricCryptoKey(makeStaticByteArray(64).buffer);
const expected = new SymmetricCryptoKey(makeStaticByteArray(64));
const actual = SymmetricCryptoKey.fromJSON({ keyB64: expected.keyB64 });
expect(actual).toEqual(expected);

View File

@@ -4,9 +4,9 @@ import { EncryptionType } from "../../../enums";
import { Utils } from "../../../platform/misc/utils";
export class SymmetricCryptoKey {
key: ArrayBuffer;
encKey?: ArrayBuffer;
macKey?: ArrayBuffer;
key: Uint8Array;
encKey?: Uint8Array;
macKey?: Uint8Array;
encType: EncryptionType;
keyB64: string;
@@ -15,7 +15,7 @@ export class SymmetricCryptoKey {
meta: any;
constructor(key: ArrayBuffer, encType?: EncryptionType) {
constructor(key: Uint8Array, encType?: EncryptionType) {
if (key == null) {
throw new Error("Must provide key");
}
@@ -67,7 +67,7 @@ export class SymmetricCryptoKey {
return null;
}
const arrayBuffer = Utils.fromB64ToArray(s).buffer;
const arrayBuffer = Utils.fromB64ToArray(s);
return new SymmetricCryptoKey(arrayBuffer);
}