diff --git a/src/abstractions/crypto.service.ts b/src/abstractions/crypto.service.ts index fc55466ee7..c4807087c1 100644 --- a/src/abstractions/crypto.service.ts +++ b/src/abstractions/crypto.service.ts @@ -12,6 +12,7 @@ export abstract class CryptoService { getKey: () => Promise; getKeyHash: () => Promise; getEncKey: () => Promise; + getPublicKey: () => Promise; getPrivateKey: () => Promise; getOrgKeys: () => Promise>; getOrgKey: (orgId: string) => Promise; @@ -24,6 +25,7 @@ export abstract class CryptoService { clearKeys: () => Promise; toggleKey: () => Promise; makeKey: (password: string, salt: string) => Promise; + makeShareKey: () => Promise<[CipherString, SymmetricCryptoKey]>; hashPassword: (password: string, key: SymmetricCryptoKey) => Promise; makeEncKey: (key: SymmetricCryptoKey) => Promise; encrypt: (plainValue: string | ArrayBuffer, key?: SymmetricCryptoKey) => Promise; diff --git a/src/services/crypto.service.ts b/src/services/crypto.service.ts index f01f05b5c0..8c913ad8cc 100644 --- a/src/services/crypto.service.ts +++ b/src/services/crypto.service.ts @@ -26,6 +26,7 @@ export class CryptoService implements CryptoServiceAbstraction { private encKey: SymmetricCryptoKey; private legacyEtmKey: SymmetricCryptoKey; private keyHash: string; + private publicKey: ArrayBuffer; private privateKey: ArrayBuffer; private orgKeys: Map; @@ -135,6 +136,20 @@ export class CryptoService implements CryptoServiceAbstraction { return this.encKey; } + async getPublicKey(): Promise { + if (this.publicKey != null) { + return this.publicKey; + } + + const privateKey = await this.getPrivateKey(); + if (privateKey == null) { + return null; + } + + this.publicKey = null; // TODO: + return this.publicKey; + } + async getPrivateKey(): Promise { if (this.privateKey != null) { return this.privateKey; @@ -258,6 +273,14 @@ export class CryptoService implements CryptoServiceAbstraction { return new SymmetricCryptoKey(key); } + async makeShareKey(): Promise<[CipherString, SymmetricCryptoKey]> { + const shareKey = await this.cryptoFunctionService.randomBytes(64); + const publicKey = await this.getPublicKey(); + const encKey = await this.getEncKey(); + const encShareKey = await this.rsaEncrypt(shareKey, publicKey, encKey); + return [encShareKey, new SymmetricCryptoKey(shareKey)]; + } + async hashPassword(password: string, key: SymmetricCryptoKey): Promise { if (key == null) { key = await this.getKey(); @@ -497,6 +520,25 @@ export class CryptoService implements CryptoServiceAbstraction { return await this.cryptoFunctionService.aesDecrypt(data, iv, theKey.encKey); } + private async rsaEncrypt(data: ArrayBuffer, publicKey?: ArrayBuffer, key?: SymmetricCryptoKey) { + if (publicKey == null) { + publicKey = await this.getPublicKey(); + } + if (publicKey == null) { + throw new Error('Public key unavailable.'); + } + + let type = EncryptionType.Rsa2048_OaepSha1_B64; + const encBytes = await this.cryptoFunctionService.rsaEncrypt(data, publicKey, 'sha1'); + let mac: string = null; + if (key != null && key.macKey != null) { + type = EncryptionType.Rsa2048_OaepSha1_HmacSha256_B64; + const macBytes = await this.cryptoFunctionService.hmac(encBytes, key.macKey, 'sha256'); + mac = Utils.fromBufferToB64(macBytes); + } + return new CipherString(type, Utils.fromBufferToB64(encBytes), null, mac); + } + private async rsaDecrypt(encValue: string): Promise { const headerPieces = encValue.split('.'); let encType: EncryptionType = null;