1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-12 22:33:35 +00:00

[PM-16699] Add decrypt trace for decrypt failures (#12749)

* Improve decrypt failure logging

* Rename decryptcontext to decrypttrace

* Improve docs

* Revert changes to decrypt logic

* Revert keyservice decryption logic change

* Undo one more change to decrypt logic
This commit is contained in:
Bernd Schoolmann
2025-01-09 20:23:55 +01:00
committed by GitHub
parent bb8e649048
commit 8cabb36c99
18 changed files with 165 additions and 43 deletions

View File

@@ -180,10 +180,18 @@ export class MasterPasswordService implements InternalMasterPasswordServiceAbstr
let decUserKey: Uint8Array; let decUserKey: Uint8Array;
if (userKey.encryptionType === EncryptionType.AesCbc256_B64) { if (userKey.encryptionType === EncryptionType.AesCbc256_B64) {
decUserKey = await this.encryptService.decryptToBytes(userKey, masterKey); decUserKey = await this.encryptService.decryptToBytes(
userKey,
masterKey,
"Content: User Key; Encrypting Key: Master Key",
);
} else if (userKey.encryptionType === EncryptionType.AesCbc256_HmacSha256_B64) { } else if (userKey.encryptionType === EncryptionType.AesCbc256_HmacSha256_B64) {
const newKey = await this.keyGenerationService.stretchKey(masterKey); const newKey = await this.keyGenerationService.stretchKey(masterKey);
decUserKey = await this.encryptService.decryptToBytes(userKey, newKey); decUserKey = await this.encryptService.decryptToBytes(
userKey,
newKey,
"Content: User Key; Encrypting Key: Stretched Master Key",
);
} else { } else {
throw new Error("Unsupported encryption type."); throw new Error("Unsupported encryption type.");
} }

View File

@@ -8,12 +8,32 @@ import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
export abstract class EncryptService { export abstract class EncryptService {
abstract encrypt(plainValue: string | Uint8Array, key: SymmetricCryptoKey): Promise<EncString>; abstract encrypt(plainValue: string | Uint8Array, key: SymmetricCryptoKey): Promise<EncString>;
abstract encryptToBytes(plainValue: Uint8Array, key: SymmetricCryptoKey): Promise<EncArrayBuffer>; abstract encryptToBytes(plainValue: Uint8Array, key: SymmetricCryptoKey): Promise<EncArrayBuffer>;
/**
* Decrypts an EncString to a string
* @param encString - The EncString to decrypt
* @param key - The key to decrypt the EncString with
* @param decryptTrace - A string to identify the context of the object being decrypted. This can include: field name, encryption type, cipher id, key type, but should not include
* sensitive information like encryption keys or data. This is used for logging when decryption errors occur in order to identify what failed to decrypt
* @returns The decrypted string
*/
abstract decryptToUtf8( abstract decryptToUtf8(
encString: EncString, encString: EncString,
key: SymmetricCryptoKey, key: SymmetricCryptoKey,
decryptContext?: string, decryptTrace?: string,
): Promise<string>; ): Promise<string>;
abstract decryptToBytes(encThing: Encrypted, key: SymmetricCryptoKey): Promise<Uint8Array>; /**
* Decrypts an Encrypted object to a Uint8Array
* @param encThing - The Encrypted object to decrypt
* @param key - The key to decrypt the Encrypted object with
* @param decryptTrace - A string to identify the context of the object being decrypted. This can include: field name, encryption type, cipher id, key type, but should not include
* sensitive information like encryption keys or data. This is used for logging when decryption errors occur in order to identify what failed to decrypt
* @returns The decrypted Uint8Array
*/
abstract decryptToBytes(
encThing: Encrypted,
key: SymmetricCryptoKey,
decryptTrace?: string,
): Promise<Uint8Array>;
abstract rsaEncrypt(data: Uint8Array, publicKey: Uint8Array): Promise<EncString>; abstract rsaEncrypt(data: Uint8Array, publicKey: Uint8Array): Promise<EncString>;
abstract rsaDecrypt(data: EncString, privateKey: Uint8Array): Promise<Uint8Array>; abstract rsaDecrypt(data: EncString, privateKey: Uint8Array): Promise<Uint8Array>;
abstract resolveLegacyKey(key: SymmetricCryptoKey, encThing: Encrypted): SymmetricCryptoKey; abstract resolveLegacyKey(key: SymmetricCryptoKey, encThing: Encrypted): SymmetricCryptoKey;

View File

@@ -63,6 +63,7 @@ export default class Domain {
map: any, map: any,
orgId: string, orgId: string,
key: SymmetricCryptoKey = null, key: SymmetricCryptoKey = null,
objectContext: string = "No Domain Context",
): Promise<T> { ): Promise<T> {
const promises = []; const promises = [];
const self: any = this; const self: any = this;
@@ -78,7 +79,11 @@ export default class Domain {
.then(() => { .then(() => {
const mapProp = map[theProp] || theProp; const mapProp = map[theProp] || theProp;
if (self[mapProp]) { if (self[mapProp]) {
return self[mapProp].decrypt(orgId, key); return self[mapProp].decrypt(
orgId,
key,
`Property: ${prop}; ObjectContext: ${objectContext}`,
);
} }
return null; return null;
}) })
@@ -114,12 +119,21 @@ export default class Domain {
key: SymmetricCryptoKey, key: SymmetricCryptoKey,
encryptService: EncryptService, encryptService: EncryptService,
_: Constructor<TThis> = this.constructor as Constructor<TThis>, _: Constructor<TThis> = this.constructor as Constructor<TThis>,
objectContext: string = "No Domain Context",
): Promise<DecryptedObject<TThis, TEncryptedKeys>> { ): Promise<DecryptedObject<TThis, TEncryptedKeys>> {
const promises = []; const promises = [];
for (const prop of encryptedProperties) { for (const prop of encryptedProperties) {
const value = (this as any)[prop] as EncString; const value = (this as any)[prop] as EncString;
promises.push(this.decryptProperty(prop, value, key, encryptService)); promises.push(
this.decryptProperty(
prop,
value,
key,
encryptService,
`Property: ${prop.toString()}; ObjectContext: ${objectContext}`,
),
);
} }
const decryptedObjects = await Promise.all(promises); const decryptedObjects = await Promise.all(promises);
@@ -137,10 +151,11 @@ export default class Domain {
value: EncString, value: EncString,
key: SymmetricCryptoKey, key: SymmetricCryptoKey,
encryptService: EncryptService, encryptService: EncryptService,
decryptTrace: string,
) { ) {
let decrypted: string = null; let decrypted: string = null;
if (value) { if (value) {
decrypted = await value.decryptWithKey(key, encryptService); decrypted = await value.decryptWithKey(key, encryptService, decryptTrace);
} else { } else {
decrypted = null; decrypted = null;
} }

View File

@@ -156,21 +156,21 @@ export class EncString implements Encrypted {
return EXPECTED_NUM_PARTS_BY_ENCRYPTION_TYPE[encType] === encPieces.length; return EXPECTED_NUM_PARTS_BY_ENCRYPTION_TYPE[encType] === encPieces.length;
} }
async decrypt(orgId: string, key: SymmetricCryptoKey = null): Promise<string> { async decrypt(orgId: string, key: SymmetricCryptoKey = null, context?: string): Promise<string> {
if (this.decryptedValue != null) { if (this.decryptedValue != null) {
return this.decryptedValue; return this.decryptedValue;
} }
let keyContext = "provided-key"; let decryptTrace = "provided-key";
try { try {
if (key == null) { if (key == null) {
key = await this.getKeyForDecryption(orgId); key = await this.getKeyForDecryption(orgId);
keyContext = orgId == null ? `domain-orgkey-${orgId}` : "domain-userkey|masterkey"; decryptTrace = orgId == null ? `domain-orgkey-${orgId}` : "domain-userkey|masterkey";
if (orgId != null) { if (orgId != null) {
keyContext = `domain-orgkey-${orgId}`; decryptTrace = `domain-orgkey-${orgId}`;
} else { } else {
const cryptoService = Utils.getContainerService().getKeyService(); const cryptoService = Utils.getContainerService().getKeyService();
keyContext = decryptTrace =
(await cryptoService.getUserKey()) == null (await cryptoService.getUserKey()) == null
? "domain-withlegacysupport-masterkey" ? "domain-withlegacysupport-masterkey"
: "domain-withlegacysupport-userkey"; : "domain-withlegacysupport-userkey";
@@ -181,20 +181,28 @@ export class EncString implements Encrypted {
} }
const encryptService = Utils.getContainerService().getEncryptService(); const encryptService = Utils.getContainerService().getEncryptService();
this.decryptedValue = await encryptService.decryptToUtf8(this, key, keyContext); this.decryptedValue = await encryptService.decryptToUtf8(
this,
key,
decryptTrace == null ? context : `${decryptTrace}${context || ""}`,
);
} catch (e) { } catch (e) {
this.decryptedValue = DECRYPT_ERROR; this.decryptedValue = DECRYPT_ERROR;
} }
return this.decryptedValue; return this.decryptedValue;
} }
async decryptWithKey(key: SymmetricCryptoKey, encryptService: EncryptService) { async decryptWithKey(
key: SymmetricCryptoKey,
encryptService: EncryptService,
decryptTrace: string = "domain-withkey",
): Promise<string> {
try { try {
if (key == null) { if (key == null) {
throw new Error("No key to decrypt EncString"); throw new Error("No key to decrypt EncString");
} }
this.decryptedValue = await encryptService.decryptToUtf8(this, key, "domain-withkey"); this.decryptedValue = await encryptService.decryptToUtf8(this, key, decryptTrace);
} catch (e) { } catch (e) {
this.decryptedValue = DECRYPT_ERROR; this.decryptedValue = DECRYPT_ERROR;
} }

View File

@@ -114,7 +114,7 @@ export class EncryptServiceImplementation implements EncryptService {
const macsEqual = await this.cryptoFunctionService.compareFast(fastParams.mac, computedMac); const macsEqual = await this.cryptoFunctionService.compareFast(fastParams.mac, computedMac);
if (!macsEqual) { if (!macsEqual) {
this.logMacFailed( this.logMacFailed(
"[Encrypt service] MAC comparison failed. Key or payload has changed. Key type " + "[Encrypt service] decryptToUtf8 MAC comparison failed. Key or payload has changed. Key type " +
encryptionTypeName(key.encType) + encryptionTypeName(key.encType) +
"Payload type " + "Payload type " +
encryptionTypeName(encString.encryptionType) + encryptionTypeName(encString.encryptionType) +
@@ -128,7 +128,11 @@ export class EncryptServiceImplementation implements EncryptService {
return await this.cryptoFunctionService.aesDecryptFast(fastParams, "cbc"); return await this.cryptoFunctionService.aesDecryptFast(fastParams, "cbc");
} }
async decryptToBytes(encThing: Encrypted, key: SymmetricCryptoKey): Promise<Uint8Array> { async decryptToBytes(
encThing: Encrypted,
key: SymmetricCryptoKey,
decryptContext: string = "no context",
): Promise<Uint8Array> {
if (key == null) { if (key == null) {
throw new Error("No encryption key provided."); throw new Error("No encryption key provided.");
} }
@@ -145,7 +149,9 @@ export class EncryptServiceImplementation implements EncryptService {
"[Encrypt service] Key has mac key but payload is missing mac bytes. Key type " + "[Encrypt service] Key has mac key but payload is missing mac bytes. Key type " +
encryptionTypeName(key.encType) + encryptionTypeName(key.encType) +
" Payload type " + " Payload type " +
encryptionTypeName(encThing.encryptionType), encryptionTypeName(encThing.encryptionType) +
" Decrypt context: " +
decryptContext,
); );
return null; return null;
} }
@@ -155,7 +161,9 @@ export class EncryptServiceImplementation implements EncryptService {
"[Encrypt service] Key encryption type does not match payload encryption type. Key type " + "[Encrypt service] Key encryption type does not match payload encryption type. Key type " +
encryptionTypeName(key.encType) + encryptionTypeName(key.encType) +
" Payload type " + " Payload type " +
encryptionTypeName(encThing.encryptionType), encryptionTypeName(encThing.encryptionType) +
" Decrypt context: " +
decryptContext,
); );
return null; return null;
} }
@@ -167,11 +175,13 @@ export class EncryptServiceImplementation implements EncryptService {
const computedMac = await this.cryptoFunctionService.hmac(macData, key.macKey, "sha256"); const computedMac = await this.cryptoFunctionService.hmac(macData, key.macKey, "sha256");
if (computedMac === null) { if (computedMac === null) {
this.logMacFailed( this.logMacFailed(
"[Encrypt service] Failed to compute MAC." + "[Encrypt service#decryptToBytes] Failed to compute MAC." +
" Key type " + " Key type " +
encryptionTypeName(key.encType) + encryptionTypeName(key.encType) +
" Payload type " + " Payload type " +
encryptionTypeName(encThing.encryptionType), encryptionTypeName(encThing.encryptionType) +
" Decrypt context: " +
decryptContext,
); );
return null; return null;
} }
@@ -179,11 +189,13 @@ export class EncryptServiceImplementation implements EncryptService {
const macsMatch = await this.cryptoFunctionService.compare(encThing.macBytes, computedMac); const macsMatch = await this.cryptoFunctionService.compare(encThing.macBytes, computedMac);
if (!macsMatch) { if (!macsMatch) {
this.logMacFailed( this.logMacFailed(
"[Encrypt service] MAC comparison failed. Key or payload has changed." + "[Encrypt service#decryptToBytes]: MAC comparison failed. Key or payload has changed." +
" Key type " + " Key type " +
encryptionTypeName(key.encType) + encryptionTypeName(key.encType) +
" Payload type " + " Payload type " +
encryptionTypeName(encThing.encryptionType), encryptionTypeName(encThing.encryptionType) +
" Decrypt context: " +
decryptContext,
); );
return null; return null;
} }

View File

@@ -123,7 +123,12 @@ describe("Send", () => {
const view = await send.decrypt(); const view = await send.decrypt();
expect(text.decrypt).toHaveBeenNthCalledWith(1, "cryptoKey"); expect(text.decrypt).toHaveBeenNthCalledWith(1, "cryptoKey");
expect(send.name.decrypt).toHaveBeenNthCalledWith(1, null, "cryptoKey"); expect(send.name.decrypt).toHaveBeenNthCalledWith(
1,
null,
"cryptoKey",
"Property: name; ObjectContext: No Domain Context",
);
expect(view).toMatchObject({ expect(view).toMatchObject({
id: "id", id: "id",

View File

@@ -101,7 +101,7 @@ describe("Attachment", () => {
it("uses the provided key without depending on KeyService", async () => { it("uses the provided key without depending on KeyService", async () => {
const providedKey = mock<SymmetricCryptoKey>(); const providedKey = mock<SymmetricCryptoKey>();
await attachment.decrypt(null, providedKey); await attachment.decrypt(null, "", providedKey);
expect(keyService.getUserKeyWithLegacySupport).not.toHaveBeenCalled(); expect(keyService.getUserKeyWithLegacySupport).not.toHaveBeenCalled();
expect(encryptService.decryptToBytes).toHaveBeenCalledWith(attachment.key, providedKey); expect(encryptService.decryptToBytes).toHaveBeenCalledWith(attachment.key, providedKey);
@@ -111,7 +111,7 @@ describe("Attachment", () => {
const orgKey = mock<OrgKey>(); const orgKey = mock<OrgKey>();
keyService.getOrgKey.calledWith("orgId").mockResolvedValue(orgKey); keyService.getOrgKey.calledWith("orgId").mockResolvedValue(orgKey);
await attachment.decrypt("orgId", null); await attachment.decrypt("orgId", "", null);
expect(keyService.getOrgKey).toHaveBeenCalledWith("orgId"); expect(keyService.getOrgKey).toHaveBeenCalledWith("orgId");
expect(encryptService.decryptToBytes).toHaveBeenCalledWith(attachment.key, orgKey); expect(encryptService.decryptToBytes).toHaveBeenCalledWith(attachment.key, orgKey);
@@ -121,7 +121,7 @@ describe("Attachment", () => {
const userKey = mock<UserKey>(); const userKey = mock<UserKey>();
keyService.getUserKeyWithLegacySupport.mockResolvedValue(userKey); keyService.getUserKeyWithLegacySupport.mockResolvedValue(userKey);
await attachment.decrypt(null, null); await attachment.decrypt(null, "", null);
expect(keyService.getUserKeyWithLegacySupport).toHaveBeenCalled(); expect(keyService.getUserKeyWithLegacySupport).toHaveBeenCalled();
expect(encryptService.decryptToBytes).toHaveBeenCalledWith(attachment.key, userKey); expect(encryptService.decryptToBytes).toHaveBeenCalledWith(attachment.key, userKey);

View File

@@ -38,7 +38,11 @@ export class Attachment extends Domain {
); );
} }
async decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise<AttachmentView> { async decrypt(
orgId: string,
context = "No Cipher Context",
encKey?: SymmetricCryptoKey,
): Promise<AttachmentView> {
const view = await this.decryptObj( const view = await this.decryptObj(
new AttachmentView(this), new AttachmentView(this),
{ {
@@ -46,6 +50,7 @@ export class Attachment extends Domain {
}, },
orgId, orgId,
encKey, encKey,
"DomainType: Attachment; " + context,
); );
if (this.key != null) { if (this.key != null) {

View File

@@ -37,7 +37,11 @@ export class Card extends Domain {
); );
} }
decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise<CardView> { async decrypt(
orgId: string,
context = "No Cipher Context",
encKey?: SymmetricCryptoKey,
): Promise<CardView> {
return this.decryptObj( return this.decryptObj(
new CardView(), new CardView(),
{ {
@@ -50,6 +54,7 @@ export class Card extends Domain {
}, },
orgId, orgId,
encKey, encKey,
"DomainType: Card; " + context,
); );
} }

View File

@@ -136,7 +136,11 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
if (this.key != null) { if (this.key != null) {
const encryptService = Utils.getContainerService().getEncryptService(); const encryptService = Utils.getContainerService().getEncryptService();
const keyBytes = await encryptService.decryptToBytes(this.key, encKey); const keyBytes = await encryptService.decryptToBytes(
this.key,
encKey,
`Cipher Id: ${this.id}; Content: CipherKey; IsEncryptedByOrgKey: ${this.organizationId != null}`,
);
if (keyBytes == null) { if (keyBytes == null) {
model.name = "[error: cannot decrypt]"; model.name = "[error: cannot decrypt]";
model.decryptionFailure = true; model.decryptionFailure = true;
@@ -158,19 +162,36 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
switch (this.type) { switch (this.type) {
case CipherType.Login: case CipherType.Login:
model.login = await this.login.decrypt(this.organizationId, bypassValidation, encKey); model.login = await this.login.decrypt(
this.organizationId,
bypassValidation,
`Cipher Id: ${this.id}`,
encKey,
);
break; break;
case CipherType.SecureNote: case CipherType.SecureNote:
model.secureNote = await this.secureNote.decrypt(this.organizationId, encKey); model.secureNote = await this.secureNote.decrypt(
this.organizationId,
`Cipher Id: ${this.id}`,
encKey,
);
break; break;
case CipherType.Card: case CipherType.Card:
model.card = await this.card.decrypt(this.organizationId, encKey); model.card = await this.card.decrypt(this.organizationId, `Cipher Id: ${this.id}`, encKey);
break; break;
case CipherType.Identity: case CipherType.Identity:
model.identity = await this.identity.decrypt(this.organizationId, encKey); model.identity = await this.identity.decrypt(
this.organizationId,
`Cipher Id: ${this.id}`,
encKey,
);
break; break;
case CipherType.SshKey: case CipherType.SshKey:
model.sshKey = await this.sshKey.decrypt(this.organizationId, encKey); model.sshKey = await this.sshKey.decrypt(
this.organizationId,
`Cipher Id: ${this.id}`,
encKey,
);
break; break;
default: default:
break; break;
@@ -181,7 +202,7 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
await this.attachments.reduce((promise, attachment) => { await this.attachments.reduce((promise, attachment) => {
return promise return promise
.then(() => { .then(() => {
return attachment.decrypt(this.organizationId, encKey); return attachment.decrypt(this.organizationId, `Cipher Id: ${this.id}`, encKey);
}) })
.then((decAttachment) => { .then((decAttachment) => {
attachments.push(decAttachment); attachments.push(decAttachment);

View File

@@ -61,7 +61,11 @@ export class Identity extends Domain {
); );
} }
decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise<IdentityView> { decrypt(
orgId: string,
context: string = "No Cipher Context",
encKey?: SymmetricCryptoKey,
): Promise<IdentityView> {
return this.decryptObj( return this.decryptObj(
new IdentityView(), new IdentityView(),
{ {
@@ -86,6 +90,7 @@ export class Identity extends Domain {
}, },
orgId, orgId,
encKey, encKey,
"DomainType: Identity; " + context,
); );
} }

View File

@@ -33,7 +33,11 @@ export class LoginUri extends Domain {
); );
} }
decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise<LoginUriView> { decrypt(
orgId: string,
context: string = "No Cipher Context",
encKey?: SymmetricCryptoKey,
): Promise<LoginUriView> {
return this.decryptObj( return this.decryptObj(
new LoginUriView(this), new LoginUriView(this),
{ {
@@ -41,6 +45,7 @@ export class LoginUri extends Domain {
}, },
orgId, orgId,
encKey, encKey,
context,
); );
} }

View File

@@ -55,6 +55,7 @@ export class Login extends Domain {
async decrypt( async decrypt(
orgId: string, orgId: string,
bypassValidation: boolean, bypassValidation: boolean,
context: string = "No Cipher Context",
encKey?: SymmetricCryptoKey, encKey?: SymmetricCryptoKey,
): Promise<LoginView> { ): Promise<LoginView> {
const view = await this.decryptObj( const view = await this.decryptObj(
@@ -66,6 +67,7 @@ export class Login extends Domain {
}, },
orgId, orgId,
encKey, encKey,
`DomainType: Login; ${context}`,
); );
if (this.uris != null) { if (this.uris != null) {
@@ -76,7 +78,7 @@ export class Login extends Domain {
continue; continue;
} }
const uri = await this.uris[i].decrypt(orgId, encKey); const uri = await this.uris[i].decrypt(orgId, context, encKey);
// URIs are shared remotely after decryption // URIs are shared remotely after decryption
// we need to validate that the string hasn't been changed by a compromised server // we need to validate that the string hasn't been changed by a compromised server
// This validation is tied to the existence of cypher.key for backwards compatibility // This validation is tied to the existence of cypher.key for backwards compatibility

View File

@@ -32,6 +32,7 @@ export class Password extends Domain {
}, },
orgId, orgId,
encKey, encKey,
"DomainType: PasswordHistory",
); );
} }

View File

@@ -20,8 +20,12 @@ export class SecureNote extends Domain {
this.type = obj.type; this.type = obj.type;
} }
decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise<SecureNoteView> { async decrypt(
return Promise.resolve(new SecureNoteView(this)); orgId: string,
context = "No Cipher Context",
encKey?: SymmetricCryptoKey,
): Promise<SecureNoteView> {
return new SecureNoteView(this);
} }
toSecureNoteData(): SecureNoteData { toSecureNoteData(): SecureNoteData {

View File

@@ -32,7 +32,11 @@ export class SshKey extends Domain {
); );
} }
decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise<SshKeyView> { decrypt(
orgId: string,
context = "No Cipher Context",
encKey?: SymmetricCryptoKey,
): Promise<SshKeyView> {
return this.decryptObj( return this.decryptObj(
new SshKeyView(), new SshKeyView(),
{ {
@@ -42,6 +46,7 @@ export class SshKey extends Domain {
}, },
orgId, orgId,
encKey, encKey,
"DomainType: SshKey; " + context,
); );
} }

View File

@@ -462,6 +462,7 @@ describe("keyService", () => {
expect(encryptService.decryptToBytes).toHaveBeenCalledWith( expect(encryptService.decryptToBytes).toHaveBeenCalledWith(
fakeEncryptedUserPrivateKey, fakeEncryptedUserPrivateKey,
userKey, userKey,
"Content: Encrypted Private Key",
); );
expect(userPrivateKey).toBe(fakeDecryptedUserPrivateKey); expect(userPrivateKey).toBe(fakeDecryptedUserPrivateKey);

View File

@@ -382,7 +382,6 @@ export class DefaultKeyService implements KeyServiceAbstraction {
key: org.key, key: org.key,
}; };
}); });
return encOrgKeyData; return encOrgKeyData;
}); });
} }
@@ -891,6 +890,7 @@ export class DefaultKeyService implements KeyServiceAbstraction {
return (await this.encryptService.decryptToBytes( return (await this.encryptService.decryptToBytes(
new EncString(encryptedPrivateKey), new EncString(encryptedPrivateKey),
key, key,
"Content: Encrypted Private Key",
)) as UserPrivateKey; )) as UserPrivateKey;
} }