1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-13 23:13:36 +00:00

Refactor symmetric encrypt interface

This commit is contained in:
Bernd Schoolmann
2025-03-31 14:44:49 +02:00
parent c8069baa24
commit 668823430e
61 changed files with 267 additions and 150 deletions

View File

@@ -1,5 +1,5 @@
{
"cSpell.words": ["Csprng", "decryptable", "Popout", "Reprompt", "takeuntil"],
"cSpell.words": ["Csprng", "Decapsulation", "decryptable", "Popout", "Reprompt", "takeuntil"],
"search.exclude": {
"**/locales/[^e]*/messages.json": true,
"**/locales/*[^n]/messages.json": true,

View File

@@ -350,7 +350,7 @@ export class NativeMessagingBackground {
await this.secureCommunication();
}
return await this.encryptService.encrypt(
return await this.encryptService.encryptString(
JSON.stringify(message),
this.secureChannel!.sharedSecret!,
);

View File

@@ -127,7 +127,7 @@ describe("LocalBackedSessionStorage", () => {
describe("save", () => {
const encString = makeEncString("encrypted");
beforeEach(() => {
encryptService.encrypt.mockResolvedValue(encString);
encryptService.encryptString.mockResolvedValue(encString);
});
it("logs a warning when saving the same value twice and in a dev environment", async () => {
@@ -157,7 +157,10 @@ describe("LocalBackedSessionStorage", () => {
it("encrypts and saves the value to local storage", async () => {
await sut.save("test", "value");
expect(encryptService.encrypt).toHaveBeenCalledWith(JSON.stringify("value"), sessionKey);
expect(encryptService.encryptString).toHaveBeenCalledWith(
JSON.stringify("value"),
sessionKey,
);
expect(localStorage.internalStore["session_test"]).toEqual(encString.encryptedString);
});

View File

@@ -140,7 +140,10 @@ export class LocalBackedSessionStorageService
}
const valueJson = JSON.stringify(value);
const encValue = await this.encryptService.encrypt(valueJson, await this.sessionKey.get());
const encValue = await this.encryptService.encryptString(
valueJson,
await this.sessionKey.get(),
);
await this.localStorage.save(this.sessionStorageKey(key), encValue.encryptedString);
}

View File

@@ -204,7 +204,7 @@ export class EditCommand {
(u) => new SelectionReadOnlyRequest(u.id, u.readOnly, u.hidePasswords, u.manage),
);
const request = new CollectionRequest();
request.name = (await this.encryptService.encrypt(req.name, orgKey)).encryptedString;
request.name = (await this.encryptService.encryptString(req.name, orgKey)).encryptedString;
request.externalId = req.externalId;
request.groups = groups;
request.users = users;

View File

@@ -61,7 +61,7 @@ export class NodeEnvSecureStorageService implements AbstractStorageService {
if (sessionKey == null) {
throw new Error("No session key available.");
}
const encValue = await this.encryptService.encryptToBytes(
const encValue = await this.encryptService.encryptFileData(
Utils.fromB64ToArray(plainValue),
sessionKey,
);

View File

@@ -227,7 +227,7 @@ export class CreateCommand {
(u) => new SelectionReadOnlyRequest(u.id, u.readOnly, u.hidePasswords, u.manage),
);
const request = new CollectionRequest();
request.name = (await this.encryptService.encrypt(req.name, orgKey)).encryptedString;
request.name = (await this.encryptService.encryptString(req.name, orgKey)).encryptedString;
request.externalId = req.externalId;
request.groups = groups;
request.users = users;

View File

@@ -110,7 +110,7 @@ export class ElectronKeyService extends DefaultKeyService {
// Set a key half if it doesn't exist
const keyBytes = await this.cryptoFunctionService.randomBytes(32);
clientKeyHalf = Utils.fromBufferToUtf8(keyBytes) as CsprngString;
const encKey = await this.encryptService.encrypt(clientKeyHalf, userKey);
const encKey = await this.encryptService.encryptString(clientKeyHalf, userKey);
await this.biometricStateService.setEncryptedClientKeyHalf(encKey, userId);
}

View File

@@ -350,7 +350,7 @@ export class BiometricMessageHandlerService {
throw new Error("Session secret is missing");
}
const encrypted = await this.encryptService.encrypt(
const encrypted = await this.encryptService.encryptString(
JSON.stringify(message),
SymmetricCryptoKey.fromString(sessionSecret),
);

View File

@@ -168,7 +168,7 @@ export class DuckDuckGoMessageHandlerService {
payload: DecryptedCommandData,
key: SymmetricCryptoKey,
): Promise<EncString> {
return await this.encryptService.encrypt(JSON.stringify(payload), key);
return await this.encryptService.encryptString(JSON.stringify(payload), key);
}
private async decryptPayload(message: EncryptedMessage): Promise<DecryptedCommandData> {

View File

@@ -36,7 +36,7 @@ describe("RotateableKeySetService", () => {
keyService.makeKeyPair.mockResolvedValue(["publicKey", encryptedPrivateKey as any]);
keyService.getUserKey.mockResolvedValue({ key: userKey.key } as any);
encryptService.rsaEncrypt.mockResolvedValue(encryptedUserKey as any);
encryptService.encrypt.mockResolvedValue(encryptedPublicKey as any);
encryptService.wrapEncapsulationKey.mockResolvedValue(encryptedPublicKey as any);
const result = await service.createKeySet(externalKey as any);

View File

@@ -26,7 +26,10 @@ export class RotateableKeySetService {
const userKey = await this.keyService.getUserKey();
const rawPublicKey = Utils.fromB64ToArray(publicKey);
const encryptedUserKey = await this.encryptService.rsaEncrypt(userKey.key, rawPublicKey);
const encryptedPublicKey = await this.encryptService.encrypt(rawPublicKey, userKey);
const encryptedPublicKey = await this.encryptService.wrapEncapsulationKey(
rawPublicKey,
userKey,
);
return new RotateableKeySet(encryptedUserKey, encryptedPublicKey, encryptedPrivateKey);
}
@@ -59,7 +62,10 @@ export class RotateableKeySetService {
if (publicKey == null) {
throw new Error("failed to rotate key set: could not decrypt public key");
}
const newEncryptedPublicKey = await this.encryptService.encrypt(publicKey, newUserKey);
const newEncryptedPublicKey = await this.encryptService.wrapEncapsulationKey(
publicKey,
newUserKey,
);
const newEncryptedUserKey = await this.encryptService.rsaEncrypt(newUserKey.key, publicKey);
const newRotateableKeySet = new RotateableKeySet<ExternalKey>(

View File

@@ -81,7 +81,10 @@ describe("AcceptOrganizationInviteService", () => {
"orgPublicKey",
{ encryptedString: "string" } as EncString,
]);
encryptService.encrypt.mockResolvedValue({ encryptedString: "string" } as EncString);
encryptService.wrapDecapsulationKey.mockResolvedValue({
encryptedString: "string",
} as EncString);
encryptService.encryptString.mockResolvedValue({ encryptedString: "string" } as EncString);
const invite = createOrgInvite({ initOrganization: true });
const result = await sut.validateAndAcceptInvite(invite);

View File

@@ -141,7 +141,7 @@ export class AcceptOrganizationInviteService {
const [encryptedOrgKey, orgKey] = await this.keyService.makeOrgKey<OrgKey>();
const [orgPublicKey, encryptedOrgPrivateKey] = await this.keyService.makeKeyPair(orgKey);
const collection = await this.encryptService.encrypt(
const collection = await this.encryptService.encryptString(
this.i18nService.t("defaultCollection"),
orgKey,
);

View File

@@ -614,7 +614,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
if (this.createOrganization) {
const orgKey = await this.keyService.makeOrgKey<OrgKey>();
const key = orgKey[0].encryptedString;
const collection = await this.encryptService.encrypt(
const collection = await this.encryptService.encryptString(
this.i18nService.t("defaultCollection"),
orgKey[1],
);
@@ -804,7 +804,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
);
const providerKey = await this.keyService.getProviderKey(this.providerId);
providerRequest.organizationCreateRequest.key = (
await this.encryptService.encrypt(orgKey.key, providerKey)
await this.encryptService.wrapSymmetricKey(orgKey, providerKey)
).encryptedString;
const orgId = (
await this.apiService.postProviderCreateOrganization(this.providerId, providerRequest)

View File

@@ -51,7 +51,7 @@ export class OrganizationSelfHostingLicenseUploaderComponent extends AbstractSel
const orgKey = await this.keyService.makeOrgKey<OrgKey>();
const key = orgKey[0].encryptedString;
const collection = await this.encryptService.encrypt(
const collection = await this.encryptService.encryptString(
this.i18nService.t("defaultCollection"),
orgKey[1],
);

View File

@@ -119,7 +119,10 @@ describe("KeyRotationService", () => {
mockKeyService.hashMasterKey.mockResolvedValue("mockMasterPasswordHash");
mockConfigService.getFeatureFlag.mockResolvedValue(true);
mockEncryptService.encrypt.mockResolvedValue({
mockEncryptService.wrapSymmetricKey.mockResolvedValue({
encryptedString: "mockEncryptedData",
} as any);
mockEncryptService.wrapDecapsulationKey.mockResolvedValue({
encryptedString: "mockEncryptedData",
} as any);

View File

@@ -125,7 +125,9 @@ export class UserKeyRotationService {
const { privateKey, publicKey } = keyPair;
const accountKeysRequest = new AccountKeysRequest(
(await this.encryptService.encrypt(privateKey, newUnencryptedUserKey)).encryptedString!,
(
await this.encryptService.wrapDecapsulationKey(privateKey, newUnencryptedUserKey)
).encryptedString!,
Utils.fromBufferToB64(publicKey),
);
@@ -357,6 +359,6 @@ export class UserKeyRotationService {
if (privateKey == null) {
throw new Error("No private key found for user key rotation");
}
return (await this.encryptService.encrypt(privateKey, newUserKey)).encryptedString;
return (await this.encryptService.wrapDecapsulationKey(privateKey, newUserKey)).encryptedString;
}
}

View File

@@ -59,7 +59,7 @@ describe("CriticalAppsService", () => {
{ id: "id2", organizationId: "org1", uri: "https://example.org" },
] as PasswordHealthReportApplicationsResponse[];
encryptService.encrypt.mockResolvedValue(new EncString("encryptedUrlName"));
encryptService.encryptString.mockResolvedValue(new EncString("encryptedUrlName"));
criticalAppsApiService.saveCriticalApps.mockReturnValue(of(response));
// act
@@ -67,7 +67,7 @@ describe("CriticalAppsService", () => {
// expectations
expect(keyService.getOrgKey).toHaveBeenCalledWith("org1");
expect(encryptService.encrypt).toHaveBeenCalledTimes(2);
expect(encryptService.encryptString).toHaveBeenCalledTimes(2);
expect(criticalAppsApiService.saveCriticalApps).toHaveBeenCalledWith(request);
});
@@ -95,7 +95,7 @@ describe("CriticalAppsService", () => {
{ id: "id1", organizationId: "org1", uri: "test" },
] as PasswordHealthReportApplicationsResponse[];
encryptService.encrypt.mockResolvedValue(new EncString("encryptedUrlName"));
encryptService.encryptString.mockResolvedValue(new EncString("encryptedUrlName"));
criticalAppsApiService.saveCriticalApps.mockReturnValue(of(response));
// act
@@ -103,7 +103,7 @@ describe("CriticalAppsService", () => {
// expectations
expect(keyService.getOrgKey).toHaveBeenCalledWith("org1");
expect(encryptService.encrypt).toHaveBeenCalledTimes(1);
expect(encryptService.encryptString).toHaveBeenCalledTimes(1);
expect(criticalAppsApiService.saveCriticalApps).toHaveBeenCalledWith(request);
});

View File

@@ -164,7 +164,7 @@ export class CriticalAppsService {
newEntries: string[],
): Promise<PasswordHealthReportApplicationsRequest[]> {
const criticalAppsPromises = newEntries.map(async (url) => {
const encryptedUrlName = await this.encryptService.encrypt(url, key);
const encryptedUrlName = await this.encryptService.encryptString(url, key);
return {
organizationId: orgId,
url: encryptedUrlName?.encryptedString?.toString() ?? "",

View File

@@ -36,7 +36,7 @@ export class WebProviderService {
const orgKey = await this.keyService.getOrgKey(organizationId);
const providerKey = await this.keyService.getProviderKey(providerId);
const encryptedOrgKey = await this.encryptService.encrypt(orgKey.key, providerKey);
const encryptedOrgKey = await this.encryptService.wrapSymmetricKey(orgKey, providerKey);
const request = new ProviderAddOrganizationRequest();
request.organizationId = organizationId;
@@ -55,7 +55,7 @@ export class WebProviderService {
),
);
const providerKey = await this.keyService.getProviderKey(providerId);
const encryptedOrgKey = await this.encryptService.encrypt(orgKey.key, providerKey);
const encryptedOrgKey = await this.encryptService.wrapSymmetricKey(orgKey, providerKey);
await this.providerApiService.addOrganizationToProvider(providerId, {
key: encryptedOrgKey.encryptedString,
organizationId,
@@ -74,15 +74,15 @@ export class WebProviderService {
const [publicKey, encryptedPrivateKey] = await this.keyService.makeKeyPair(organizationKey);
const encryptedCollectionName = await this.encryptService.encrypt(
const encryptedCollectionName = await this.encryptService.encryptString(
this.i18nService.t("defaultCollection"),
organizationKey,
);
const providerKey = await this.keyService.getProviderKey(providerId);
const encryptedProviderKey = await this.encryptService.encrypt(
organizationKey.key,
const encryptedProviderKey = await this.encryptService.wrapSymmetricKey(
organizationKey,
providerKey,
);

View File

@@ -93,7 +93,7 @@ export class ProjectService {
): Promise<ProjectRequest> {
const orgKey = await this.getOrganizationKey(organizationId);
const request = new ProjectRequest();
request.name = await this.encryptService.encrypt(projectView.name, orgKey);
request.name = await this.encryptService.encryptString(projectView.name, orgKey);
return request;
}

View File

@@ -24,7 +24,7 @@ describe("SecretService", () => {
sut = new SecretService(keyService, apiService, encryptService, accessPolicyService);
encryptService.encrypt.mockResolvedValue({
encryptService.encryptString.mockResolvedValue({
encryptedString: "mockEncryptedString",
} as EncString);
encryptService.decryptToUtf8.mockResolvedValue(mockUnencryptedData);

View File

@@ -166,9 +166,9 @@ export class SecretService {
const orgKey = await this.getOrganizationKey(organizationId);
const request = new SecretRequest();
const [key, value, note] = await Promise.all([
this.encryptService.encrypt(secretView.name, orgKey),
this.encryptService.encrypt(secretView.value, orgKey),
this.encryptService.encrypt(secretView.note, orgKey),
this.encryptService.encryptString(secretView.name, orgKey),
this.encryptService.encryptString(secretView.value, orgKey),
this.encryptService.encryptString(secretView.note, orgKey),
]);
request.key = key.encryptedString;
request.value = value.encryptedString;

View File

@@ -102,12 +102,12 @@ export class AccessService {
const organizationKey = await this.getOrganizationKey(organizationId);
const accessTokenRequest = new AccessTokenRequest();
const [name, encryptedPayload, key] = await Promise.all([
await this.encryptService.encrypt(accessTokenView.name, organizationKey),
await this.encryptService.encrypt(
await this.encryptService.encryptString(accessTokenView.name, organizationKey),
await this.encryptService.encryptString(
JSON.stringify({ encryptionKey: organizationKey.keyB64 }),
encryptionKey,
),
await this.encryptService.encrypt(encryptionKey.keyB64, organizationKey),
await this.encryptService.encryptString(encryptionKey.keyB64, organizationKey),
]);
accessTokenRequest.name = name;

View File

@@ -130,7 +130,10 @@ export class ServiceAccountService {
serviceAccountView: ServiceAccountView,
) {
const request = new ServiceAccountRequest();
request.name = await this.encryptService.encrypt(serviceAccountView.name, organizationKey);
request.name = await this.encryptService.encryptString(
serviceAccountView.name,
organizationKey,
);
return request;
}

View File

@@ -28,7 +28,7 @@ describe("SecretsManagerPortingApiService", () => {
sut = new SecretsManagerPortingApiService(apiService, encryptService, keyService);
encryptService.encrypt.mockResolvedValue(mockEncryptedString);
encryptService.encryptString.mockResolvedValue(mockEncryptedString);
encryptService.decryptToUtf8.mockResolvedValue(mockUnencryptedString);
const mockRandomBytes = new Uint8Array(64) as CsprngArray;

View File

@@ -86,7 +86,7 @@ export class SecretsManagerPortingApiService {
importData.projects.map(async (p: any) => {
const project = new SecretsManagerImportedProjectRequest();
project.id = p.id;
project.name = await this.encryptService.encrypt(p.name, orgKey);
project.name = await this.encryptService.encryptString(p.name, orgKey);
return project;
}),
);
@@ -96,9 +96,9 @@ export class SecretsManagerPortingApiService {
const secret = new SecretsManagerImportedSecretRequest();
[secret.key, secret.value, secret.note] = await Promise.all([
this.encryptService.encrypt(s.key, orgKey),
this.encryptService.encrypt(s.value, orgKey),
this.encryptService.encrypt(s.note, orgKey),
this.encryptService.encryptString(s.key, orgKey),
this.encryptService.encryptString(s.value, orgKey),
this.encryptService.encryptString(s.note, orgKey),
]);
secret.id = s.id;

View File

@@ -146,7 +146,7 @@ export class DefaultCollectionAdminService implements CollectionAdminService {
}
const collection = new CollectionRequest();
collection.externalId = model.externalId;
collection.name = (await this.encryptService.encrypt(model.name, key)).encryptedString;
collection.name = (await this.encryptService.encryptString(model.name, key)).encryptedString;
collection.groups = model.groups.map(
(group) =>
new SelectionReadOnlyRequest(group.id, group.readOnly, group.hidePasswords, group.manage),

View File

@@ -112,7 +112,7 @@ export class DefaultCollectionService implements CollectionService {
collection.organizationId = model.organizationId;
collection.readOnly = model.readOnly;
collection.externalId = model.externalId;
collection.name = await this.encryptService.encrypt(model.name, key);
collection.name = await this.encryptService.encryptString(model.name, key);
return collection;
}

View File

@@ -113,7 +113,7 @@ export class DefaultvNextCollectionService implements vNextCollectionService {
collection.organizationId = model.organizationId;
collection.readOnly = model.readOnly;
collection.externalId = model.externalId;
collection.name = await this.encryptService.encrypt(model.name, key);
collection.name = await this.encryptService.encryptString(model.name, key);
return collection;
}

View File

@@ -178,7 +178,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent implements
const existingUserPublicKeyB64 = Utils.fromBufferToB64(existingUserPublicKey);
newKeyPair = [
existingUserPublicKeyB64,
await this.encryptService.encrypt(existingUserPrivateKey, userKey[0]),
await this.encryptService.wrapDecapsulationKey(existingUserPrivateKey, userKey[0]),
];
} else {
newKeyPair = await this.keyService.makeKeyPair(userKey[0]);

View File

@@ -193,7 +193,7 @@ export class PinService implements PinServiceAbstraction {
const pinKey = await this.makePinKey(pin, email, kdfConfig);
return await this.encryptService.encrypt(userKey.key, pinKey);
return await this.encryptService.wrapSymmetricKey(userKey, pinKey);
}
async storePinKeyEncryptedUserKey(
@@ -239,7 +239,7 @@ export class PinService implements PinServiceAbstraction {
throw new Error("No UserKey provided. Cannot create userKeyEncryptedPin.");
}
return await this.encryptService.encrypt(pin, userKey);
return await this.encryptService.encryptString(pin, userKey);
}
async getOldPinKeyEncryptedMasterKey(userId: UserId): Promise<EncryptedString | null> {

View File

@@ -189,7 +189,7 @@ describe("PinService", () => {
await sut.createPinKeyEncryptedUserKey(mockPin, mockUserKey, mockUserId);
// Assert
expect(encryptService.encrypt).toHaveBeenCalledWith(mockUserKey.key, mockPinKey);
expect(encryptService.wrapSymmetricKey).toHaveBeenCalledWith(mockUserKey, mockPinKey);
});
});
@@ -278,11 +278,11 @@ describe("PinService", () => {
});
it("should create a userKeyEncryptedPin from the provided PIN and userKey", async () => {
encryptService.encrypt.mockResolvedValue(mockUserKeyEncryptedPin);
encryptService.encryptString.mockResolvedValue(mockUserKeyEncryptedPin);
const result = await sut.createUserKeyEncryptedPin(mockPin, mockUserKey);
expect(encryptService.encrypt).toHaveBeenCalledWith(mockPin, mockUserKey);
expect(encryptService.encryptString).toHaveBeenCalledWith(mockPin, mockUserKey);
expect(result).toEqual(mockUserKeyEncryptedPin);
});
});

View File

@@ -293,7 +293,7 @@ describe("TokenService", () => {
const mockEncryptedAccessToken = "encryptedAccessToken";
encryptService.encrypt.mockResolvedValue({
encryptService.encryptString.mockResolvedValue({
encryptedString: mockEncryptedAccessToken,
} as any);

View File

@@ -289,7 +289,7 @@ export class TokenService implements TokenServiceAbstraction {
private async encryptAccessToken(accessToken: string, userId: UserId): Promise<EncString> {
const accessTokenKey = await this.getOrCreateAccessTokenKey(userId);
return await this.encryptService.encrypt(accessToken, accessTokenKey);
return await this.encryptService.encryptString(accessToken, accessTokenKey);
}
private async decryptAccessToken(

View File

@@ -114,7 +114,7 @@ export class OrganizationBillingService implements OrganizationBillingServiceAbs
private async makeOrganizationKeys(): Promise<OrganizationKeys> {
const [encryptedKey, key] = await this.keyService.makeOrgKey<OrgKey>();
const [publicKey, encryptedPrivateKey] = await this.keyService.makeKeyPair(key);
const encryptedCollectionName = await this.encryptService.encrypt(
const encryptedCollectionName = await this.encryptService.encryptString(
this.i18nService.t("defaultCollection"),
key,
);

View File

@@ -6,8 +6,24 @@ import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
export abstract class EncryptService {
abstract encrypt(plainValue: string | Uint8Array, key: SymmetricCryptoKey): Promise<EncString>;
abstract encryptToBytes(plainValue: Uint8Array, key: SymmetricCryptoKey): Promise<EncArrayBuffer>;
abstract encryptString(plainValue: string, key: SymmetricCryptoKey): Promise<EncString>;
abstract encryptFileData(
plainValue: Uint8Array,
key: SymmetricCryptoKey,
): Promise<EncArrayBuffer>;
abstract wrapDecapsulationKey(
decapsulationKeyPcks8: Uint8Array,
key: SymmetricCryptoKey,
): Promise<EncString>;
abstract wrapEncapsulationKey(
encapsulationKeySpki: Uint8Array,
key: SymmetricCryptoKey,
): Promise<EncString>;
abstract wrapSymmetricKey(
encapsulatedKey: SymmetricCryptoKey,
key: SymmetricCryptoKey,
): Promise<EncString>;
/**
* Decrypts an EncString to a string
* @param encString - The EncString to decrypt

View File

@@ -24,7 +24,7 @@ export class EncryptServiceImplementation implements EncryptService {
protected logMacFailures: boolean,
) {}
async encrypt(plainValue: string | Uint8Array, key: SymmetricCryptoKey): Promise<EncString> {
async encryptString(plainValue: string, key: SymmetricCryptoKey): Promise<EncString> {
if (key == null) {
throw new Error("No encryption key provided.");
}
@@ -33,21 +33,75 @@ export class EncryptServiceImplementation implements EncryptService {
return Promise.resolve(null);
}
let plainBuf: Uint8Array;
if (typeof plainValue === "string") {
plainBuf = Utils.fromUtf8ToArray(plainValue);
} else {
plainBuf = plainValue;
const plainBuf: Uint8Array = Utils.fromUtf8ToArray(plainValue);
return this.encryptUint8Array(plainBuf, key);
}
async wrapDecapsulationKey(
privateKeyPkcs8: Uint8Array,
key: SymmetricCryptoKey,
): Promise<EncString> {
if (privateKeyPkcs8 == null) {
throw new Error("No private key provided for encapsulation.");
}
const encObj = await this.aesEncrypt(plainBuf, key);
if (key == null) {
throw new Error("No encryption key provided for encapsulation.");
}
return await this.encryptUint8Array(privateKeyPkcs8, key);
}
async wrapEncapsulationKey(
encapsulationKeySpki: Uint8Array,
key: SymmetricCryptoKey,
): Promise<EncString> {
if (encapsulationKeySpki == null) {
throw new Error("No encapsulation key provided for encapsulation.");
}
if (key == null) {
throw new Error("No encryption key provided for encapsulation.");
}
return await this.encryptUint8Array(encapsulationKeySpki, key);
}
async wrapSymmetricKey(
encapsulatedKey: SymmetricCryptoKey,
key: SymmetricCryptoKey,
): Promise<EncString> {
if (encapsulatedKey == null) {
throw new Error("No encapsulated key provided for encapsulation.");
}
if (key == null) {
throw new Error("No encryption key provided for encapsulation.");
}
return await this.encryptUint8Array(encapsulatedKey.encKey, key);
}
private async encryptUint8Array(
plainValue: Uint8Array,
key: SymmetricCryptoKey,
): Promise<EncString> {
if (key == null) {
throw new Error("No encryption key provided.");
}
if (plainValue == null) {
return Promise.resolve(null);
}
const encObj = await this.aesEncrypt(plainValue, key);
const iv = Utils.fromBufferToB64(encObj.iv);
const data = Utils.fromBufferToB64(encObj.data);
const mac = encObj.mac != null ? Utils.fromBufferToB64(encObj.mac) : null;
return new EncString(encObj.key.encType, data, iv, mac);
}
async encryptToBytes(plainValue: Uint8Array, key: SymmetricCryptoKey): Promise<EncArrayBuffer> {
async encryptFileData(plainValue: Uint8Array, key: SymmetricCryptoKey): Promise<EncArrayBuffer> {
if (key == null) {
throw new Error("No encryption key provided.");
}

View File

@@ -28,13 +28,13 @@ describe("EncryptService", () => {
describe("encrypt", () => {
it("throws if no key is provided", () => {
return expect(encryptService.encrypt(null, null)).rejects.toThrow(
return expect(encryptService.encryptString(null, null)).rejects.toThrow(
"No encryption key provided.",
);
});
it("returns null if no data is provided", async () => {
const key = mock<SymmetricCryptoKey>();
const actual = await encryptService.encrypt(null, key);
const actual = await encryptService.encryptString(null, key);
expect(actual).toBeNull();
});
it("creates an EncString for Aes256Cbc", async () => {
@@ -42,7 +42,7 @@ describe("EncryptService", () => {
const plainValue = "data";
cryptoFunctionService.aesEncrypt.mockResolvedValue(makeStaticByteArray(4, 100));
cryptoFunctionService.randomBytes.mockResolvedValue(makeStaticByteArray(16) as CsprngArray);
const result = await encryptService.encrypt(plainValue, key);
const result = await encryptService.encryptString(plainValue, key);
expect(cryptoFunctionService.aesEncrypt).toHaveBeenCalledWith(
Utils.fromByteStringToArray(plainValue),
makeStaticByteArray(16),
@@ -59,7 +59,7 @@ describe("EncryptService", () => {
cryptoFunctionService.hmac.mockResolvedValue(makeStaticByteArray(32));
cryptoFunctionService.aesEncrypt.mockResolvedValue(makeStaticByteArray(4, 100));
cryptoFunctionService.randomBytes.mockResolvedValue(makeStaticByteArray(16) as CsprngArray);
const result = await encryptService.encrypt(plainValue, key);
const result = await encryptService.encryptString(plainValue, key);
expect(cryptoFunctionService.aesEncrypt).toHaveBeenCalledWith(
Utils.fromByteStringToArray(plainValue),
makeStaticByteArray(16),
@@ -85,7 +85,7 @@ describe("EncryptService", () => {
const plainValue = makeStaticByteArray(16, 1);
it("throws if no key is provided", () => {
return expect(encryptService.encryptToBytes(plainValue, null)).rejects.toThrow(
return expect(encryptService.encryptFileData(plainValue, null)).rejects.toThrow(
"No encryption key",
);
});
@@ -97,7 +97,7 @@ describe("EncryptService", () => {
cryptoFunctionService.randomBytes.mockResolvedValue(iv as CsprngArray);
cryptoFunctionService.aesEncrypt.mockResolvedValue(cipherText);
const actual = await encryptService.encryptToBytes(plainValue, key);
const actual = await encryptService.encryptFileData(plainValue, key);
const expectedBytes = new Uint8Array(1 + iv.byteLength + cipherText.byteLength);
expectedBytes.set([EncryptionType.AesCbc256_B64]);
expectedBytes.set(iv, 1);
@@ -115,7 +115,7 @@ describe("EncryptService", () => {
cryptoFunctionService.aesEncrypt.mockResolvedValue(cipherText);
cryptoFunctionService.hmac.mockResolvedValue(mac);
const actual = await encryptService.encryptToBytes(plainValue, key);
const actual = await encryptService.encryptFileData(plainValue, key);
const expectedBytes = new Uint8Array(
1 + iv.byteLength + mac.byteLength + cipherText.byteLength,
);

View File

@@ -163,10 +163,10 @@ export class DeviceTrustService implements DeviceTrustServiceAbstraction {
this.encryptService.rsaEncrypt(userKey.key, devicePublicKey),
// Encrypt devicePublicKey with user key
this.encryptService.encrypt(devicePublicKey, userKey),
this.encryptService.wrapEncapsulationKey(devicePublicKey, userKey),
// Encrypt devicePrivateKey with deviceKey
this.encryptService.encrypt(devicePrivateKey, deviceKey),
this.encryptService.wrapDecapsulationKey(devicePrivateKey, deviceKey),
]);
// Send encrypted keys to server
@@ -234,7 +234,7 @@ export class DeviceTrustService implements DeviceTrustServiceAbstraction {
);
// Re-encrypt the device public key with the new user key
const encryptedDevicePublicKey = await this.encryptService.encrypt(
const encryptedDevicePublicKey = await this.encryptService.wrapEncapsulationKey(
decryptedDevicePublicKey,
newUserKey,
);

View File

@@ -345,8 +345,6 @@ describe("deviceTrustService", () => {
const deviceRsaKeyLength = 2048;
let mockDeviceRsaKeyPair: [Uint8Array, Uint8Array];
let mockDevicePrivateKey: Uint8Array;
let mockDevicePublicKey: Uint8Array;
let mockDevicePublicKeyEncryptedUserKey: EncString;
let mockUserKeyEncryptedDevicePublicKey: EncString;
let mockDeviceKeyEncryptedDevicePrivateKey: EncString;
@@ -365,7 +363,8 @@ describe("deviceTrustService", () => {
let rsaGenerateKeyPairSpy: jest.SpyInstance;
let cryptoSvcGetUserKeySpy: jest.SpyInstance;
let cryptoSvcRsaEncryptSpy: jest.SpyInstance;
let encryptServiceEncryptSpy: jest.SpyInstance;
let encryptServiceWrapDecapsulationKeySpy: jest.SpyInstance;
let encryptServiceWrapEncapsulationKeySpy: jest.SpyInstance;
let appIdServiceGetAppIdSpy: jest.SpyInstance;
let devicesApiServiceUpdateTrustedDeviceKeysSpy: jest.SpyInstance;
@@ -383,9 +382,6 @@ describe("deviceTrustService", () => {
new Uint8Array(deviceRsaKeyLength),
];
mockDevicePublicKey = mockDeviceRsaKeyPair[0];
mockDevicePrivateKey = mockDeviceRsaKeyPair[1];
mockDevicePublicKeyEncryptedUserKey = new EncString(
EncryptionType.Rsa2048_OaepSha1_B64,
"mockDevicePublicKeyEncryptedUserKey",
@@ -418,13 +414,17 @@ describe("deviceTrustService", () => {
.spyOn(encryptService, "rsaEncrypt")
.mockResolvedValue(mockDevicePublicKeyEncryptedUserKey);
encryptServiceEncryptSpy = jest
.spyOn(encryptService, "encrypt")
encryptServiceWrapEncapsulationKeySpy = jest
.spyOn(encryptService, "wrapEncapsulationKey")
.mockImplementation((plainValue, key) => {
if (plainValue === mockDevicePublicKey && key === mockUserKey) {
if (plainValue instanceof Uint8Array && key instanceof SymmetricCryptoKey) {
return Promise.resolve(mockUserKeyEncryptedDevicePublicKey);
}
if (plainValue === mockDevicePrivateKey && key === mockDeviceKey) {
});
encryptServiceWrapDecapsulationKeySpy = jest
.spyOn(encryptService, "wrapDecapsulationKey")
.mockImplementation((plainValue, key) => {
if (plainValue instanceof Uint8Array && key instanceof SymmetricCryptoKey) {
return Promise.resolve(mockDeviceKeyEncryptedDevicePrivateKey);
}
});
@@ -451,7 +451,8 @@ describe("deviceTrustService", () => {
const userKeyKey: Uint8Array = cryptoSvcRsaEncryptSpy.mock.calls[0][0];
expect(userKeyKey.byteLength).toBe(64);
expect(encryptServiceEncryptSpy).toHaveBeenCalledTimes(2);
expect(encryptServiceWrapDecapsulationKeySpy).toHaveBeenCalledTimes(1);
expect(encryptServiceWrapEncapsulationKeySpy).toHaveBeenCalledTimes(1);
expect(appIdServiceGetAppIdSpy).toHaveBeenCalledTimes(1);
expect(devicesApiServiceUpdateTrustedDeviceKeysSpy).toHaveBeenCalledTimes(1);
@@ -507,9 +508,14 @@ describe("deviceTrustService", () => {
errorText: "rsaEncrypt error",
},
{
method: "encryptService.encrypt",
spy: () => encryptServiceEncryptSpy,
errorText: "encryptService.encrypt error",
method: "encryptService.wrapEncapsulationKey",
spy: () => encryptServiceWrapEncapsulationKeySpy,
errorText: "encryptService.wrapEncapsulationKey error",
},
{
method: "encryptService.wrapDecapsulationKey",
spy: () => encryptServiceWrapDecapsulationKeySpy,
errorText: "encryptService.wrapDecapsulationKey error",
},
];
@@ -748,7 +754,7 @@ describe("deviceTrustService", () => {
});
// Mock the reencryption of the device public key with the new user key
encryptService.encrypt.mockImplementationOnce((plainValue, key) => {
encryptService.wrapEncapsulationKey.mockImplementationOnce((plainValue, key) => {
expect(plainValue).toBeInstanceOf(Uint8Array);
expect(new Uint8Array(plainValue as Uint8Array)[0]).toBe(FakeDecryptedPublicKeyMarker);

View File

@@ -22,7 +22,7 @@ describe("DomainBase", () => {
});
function setUpCryptography() {
encryptService.encrypt.mockImplementation((value) => {
encryptService.encryptString.mockImplementation((value) => {
let data: string;
if (typeof value === "string") {
data = value;
@@ -82,7 +82,7 @@ describe("DomainBase", () => {
const domain = new TestDomain();
domain.encToString = await encryptService.encrypt("string", key);
domain.encToString = await encryptService.encryptString("string", key);
const decrypted = await domain["decryptObjWithKey"](["encToString"], key, encryptService);
@@ -96,8 +96,8 @@ describe("DomainBase", () => {
const domain = new TestDomain();
domain.encToString = await encryptService.encrypt("string", key);
domain.encString2 = await encryptService.encrypt("string2", key);
domain.encToString = await encryptService.encryptString("string", key);
domain.encString2 = await encryptService.encryptString("string2", key);
const decrypted = await domain["decryptObjWithKey"](
["encToString", "encString2"],

View File

@@ -123,7 +123,7 @@ describe("EncString", () => {
.mockResolvedValue("decrypted");
function setupEncryption() {
encryptService.encrypt.mockImplementation(async (data, key) => {
encryptService.encryptString.mockImplementation(async (data, key) => {
if (typeof data === "string") {
return makeEncString(data);
} else {

View File

@@ -22,7 +22,9 @@ describe("OrgKeyEncryptor", () => {
// on this property--that the facade treats its data like a opaque objects--to trace
// the data through several function calls. Should the encryptor interact with the
// objects themselves, these mocks will break.
encryptService.encrypt.mockImplementation((p) => Promise.resolve(p as unknown as EncString));
encryptService.encryptString.mockImplementation((p) =>
Promise.resolve(p as unknown as EncString),
);
encryptService.decryptToUtf8.mockImplementation((c) => Promise.resolve(c as unknown as string));
dataPacker.pack.mockImplementation((v) => v as string);
dataPacker.unpack.mockImplementation(<T>(v: string) => v as T);
@@ -95,7 +97,7 @@ describe("OrgKeyEncryptor", () => {
// these are data flow expectations; the operations all all pass-through mocks
expect(dataPacker.pack).toHaveBeenCalledWith(value);
expect(encryptService.encrypt).toHaveBeenCalledWith(value, orgKey);
expect(encryptService.encryptString).toHaveBeenCalledWith(value, orgKey);
expect(result).toBe(value);
});
});

View File

@@ -37,7 +37,7 @@ export class OrganizationKeyEncryptor extends OrganizationEncryptor {
this.assertHasValue("secret", secret);
let packed = this.dataPacker.pack(secret);
const encrypted = await this.encryptService.encrypt(packed, this.key);
const encrypted = await this.encryptService.encryptString(packed, this.key);
packed = null;
return encrypted;

View File

@@ -22,7 +22,9 @@ describe("UserKeyEncryptor", () => {
// on this property--that the facade treats its data like a opaque objects--to trace
// the data through several function calls. Should the encryptor interact with the
// objects themselves, these mocks will break.
encryptService.encrypt.mockImplementation((p) => Promise.resolve(p as unknown as EncString));
encryptService.encryptString.mockImplementation((p) =>
Promise.resolve(p as unknown as EncString),
);
encryptService.decryptToUtf8.mockImplementation((c) => Promise.resolve(c as unknown as string));
dataPacker.pack.mockImplementation((v) => v as string);
dataPacker.unpack.mockImplementation(<T>(v: string) => v as T);
@@ -95,7 +97,7 @@ describe("UserKeyEncryptor", () => {
// these are data flow expectations; the operations all all pass-through mocks
expect(dataPacker.pack).toHaveBeenCalledWith(value);
expect(encryptService.encrypt).toHaveBeenCalledWith(value, userKey);
expect(encryptService.encryptString).toHaveBeenCalledWith(value, userKey);
expect(result).toBe(value);
});
});

View File

@@ -37,7 +37,7 @@ export class UserKeyEncryptor extends UserEncryptor {
this.assertHasValue("secret", secret);
let packed = this.dataPacker.pack(secret);
const encrypted = await this.encryptService.encrypt(packed, this.key);
const encrypted = await this.encryptService.encryptString(packed, this.key);
packed = null;
return encrypted;

View File

@@ -479,7 +479,7 @@ describe("SendService", () => {
beforeEach(() => {
encryptService.decryptToBytes.mockResolvedValue(new Uint8Array(32));
encryptedKey = new EncString("Re-encrypted Send Key");
encryptService.encrypt.mockResolvedValue(encryptedKey);
encryptService.wrapSymmetricKey.mockResolvedValue(encryptedKey);
});
it("returns re-encrypted user sends", async () => {

View File

@@ -81,12 +81,12 @@ export class SendService implements InternalSendServiceAbstraction {
if (key == null) {
key = await this.keyService.getUserKey();
}
send.key = await this.encryptService.encrypt(model.key, key);
send.name = await this.encryptService.encrypt(model.name, model.cryptoKey);
send.notes = await this.encryptService.encrypt(model.notes, model.cryptoKey);
send.key = await this.encryptService.wrapSymmetricKey(new SymmetricCryptoKey(model.key), key);
send.name = await this.encryptService.encryptString(model.name, model.cryptoKey);
send.notes = await this.encryptService.encryptString(model.notes, model.cryptoKey);
if (send.type === SendType.Text) {
send.text = new SendText();
send.text.text = await this.encryptService.encrypt(model.text.text, model.cryptoKey);
send.text.text = await this.encryptService.encryptString(model.text.text, model.cryptoKey);
send.text.hidden = model.text.hidden;
} else if (send.type === SendType.File) {
send.file = new SendFile();
@@ -287,8 +287,10 @@ export class SendService implements InternalSendServiceAbstraction {
) {
const requests = await Promise.all(
sends.map(async (send) => {
const sendKey = await this.encryptService.decryptToBytes(send.key, originalUserKey);
send.key = await this.encryptService.encrypt(sendKey, rotateUserKey);
const sendKey = new SymmetricCryptoKey(
await this.encryptService.decryptToBytes(send.key, originalUserKey),
);
send.key = await this.encryptService.wrapSymmetricKey(sendKey, rotateUserKey);
return new SendWithIdRequest(send);
}),
);
@@ -326,8 +328,8 @@ export class SendService implements InternalSendServiceAbstraction {
if (key == null) {
key = await this.keyService.getUserKey();
}
const encFileName = await this.encryptService.encrypt(fileName, key);
const encFileData = await this.encryptService.encryptToBytes(new Uint8Array(data), key);
const encFileName = await this.encryptService.encryptString(fileName, key);
const encFileData = await this.encryptService.encryptFileData(new Uint8Array(data), key);
return [encFileName, encFileData];
}

View File

@@ -129,8 +129,8 @@ describe("Cipher Service", () => {
let cipherObj: Cipher;
beforeEach(() => {
encryptService.encryptToBytes.mockReturnValue(Promise.resolve(ENCRYPTED_BYTES));
encryptService.encrypt.mockReturnValue(Promise.resolve(new EncString(ENCRYPTED_TEXT)));
encryptService.encryptFileData.mockReturnValue(Promise.resolve(ENCRYPTED_BYTES));
encryptService.encryptString.mockReturnValue(Promise.resolve(new EncString(ENCRYPTED_TEXT)));
(window as any).bitwardenContainerService = new ContainerService(keyService, encryptService);
@@ -276,7 +276,8 @@ describe("Cipher Service", () => {
keyService.makeCipherKey.mockReturnValue(
Promise.resolve(new SymmetricCryptoKey(makeStaticByteArray(64)) as CipherKey),
);
encryptService.encrypt.mockImplementation(encryptText);
encryptService.encryptString.mockImplementation(encryptText);
encryptService.wrapSymmetricKey.mockResolvedValue(new EncString("Re-encrypted Cipher Key"));
jest.spyOn(cipherService as any, "getAutofillOnPageLoadDefault").mockResolvedValue(true);
});
@@ -398,7 +399,7 @@ describe("Cipher Service", () => {
encryptService.decryptToBytes.mockResolvedValue(new Uint8Array(32));
encryptedKey = new EncString("Re-encrypted Cipher Key");
encryptService.encrypt.mockResolvedValue(encryptedKey);
encryptService.wrapSymmetricKey.mockResolvedValue(encryptedKey);
keyService.makeCipherKey.mockResolvedValue(
new SymmetricCryptoKey(new Uint8Array(32)) as CipherKey,

View File

@@ -271,7 +271,7 @@ export class CipherService implements CipherServiceAbstraction {
key,
).then(async () => {
if (model.key != null) {
attachment.key = await this.encryptService.encrypt(model.key.key, key);
attachment.key = await this.encryptService.wrapSymmetricKey(model.key, key);
}
encAttachments.push(attachment);
});
@@ -893,10 +893,10 @@ export class CipherService implements CipherServiceAbstraction {
await this.updateWithServer(cipher);
}
const encFileName = await this.encryptService.encrypt(filename, cipherEncKey);
const encFileName = await this.encryptService.encryptString(filename, cipherEncKey);
const dataEncKey = await this.keyService.makeDataEncKey(cipherEncKey);
const encData = await this.encryptService.encryptToBytes(new Uint8Array(data), dataEncKey[0]);
const encData = await this.encryptService.encryptFileData(new Uint8Array(data), dataEncKey[0]);
const response = await this.cipherFileUploadService.upload(
cipher,
@@ -1496,8 +1496,11 @@ export class CipherService implements CipherServiceAbstraction {
const dataEncKey = await this.keyService.makeDataEncKey(encKey);
const encFileName = await this.encryptService.encrypt(attachmentView.fileName, encKey);
const encData = await this.encryptService.encryptToBytes(new Uint8Array(decBuf), dataEncKey[0]);
const encFileName = await this.encryptService.encryptString(attachmentView.fileName, encKey);
const encData = await this.encryptService.encryptFileData(
new Uint8Array(decBuf),
dataEncKey[0],
);
const fd = new FormData();
try {
@@ -1552,7 +1555,7 @@ export class CipherService implements CipherServiceAbstraction {
.then(() => {
const modelProp = (model as any)[map[theProp] || theProp];
if (modelProp && modelProp !== "") {
return self.encryptService.encrypt(modelProp, key);
return self.encryptService.encryptString(modelProp, key);
}
return null;
})
@@ -1598,7 +1601,7 @@ export class CipherService implements CipherServiceAbstraction {
key,
);
const uriHash = await this.encryptService.hash(model.login.uris[i].uri, "sha256");
loginUri.uriChecksum = await this.encryptService.encrypt(uriHash, key);
loginUri.uriChecksum = await this.encryptService.encryptString(uriHash, key);
cipher.login.uris.push(loginUri);
}
}
@@ -1625,8 +1628,11 @@ export class CipherService implements CipherServiceAbstraction {
},
key,
);
domainKey.counter = await this.encryptService.encrypt(String(viewKey.counter), key);
domainKey.discoverable = await this.encryptService.encrypt(
domainKey.counter = await this.encryptService.encryptString(
String(viewKey.counter),
key,
);
domainKey.discoverable = await this.encryptService.encryptString(
String(viewKey.discoverable),
key,
);
@@ -1818,8 +1824,8 @@ export class CipherService implements CipherServiceAbstraction {
}
// Then, we have to encrypt the cipher key with the proper key.
cipher.key = await this.encryptService.encrypt(
decryptedCipherKey.key,
cipher.key = await this.encryptService.wrapSymmetricKey(
decryptedCipherKey,
keyForCipherKeyEncryption,
);

View File

@@ -110,7 +110,7 @@ describe("Folder Service", () => {
model.id = "2";
model.name = "Test Folder";
encryptService.encrypt.mockResolvedValue(new EncString("ENC"));
encryptService.encryptString.mockResolvedValue(new EncString("ENC"));
const result = await folderService.encrypt(model, null);
@@ -211,7 +211,7 @@ describe("Folder Service", () => {
beforeEach(() => {
encryptedKey = new EncString("Re-encrypted Folder");
encryptService.encrypt.mockResolvedValue(encryptedKey);
encryptService.encryptString.mockResolvedValue(encryptedKey);
});
it("returns re-encrypted user folders", async () => {

View File

@@ -84,7 +84,7 @@ export class FolderService implements InternalFolderServiceAbstraction {
async encrypt(model: FolderView, key: SymmetricCryptoKey): Promise<Folder> {
const folder = new Folder();
folder.id = model.id;
folder.name = await this.encryptService.encrypt(model.name, key);
folder.name = await this.encryptService.encryptString(model.name, key);
return folder;
}

View File

@@ -232,7 +232,7 @@ export class DefaultKeyService implements KeyServiceAbstraction {
}
const newUserKey = await this.keyGenerationService.createKey(512);
return this.buildProtectedSymmetricKey(masterKey, newUserKey.key);
return this.buildProtectedSymmetricKey(masterKey, newUserKey);
}
/**
@@ -319,7 +319,7 @@ export class DefaultKeyService implements KeyServiceAbstraction {
userKey?: UserKey,
): Promise<[UserKey, EncString]> {
userKey ||= await this.getUserKey();
return await this.buildProtectedSymmetricKey(masterKey, userKey.key);
return await this.buildProtectedSymmetricKey(masterKey, userKey);
}
// TODO: move to MasterPasswordService
@@ -429,7 +429,7 @@ export class DefaultKeyService implements KeyServiceAbstraction {
}
const newSymKey = await this.keyGenerationService.createKey(512);
return this.buildProtectedSymmetricKey(key, newSymKey.key);
return this.buildProtectedSymmetricKey(key, newSymKey);
}
private async clearOrgKeys(userId: UserId): Promise<void> {
@@ -543,7 +543,7 @@ export class DefaultKeyService implements KeyServiceAbstraction {
const keyPair = await this.cryptoFunctionService.rsaGenerateKeyPair(2048);
const publicB64 = Utils.fromBufferToB64(keyPair[0]);
const privateEnc = await this.encryptService.encrypt(keyPair[1], key);
const privateEnc = await this.encryptService.wrapDecapsulationKey(keyPair[1], key);
return [publicB64, privateEnc];
}
@@ -821,18 +821,21 @@ export class DefaultKeyService implements KeyServiceAbstraction {
private async buildProtectedSymmetricKey<T extends SymmetricCryptoKey>(
encryptionKey: SymmetricCryptoKey,
newSymKey: Uint8Array,
newSymKey: SymmetricCryptoKey,
): Promise<[T, EncString]> {
let protectedSymKey: EncString;
if (encryptionKey.key.byteLength === 32) {
const stretchedEncryptionKey = await this.keyGenerationService.stretchKey(encryptionKey);
protectedSymKey = await this.encryptService.encrypt(newSymKey, stretchedEncryptionKey);
protectedSymKey = await this.encryptService.wrapSymmetricKey(
newSymKey,
stretchedEncryptionKey,
);
} else if (encryptionKey.key.byteLength === 64) {
protectedSymKey = await this.encryptService.encrypt(newSymKey, encryptionKey);
protectedSymKey = await this.encryptService.wrapSymmetricKey(newSymKey, encryptionKey);
} else {
throw new Error("Invalid key size.");
}
return [new SymmetricCryptoKey(newSymKey) as T, protectedSymKey];
return [newSymKey as T, protectedSymKey];
}
// --LEGACY METHODS--

View File

@@ -23,8 +23,8 @@ export class BaseVaultExportService {
const salt = Utils.fromBufferToB64(await this.cryptoFunctionService.randomBytes(16));
const key = await this.pinService.makePinKey(password, salt, kdfConfig);
const encKeyValidation = await this.encryptService.encrypt(Utils.newGuid(), key);
const encText = await this.encryptService.encrypt(clearText, key);
const encKeyValidation = await this.encryptService.encryptString(Utils.newGuid(), key);
const encText = await this.encryptService.encryptString(clearText, key);
const jsonDoc: BitwardenPasswordProtectedFileFormat = {
encrypted: true,

View File

@@ -181,7 +181,7 @@ describe("VaultExportService", () => {
folderService.folderViews$.mockReturnValue(of(UserFolderViews));
folderService.folders$.mockReturnValue(of(UserFolders));
kdfConfigService.getKdfConfig.mockResolvedValue(DEFAULT_KDF_CONFIG);
encryptService.encrypt.mockResolvedValue(new EncString("encrypted"));
encryptService.encryptString.mockResolvedValue(new EncString("encrypted"));
exportService = new IndividualVaultExportService(
folderService,
@@ -271,7 +271,7 @@ describe("VaultExportService", () => {
});
it("has a mac property", async () => {
encryptService.encrypt.mockResolvedValue(mac);
encryptService.encryptString.mockResolvedValue(mac);
exportString = await exportService.getPasswordProtectedExport(password);
exportObject = JSON.parse(exportString);
@@ -279,7 +279,7 @@ describe("VaultExportService", () => {
});
it("has data property", async () => {
encryptService.encrypt.mockResolvedValue(data);
encryptService.encryptString.mockResolvedValue(data);
exportString = await exportService.getPasswordProtectedExport(password);
exportObject = JSON.parse(exportString);

View File

@@ -108,7 +108,7 @@ export class IndividualVaultExportService
const userKey = await this.keyService.getUserKeyWithLegacySupport(
await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId)),
);
const encKeyValidation = await this.encryptService.encrypt(Utils.newGuid(), userKey);
const encKeyValidation = await this.encryptService.encryptString(Utils.newGuid(), userKey);
const jsonDoc: BitwardenEncryptedIndividualJsonExport = {
encrypted: true,

View File

@@ -248,7 +248,7 @@ export class OrganizationVaultExportService
ciphers: Cipher[],
): Promise<string> {
const orgKey = await this.keyService.getOrgKey(organizationId);
const encKeyValidation = await this.encryptService.encrypt(Utils.newGuid(), orgKey);
const encKeyValidation = await this.encryptService.encryptString(Utils.newGuid(), orgKey);
const jsonDoc: BitwardenEncryptedOrgJsonExport = {
encrypted: true,

View File

@@ -171,7 +171,7 @@ describe("VaultExportService", () => {
folderService.folderViews$.mockReturnValue(of(UserFolderViews));
folderService.folders$.mockReturnValue(of(UserFolders));
kdfConfigService.getKdfConfig.mockResolvedValue(DEFAULT_KDF_CONFIG);
encryptService.encrypt.mockResolvedValue(new EncString("encrypted"));
encryptService.encryptString.mockResolvedValue(new EncString("encrypted"));
keyService.userKey$.mockReturnValue(new BehaviorSubject("mockOriginalUserKey" as any));
const userId = "" as UserId;
const accountInfo: AccountInfo = {
@@ -270,7 +270,7 @@ describe("VaultExportService", () => {
});
it("has a mac property", async () => {
encryptService.encrypt.mockResolvedValue(mac);
encryptService.encryptString.mockResolvedValue(mac);
exportString = await exportService.getPasswordProtectedExport(password);
exportObject = JSON.parse(exportString);
@@ -278,7 +278,7 @@ describe("VaultExportService", () => {
});
it("has data property", async () => {
encryptService.encrypt.mockResolvedValue(data);
encryptService.encryptString.mockResolvedValue(data);
exportString = await exportService.getPasswordProtectedExport(password);
exportObject = JSON.parse(exportString);

View File

@@ -22,7 +22,9 @@ describe("LocalGeneratorHistoryService", () => {
const userKey = new SymmetricCryptoKey(new Uint8Array(64) as CsprngArray) as UserKey;
beforeEach(() => {
encryptService.encrypt.mockImplementation((p) => Promise.resolve(p as unknown as EncString));
encryptService.encryptString.mockImplementation((p) =>
Promise.resolve(p as unknown as EncString),
);
encryptService.decryptToUtf8.mockImplementation((c) => Promise.resolve(c.encryptedString));
keyService.getUserKey.mockImplementation(() => Promise.resolve(userKey));
keyService.userKey$.mockImplementation(() => of(true as unknown as UserKey));