mirror of
https://github.com/bitwarden/browser
synced 2025-12-11 05:43:41 +00:00
[PM-16831] TS Strict crypto function service (#12737)
* strict types in crypto function services * Improve aesDecrypt types
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { CsprngArray } from "../../types/csprng";
|
import { CsprngArray } from "../../types/csprng";
|
||||||
import { DecryptParameters } from "../models/domain/decrypt-parameters";
|
import { CbcDecryptParameters, EcbDecryptParameters } from "../models/domain/decrypt-parameters";
|
||||||
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
||||||
|
|
||||||
export abstract class CryptoFunctionService {
|
export abstract class CryptoFunctionService {
|
||||||
@@ -51,11 +51,13 @@ export abstract class CryptoFunctionService {
|
|||||||
iv: string,
|
iv: string,
|
||||||
mac: string,
|
mac: string,
|
||||||
key: SymmetricCryptoKey,
|
key: SymmetricCryptoKey,
|
||||||
): DecryptParameters<Uint8Array | string>;
|
): CbcDecryptParameters<Uint8Array | string>;
|
||||||
abstract aesDecryptFast(
|
abstract aesDecryptFast({
|
||||||
parameters: DecryptParameters<Uint8Array | string>,
|
mode,
|
||||||
mode: "cbc" | "ecb",
|
parameters,
|
||||||
): Promise<string>;
|
}:
|
||||||
|
| { mode: "cbc"; parameters: CbcDecryptParameters<Uint8Array | string> }
|
||||||
|
| { mode: "ecb"; parameters: EcbDecryptParameters<Uint8Array | string> }): Promise<string>;
|
||||||
abstract aesDecrypt(
|
abstract aesDecrypt(
|
||||||
data: Uint8Array,
|
data: Uint8Array,
|
||||||
iv: Uint8Array,
|
iv: Uint8Array,
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
export type CbcDecryptParameters<T> = {
|
||||||
// @ts-strict-ignore
|
|
||||||
export class DecryptParameters<T> {
|
|
||||||
encKey: T;
|
encKey: T;
|
||||||
data: T;
|
data: T;
|
||||||
iv: T;
|
iv: T;
|
||||||
macKey: T;
|
macKey?: T;
|
||||||
mac: T;
|
mac?: T;
|
||||||
macData: T;
|
macData: T;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export type EcbDecryptParameters<T> = {
|
||||||
|
encKey: T;
|
||||||
|
data: T;
|
||||||
|
};
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { EncryptionType } from "../../enums";
|
|||||||
|
|
||||||
export class SymmetricCryptoKey {
|
export class SymmetricCryptoKey {
|
||||||
key: Uint8Array;
|
key: Uint8Array;
|
||||||
encKey?: Uint8Array;
|
encKey: Uint8Array;
|
||||||
macKey?: Uint8Array;
|
macKey?: Uint8Array;
|
||||||
encType: EncryptionType;
|
encType: EncryptionType;
|
||||||
|
|
||||||
@@ -48,12 +48,8 @@ export class SymmetricCryptoKey {
|
|||||||
throw new Error("Unsupported encType/key length.");
|
throw new Error("Unsupported encType/key length.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.key != null) {
|
this.keyB64 = Utils.fromBufferToB64(this.key);
|
||||||
this.keyB64 = Utils.fromBufferToB64(this.key);
|
this.encKeyB64 = Utils.fromBufferToB64(this.encKey);
|
||||||
}
|
|
||||||
if (this.encKey != null) {
|
|
||||||
this.encKeyB64 = Utils.fromBufferToB64(this.encKey);
|
|
||||||
}
|
|
||||||
if (this.macKey != null) {
|
if (this.macKey != null) {
|
||||||
this.macKeyB64 = Utils.fromBufferToB64(this.macKey);
|
this.macKeyB64 = Utils.fromBufferToB64(this.macKey);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ export class EncryptServiceImplementation implements EncryptService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return await this.cryptoFunctionService.aesDecryptFast(fastParams, "cbc");
|
return await this.cryptoFunctionService.aesDecryptFast({ mode: "cbc", parameters: fastParams });
|
||||||
}
|
}
|
||||||
|
|
||||||
async decryptToBytes(
|
async decryptToBytes(
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { mock } from "jest-mock-extended";
|
|||||||
|
|
||||||
import { Utils } from "../../platform/misc/utils";
|
import { Utils } from "../../platform/misc/utils";
|
||||||
import { PlatformUtilsService } from "../abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "../abstractions/platform-utils.service";
|
||||||
import { DecryptParameters } from "../models/domain/decrypt-parameters";
|
import { EcbDecryptParameters } from "../models/domain/decrypt-parameters";
|
||||||
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
||||||
|
|
||||||
import { WebCryptoFunctionService } from "./web-crypto-function.service";
|
import { WebCryptoFunctionService } from "./web-crypto-function.service";
|
||||||
@@ -253,8 +253,13 @@ describe("WebCrypto Function Service", () => {
|
|||||||
const encData = Utils.fromBufferToB64(encValue);
|
const encData = Utils.fromBufferToB64(encValue);
|
||||||
const b64Iv = Utils.fromBufferToB64(iv);
|
const b64Iv = Utils.fromBufferToB64(iv);
|
||||||
const symKey = new SymmetricCryptoKey(key);
|
const symKey = new SymmetricCryptoKey(key);
|
||||||
const params = cryptoFunctionService.aesDecryptFastParameters(encData, b64Iv, null, symKey);
|
const parameters = cryptoFunctionService.aesDecryptFastParameters(
|
||||||
const decValue = await cryptoFunctionService.aesDecryptFast(params, "cbc");
|
encData,
|
||||||
|
b64Iv,
|
||||||
|
null,
|
||||||
|
symKey,
|
||||||
|
);
|
||||||
|
const decValue = await cryptoFunctionService.aesDecryptFast({ mode: "cbc", parameters });
|
||||||
expect(decValue).toBe(value);
|
expect(decValue).toBe(value);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -276,8 +281,8 @@ describe("WebCrypto Function Service", () => {
|
|||||||
const iv = Utils.fromBufferToB64(makeStaticByteArray(16));
|
const iv = Utils.fromBufferToB64(makeStaticByteArray(16));
|
||||||
const symKey = new SymmetricCryptoKey(makeStaticByteArray(32));
|
const symKey = new SymmetricCryptoKey(makeStaticByteArray(32));
|
||||||
const data = "ByUF8vhyX4ddU9gcooznwA==";
|
const data = "ByUF8vhyX4ddU9gcooznwA==";
|
||||||
const params = cryptoFunctionService.aesDecryptFastParameters(data, iv, null, symKey);
|
const parameters = cryptoFunctionService.aesDecryptFastParameters(data, iv, null, symKey);
|
||||||
const decValue = await cryptoFunctionService.aesDecryptFast(params, "cbc");
|
const decValue = await cryptoFunctionService.aesDecryptFast({ mode: "cbc", parameters });
|
||||||
expect(decValue).toBe("EncryptMe!");
|
expect(decValue).toBe("EncryptMe!");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -287,10 +292,11 @@ describe("WebCrypto Function Service", () => {
|
|||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const key = makeStaticByteArray(32);
|
const key = makeStaticByteArray(32);
|
||||||
const data = Utils.fromB64ToArray("z5q2XSxYCdQFdI+qK2yLlw==");
|
const data = Utils.fromB64ToArray("z5q2XSxYCdQFdI+qK2yLlw==");
|
||||||
const params = new DecryptParameters<string>();
|
const parameters: EcbDecryptParameters<string> = {
|
||||||
params.encKey = Utils.fromBufferToByteString(key);
|
encKey: Utils.fromBufferToByteString(key),
|
||||||
params.data = Utils.fromBufferToByteString(data);
|
data: Utils.fromBufferToByteString(data),
|
||||||
const decValue = await cryptoFunctionService.aesDecryptFast(params, "ecb");
|
};
|
||||||
|
const decValue = await cryptoFunctionService.aesDecryptFast({ mode: "ecb", parameters });
|
||||||
expect(decValue).toBe("EncryptMe!");
|
expect(decValue).toBe("EncryptMe!");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -304,6 +310,15 @@ describe("WebCrypto Function Service", () => {
|
|||||||
const decValue = await cryptoFunctionService.aesDecrypt(data, iv, key, "cbc");
|
const decValue = await cryptoFunctionService.aesDecrypt(data, iv, key, "cbc");
|
||||||
expect(Utils.fromBufferToUtf8(decValue)).toBe("EncryptMe!");
|
expect(Utils.fromBufferToUtf8(decValue)).toBe("EncryptMe!");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("throws if iv is not provided", async () => {
|
||||||
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
|
const key = makeStaticByteArray(32);
|
||||||
|
const data = Utils.fromB64ToArray("ByUF8vhyX4ddU9gcooznwA==");
|
||||||
|
await expect(() => cryptoFunctionService.aesDecrypt(data, null, key, "cbc")).rejects.toThrow(
|
||||||
|
"IV is required for CBC mode",
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("aesDecrypt ECB mode", () => {
|
describe("aesDecrypt ECB mode", () => {
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
|
||||||
// @ts-strict-ignore
|
|
||||||
import * as argon2 from "argon2-browser";
|
import * as argon2 from "argon2-browser";
|
||||||
import * as forge from "node-forge";
|
import * as forge from "node-forge";
|
||||||
|
|
||||||
import { Utils } from "../../platform/misc/utils";
|
import { Utils } from "../../platform/misc/utils";
|
||||||
import { CsprngArray } from "../../types/csprng";
|
import { CsprngArray } from "../../types/csprng";
|
||||||
import { CryptoFunctionService } from "../abstractions/crypto-function.service";
|
import { CryptoFunctionService } from "../abstractions/crypto-function.service";
|
||||||
import { DecryptParameters } from "../models/domain/decrypt-parameters";
|
import { CbcDecryptParameters, EcbDecryptParameters } from "../models/domain/decrypt-parameters";
|
||||||
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
||||||
|
|
||||||
export class WebCryptoFunctionService implements CryptoFunctionService {
|
export class WebCryptoFunctionService implements CryptoFunctionService {
|
||||||
@@ -14,10 +12,14 @@ export class WebCryptoFunctionService implements CryptoFunctionService {
|
|||||||
private subtle: SubtleCrypto;
|
private subtle: SubtleCrypto;
|
||||||
private wasmSupported: boolean;
|
private wasmSupported: boolean;
|
||||||
|
|
||||||
constructor(globalContext: Window | typeof global) {
|
constructor(globalContext: { crypto: Crypto }) {
|
||||||
this.crypto = typeof globalContext.crypto !== "undefined" ? globalContext.crypto : null;
|
if (globalContext?.crypto?.subtle == null) {
|
||||||
this.subtle =
|
throw new Error(
|
||||||
!!this.crypto && typeof this.crypto.subtle !== "undefined" ? this.crypto.subtle : null;
|
"Could not instantiate WebCryptoFunctionService. Could not locate Subtle crypto.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.crypto = globalContext.crypto;
|
||||||
|
this.subtle = this.crypto.subtle;
|
||||||
this.wasmSupported = this.checkIfWasmSupported();
|
this.wasmSupported = this.checkIfWasmSupported();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,7 +222,7 @@ export class WebCryptoFunctionService implements CryptoFunctionService {
|
|||||||
hmac.update(a);
|
hmac.update(a);
|
||||||
const mac1 = hmac.digest().getBytes();
|
const mac1 = hmac.digest().getBytes();
|
||||||
|
|
||||||
hmac.start(null, null);
|
hmac.start("sha256", null);
|
||||||
hmac.update(b);
|
hmac.update(b);
|
||||||
const mac2 = hmac.digest().getBytes();
|
const mac2 = hmac.digest().getBytes();
|
||||||
|
|
||||||
@@ -239,10 +241,10 @@ export class WebCryptoFunctionService implements CryptoFunctionService {
|
|||||||
aesDecryptFastParameters(
|
aesDecryptFastParameters(
|
||||||
data: string,
|
data: string,
|
||||||
iv: string,
|
iv: string,
|
||||||
mac: string,
|
mac: string | null,
|
||||||
key: SymmetricCryptoKey,
|
key: SymmetricCryptoKey,
|
||||||
): DecryptParameters<string> {
|
): CbcDecryptParameters<string> {
|
||||||
const p = new DecryptParameters<string>();
|
const p = {} as CbcDecryptParameters<string>;
|
||||||
if (key.meta != null) {
|
if (key.meta != null) {
|
||||||
p.encKey = key.meta.encKeyByteString;
|
p.encKey = key.meta.encKeyByteString;
|
||||||
p.macKey = key.meta.macKeyByteString;
|
p.macKey = key.meta.macKeyByteString;
|
||||||
@@ -275,7 +277,12 @@ export class WebCryptoFunctionService implements CryptoFunctionService {
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
aesDecryptFast(parameters: DecryptParameters<string>, mode: "cbc" | "ecb"): Promise<string> {
|
aesDecryptFast({
|
||||||
|
mode,
|
||||||
|
parameters,
|
||||||
|
}:
|
||||||
|
| { mode: "cbc"; parameters: CbcDecryptParameters<string> }
|
||||||
|
| { mode: "ecb"; parameters: EcbDecryptParameters<string> }): Promise<string> {
|
||||||
const decipher = (forge as any).cipher.createDecipher(
|
const decipher = (forge as any).cipher.createDecipher(
|
||||||
this.toWebCryptoAesMode(mode),
|
this.toWebCryptoAesMode(mode),
|
||||||
parameters.encKey,
|
parameters.encKey,
|
||||||
@@ -294,21 +301,27 @@ export class WebCryptoFunctionService implements CryptoFunctionService {
|
|||||||
|
|
||||||
async aesDecrypt(
|
async aesDecrypt(
|
||||||
data: Uint8Array,
|
data: Uint8Array,
|
||||||
iv: Uint8Array,
|
iv: Uint8Array | null,
|
||||||
key: Uint8Array,
|
key: Uint8Array,
|
||||||
mode: "cbc" | "ecb",
|
mode: "cbc" | "ecb",
|
||||||
): Promise<Uint8Array> {
|
): Promise<Uint8Array> {
|
||||||
if (mode === "ecb") {
|
if (mode === "ecb") {
|
||||||
// Web crypto does not support AES-ECB mode, so we need to do this in forge.
|
// Web crypto does not support AES-ECB mode, so we need to do this in forge.
|
||||||
const params = new DecryptParameters<string>();
|
const parameters: EcbDecryptParameters<string> = {
|
||||||
params.data = this.toByteString(data);
|
data: this.toByteString(data),
|
||||||
params.encKey = this.toByteString(key);
|
encKey: this.toByteString(key),
|
||||||
const result = await this.aesDecryptFast(params, "ecb");
|
};
|
||||||
|
const result = await this.aesDecryptFast({ mode: "ecb", parameters });
|
||||||
return Utils.fromByteStringToArray(result);
|
return Utils.fromByteStringToArray(result);
|
||||||
}
|
}
|
||||||
const impKey = await this.subtle.importKey("raw", key, { name: "AES-CBC" } as any, false, [
|
const impKey = await this.subtle.importKey("raw", key, { name: "AES-CBC" } as any, false, [
|
||||||
"decrypt",
|
"decrypt",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// CBC
|
||||||
|
if (iv == null) {
|
||||||
|
throw new Error("IV is required for CBC mode.");
|
||||||
|
}
|
||||||
const buffer = await this.subtle.decrypt({ name: "AES-CBC", iv: iv }, impKey, data);
|
const buffer = await this.subtle.decrypt({ name: "AES-CBC", iv: iv }, impKey, data);
|
||||||
return new Uint8Array(buffer);
|
return new Uint8Array(buffer);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { DecryptParameters } from "@bitwarden/common/platform/models/domain/decrypt-parameters";
|
import { EcbDecryptParameters } from "@bitwarden/common/platform/models/domain/decrypt-parameters";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
|
|
||||||
import { NodeCryptoFunctionService } from "./node-crypto-function.service";
|
import { NodeCryptoFunctionService } from "./node-crypto-function.service";
|
||||||
@@ -193,8 +193,8 @@ describe("NodeCrypto Function Service", () => {
|
|||||||
const iv = Utils.fromBufferToB64(makeStaticByteArray(16));
|
const iv = Utils.fromBufferToB64(makeStaticByteArray(16));
|
||||||
const symKey = new SymmetricCryptoKey(makeStaticByteArray(32));
|
const symKey = new SymmetricCryptoKey(makeStaticByteArray(32));
|
||||||
const data = "ByUF8vhyX4ddU9gcooznwA==";
|
const data = "ByUF8vhyX4ddU9gcooznwA==";
|
||||||
const params = nodeCryptoFunctionService.aesDecryptFastParameters(data, iv, null, symKey);
|
const parameters = nodeCryptoFunctionService.aesDecryptFastParameters(data, iv, null, symKey);
|
||||||
const decValue = await nodeCryptoFunctionService.aesDecryptFast(params, "cbc");
|
const decValue = await nodeCryptoFunctionService.aesDecryptFast({ mode: "cbc", parameters });
|
||||||
expect(decValue).toBe("EncryptMe!");
|
expect(decValue).toBe("EncryptMe!");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -202,10 +202,11 @@ describe("NodeCrypto Function Service", () => {
|
|||||||
describe("aesDecryptFast ECB mode", () => {
|
describe("aesDecryptFast ECB mode", () => {
|
||||||
it("should successfully decrypt data", async () => {
|
it("should successfully decrypt data", async () => {
|
||||||
const nodeCryptoFunctionService = new NodeCryptoFunctionService();
|
const nodeCryptoFunctionService = new NodeCryptoFunctionService();
|
||||||
const params = new DecryptParameters<Uint8Array>();
|
const parameters: EcbDecryptParameters<Uint8Array> = {
|
||||||
params.encKey = makeStaticByteArray(32);
|
encKey: makeStaticByteArray(32),
|
||||||
params.data = Utils.fromB64ToArray("z5q2XSxYCdQFdI+qK2yLlw==");
|
data: Utils.fromB64ToArray("z5q2XSxYCdQFdI+qK2yLlw=="),
|
||||||
const decValue = await nodeCryptoFunctionService.aesDecryptFast(params, "ecb");
|
};
|
||||||
|
const decValue = await nodeCryptoFunctionService.aesDecryptFast({ mode: "ecb", parameters });
|
||||||
expect(decValue).toBe("EncryptMe!");
|
expect(decValue).toBe("EncryptMe!");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -219,6 +220,15 @@ describe("NodeCrypto Function Service", () => {
|
|||||||
const decValue = await nodeCryptoFunctionService.aesDecrypt(data, iv, key, "cbc");
|
const decValue = await nodeCryptoFunctionService.aesDecrypt(data, iv, key, "cbc");
|
||||||
expect(Utils.fromBufferToUtf8(decValue)).toBe("EncryptMe!");
|
expect(Utils.fromBufferToUtf8(decValue)).toBe("EncryptMe!");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("throws if IV is not provided", async () => {
|
||||||
|
const nodeCryptoFunctionService = new NodeCryptoFunctionService();
|
||||||
|
const key = makeStaticByteArray(32);
|
||||||
|
const data = Utils.fromB64ToArray("ByUF8vhyX4ddU9gcooznwA==");
|
||||||
|
await expect(
|
||||||
|
async () => await nodeCryptoFunctionService.aesDecrypt(data, null, key, "cbc"),
|
||||||
|
).rejects.toThrow("Invalid initialization vector");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("aesDecrypt ECB mode", () => {
|
describe("aesDecrypt ECB mode", () => {
|
||||||
@@ -454,7 +464,7 @@ function testHmac(algorithm: "sha1" | "sha256" | "sha512", mac: string, fast = f
|
|||||||
const cryptoFunctionService = new NodeCryptoFunctionService();
|
const cryptoFunctionService = new NodeCryptoFunctionService();
|
||||||
const value = Utils.fromUtf8ToArray("SignMe!!");
|
const value = Utils.fromUtf8ToArray("SignMe!!");
|
||||||
const key = Utils.fromUtf8ToArray("secretkey");
|
const key = Utils.fromUtf8ToArray("secretkey");
|
||||||
let computedMac: ArrayBuffer = null;
|
let computedMac: ArrayBuffer;
|
||||||
if (fast) {
|
if (fast) {
|
||||||
computedMac = await cryptoFunctionService.hmacFast(value, key, algorithm);
|
computedMac = await cryptoFunctionService.hmacFast(value, key, algorithm);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
|
||||||
// @ts-strict-ignore
|
|
||||||
import * as crypto from "crypto";
|
import * as crypto from "crypto";
|
||||||
|
|
||||||
import * as forge from "node-forge";
|
import * as forge from "node-forge";
|
||||||
|
|
||||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { DecryptParameters } from "@bitwarden/common/platform/models/domain/decrypt-parameters";
|
import {
|
||||||
|
CbcDecryptParameters,
|
||||||
|
EcbDecryptParameters,
|
||||||
|
} from "@bitwarden/common/platform/models/domain/decrypt-parameters";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
||||||
|
|
||||||
@@ -168,10 +169,10 @@ export class NodeCryptoFunctionService implements CryptoFunctionService {
|
|||||||
aesDecryptFastParameters(
|
aesDecryptFastParameters(
|
||||||
data: string,
|
data: string,
|
||||||
iv: string,
|
iv: string,
|
||||||
mac: string,
|
mac: string | null,
|
||||||
key: SymmetricCryptoKey,
|
key: SymmetricCryptoKey,
|
||||||
): DecryptParameters<Uint8Array> {
|
): CbcDecryptParameters<Uint8Array> {
|
||||||
const p = new DecryptParameters<Uint8Array>();
|
const p = {} as CbcDecryptParameters<Uint8Array>;
|
||||||
p.encKey = key.encKey;
|
p.encKey = key.encKey;
|
||||||
p.data = Utils.fromB64ToArray(data);
|
p.data = Utils.fromB64ToArray(data);
|
||||||
p.iv = Utils.fromB64ToArray(iv);
|
p.iv = Utils.fromB64ToArray(iv);
|
||||||
@@ -191,22 +192,25 @@ export class NodeCryptoFunctionService implements CryptoFunctionService {
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
async aesDecryptFast(
|
async aesDecryptFast({
|
||||||
parameters: DecryptParameters<Uint8Array>,
|
mode,
|
||||||
mode: "cbc" | "ecb",
|
parameters,
|
||||||
): Promise<string> {
|
}:
|
||||||
const decBuf = await this.aesDecrypt(parameters.data, parameters.iv, parameters.encKey, mode);
|
| { mode: "cbc"; parameters: CbcDecryptParameters<Uint8Array> }
|
||||||
|
| { mode: "ecb"; parameters: EcbDecryptParameters<Uint8Array> }): Promise<string> {
|
||||||
|
const iv = mode === "cbc" ? parameters.iv : null;
|
||||||
|
const decBuf = await this.aesDecrypt(parameters.data, iv, parameters.encKey, mode);
|
||||||
return Utils.fromBufferToUtf8(decBuf);
|
return Utils.fromBufferToUtf8(decBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
aesDecrypt(
|
aesDecrypt(
|
||||||
data: Uint8Array,
|
data: Uint8Array,
|
||||||
iv: Uint8Array,
|
iv: Uint8Array | null,
|
||||||
key: Uint8Array,
|
key: Uint8Array,
|
||||||
mode: "cbc" | "ecb",
|
mode: "cbc" | "ecb",
|
||||||
): Promise<Uint8Array> {
|
): Promise<Uint8Array> {
|
||||||
const nodeData = this.toNodeBuffer(data);
|
const nodeData = this.toNodeBuffer(data);
|
||||||
const nodeIv = mode === "ecb" ? null : this.toNodeBuffer(iv);
|
const nodeIv = this.toNodeBufferOrNull(iv);
|
||||||
const nodeKey = this.toNodeBuffer(key);
|
const nodeKey = this.toNodeBuffer(key);
|
||||||
const decipher = crypto.createDecipheriv(this.toNodeCryptoAesMode(mode), nodeKey, nodeIv);
|
const decipher = crypto.createDecipheriv(this.toNodeCryptoAesMode(mode), nodeKey, nodeIv);
|
||||||
const decBuf = Buffer.concat([decipher.update(nodeData), decipher.final()]);
|
const decBuf = Buffer.concat([decipher.update(nodeData), decipher.final()]);
|
||||||
@@ -311,6 +315,13 @@ export class NodeCryptoFunctionService implements CryptoFunctionService {
|
|||||||
return Buffer.from(value);
|
return Buffer.from(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private toNodeBufferOrNull(value: Uint8Array | null): Buffer | null {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return this.toNodeBuffer(value);
|
||||||
|
}
|
||||||
|
|
||||||
private toUint8Buffer(value: Buffer | string | Uint8Array): Uint8Array {
|
private toUint8Buffer(value: Buffer | string | Uint8Array): Uint8Array {
|
||||||
let buf: Uint8Array;
|
let buf: Uint8Array;
|
||||||
if (typeof value === "string") {
|
if (typeof value === "string") {
|
||||||
|
|||||||
Reference in New Issue
Block a user