mirror of
https://github.com/bitwarden/browser
synced 2025-12-10 21:33:27 +00:00
[PM-19603] Change asymmetric interface to only allow key encapsulation (#14046)
* Change asymmetric interface to only allow key encapsulation * Fix naming * Clean up naming * Update libs/common/src/key-management/crypto/abstractions/encrypt.service.ts Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update libs/common/src/key-management/crypto/services/encrypt.service.implementation.ts Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update libs/common/src/key-management/crypto/abstractions/encrypt.service.ts Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Fix test --------- Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>
This commit is contained in:
@@ -71,7 +71,7 @@ export abstract class BaseBulkConfirmComponent implements OnInit {
|
|||||||
if (publicKey == null) {
|
if (publicKey == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const encryptedKey = await this.encryptService.rsaEncrypt(key.key, publicKey);
|
const encryptedKey = await this.encryptService.encapsulateKeyUnsigned(key, publicKey);
|
||||||
userIdsWithKeys.push({
|
userIdsWithKeys.push({
|
||||||
id: user.id,
|
id: user.id,
|
||||||
key: encryptedKey.encryptedString,
|
key: encryptedKey.encryptedString,
|
||||||
|
|||||||
@@ -322,7 +322,7 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
|
|||||||
|
|
||||||
async confirmUser(user: OrganizationUserView, publicKey: Uint8Array): Promise<void> {
|
async confirmUser(user: OrganizationUserView, publicKey: Uint8Array): Promise<void> {
|
||||||
const orgKey = await this.keyService.getOrgKey(this.organization.id);
|
const orgKey = await this.keyService.getOrgKey(this.organization.id);
|
||||||
const key = await this.encryptService.rsaEncrypt(orgKey.key, publicKey);
|
const key = await this.encryptService.encapsulateKeyUnsigned(orgKey, publicKey);
|
||||||
const request = new OrganizationUserConfirmRequest();
|
const request = new OrganizationUserConfirmRequest();
|
||||||
request.key = key.encryptedString;
|
request.key = key.encryptedString;
|
||||||
await this.organizationUserApiService.postOrganizationUserConfirm(
|
await this.organizationUserApiService.postOrganizationUserConfirm(
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ describe("OrganizationUserResetPasswordService", () => {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
encryptService.rsaEncrypt.mockResolvedValue(
|
encryptService.encapsulateKeyUnsigned.mockResolvedValue(
|
||||||
new EncString(EncryptionType.Rsa2048_OaepSha1_B64, "mockEncryptedUserKey"),
|
new EncString(EncryptionType.Rsa2048_OaepSha1_B64, "mockEncryptedUserKey"),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -111,7 +111,10 @@ describe("OrganizationUserResetPasswordService", () => {
|
|||||||
|
|
||||||
it("should rsa encrypt the user key", async () => {
|
it("should rsa encrypt the user key", async () => {
|
||||||
await sut.buildRecoveryKey(mockOrgId, mockUserKey, mockPublicKeys);
|
await sut.buildRecoveryKey(mockOrgId, mockUserKey, mockPublicKeys);
|
||||||
expect(encryptService.rsaEncrypt).toHaveBeenCalledWith(expect.anything(), expect.anything());
|
expect(encryptService.encapsulateKeyUnsigned).toHaveBeenCalledWith(
|
||||||
|
expect.anything(),
|
||||||
|
expect.anything(),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should throw an error if the public key is not trusted", async () => {
|
it("should throw an error if the public key is not trusted", async () => {
|
||||||
@@ -199,7 +202,7 @@ describe("OrganizationUserResetPasswordService", () => {
|
|||||||
publicKey: Utils.fromUtf8ToArray("test-public-key"),
|
publicKey: Utils.fromUtf8ToArray("test-public-key"),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
encryptService.rsaEncrypt.mockResolvedValue(
|
encryptService.encapsulateKeyUnsigned.mockResolvedValue(
|
||||||
new EncString(EncryptionType.Rsa2048_OaepSha1_B64, "mockEncryptedUserKey"),
|
new EncString(EncryptionType.Rsa2048_OaepSha1_B64, "mockEncryptedUserKey"),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import { EncryptService } from "@bitwarden/common/key-management/crypto/abstract
|
|||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { EncryptedString, EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
import { EncryptedString, EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
import { UserKey } from "@bitwarden/common/types/key";
|
import { UserKey } from "@bitwarden/common/types/key";
|
||||||
import {
|
import {
|
||||||
@@ -59,6 +58,10 @@ export class OrganizationUserResetPasswordService
|
|||||||
userKey: UserKey,
|
userKey: UserKey,
|
||||||
trustedPublicKeys: Uint8Array[],
|
trustedPublicKeys: Uint8Array[],
|
||||||
): Promise<EncryptedString> {
|
): Promise<EncryptedString> {
|
||||||
|
if (userKey == null) {
|
||||||
|
throw new Error("User key is required for recovery.");
|
||||||
|
}
|
||||||
|
|
||||||
// Retrieve Public Key
|
// Retrieve Public Key
|
||||||
const orgKeys = await this.organizationApiService.getKeys(orgId);
|
const orgKeys = await this.organizationApiService.getKeys(orgId);
|
||||||
if (orgKeys == null) {
|
if (orgKeys == null) {
|
||||||
@@ -76,7 +79,8 @@ export class OrganizationUserResetPasswordService
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RSA Encrypt user key with organization's public key
|
// RSA Encrypt user key with organization's public key
|
||||||
const encryptedKey = await this.encryptService.rsaEncrypt(userKey.key, publicKey);
|
const encryptedKey = await this.encryptService.encapsulateKeyUnsigned(userKey, publicKey);
|
||||||
|
|
||||||
return encryptedKey.encryptedString;
|
return encryptedKey.encryptedString;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,11 +118,11 @@ export class OrganizationUserResetPasswordService
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Decrypt User's Reset Password Key to get UserKey
|
// Decrypt User's Reset Password Key to get UserKey
|
||||||
const decValue = await this.encryptService.rsaDecrypt(
|
const userKey = await this.encryptService.decapsulateKeyUnsigned(
|
||||||
new EncString(response.resetPasswordKey),
|
new EncString(response.resetPasswordKey),
|
||||||
decPrivateKey,
|
decPrivateKey,
|
||||||
);
|
);
|
||||||
const existingUserKey = new SymmetricCryptoKey(decValue) as UserKey;
|
const existingUserKey = userKey as UserKey;
|
||||||
|
|
||||||
// determine Kdf Algorithm
|
// determine Kdf Algorithm
|
||||||
const kdfConfig: KdfConfig =
|
const kdfConfig: KdfConfig =
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ describe("RotateableKeySetService", () => {
|
|||||||
const encryptedPrivateKey = Symbol();
|
const encryptedPrivateKey = Symbol();
|
||||||
keyService.makeKeyPair.mockResolvedValue(["publicKey", encryptedPrivateKey as any]);
|
keyService.makeKeyPair.mockResolvedValue(["publicKey", encryptedPrivateKey as any]);
|
||||||
keyService.getUserKey.mockResolvedValue({ key: userKey.key } as any);
|
keyService.getUserKey.mockResolvedValue({ key: userKey.key } as any);
|
||||||
encryptService.rsaEncrypt.mockResolvedValue(encryptedUserKey as any);
|
encryptService.encapsulateKeyUnsigned.mockResolvedValue(encryptedUserKey as any);
|
||||||
encryptService.encrypt.mockResolvedValue(encryptedPublicKey as any);
|
encryptService.encrypt.mockResolvedValue(encryptedPublicKey as any);
|
||||||
|
|
||||||
const result = await service.createKeySet(externalKey as any);
|
const result = await service.createKeySet(externalKey as any);
|
||||||
|
|||||||
@@ -25,7 +25,10 @@ export class RotateableKeySetService {
|
|||||||
|
|
||||||
const userKey = await this.keyService.getUserKey();
|
const userKey = await this.keyService.getUserKey();
|
||||||
const rawPublicKey = Utils.fromB64ToArray(publicKey);
|
const rawPublicKey = Utils.fromB64ToArray(publicKey);
|
||||||
const encryptedUserKey = await this.encryptService.rsaEncrypt(userKey.key, rawPublicKey);
|
const encryptedUserKey = await this.encryptService.encapsulateKeyUnsigned(
|
||||||
|
userKey,
|
||||||
|
rawPublicKey,
|
||||||
|
);
|
||||||
const encryptedPublicKey = await this.encryptService.encrypt(rawPublicKey, userKey);
|
const encryptedPublicKey = await this.encryptService.encrypt(rawPublicKey, userKey);
|
||||||
return new RotateableKeySet(encryptedUserKey, encryptedPublicKey, encryptedPrivateKey);
|
return new RotateableKeySet(encryptedUserKey, encryptedPublicKey, encryptedPrivateKey);
|
||||||
}
|
}
|
||||||
@@ -60,7 +63,10 @@ export class RotateableKeySetService {
|
|||||||
throw new Error("failed to rotate key set: could not decrypt public key");
|
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.encrypt(publicKey, newUserKey);
|
||||||
const newEncryptedUserKey = await this.encryptService.rsaEncrypt(newUserKey.key, publicKey);
|
const newEncryptedUserKey = await this.encryptService.encapsulateKeyUnsigned(
|
||||||
|
newUserKey,
|
||||||
|
publicKey,
|
||||||
|
);
|
||||||
|
|
||||||
const newRotateableKeySet = new RotateableKeySet<ExternalKey>(
|
const newRotateableKeySet = new RotateableKeySet<ExternalKey>(
|
||||||
newEncryptedUserKey,
|
newEncryptedUserKey,
|
||||||
|
|||||||
@@ -130,7 +130,9 @@ describe("EmergencyAccessService", () => {
|
|||||||
|
|
||||||
keyService.getUserKey.mockResolvedValueOnce(mockUserKey);
|
keyService.getUserKey.mockResolvedValueOnce(mockUserKey);
|
||||||
|
|
||||||
encryptService.rsaEncrypt.mockResolvedValueOnce(mockUserPublicKeyEncryptedUserKey);
|
encryptService.encapsulateKeyUnsigned.mockResolvedValueOnce(
|
||||||
|
mockUserPublicKeyEncryptedUserKey,
|
||||||
|
);
|
||||||
|
|
||||||
emergencyAccessApiService.postEmergencyAccessConfirm.mockResolvedValueOnce();
|
emergencyAccessApiService.postEmergencyAccessConfirm.mockResolvedValueOnce();
|
||||||
|
|
||||||
@@ -160,7 +162,9 @@ describe("EmergencyAccessService", () => {
|
|||||||
|
|
||||||
const mockDecryptedGrantorUserKey = new Uint8Array(64);
|
const mockDecryptedGrantorUserKey = new Uint8Array(64);
|
||||||
keyService.getPrivateKey.mockResolvedValue(new Uint8Array(64));
|
keyService.getPrivateKey.mockResolvedValue(new Uint8Array(64));
|
||||||
encryptService.rsaDecrypt.mockResolvedValueOnce(mockDecryptedGrantorUserKey);
|
encryptService.decapsulateKeyUnsigned.mockResolvedValueOnce(
|
||||||
|
new SymmetricCryptoKey(mockDecryptedGrantorUserKey),
|
||||||
|
);
|
||||||
|
|
||||||
const mockMasterKey = new SymmetricCryptoKey(new Uint8Array(64) as CsprngArray) as MasterKey;
|
const mockMasterKey = new SymmetricCryptoKey(new Uint8Array(64) as CsprngArray) as MasterKey;
|
||||||
|
|
||||||
@@ -253,7 +257,7 @@ describe("EmergencyAccessService", () => {
|
|||||||
publicKey: Utils.fromUtf8ToB64("trustedPublicKey"),
|
publicKey: Utils.fromUtf8ToB64("trustedPublicKey"),
|
||||||
} as UserKeyResponse);
|
} as UserKeyResponse);
|
||||||
|
|
||||||
encryptService.rsaEncrypt.mockImplementation((plainValue, publicKey) => {
|
encryptService.encapsulateKeyUnsigned.mockImplementation((plainValue, publicKey) => {
|
||||||
return Promise.resolve(
|
return Promise.resolve(
|
||||||
new EncString(EncryptionType.Rsa2048_OaepSha1_B64, "Encrypted: " + plainValue),
|
new EncString(EncryptionType.Rsa2048_OaepSha1_B64, "Encrypted: " + plainValue),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import { ConfigService } from "@bitwarden/common/platform/abstractions/config/co
|
|||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { EncryptedString, EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
import { EncryptedString, EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
import { UserKey } from "@bitwarden/common/types/key";
|
import { UserKey } from "@bitwarden/common/types/key";
|
||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
@@ -234,11 +233,10 @@ export class EmergencyAccessService
|
|||||||
throw new Error("Active user does not have a private key, cannot get view only ciphers.");
|
throw new Error("Active user does not have a private key, cannot get view only ciphers.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const grantorKeyBuffer = await this.encryptService.rsaDecrypt(
|
const grantorUserKey = (await this.encryptService.decapsulateKeyUnsigned(
|
||||||
new EncString(response.keyEncrypted),
|
new EncString(response.keyEncrypted),
|
||||||
activeUserPrivateKey,
|
activeUserPrivateKey,
|
||||||
);
|
)) as UserKey;
|
||||||
const grantorUserKey = new SymmetricCryptoKey(grantorKeyBuffer) as UserKey;
|
|
||||||
|
|
||||||
let ciphers: CipherView[] = [];
|
let ciphers: CipherView[] = [];
|
||||||
if (await this.configService.getFeatureFlag(FeatureFlag.PM4154_BulkEncryptionService)) {
|
if (await this.configService.getFeatureFlag(FeatureFlag.PM4154_BulkEncryptionService)) {
|
||||||
@@ -271,15 +269,15 @@ export class EmergencyAccessService
|
|||||||
throw new Error("Active user does not have a private key, cannot complete a takeover.");
|
throw new Error("Active user does not have a private key, cannot complete a takeover.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const grantorKeyBuffer = await this.encryptService.rsaDecrypt(
|
const grantorKey = await this.encryptService.decapsulateKeyUnsigned(
|
||||||
new EncString(takeoverResponse.keyEncrypted),
|
new EncString(takeoverResponse.keyEncrypted),
|
||||||
activeUserPrivateKey,
|
activeUserPrivateKey,
|
||||||
);
|
);
|
||||||
if (grantorKeyBuffer == null) {
|
if (grantorKey == null) {
|
||||||
throw new Error("Failed to decrypt grantor key");
|
throw new Error("Failed to decrypt grantor key");
|
||||||
}
|
}
|
||||||
|
|
||||||
const grantorUserKey = new SymmetricCryptoKey(grantorKeyBuffer) as UserKey;
|
const grantorUserKey = grantorKey as UserKey;
|
||||||
|
|
||||||
let config: KdfConfig;
|
let config: KdfConfig;
|
||||||
|
|
||||||
@@ -407,6 +405,6 @@ export class EmergencyAccessService
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async encryptKey(userKey: UserKey, publicKey: Uint8Array): Promise<EncryptedString> {
|
private async encryptKey(userKey: UserKey, publicKey: Uint8Array): Promise<EncryptedString> {
|
||||||
return (await this.encryptService.rsaEncrypt(userKey.key, publicKey)).encryptedString;
|
return (await this.encryptService.encapsulateKeyUnsigned(userKey, publicKey)).encryptedString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ describe("AcceptOrganizationInviteService", () => {
|
|||||||
);
|
);
|
||||||
accountService.activeAccount$ = new BehaviorSubject({ id: "activeUserId" }) as any;
|
accountService.activeAccount$ = new BehaviorSubject({ id: "activeUserId" }) as any;
|
||||||
keyService.userKey$.mockReturnValue(new BehaviorSubject({ key: "userKey" } as any));
|
keyService.userKey$.mockReturnValue(new BehaviorSubject({ key: "userKey" } as any));
|
||||||
encryptService.rsaEncrypt.mockResolvedValue({
|
encryptService.encapsulateKeyUnsigned.mockResolvedValue({
|
||||||
encryptedString: "encryptedString",
|
encryptedString: "encryptedString",
|
||||||
} as EncString);
|
} as EncString);
|
||||||
|
|
||||||
@@ -218,8 +218,8 @@ describe("AcceptOrganizationInviteService", () => {
|
|||||||
|
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
expect(OrganizationTrustComponent.open).toHaveBeenCalled();
|
expect(OrganizationTrustComponent.open).toHaveBeenCalled();
|
||||||
expect(encryptService.rsaEncrypt).toHaveBeenCalledWith(
|
expect(encryptService.encapsulateKeyUnsigned).toHaveBeenCalledWith(
|
||||||
"userKey",
|
{ key: "userKey" },
|
||||||
Utils.fromB64ToArray("publicKey"),
|
Utils.fromB64ToArray("publicKey"),
|
||||||
);
|
);
|
||||||
expect(organizationUserApiService.postOrganizationUserAccept).toHaveBeenCalled();
|
expect(organizationUserApiService.postOrganizationUserAccept).toHaveBeenCalled();
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ export class AcceptOrganizationInviteService {
|
|||||||
const activeUserId = (await firstValueFrom(this.accountService.activeAccount$)).id;
|
const activeUserId = (await firstValueFrom(this.accountService.activeAccount$)).id;
|
||||||
const userKey = await firstValueFrom(this.keyService.userKey$(activeUserId));
|
const userKey = await firstValueFrom(this.keyService.userKey$(activeUserId));
|
||||||
// RSA Encrypt user's encKey.key with organization public key
|
// RSA Encrypt user's encKey.key with organization public key
|
||||||
const encryptedKey = await this.encryptService.rsaEncrypt(userKey.key, publicKey);
|
const encryptedKey = await this.encryptService.encapsulateKeyUnsigned(userKey, publicKey);
|
||||||
|
|
||||||
// Add reset password key to accept request
|
// Add reset password key to accept request
|
||||||
request.resetPasswordKey = encryptedKey.encryptedString;
|
request.resetPasswordKey = encryptedKey.encryptedString;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||||
import { ListResponse } from "@bitwarden/common/models/response/list.response";
|
import { ListResponse } from "@bitwarden/common/models/response/list.response";
|
||||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||||
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
import { KeyService } from "@bitwarden/key-management";
|
import { KeyService } from "@bitwarden/key-management";
|
||||||
|
|
||||||
import { OrganizationAuthRequestApiService } from "./organization-auth-request-api.service";
|
import { OrganizationAuthRequestApiService } from "./organization-auth-request-api.service";
|
||||||
@@ -124,8 +125,10 @@ describe("OrganizationAuthRequestService", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const encryptedUserKey = new EncString("encryptedUserKey");
|
const encryptedUserKey = new EncString("encryptedUserKey");
|
||||||
encryptService.rsaDecrypt.mockResolvedValue(new Uint8Array(32));
|
encryptService.decapsulateKeyUnsigned.mockResolvedValue(
|
||||||
encryptService.rsaEncrypt.mockResolvedValue(encryptedUserKey);
|
new SymmetricCryptoKey(new Uint8Array(32)),
|
||||||
|
);
|
||||||
|
encryptService.encapsulateKeyUnsigned.mockResolvedValue(encryptedUserKey);
|
||||||
|
|
||||||
const mockPendingAuthRequest = new PendingAuthRequestView();
|
const mockPendingAuthRequest = new PendingAuthRequestView();
|
||||||
mockPendingAuthRequest.id = "requestId1";
|
mockPendingAuthRequest.id = "requestId1";
|
||||||
@@ -166,8 +169,10 @@ describe("OrganizationAuthRequestService", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const encryptedUserKey = new EncString("encryptedUserKey");
|
const encryptedUserKey = new EncString("encryptedUserKey");
|
||||||
encryptService.rsaDecrypt.mockResolvedValue(new Uint8Array(32));
|
encryptService.decapsulateKeyUnsigned.mockResolvedValue(
|
||||||
encryptService.rsaEncrypt.mockResolvedValue(encryptedUserKey);
|
new SymmetricCryptoKey(new Uint8Array(32)),
|
||||||
|
);
|
||||||
|
encryptService.encapsulateKeyUnsigned.mockResolvedValue(encryptedUserKey);
|
||||||
|
|
||||||
const mockPendingAuthRequest = new PendingAuthRequestView();
|
const mockPendingAuthRequest = new PendingAuthRequestView();
|
||||||
mockPendingAuthRequest.id = "requestId1";
|
mockPendingAuthRequest.id = "requestId1";
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
|
||||||
import { KeyService } from "@bitwarden/key-management";
|
import { KeyService } from "@bitwarden/key-management";
|
||||||
|
|
||||||
import { OrganizationAuthRequestApiService } from "./organization-auth-request-api.service";
|
import { OrganizationAuthRequestApiService } from "./organization-auth-request-api.service";
|
||||||
@@ -119,13 +118,12 @@ export class OrganizationAuthRequestService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Decrypt user key with decrypted org private key
|
// Decrypt user key with decrypted org private key
|
||||||
const decValue = await this.encryptService.rsaDecrypt(
|
const userKey = await this.encryptService.decapsulateKeyUnsigned(
|
||||||
new EncString(encryptedUserKey),
|
new EncString(encryptedUserKey),
|
||||||
decOrgPrivateKey,
|
decOrgPrivateKey,
|
||||||
);
|
);
|
||||||
const userKey = new SymmetricCryptoKey(decValue);
|
|
||||||
|
|
||||||
// Re-encrypt user Key with the Device Public Key
|
// Re-encrypt user Key with the Device Public Key
|
||||||
return await this.encryptService.rsaEncrypt(userKey.key, devicePubKey);
|
return await this.encryptService.encapsulateKeyUnsigned(userKey, devicePubKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ export class MembersComponent extends BaseMembersComponent<ProviderUser> {
|
|||||||
|
|
||||||
async confirmUser(user: ProviderUser, publicKey: Uint8Array): Promise<void> {
|
async confirmUser(user: ProviderUser, publicKey: Uint8Array): Promise<void> {
|
||||||
const providerKey = await this.keyService.getProviderKey(this.providerId);
|
const providerKey = await this.keyService.getProviderKey(this.providerId);
|
||||||
const key = await this.encryptService.rsaEncrypt(providerKey.key, publicKey);
|
const key = await this.encryptService.encapsulateKeyUnsigned(providerKey, publicKey);
|
||||||
const request = new ProviderUserConfirmRequest();
|
const request = new ProviderUserConfirmRequest();
|
||||||
request.key = key.encryptedString;
|
request.key = key.encryptedString;
|
||||||
await this.apiService.postProviderUserConfirm(this.providerId, user.id, request);
|
await this.apiService.postProviderUserConfirm(this.providerId, user.id, request);
|
||||||
|
|||||||
@@ -211,7 +211,10 @@ export class SetPasswordComponent extends BaseChangePasswordComponent implements
|
|||||||
|
|
||||||
// RSA Encrypt user key with organization public key
|
// RSA Encrypt user key with organization public key
|
||||||
const userKey = await this.keyService.getUserKey();
|
const userKey = await this.keyService.getUserKey();
|
||||||
const encryptedUserKey = await this.encryptService.rsaEncrypt(userKey.key, publicKey);
|
const encryptedUserKey = await this.encryptService.encapsulateKeyUnsigned(
|
||||||
|
userKey,
|
||||||
|
publicKey,
|
||||||
|
);
|
||||||
|
|
||||||
const resetRequest = new OrganizationUserResetPasswordEnrollmentRequest();
|
const resetRequest = new OrganizationUserResetPasswordEnrollmentRequest();
|
||||||
resetRequest.masterPasswordHash = masterPasswordHash;
|
resetRequest.masterPasswordHash = masterPasswordHash;
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ describe("DefaultSetPasswordJitService", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
keyService.userKey$.mockReturnValue(of(userKey));
|
keyService.userKey$.mockReturnValue(of(userKey));
|
||||||
encryptService.rsaEncrypt.mockResolvedValue(userKeyEncString);
|
encryptService.encapsulateKeyUnsigned.mockResolvedValue(userKeyEncString);
|
||||||
|
|
||||||
organizationUserApiService.putOrganizationUserResetPasswordEnrollment.mockResolvedValue(
|
organizationUserApiService.putOrganizationUserResetPasswordEnrollment.mockResolvedValue(
|
||||||
undefined,
|
undefined,
|
||||||
@@ -216,7 +216,7 @@ describe("DefaultSetPasswordJitService", () => {
|
|||||||
// Assert
|
// Assert
|
||||||
expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest);
|
expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest);
|
||||||
expect(organizationApiService.getKeys).toHaveBeenCalledWith(orgId);
|
expect(organizationApiService.getKeys).toHaveBeenCalledWith(orgId);
|
||||||
expect(encryptService.rsaEncrypt).toHaveBeenCalledWith(userKey.key, orgPublicKey);
|
expect(encryptService.encapsulateKeyUnsigned).toHaveBeenCalledWith(userKey, orgPublicKey);
|
||||||
expect(
|
expect(
|
||||||
organizationUserApiService.putOrganizationUserResetPasswordEnrollment,
|
organizationUserApiService.putOrganizationUserResetPasswordEnrollment,
|
||||||
).toHaveBeenCalled();
|
).toHaveBeenCalled();
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ export class DefaultSetPasswordJitService implements SetPasswordJitService {
|
|||||||
throw new Error("userKey not found. Could not handle reset password auto enroll.");
|
throw new Error("userKey not found. Could not handle reset password auto enroll.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const encryptedUserKey = await this.encryptService.rsaEncrypt(userKey.key, publicKey);
|
const encryptedUserKey = await this.encryptService.encapsulateKeyUnsigned(userKey, publicKey);
|
||||||
|
|
||||||
const resetRequest = new OrganizationUserResetPasswordEnrollmentRequest();
|
const resetRequest = new OrganizationUserResetPasswordEnrollmentRequest();
|
||||||
resetRequest.masterPasswordHash = masterKeyHash;
|
resetRequest.masterPasswordHash = masterKeyHash;
|
||||||
|
|||||||
@@ -231,7 +231,9 @@ describe("WebAuthnLoginStrategy", () => {
|
|||||||
const mockUserKey = new SymmetricCryptoKey(mockUserKeyArray) as UserKey;
|
const mockUserKey = new SymmetricCryptoKey(mockUserKeyArray) as UserKey;
|
||||||
|
|
||||||
encryptService.decryptToBytes.mockResolvedValue(mockPrfPrivateKey);
|
encryptService.decryptToBytes.mockResolvedValue(mockPrfPrivateKey);
|
||||||
encryptService.rsaDecrypt.mockResolvedValue(mockUserKeyArray);
|
encryptService.decapsulateKeyUnsigned.mockResolvedValue(
|
||||||
|
new SymmetricCryptoKey(mockUserKeyArray),
|
||||||
|
);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await webAuthnLoginStrategy.logIn(webAuthnCredentials);
|
await webAuthnLoginStrategy.logIn(webAuthnCredentials);
|
||||||
@@ -249,8 +251,8 @@ describe("WebAuthnLoginStrategy", () => {
|
|||||||
idTokenResponse.userDecryptionOptions.webAuthnPrfOption.encryptedPrivateKey,
|
idTokenResponse.userDecryptionOptions.webAuthnPrfOption.encryptedPrivateKey,
|
||||||
webAuthnCredentials.prfKey,
|
webAuthnCredentials.prfKey,
|
||||||
);
|
);
|
||||||
expect(encryptService.rsaDecrypt).toHaveBeenCalledTimes(1);
|
expect(encryptService.decapsulateKeyUnsigned).toHaveBeenCalledTimes(1);
|
||||||
expect(encryptService.rsaDecrypt).toHaveBeenCalledWith(
|
expect(encryptService.decapsulateKeyUnsigned).toHaveBeenCalledWith(
|
||||||
idTokenResponse.userDecryptionOptions.webAuthnPrfOption.encryptedUserKey,
|
idTokenResponse.userDecryptionOptions.webAuthnPrfOption.encryptedUserKey,
|
||||||
mockPrfPrivateKey,
|
mockPrfPrivateKey,
|
||||||
);
|
);
|
||||||
@@ -278,7 +280,7 @@ describe("WebAuthnLoginStrategy", () => {
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(encryptService.decryptToBytes).not.toHaveBeenCalled();
|
expect(encryptService.decryptToBytes).not.toHaveBeenCalled();
|
||||||
expect(encryptService.rsaDecrypt).not.toHaveBeenCalled();
|
expect(encryptService.decapsulateKeyUnsigned).not.toHaveBeenCalled();
|
||||||
expect(keyService.setUserKey).not.toHaveBeenCalled();
|
expect(keyService.setUserKey).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -330,7 +332,7 @@ describe("WebAuthnLoginStrategy", () => {
|
|||||||
|
|
||||||
apiService.postIdentityToken.mockResolvedValue(idTokenResponse);
|
apiService.postIdentityToken.mockResolvedValue(idTokenResponse);
|
||||||
|
|
||||||
encryptService.rsaDecrypt.mockResolvedValue(null);
|
encryptService.decapsulateKeyUnsigned.mockResolvedValue(null);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await webAuthnLoginStrategy.logIn(webAuthnCredentials);
|
await webAuthnLoginStrategy.logIn(webAuthnCredentials);
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
|||||||
import { WebAuthnLoginTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/webauthn-login-token.request";
|
import { WebAuthnLoginTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/webauthn-login-token.request";
|
||||||
import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response";
|
import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response";
|
||||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
import { UserKey } from "@bitwarden/common/types/key";
|
import { UserKey } from "@bitwarden/common/types/key";
|
||||||
|
|
||||||
@@ -89,13 +88,13 @@ export class WebAuthnLoginStrategy extends LoginStrategy {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// decrypt user key with private key
|
// decrypt user key with private key
|
||||||
const userKey = await this.encryptService.rsaDecrypt(
|
const userKey = await this.encryptService.decapsulateKeyUnsigned(
|
||||||
new EncString(webAuthnPrfOption.encryptedUserKey.encryptedString),
|
new EncString(webAuthnPrfOption.encryptedUserKey.encryptedString),
|
||||||
privateKey,
|
privateKey,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (userKey) {
|
if (userKey) {
|
||||||
await this.keyService.setUserKey(new SymmetricCryptoKey(userKey) as UserKey, userId);
|
await this.keyService.setUserKey(userKey as UserKey, userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,6 +88,9 @@ describe("AuthRequestService", () => {
|
|||||||
encryptService.rsaEncrypt.mockResolvedValue({
|
encryptService.rsaEncrypt.mockResolvedValue({
|
||||||
encryptedString: "ENCRYPTED_STRING",
|
encryptedString: "ENCRYPTED_STRING",
|
||||||
} as EncString);
|
} as EncString);
|
||||||
|
encryptService.encapsulateKeyUnsigned.mockResolvedValue({
|
||||||
|
encryptedString: "ENCRYPTED_STRING",
|
||||||
|
} as EncString);
|
||||||
appIdService.getAppId.mockResolvedValue("APP_ID");
|
appIdService.getAppId.mockResolvedValue("APP_ID");
|
||||||
});
|
});
|
||||||
it("should throw if auth request is missing id or key", async () => {
|
it("should throw if auth request is missing id or key", async () => {
|
||||||
@@ -111,7 +114,10 @@ describe("AuthRequestService", () => {
|
|||||||
new AuthRequestResponse({ id: "123", publicKey: "KEY" }),
|
new AuthRequestResponse({ id: "123", publicKey: "KEY" }),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(encryptService.rsaEncrypt).toHaveBeenCalledWith(new Uint8Array(64), expect.anything());
|
expect(encryptService.encapsulateKeyUnsigned).toHaveBeenCalledWith(
|
||||||
|
{ encKey: new Uint8Array(64) },
|
||||||
|
expect.anything(),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should use the user key if the master key and hash do not exist", async () => {
|
it("should use the user key if the master key and hash do not exist", async () => {
|
||||||
@@ -122,7 +128,10 @@ describe("AuthRequestService", () => {
|
|||||||
new AuthRequestResponse({ id: "123", publicKey: "KEY" }),
|
new AuthRequestResponse({ id: "123", publicKey: "KEY" }),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(encryptService.rsaEncrypt).toHaveBeenCalledWith(new Uint8Array(64), expect.anything());
|
expect(encryptService.encapsulateKeyUnsigned).toHaveBeenCalledWith(
|
||||||
|
{ key: new Uint8Array(64) },
|
||||||
|
expect.anything(),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe("setUserKeyAfterDecryptingSharedUserKey", () => {
|
describe("setUserKeyAfterDecryptingSharedUserKey", () => {
|
||||||
@@ -214,7 +223,9 @@ describe("AuthRequestService", () => {
|
|||||||
const mockDecryptedUserKeyBytes = new Uint8Array(64);
|
const mockDecryptedUserKeyBytes = new Uint8Array(64);
|
||||||
const mockDecryptedUserKey = new SymmetricCryptoKey(mockDecryptedUserKeyBytes) as UserKey;
|
const mockDecryptedUserKey = new SymmetricCryptoKey(mockDecryptedUserKeyBytes) as UserKey;
|
||||||
|
|
||||||
encryptService.rsaDecrypt.mockResolvedValueOnce(mockDecryptedUserKeyBytes);
|
encryptService.decapsulateKeyUnsigned.mockResolvedValueOnce(
|
||||||
|
new SymmetricCryptoKey(mockDecryptedUserKeyBytes),
|
||||||
|
);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const result = await sut.decryptPubKeyEncryptedUserKey(
|
const result = await sut.decryptPubKeyEncryptedUserKey(
|
||||||
@@ -223,7 +234,7 @@ describe("AuthRequestService", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(encryptService.rsaDecrypt).toBeCalledWith(
|
expect(encryptService.decapsulateKeyUnsigned).toBeCalledWith(
|
||||||
new EncString(mockPubKeyEncryptedUserKey),
|
new EncString(mockPubKeyEncryptedUserKey),
|
||||||
mockPrivateKey,
|
mockPrivateKey,
|
||||||
);
|
);
|
||||||
@@ -244,9 +255,10 @@ describe("AuthRequestService", () => {
|
|||||||
const mockDecryptedMasterKeyHashBytes = new Uint8Array(64);
|
const mockDecryptedMasterKeyHashBytes = new Uint8Array(64);
|
||||||
const mockDecryptedMasterKeyHash = Utils.fromBufferToUtf8(mockDecryptedMasterKeyHashBytes);
|
const mockDecryptedMasterKeyHash = Utils.fromBufferToUtf8(mockDecryptedMasterKeyHashBytes);
|
||||||
|
|
||||||
encryptService.rsaDecrypt
|
encryptService.rsaDecrypt.mockResolvedValueOnce(mockDecryptedMasterKeyHashBytes);
|
||||||
.mockResolvedValueOnce(mockDecryptedMasterKeyBytes)
|
encryptService.decapsulateKeyUnsigned.mockResolvedValueOnce(
|
||||||
.mockResolvedValueOnce(mockDecryptedMasterKeyHashBytes);
|
new SymmetricCryptoKey(mockDecryptedMasterKeyBytes),
|
||||||
|
);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const result = await sut.decryptPubKeyEncryptedMasterKeyAndHash(
|
const result = await sut.decryptPubKeyEncryptedMasterKeyAndHash(
|
||||||
@@ -256,13 +268,11 @@ describe("AuthRequestService", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(encryptService.rsaDecrypt).toHaveBeenNthCalledWith(
|
expect(encryptService.decapsulateKeyUnsigned).toHaveBeenCalledWith(
|
||||||
1,
|
|
||||||
new EncString(mockPubKeyEncryptedMasterKey),
|
new EncString(mockPubKeyEncryptedMasterKey),
|
||||||
mockPrivateKey,
|
mockPrivateKey,
|
||||||
);
|
);
|
||||||
expect(encryptService.rsaDecrypt).toHaveBeenNthCalledWith(
|
expect(encryptService.rsaDecrypt).toHaveBeenCalledWith(
|
||||||
2,
|
|
||||||
new EncString(mockPubKeyEncryptedMasterKeyHash),
|
new EncString(mockPubKeyEncryptedMasterKeyHash),
|
||||||
mockPrivateKey,
|
mockPrivateKey,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import { AuthRequestPushNotification } from "@bitwarden/common/models/response/n
|
|||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
|
||||||
import {
|
import {
|
||||||
AUTH_REQUEST_DISK_LOCAL,
|
AUTH_REQUEST_DISK_LOCAL,
|
||||||
StateProvider,
|
StateProvider,
|
||||||
@@ -116,13 +115,12 @@ export class AuthRequestService implements AuthRequestServiceAbstraction {
|
|||||||
Utils.fromUtf8ToArray(masterKeyHash),
|
Utils.fromUtf8ToArray(masterKeyHash),
|
||||||
pubKey,
|
pubKey,
|
||||||
);
|
);
|
||||||
keyToEncrypt = masterKey.encKey;
|
keyToEncrypt = masterKey;
|
||||||
} else {
|
} else {
|
||||||
const userKey = await this.keyService.getUserKey();
|
keyToEncrypt = await this.keyService.getUserKey();
|
||||||
keyToEncrypt = userKey.key;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const encryptedKey = await this.encryptService.rsaEncrypt(keyToEncrypt, pubKey);
|
const encryptedKey = await this.encryptService.encapsulateKeyUnsigned(keyToEncrypt, pubKey);
|
||||||
|
|
||||||
const response = new PasswordlessAuthRequest(
|
const response = new PasswordlessAuthRequest(
|
||||||
encryptedKey.encryptedString,
|
encryptedKey.encryptedString,
|
||||||
@@ -171,12 +169,10 @@ export class AuthRequestService implements AuthRequestServiceAbstraction {
|
|||||||
pubKeyEncryptedUserKey: string,
|
pubKeyEncryptedUserKey: string,
|
||||||
privateKey: Uint8Array,
|
privateKey: Uint8Array,
|
||||||
): Promise<UserKey> {
|
): Promise<UserKey> {
|
||||||
const decryptedUserKeyBytes = await this.encryptService.rsaDecrypt(
|
return (await this.encryptService.decapsulateKeyUnsigned(
|
||||||
new EncString(pubKeyEncryptedUserKey),
|
new EncString(pubKeyEncryptedUserKey),
|
||||||
privateKey,
|
privateKey,
|
||||||
);
|
)) as UserKey;
|
||||||
|
|
||||||
return new SymmetricCryptoKey(decryptedUserKeyBytes) as UserKey;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async decryptPubKeyEncryptedMasterKeyAndHash(
|
async decryptPubKeyEncryptedMasterKeyAndHash(
|
||||||
@@ -184,17 +180,15 @@ export class AuthRequestService implements AuthRequestServiceAbstraction {
|
|||||||
pubKeyEncryptedMasterKeyHash: string,
|
pubKeyEncryptedMasterKeyHash: string,
|
||||||
privateKey: Uint8Array,
|
privateKey: Uint8Array,
|
||||||
): Promise<{ masterKey: MasterKey; masterKeyHash: string }> {
|
): Promise<{ masterKey: MasterKey; masterKeyHash: string }> {
|
||||||
const decryptedMasterKeyArrayBuffer = await this.encryptService.rsaDecrypt(
|
const masterKey = (await this.encryptService.decapsulateKeyUnsigned(
|
||||||
new EncString(pubKeyEncryptedMasterKey),
|
new EncString(pubKeyEncryptedMasterKey),
|
||||||
privateKey,
|
privateKey,
|
||||||
);
|
)) as MasterKey;
|
||||||
|
|
||||||
const decryptedMasterKeyHashArrayBuffer = await this.encryptService.rsaDecrypt(
|
const decryptedMasterKeyHashArrayBuffer = await this.encryptService.rsaDecrypt(
|
||||||
new EncString(pubKeyEncryptedMasterKeyHash),
|
new EncString(pubKeyEncryptedMasterKeyHash),
|
||||||
privateKey,
|
privateKey,
|
||||||
);
|
);
|
||||||
|
|
||||||
const masterKey = new SymmetricCryptoKey(decryptedMasterKeyArrayBuffer) as MasterKey;
|
|
||||||
const masterKeyHash = Utils.fromBufferToUtf8(decryptedMasterKeyHashArrayBuffer);
|
const masterKeyHash = Utils.fromBufferToUtf8(decryptedMasterKeyHashArrayBuffer);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -31,8 +31,10 @@ export class EncryptedOrganizationKey implements BaseEncryptedOrganizationKey {
|
|||||||
constructor(private key: string) {}
|
constructor(private key: string) {}
|
||||||
|
|
||||||
async decrypt(encryptService: EncryptService, privateKey: UserPrivateKey) {
|
async decrypt(encryptService: EncryptService, privateKey: UserPrivateKey) {
|
||||||
const decValue = await encryptService.rsaDecrypt(this.encryptedOrganizationKey, privateKey);
|
return (await encryptService.decapsulateKeyUnsigned(
|
||||||
return new SymmetricCryptoKey(decValue) as OrgKey;
|
this.encryptedOrganizationKey,
|
||||||
|
privateKey,
|
||||||
|
)) as OrgKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
get encryptedOrganizationKey() {
|
get encryptedOrganizationKey() {
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ describe("PasswordResetEnrollmentServiceImplementation", () => {
|
|||||||
activeAccountSubject.next(Object.assign(user1AccountInfo, { id: "userId" as UserId }));
|
activeAccountSubject.next(Object.assign(user1AccountInfo, { id: "userId" as UserId }));
|
||||||
|
|
||||||
keyService.getUserKey.mockResolvedValue({ key: "key" } as any);
|
keyService.getUserKey.mockResolvedValue({ key: "key" } as any);
|
||||||
encryptService.rsaEncrypt.mockResolvedValue(encryptedKey as any);
|
encryptService.encapsulateKeyUnsigned.mockResolvedValue(encryptedKey as any);
|
||||||
|
|
||||||
await service.enroll("orgId");
|
await service.enroll("orgId");
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ describe("PasswordResetEnrollmentServiceImplementation", () => {
|
|||||||
};
|
};
|
||||||
const encryptedKey = { encryptedString: "encryptedString" };
|
const encryptedKey = { encryptedString: "encryptedString" };
|
||||||
organizationApiService.getKeys.mockResolvedValue(orgKeyResponse as any);
|
organizationApiService.getKeys.mockResolvedValue(orgKeyResponse as any);
|
||||||
encryptService.rsaEncrypt.mockResolvedValue(encryptedKey as any);
|
encryptService.encapsulateKeyUnsigned.mockResolvedValue(encryptedKey as any);
|
||||||
|
|
||||||
await service.enroll("orgId", "userId", { key: "key" } as any);
|
await service.enroll("orgId", "userId", { key: "key" } as any);
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export class PasswordResetEnrollmentServiceImplementation
|
|||||||
userId ?? (await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id))));
|
userId ?? (await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id))));
|
||||||
userKey = userKey ?? (await this.keyService.getUserKey(userId));
|
userKey = userKey ?? (await this.keyService.getUserKey(userId));
|
||||||
// RSA Encrypt user's userKey.key with organization public key
|
// RSA Encrypt user's userKey.key with organization public key
|
||||||
const encryptedKey = await this.encryptService.rsaEncrypt(userKey.key, orgPublicKey);
|
const encryptedKey = await this.encryptService.encapsulateKeyUnsigned(userKey, orgPublicKey);
|
||||||
|
|
||||||
const resetRequest = new OrganizationUserResetPasswordEnrollmentRequest();
|
const resetRequest = new OrganizationUserResetPasswordEnrollmentRequest();
|
||||||
resetRequest.resetPasswordKey = encryptedKey.encryptedString;
|
resetRequest.resetPasswordKey = encryptedKey.encryptedString;
|
||||||
|
|||||||
@@ -35,7 +35,38 @@ export abstract class EncryptService {
|
|||||||
key: SymmetricCryptoKey,
|
key: SymmetricCryptoKey,
|
||||||
decryptTrace?: string,
|
decryptTrace?: string,
|
||||||
): Promise<Uint8Array | null>;
|
): Promise<Uint8Array | null>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates a symmetric key with an asymmetric public key
|
||||||
|
* Note: This does not establish sender authenticity
|
||||||
|
* @param sharedKey - The symmetric key that is to be shared
|
||||||
|
* @param encapsulationKey - The encapsulation key (public key) of the receiver that the key is shared with
|
||||||
|
*/
|
||||||
|
abstract encapsulateKeyUnsigned(
|
||||||
|
sharedKey: SymmetricCryptoKey,
|
||||||
|
encapsulationKey: Uint8Array,
|
||||||
|
): Promise<EncString>;
|
||||||
|
/**
|
||||||
|
* Decapsulates a shared symmetric key with an asymmetric private key
|
||||||
|
* Note: This does not establish sender authenticity
|
||||||
|
* @param encryptedSharedKey - The encrypted shared symmetric key
|
||||||
|
* @param decapsulationKey - The key to decapsulate with (private key)
|
||||||
|
*/
|
||||||
|
abstract decapsulateKeyUnsigned(
|
||||||
|
encryptedSharedKey: EncString,
|
||||||
|
decapsulationKey: Uint8Array,
|
||||||
|
): Promise<SymmetricCryptoKey>;
|
||||||
|
/**
|
||||||
|
* @deprecated Use encapsulateKeyUnsigned instead
|
||||||
|
* @param data - The data to encrypt
|
||||||
|
* @param publicKey - The public key to encrypt with
|
||||||
|
*/
|
||||||
abstract rsaEncrypt(data: Uint8Array, publicKey: Uint8Array): Promise<EncString>;
|
abstract rsaEncrypt(data: Uint8Array, publicKey: Uint8Array): Promise<EncString>;
|
||||||
|
/**
|
||||||
|
* @deprecated Use decapsulateKeyUnsigned instead
|
||||||
|
* @param data - The ciphertext to decrypt
|
||||||
|
* @param privateKey - The privateKey to decrypt with
|
||||||
|
*/
|
||||||
abstract rsaDecrypt(data: EncString, privateKey: Uint8Array): Promise<Uint8Array>;
|
abstract rsaDecrypt(data: EncString, privateKey: Uint8Array): Promise<Uint8Array>;
|
||||||
/**
|
/**
|
||||||
* @deprecated Replaced by BulkEncryptService, remove once the feature is tested and the featureflag PM-4154-multi-worker-encryption-service is removed
|
* @deprecated Replaced by BulkEncryptService, remove once the feature is tested and the featureflag PM-4154-multi-worker-encryption-service is removed
|
||||||
|
|||||||
@@ -235,42 +235,22 @@ export class EncryptServiceImplementation implements EncryptService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async rsaEncrypt(data: Uint8Array, publicKey: Uint8Array): Promise<EncString> {
|
async encapsulateKeyUnsigned(
|
||||||
if (data == null) {
|
sharedKey: SymmetricCryptoKey,
|
||||||
throw new Error("No data provided for encryption.");
|
encapsulationKey: Uint8Array,
|
||||||
|
): Promise<EncString> {
|
||||||
|
if (sharedKey == null) {
|
||||||
|
throw new Error("No sharedKey provided for encapsulation");
|
||||||
}
|
}
|
||||||
|
return await this.rsaEncrypt(sharedKey.toEncoded(), encapsulationKey);
|
||||||
if (publicKey == null) {
|
|
||||||
throw new Error("No public key provided for encryption.");
|
|
||||||
}
|
|
||||||
const encrypted = await this.cryptoFunctionService.rsaEncrypt(data, publicKey, "sha1");
|
|
||||||
return new EncString(EncryptionType.Rsa2048_OaepSha1_B64, Utils.fromBufferToB64(encrypted));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async rsaDecrypt(data: EncString, privateKey: Uint8Array): Promise<Uint8Array> {
|
async decapsulateKeyUnsigned(
|
||||||
if (data == null) {
|
encryptedSharedKey: EncString,
|
||||||
throw new Error("[Encrypt service] rsaDecrypt: No data provided for decryption.");
|
decapsulationKey: Uint8Array,
|
||||||
}
|
): Promise<SymmetricCryptoKey> {
|
||||||
|
const keyBytes = await this.rsaDecrypt(encryptedSharedKey, decapsulationKey);
|
||||||
let algorithm: "sha1" | "sha256";
|
return new SymmetricCryptoKey(keyBytes);
|
||||||
switch (data.encryptionType) {
|
|
||||||
case EncryptionType.Rsa2048_OaepSha1_B64:
|
|
||||||
case EncryptionType.Rsa2048_OaepSha1_HmacSha256_B64:
|
|
||||||
algorithm = "sha1";
|
|
||||||
break;
|
|
||||||
case EncryptionType.Rsa2048_OaepSha256_B64:
|
|
||||||
case EncryptionType.Rsa2048_OaepSha256_HmacSha256_B64:
|
|
||||||
algorithm = "sha256";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Error("Invalid encryption type.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (privateKey == null) {
|
|
||||||
throw new Error("[Encrypt service] rsaDecrypt: No private key provided for decryption.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.cryptoFunctionService.rsaDecrypt(data.dataBytes, privateKey, algorithm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -341,4 +321,42 @@ export class EncryptServiceImplementation implements EncryptService {
|
|||||||
this.logDecryptError(msg, keyEncType, dataEncType, decryptContext);
|
this.logDecryptError(msg, keyEncType, dataEncType, decryptContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async rsaEncrypt(data: Uint8Array, publicKey: Uint8Array): Promise<EncString> {
|
||||||
|
if (data == null) {
|
||||||
|
throw new Error("No data provided for encryption.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (publicKey == null) {
|
||||||
|
throw new Error("No public key provided for encryption.");
|
||||||
|
}
|
||||||
|
const encrypted = await this.cryptoFunctionService.rsaEncrypt(data, publicKey, "sha1");
|
||||||
|
return new EncString(EncryptionType.Rsa2048_OaepSha1_B64, Utils.fromBufferToB64(encrypted));
|
||||||
|
}
|
||||||
|
|
||||||
|
async rsaDecrypt(data: EncString, privateKey: Uint8Array): Promise<Uint8Array> {
|
||||||
|
if (data == null) {
|
||||||
|
throw new Error("[Encrypt service] rsaDecrypt: No data provided for decryption.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let algorithm: "sha1" | "sha256";
|
||||||
|
switch (data.encryptionType) {
|
||||||
|
case EncryptionType.Rsa2048_OaepSha1_B64:
|
||||||
|
case EncryptionType.Rsa2048_OaepSha1_HmacSha256_B64:
|
||||||
|
algorithm = "sha1";
|
||||||
|
break;
|
||||||
|
case EncryptionType.Rsa2048_OaepSha256_B64:
|
||||||
|
case EncryptionType.Rsa2048_OaepSha256_HmacSha256_B64:
|
||||||
|
algorithm = "sha256";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error("Invalid encryption type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (privateKey == null) {
|
||||||
|
throw new Error("[Encrypt service] rsaDecrypt: No private key provided for decryption.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.cryptoFunctionService.rsaDecrypt(data.dataBytes, privateKey, algorithm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -412,7 +412,8 @@ describe("EncryptService", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("rsa", () => {
|
describe("rsa", () => {
|
||||||
const data = makeStaticByteArray(10, 100);
|
const data = makeStaticByteArray(64, 100);
|
||||||
|
const testKey = new SymmetricCryptoKey(data);
|
||||||
const encryptedData = makeStaticByteArray(10, 150);
|
const encryptedData = makeStaticByteArray(10, 150);
|
||||||
const publicKey = makeStaticByteArray(10, 200);
|
const publicKey = makeStaticByteArray(10, 200);
|
||||||
const privateKey = makeStaticByteArray(10, 250);
|
const privateKey = makeStaticByteArray(10, 250);
|
||||||
@@ -422,22 +423,26 @@ describe("EncryptService", () => {
|
|||||||
return new EncString(EncryptionType.Rsa2048_OaepSha1_B64, Utils.fromBufferToB64(data));
|
return new EncString(EncryptionType.Rsa2048_OaepSha1_B64, Utils.fromBufferToB64(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("rsaEncrypt", () => {
|
describe("encapsulateKeyUnsigned", () => {
|
||||||
it("throws if no data is provided", () => {
|
it("throws if no data is provided", () => {
|
||||||
return expect(encryptService.rsaEncrypt(null, publicKey)).rejects.toThrow("No data");
|
return expect(encryptService.encapsulateKeyUnsigned(null, publicKey)).rejects.toThrow(
|
||||||
|
"No sharedKey provided for encapsulation",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("throws if no public key is provided", () => {
|
it("throws if no public key is provided", () => {
|
||||||
return expect(encryptService.rsaEncrypt(data, null)).rejects.toThrow("No public key");
|
return expect(encryptService.encapsulateKeyUnsigned(testKey, null)).rejects.toThrow(
|
||||||
|
"No public key",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("encrypts data with provided key", async () => {
|
it("encrypts data with provided key", async () => {
|
||||||
cryptoFunctionService.rsaEncrypt.mockResolvedValue(encryptedData);
|
cryptoFunctionService.rsaEncrypt.mockResolvedValue(encryptedData);
|
||||||
|
|
||||||
const actual = await encryptService.rsaEncrypt(data, publicKey);
|
const actual = await encryptService.encapsulateKeyUnsigned(testKey, publicKey);
|
||||||
|
|
||||||
expect(cryptoFunctionService.rsaEncrypt).toBeCalledWith(
|
expect(cryptoFunctionService.rsaEncrypt).toBeCalledWith(
|
||||||
expect.toEqualBuffer(data),
|
expect.toEqualBuffer(testKey.key),
|
||||||
expect.toEqualBuffer(publicKey),
|
expect.toEqualBuffer(publicKey),
|
||||||
"sha1",
|
"sha1",
|
||||||
);
|
);
|
||||||
@@ -447,13 +452,17 @@ describe("EncryptService", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("rsaDecrypt", () => {
|
describe("decapsulateKeyUnsigned", () => {
|
||||||
it("throws if no data is provided", () => {
|
it("throws if no data is provided", () => {
|
||||||
return expect(encryptService.rsaDecrypt(null, privateKey)).rejects.toThrow("No data");
|
return expect(encryptService.decapsulateKeyUnsigned(null, privateKey)).rejects.toThrow(
|
||||||
|
"No data",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("throws if no private key is provided", () => {
|
it("throws if no private key is provided", () => {
|
||||||
return expect(encryptService.rsaDecrypt(encString, null)).rejects.toThrow("No private key");
|
return expect(encryptService.decapsulateKeyUnsigned(encString, null)).rejects.toThrow(
|
||||||
|
"No private key",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each([EncryptionType.AesCbc256_B64, EncryptionType.AesCbc256_HmacSha256_B64])(
|
it.each([EncryptionType.AesCbc256_B64, EncryptionType.AesCbc256_HmacSha256_B64])(
|
||||||
@@ -461,16 +470,16 @@ describe("EncryptService", () => {
|
|||||||
async (encType) => {
|
async (encType) => {
|
||||||
encString.encryptionType = encType;
|
encString.encryptionType = encType;
|
||||||
|
|
||||||
await expect(encryptService.rsaDecrypt(encString, privateKey)).rejects.toThrow(
|
await expect(
|
||||||
"Invalid encryption type",
|
encryptService.decapsulateKeyUnsigned(encString, privateKey),
|
||||||
);
|
).rejects.toThrow("Invalid encryption type");
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
it("decrypts data with provided key", async () => {
|
it("decrypts data with provided key", async () => {
|
||||||
cryptoFunctionService.rsaDecrypt.mockResolvedValue(data);
|
cryptoFunctionService.rsaDecrypt.mockResolvedValue(data);
|
||||||
|
|
||||||
const actual = await encryptService.rsaDecrypt(makeEncString(data), privateKey);
|
const actual = await encryptService.decapsulateKeyUnsigned(makeEncString(data), privateKey);
|
||||||
|
|
||||||
expect(cryptoFunctionService.rsaDecrypt).toBeCalledWith(
|
expect(cryptoFunctionService.rsaDecrypt).toBeCalledWith(
|
||||||
expect.toEqualBuffer(data),
|
expect.toEqualBuffer(data),
|
||||||
@@ -478,7 +487,7 @@ describe("EncryptService", () => {
|
|||||||
"sha1",
|
"sha1",
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(actual).toEqualBuffer(data);
|
expect(actual.key).toEqualBuffer(data);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ export class DeviceTrustService implements DeviceTrustServiceAbstraction {
|
|||||||
deviceKeyEncryptedDevicePrivateKey,
|
deviceKeyEncryptedDevicePrivateKey,
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
// Encrypt user key with the DevicePublicKey
|
// Encrypt user key with the DevicePublicKey
|
||||||
this.encryptService.rsaEncrypt(userKey.key, devicePublicKey),
|
this.encryptService.encapsulateKeyUnsigned(userKey, devicePublicKey),
|
||||||
|
|
||||||
// Encrypt devicePublicKey with user key
|
// Encrypt devicePublicKey with user key
|
||||||
this.encryptService.encrypt(devicePublicKey, userKey),
|
this.encryptService.encrypt(devicePublicKey, userKey),
|
||||||
@@ -285,8 +285,8 @@ export class DeviceTrustService implements DeviceTrustServiceAbstraction {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Encrypt the brand new user key with the now-decrypted public key for the device
|
// Encrypt the brand new user key with the now-decrypted public key for the device
|
||||||
const encryptedNewUserKey = await this.encryptService.rsaEncrypt(
|
const encryptedNewUserKey = await this.encryptService.encapsulateKeyUnsigned(
|
||||||
newUserKey.key,
|
newUserKey,
|
||||||
decryptedDevicePublicKey,
|
decryptedDevicePublicKey,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -401,12 +401,12 @@ export class DeviceTrustService implements DeviceTrustServiceAbstraction {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Attempt to decrypt encryptedUserDataKey with devicePrivateKey
|
// Attempt to decrypt encryptedUserDataKey with devicePrivateKey
|
||||||
const userKey = await this.encryptService.rsaDecrypt(
|
const userKey = await this.encryptService.decapsulateKeyUnsigned(
|
||||||
new EncString(encryptedUserKey.encryptedString),
|
new EncString(encryptedUserKey.encryptedString),
|
||||||
devicePrivateKey,
|
devicePrivateKey,
|
||||||
);
|
);
|
||||||
|
|
||||||
return new SymmetricCryptoKey(userKey) as UserKey;
|
return userKey as UserKey;
|
||||||
// FIXME: Remove when updating file. Eslint update
|
// FIXME: Remove when updating file. Eslint update
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -416,7 +416,7 @@ describe("deviceTrustService", () => {
|
|||||||
.mockResolvedValue(mockUserKey);
|
.mockResolvedValue(mockUserKey);
|
||||||
|
|
||||||
cryptoSvcRsaEncryptSpy = jest
|
cryptoSvcRsaEncryptSpy = jest
|
||||||
.spyOn(encryptService, "rsaEncrypt")
|
.spyOn(encryptService, "encapsulateKeyUnsigned")
|
||||||
.mockResolvedValue(mockDevicePublicKeyEncryptedUserKey);
|
.mockResolvedValue(mockDevicePublicKeyEncryptedUserKey);
|
||||||
|
|
||||||
encryptServiceEncryptSpy = jest
|
encryptServiceEncryptSpy = jest
|
||||||
@@ -449,8 +449,8 @@ describe("deviceTrustService", () => {
|
|||||||
expect(cryptoSvcRsaEncryptSpy).toHaveBeenCalledTimes(1);
|
expect(cryptoSvcRsaEncryptSpy).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
// RsaEncrypt must be called w/ a user key array buffer of 64 bytes
|
// RsaEncrypt must be called w/ a user key array buffer of 64 bytes
|
||||||
const userKeyKey: Uint8Array = cryptoSvcRsaEncryptSpy.mock.calls[0][0];
|
const userKey = cryptoSvcRsaEncryptSpy.mock.calls[0][0];
|
||||||
expect(userKeyKey.byteLength).toBe(64);
|
expect(userKey.key.byteLength).toBe(64);
|
||||||
|
|
||||||
expect(encryptServiceEncryptSpy).toHaveBeenCalledTimes(2);
|
expect(encryptServiceEncryptSpy).toHaveBeenCalledTimes(2);
|
||||||
|
|
||||||
@@ -610,7 +610,7 @@ describe("deviceTrustService", () => {
|
|||||||
mockUserId,
|
mockUserId,
|
||||||
mockEncryptedDevicePrivateKey,
|
mockEncryptedDevicePrivateKey,
|
||||||
mockEncryptedUserKey,
|
mockEncryptedUserKey,
|
||||||
mockDeviceKey,
|
null,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result).toBeNull();
|
expect(result).toBeNull();
|
||||||
@@ -621,8 +621,8 @@ describe("deviceTrustService", () => {
|
|||||||
.spyOn(encryptService, "decryptToBytes")
|
.spyOn(encryptService, "decryptToBytes")
|
||||||
.mockResolvedValue(new Uint8Array(userKeyBytesLength));
|
.mockResolvedValue(new Uint8Array(userKeyBytesLength));
|
||||||
const rsaDecryptSpy = jest
|
const rsaDecryptSpy = jest
|
||||||
.spyOn(encryptService, "rsaDecrypt")
|
.spyOn(encryptService, "decapsulateKeyUnsigned")
|
||||||
.mockResolvedValue(new Uint8Array(userKeyBytesLength));
|
.mockResolvedValue(new SymmetricCryptoKey(new Uint8Array(userKeyBytesLength)));
|
||||||
|
|
||||||
const result = await deviceTrustService.decryptUserKeyWithDeviceKey(
|
const result = await deviceTrustService.decryptUserKeyWithDeviceKey(
|
||||||
mockUserId,
|
mockUserId,
|
||||||
@@ -863,9 +863,9 @@ describe("deviceTrustService", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Mock the encryption of the new user key with the decrypted public key
|
// Mock the encryption of the new user key with the decrypted public key
|
||||||
encryptService.rsaEncrypt.mockImplementationOnce((data, publicKey) => {
|
encryptService.encapsulateKeyUnsigned.mockImplementationOnce((data, publicKey) => {
|
||||||
expect(data.byteLength).toBe(64); // New key should also be 64 bytes
|
expect(data.key.byteLength).toBe(64); // New key should also be 64 bytes
|
||||||
expect(new Uint8Array(data)[0]).toBe(FakeNewUserKeyMarker); // New key should have the first byte be '1';
|
expect(new Uint8Array(data.key)[0]).toBe(FakeNewUserKeyMarker); // New key should have the first byte be '1';
|
||||||
|
|
||||||
expect(new Uint8Array(publicKey)[0]).toBe(FakeDecryptedPublicKeyMarker);
|
expect(new Uint8Array(publicKey)[0]).toBe(FakeDecryptedPublicKeyMarker);
|
||||||
return Promise.resolve(new EncString("4.ZW5jcnlwdGVkdXNlcg=="));
|
return Promise.resolve(new EncString("4.ZW5jcnlwdGVkdXNlcg=="));
|
||||||
|
|||||||
@@ -557,8 +557,8 @@ describe("keyService", () => {
|
|||||||
return Promise.resolve(fakePrivateKeyDecryption(encryptedPrivateKey, userKey));
|
return Promise.resolve(fakePrivateKeyDecryption(encryptedPrivateKey, userKey));
|
||||||
});
|
});
|
||||||
|
|
||||||
encryptService.rsaDecrypt.mockImplementation((data, privateKey) => {
|
encryptService.decapsulateKeyUnsigned.mockImplementation((data, privateKey) => {
|
||||||
return Promise.resolve(fakeOrgKeyDecryption(data, privateKey));
|
return Promise.resolve(new SymmetricCryptoKey(fakeOrgKeyDecryption(data, privateKey)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -493,7 +493,7 @@ export class DefaultKeyService implements KeyServiceAbstraction {
|
|||||||
throw new Error("No public key found.");
|
throw new Error("No public key found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const encShareKey = await this.encryptService.rsaEncrypt(shareKey.key, publicKey);
|
const encShareKey = await this.encryptService.encapsulateKeyUnsigned(shareKey, publicKey);
|
||||||
return [encShareKey, shareKey as T];
|
return [encShareKey, shareKey as T];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -968,11 +968,11 @@ export class DefaultKeyService implements KeyServiceAbstraction {
|
|||||||
return this.stateProvider.getUser(userId, USER_ENCRYPTED_PROVIDER_KEYS).state$.pipe(
|
return this.stateProvider.getUser(userId, USER_ENCRYPTED_PROVIDER_KEYS).state$.pipe(
|
||||||
// Convert each value in the record to it's own decryption observable
|
// Convert each value in the record to it's own decryption observable
|
||||||
convertValues(async (_, value) => {
|
convertValues(async (_, value) => {
|
||||||
const decrypted = await this.encryptService.rsaDecrypt(
|
const decapsulatedKey = await this.encryptService.decapsulateKeyUnsigned(
|
||||||
new EncString(value),
|
new EncString(value),
|
||||||
userPrivateKey,
|
userPrivateKey,
|
||||||
);
|
);
|
||||||
return new SymmetricCryptoKey(decrypted) as ProviderKey;
|
return decapsulatedKey as ProviderKey;
|
||||||
}),
|
}),
|
||||||
// switchMap since there are no side effects
|
// switchMap since there are no side effects
|
||||||
switchMap((encryptedProviderKeys) => {
|
switchMap((encryptedProviderKeys) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user