Skip to content

Commit

Permalink
Fix failing crypto tests (#5948)
Browse files Browse the repository at this point in the history
* Change everything to Uint8Array

related to jestjs/jest#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>
  • Loading branch information
MGibson1 and eliykat committed Aug 4, 2023
1 parent efb26e3 commit 36b7d30
Show file tree
Hide file tree
Showing 62 changed files with 401 additions and 424 deletions.
8 changes: 4 additions & 4 deletions apps/browser/src/background/nativeMessaging.background.ts
Expand Up @@ -59,8 +59,8 @@ export class NativeMessagingBackground {
private port: browser.runtime.Port | chrome.runtime.Port;

private resolver: any = null;
private privateKey: ArrayBuffer = null;
private publicKey: ArrayBuffer = null;
private privateKey: Uint8Array = null;
private publicKey: Uint8Array = null;
private secureSetupResolve: any = null;
private sharedSecret: SymmetricCryptoKey;
private appId: string;
Expand Down Expand Up @@ -129,7 +129,7 @@ export class NativeMessagingBackground {

const encrypted = Utils.fromB64ToArray(message.sharedSecret);
const decrypted = await this.cryptoFunctionService.rsaDecrypt(
encrypted.buffer,
encrypted,
this.privateKey,
EncryptionAlgorithm
);
Expand Down Expand Up @@ -321,7 +321,7 @@ export class NativeMessagingBackground {

if (message.response === "unlocked") {
await this.cryptoService.setKey(
new SymmetricCryptoKey(Utils.fromB64ToArray(message.keyB64).buffer)
new SymmetricCryptoKey(Utils.fromB64ToArray(message.keyB64))
);

// Verify key is correct by attempting to decrypt a secret
Expand Down
Expand Up @@ -21,9 +21,7 @@ describe("Browser Session Storage Service", () => {
let localStorage: BrowserLocalStorageService;
let sessionStorage: BrowserMemoryStorageService;

const key = new SymmetricCryptoKey(
Utils.fromUtf8ToArray("00000000000000000000000000000000").buffer
);
const key = new SymmetricCryptoKey(Utils.fromUtf8ToArray("00000000000000000000000000000000"));
let getSessionKeySpy: jest.SpyInstance;
const mockEnc = (input: string) => Promise.resolve(new EncString("ENCRYPTED" + input));

Expand Down
2 changes: 1 addition & 1 deletion apps/cli/src/admin-console/commands/confirm.command.ts
Expand Up @@ -51,7 +51,7 @@ export class ConfirmCommand {
}
const publicKeyResponse = await this.apiService.getUserPublicKey(orgUser.userId);
const publicKey = Utils.fromB64ToArray(publicKeyResponse.publicKey);
const key = await this.cryptoService.rsaEncrypt(orgKey.key, publicKey.buffer);
const key = await this.cryptoService.rsaEncrypt(orgKey.key, publicKey);
const req = new OrganizationUserConfirmRequest();
req.key = key.encryptedString;
await this.organizationUserService.postOrganizationUserConfirm(
Expand Down
2 changes: 1 addition & 1 deletion apps/cli/src/commands/get.command.ts
Expand Up @@ -513,7 +513,7 @@ export class GetCommand extends DownloadCommand {
try {
const response = await this.apiService.getUserPublicKey(id);
const pubKey = Utils.fromB64ToArray(response.publicKey);
fingerprint = await this.cryptoService.getFingerprint(id, pubKey.buffer);
fingerprint = await this.cryptoService.getFingerprint(id, pubKey);
} catch {
// eslint-disable-next-line
}
Expand Down
Expand Up @@ -47,7 +47,7 @@ export class NodeEnvSecureStorageService implements AbstractStorageService {
throw new Error("No session key available.");
}
const encValue = await this.cryptoService().encryptToBytes(
Utils.fromB64ToArray(plainValue).buffer,
Utils.fromB64ToArray(plainValue),
sessionKey
);
if (encValue == null) {
Expand Down Expand Up @@ -81,7 +81,7 @@ export class NodeEnvSecureStorageService implements AbstractStorageService {
private getSessionKey() {
try {
if (process.env.BW_SESSION != null) {
const sessionBuffer = Utils.fromB64ToArray(process.env.BW_SESSION).buffer;
const sessionBuffer = Utils.fromB64ToArray(process.env.BW_SESSION);
if (sessionBuffer != null) {
const sessionKey = new SymmetricCryptoKey(sessionBuffer);
if (sessionBuffer != null) {
Expand Down
4 changes: 2 additions & 2 deletions apps/cli/src/tools/send/commands/receive.command.ts
Expand Up @@ -121,7 +121,7 @@ export class SendReceiveCommand extends DownloadCommand {
}
}

private async getUnlockedPassword(password: string, keyArray: ArrayBuffer) {
private async getUnlockedPassword(password: string, keyArray: Uint8Array) {
const passwordHash = await this.cryptoFunctionService.pbkdf2(
password,
keyArray,
Expand All @@ -134,7 +134,7 @@ export class SendReceiveCommand extends DownloadCommand {
private async sendRequest(
url: string,
id: string,
key: ArrayBuffer
key: Uint8Array
): Promise<Response | SendAccessView> {
try {
const sendResponse = await this.sendApiService.postSendAccess(
Expand Down
Expand Up @@ -225,8 +225,8 @@ export default class NativeMessageService {
}

private async getSharedKeyForKey(key: string): Promise<SymmetricCryptoKey> {
const dataBuffer = Utils.fromB64ToArray(key).buffer;
const privKey = Utils.fromB64ToArray(config.testRsaPrivateKey).buffer;
const dataBuffer = Utils.fromB64ToArray(key);
const privKey = Utils.fromB64ToArray(config.testRsaPrivateKey);

return new SymmetricCryptoKey(
await this.nodeCryptoFunctionService.rsaDecrypt(dataBuffer, privKey, "sha1")
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/auth/login/login-approval.component.ts
Expand Up @@ -68,7 +68,7 @@ export class LoginApprovalComponent implements OnInit, OnDestroy {
const publicKey = Utils.fromB64ToArray(this.authRequestResponse.publicKey);
this.email = await this.stateService.getEmail();
this.fingerprintPhrase = (
await this.cryptoService.getFingerprint(this.email, publicKey.buffer)
await this.cryptoService.getFingerprint(this.email, publicKey)
).join("-");
this.updateTimeText();

Expand Down
Expand Up @@ -98,7 +98,7 @@ export class ElectronStateService
options
);

return new SymmetricCryptoKey(Utils.fromB64ToArray(b64DeviceKey).buffer) as DeviceKey;
return new SymmetricCryptoKey(Utils.fromB64ToArray(b64DeviceKey)) as DeviceKey;
}

override async setDeviceKey(value: DeviceKey, options?: StorageOptions): Promise<void> {
Expand Down
Expand Up @@ -70,7 +70,7 @@ export class NativeMessageHandlerService {
}

try {
const remotePublicKey = Utils.fromB64ToArray(publicKey).buffer;
const remotePublicKey = Utils.fromB64ToArray(publicKey);
const ddgEnabled = await this.stateService.getEnableDuckDuckGoBrowserIntegration();

if (!ddgEnabled) {
Expand Down
4 changes: 2 additions & 2 deletions apps/desktop/src/services/native-messaging.service.ts
Expand Up @@ -56,7 +56,7 @@ export class NativeMessagingService {

// Request to setup secure encryption
if ("command" in rawMessage && rawMessage.command === "setupEncryption") {
const remotePublicKey = Utils.fromB64ToArray(rawMessage.publicKey).buffer;
const remotePublicKey = Utils.fromB64ToArray(rawMessage.publicKey);

// Validate the UserId to ensure we are logged into the same account.
const accounts = await firstValueFrom(this.stateService.accounts$);
Expand Down Expand Up @@ -169,7 +169,7 @@ export class NativeMessagingService {
ipcRenderer.send("nativeMessagingReply", { appId: appId, message: encrypted });
}

private async secureCommunication(remotePublicKey: ArrayBuffer, appId: string) {
private async secureCommunication(remotePublicKey: Uint8Array, appId: string) {
const secret = await this.cryptoFunctionService.randomBytes(64);
this.sharedSecrets.set(appId, new SymmetricCryptoKey(secret));

Expand Down
Expand Up @@ -28,10 +28,7 @@ export class UserConfirmComponent implements OnInit {
async ngOnInit() {
try {
if (this.publicKey != null) {
const fingerprint = await this.cryptoService.getFingerprint(
this.userId,
this.publicKey.buffer
);
const fingerprint = await this.cryptoService.getFingerprint(this.userId, this.publicKey);
if (fingerprint != null) {
this.fingerprint = fingerprint.join("-");
}
Expand Down
Expand Up @@ -47,7 +47,7 @@ export class BulkConfirmComponent implements OnInit {

for (const entry of response.data) {
const publicKey = Utils.fromB64ToArray(entry.key);
const fingerprint = await this.cryptoService.getFingerprint(entry.userId, publicKey.buffer);
const fingerprint = await this.cryptoService.getFingerprint(entry.userId, publicKey);
if (fingerprint != null) {
this.publicKeys.set(entry.id, publicKey);
this.fingerprints.set(entry.id, fingerprint.join("-"));
Expand All @@ -67,7 +67,7 @@ export class BulkConfirmComponent implements OnInit {
if (publicKey == null) {
continue;
}
const encryptedKey = await this.cryptoService.rsaEncrypt(key.key, publicKey.buffer);
const encryptedKey = await this.cryptoService.rsaEncrypt(key.key, publicKey);
userIdsWithKeys.push({
id: user.id,
key: encryptedKey.encryptedString,
Expand Down
Expand Up @@ -302,7 +302,7 @@ export class PeopleComponent

async confirmUser(user: OrganizationUserView, publicKey: Uint8Array): Promise<void> {
const orgKey = await this.cryptoService.getOrgKey(this.organization.id);
const key = await this.cryptoService.rsaEncrypt(orgKey.key, publicKey.buffer);
const key = await this.cryptoService.rsaEncrypt(orgKey.key, publicKey);
const request = new OrganizationUserConfirmRequest();
request.key = key.encryptedString;
await this.organizationUserService.postOrganizationUserConfirm(
Expand Down
Expand Up @@ -61,7 +61,7 @@ export class AccountComponent {
});

protected organizationId: string;
protected publicKeyBuffer: ArrayBuffer;
protected publicKeyBuffer: Uint8Array;

private destroy$ = new Subject<void>();

Expand Down Expand Up @@ -106,7 +106,7 @@ export class AccountComponent {
this.org = orgResponse;

// Public Key Buffer for Org Fingerprint Generation
this.publicKeyBuffer = Utils.fromB64ToArray(orgKeys?.publicKey)?.buffer;
this.publicKeyBuffer = Utils.fromB64ToArray(orgKeys?.publicKey);

// Patch existing values
this.formGroup.patchValue({
Expand Down
Expand Up @@ -59,7 +59,7 @@ export class EnrollMasterPasswordReset {

// RSA Encrypt user's encKey.key with organization public key
const encKey = await this.cryptoService.getEncKey();
const encryptedKey = await this.cryptoService.rsaEncrypt(encKey.key, publicKey.buffer);
const encryptedKey = await this.cryptoService.rsaEncrypt(encKey.key, publicKey);
keyString = encryptedKey.encryptedString;
toastStringRef = "enrollPasswordResetSuccess";

Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/app/auth/accept-organization.component.ts
Expand Up @@ -142,7 +142,7 @@ export class AcceptOrganizationComponent extends BaseAcceptComponent {

// RSA Encrypt user's encKey.key with organization public key
const encKey = await this.cryptoService.getEncKey();
const encryptedKey = await this.cryptoService.rsaEncrypt(encKey.key, publicKey.buffer);
const encryptedKey = await this.cryptoService.rsaEncrypt(encKey.key, publicKey);

// Add reset password key to accept request
request.resetPasswordKey = encryptedKey.encryptedString;
Expand Down
Expand Up @@ -33,7 +33,7 @@ export class EmergencyAccessConfirmComponent implements OnInit {
const publicKeyResponse = await this.apiService.getUserPublicKey(this.userId);
if (publicKeyResponse != null) {
const publicKey = Utils.fromB64ToArray(publicKeyResponse.publicKey);
const fingerprint = await this.cryptoService.getFingerprint(this.userId, publicKey.buffer);
const fingerprint = await this.cryptoService.getFingerprint(this.userId, publicKey);
if (fingerprint != null) {
this.fingerprint = fingerprint.join("-");
}
Expand Down
Expand Up @@ -309,13 +309,13 @@ export class EmergencyAccessComponent implements OnInit {
try {
this.logService.debug(
"User's fingerprint: " +
(await this.cryptoService.getFingerprint(details.granteeId, publicKey.buffer)).join("-")
(await this.cryptoService.getFingerprint(details.granteeId, publicKey)).join("-")
);
} catch {
// Ignore errors since it's just a debug message
}

const encryptedKey = await this.cryptoService.rsaEncrypt(encKey.key, publicKey.buffer);
const encryptedKey = await this.cryptoService.rsaEncrypt(encKey.key, publicKey);
const request = new EmergencyAccessConfirmRequest();
request.key = encryptedKey.encryptedString;
await this.apiService.postEmergencyAccessConfirm(details.id, request);
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/app/common/base.people.component.ts
Expand Up @@ -374,7 +374,7 @@ export abstract class BasePeopleComponent<
}

try {
const fingerprint = await this.cryptoService.getFingerprint(user.userId, publicKey.buffer);
const fingerprint = await this.cryptoService.getFingerprint(user.userId, publicKey);
this.logService.info(`User's fingerprint: ${fingerprint.join("-")}`);
} catch (e) {
this.logService.error(e);
Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/app/settings/change-password.component.ts
Expand Up @@ -274,7 +274,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
const publicKeyResponse = await this.apiService.getUserPublicKey(details.granteeId);
const publicKey = Utils.fromB64ToArray(publicKeyResponse.publicKey);

const encryptedKey = await this.cryptoService.rsaEncrypt(encKey.key, publicKey.buffer);
const encryptedKey = await this.cryptoService.rsaEncrypt(encKey.key, publicKey);

const updateRequest = new EmergencyAccessUpdateRequest();
updateRequest.type = details.type;
Expand All @@ -299,7 +299,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
const publicKey = Utils.fromB64ToArray(response?.publicKey);

// Re-enroll - encrypt user's encKey.key with organization public key
const encryptedKey = await this.cryptoService.rsaEncrypt(encKey.key, publicKey.buffer);
const encryptedKey = await this.cryptoService.rsaEncrypt(encKey.key, publicKey);

// Create/Execute request
const request = new OrganizationUserResetPasswordEnrollmentRequest();
Expand Down
Expand Up @@ -12,7 +12,7 @@ import { SharedModule } from "../../shared.module";
})
export class AccountFingerprintComponent implements OnInit {
@Input() fingerprintMaterial: string;
@Input() publicKeyBuffer: ArrayBuffer;
@Input() publicKeyBuffer: Uint8Array;
@Input() fingerprintLabel: string;

protected fingerprint: string;
Expand Down
Expand Up @@ -277,7 +277,7 @@ function createCipherView(i: number, deleted = false): CipherView {
view.attachments = [attachment];
} else if (i % 5 === 0) {
const attachment = new AttachmentView();
attachment.key = new SymmetricCryptoKey(new ArrayBuffer(32));
attachment.key = new SymmetricCryptoKey(new Uint8Array(32));
view.attachments = [attachment];
}

Expand Down
Expand Up @@ -90,7 +90,7 @@ export class DeviceApprovalsComponent implements OnInit, OnDestroy {
const userSymKey = new SymmetricCryptoKey(decValue);

// Re-encrypt User's Symmetric Key with the Device Public Key
return await this.cryptoService.rsaEncrypt(userSymKey.key, devicePubKey.buffer);
return await this.cryptoService.rsaEncrypt(userSymKey.key, devicePubKey);
}

async approveRequest(authRequest: PendingAuthRequestView) {
Expand Down
Expand Up @@ -138,7 +138,7 @@ export class PeopleComponent

async confirmUser(user: ProviderUserUserDetailsResponse, publicKey: Uint8Array): Promise<any> {
const providerKey = await this.cryptoService.getProviderKey(this.providerId);
const key = await this.cryptoService.rsaEncrypt(providerKey.key, publicKey.buffer);
const key = await this.cryptoService.rsaEncrypt(providerKey.key, publicKey);
const request = new ProviderUserConfirmRequest();
request.key = key.encryptedString;
await this.apiService.postProviderUserConfirm(this.providerId, user.id, request);
Expand Down
Expand Up @@ -46,7 +46,7 @@ export class LoginWithDeviceComponent
protected successRoute = "vault";
protected forcePasswordResetRoute = "update-temp-password";
private resendTimeout = 12000;
private authRequestKeyPair: [publicKey: ArrayBuffer, privateKey: ArrayBuffer];
private authRequestKeyPair: [publicKey: Uint8Array, privateKey: Uint8Array];

constructor(
protected router: Router,
Expand Down
5 changes: 1 addition & 4 deletions libs/angular/src/components/set-password.component.ts
Expand Up @@ -133,10 +133,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {

// RSA Encrypt user's encKey.key with organization public key
const userEncKey = await this.cryptoService.getEncKey();
const encryptedKey = await this.cryptoService.rsaEncrypt(
userEncKey.key,
publicKey.buffer
);
const encryptedKey = await this.cryptoService.rsaEncrypt(userEncKey.key, publicKey);

const resetRequest = new OrganizationUserResetPasswordEnrollmentRequest();
resetRequest.masterPasswordHash = masterPasswordHash;
Expand Down
5 changes: 1 addition & 4 deletions libs/angular/src/platform/pipes/fingerprint.pipe.ts
Expand Up @@ -15,10 +15,7 @@ export class FingerprintPipe {
publicKey = Utils.fromB64ToArray(publicKey);
}

const fingerprint = await this.cryptoService.getFingerprint(
fingerprintMaterial,
publicKey.buffer
);
const fingerprint = await this.cryptoService.getFingerprint(fingerprintMaterial, publicKey);

if (fingerprint != null) {
return fingerprint.join("-");
Expand Down
15 changes: 15 additions & 0 deletions libs/common/custom-matchers.d.ts
@@ -0,0 +1,15 @@
import type { CustomMatchers } from "./test.setup";

// This declares the types for our custom matchers so that they're recognised by Typescript
// This file must also be included in the TS compilation (via the tsconfig.json "include" property) to be recognised by
// vscode

/* eslint-disable */
declare global {
namespace jest {
interface Expect extends CustomMatchers {}
interface Matchers<R> extends CustomMatchers<R> {}
interface InverseAsymmetricMatchers extends CustomMatchers {}
}
}
/* eslint-enable */
9 changes: 3 additions & 6 deletions libs/common/spec/matchers/to-equal-buffer.ts
Expand Up @@ -5,14 +5,11 @@
* (and optionally, the expected value) and then call toEqual() on the resulting Uint8Arrays.
*/
export const toEqualBuffer: jest.CustomMatcher = function (
received: ArrayBuffer,
expected: Uint8Array | ArrayBuffer
received: ArrayBuffer | Uint8Array,
expected: ArrayBuffer | Uint8Array
) {
received = new Uint8Array(received);

if (expected instanceof ArrayBuffer) {
expected = new Uint8Array(expected);
}
expected = new Uint8Array(expected);

if (this.equals(received, expected)) {
return {
Expand Down
4 changes: 2 additions & 2 deletions libs/common/src/auth/services/auth.service.ts
Expand Up @@ -302,13 +302,13 @@ export class AuthService implements AuthServiceAbstraction {
(
await this.cryptoService.getKey()
).encKey,
pubKey.buffer
pubKey
);
let encryptedMasterPassword = null;
if ((await this.stateService.getKeyHash()) != null) {
encryptedMasterPassword = await this.cryptoService.rsaEncrypt(
Utils.fromUtf8ToArray(await this.stateService.getKeyHash()),
pubKey.buffer
pubKey
);
}
const request = new PasswordlessAuthRequest(
Expand Down

0 comments on commit 36b7d30

Please sign in to comment.