| /** | |
| * @license | |
| * Copyright 2020 Google LLC | |
| * SPDX-License-Identifier: Apache-2.0 | |
| */ | |
| import {SecurityException} from '../exception/security_exception'; | |
| import {CryptoFormat} from '../internal/crypto_format'; | |
| import * as PrimitiveSet from '../internal/primitive_set'; | |
| import {PrimitiveWrapper} from '../internal/primitive_wrapper'; | |
| import {PbKeyStatusType} from '../internal/proto'; | |
| import * as Registry from '../internal/registry'; | |
| import {Constructor} from '../internal/util'; | |
| import {Aead} from './internal/aead'; | |
| /** | |
| * @final | |
| */ | |
| class WrappedAead extends Aead { | |
| // The constructor should be @private, but it is not supported by Closure | |
| // (see https://github.com/google/closure-compiler/issues/2761). | |
| constructor(private readonly aeadSet: PrimitiveSet.PrimitiveSet<Aead>) { | |
| super(); | |
| } | |
| static newAead(aeadSet: PrimitiveSet.PrimitiveSet<Aead>): Aead { | |
| if (!aeadSet) { | |
| throw new SecurityException('Primitive set has to be non-null.'); | |
| } | |
| if (!aeadSet.getPrimary()) { | |
| throw new SecurityException('Primary has to be non-null.'); | |
| } | |
| return new WrappedAead(aeadSet); | |
| } | |
| /** | |
| */ | |
| async encrypt(plaintext: Uint8Array, opt_associatedData?: Uint8Array|null): | |
| Promise<Uint8Array> { | |
| if (!plaintext) { | |
| throw new SecurityException('Plaintext has to be non-null.'); | |
| } | |
| const primary = this.aeadSet.getPrimary() | |
| if (!primary) { | |
| throw new SecurityException('Primary has to be non-null.'); | |
| } | |
| const primitive = primary.getPrimitive(); | |
| const encryptedText = | |
| await primitive.encrypt(plaintext, opt_associatedData); | |
| const keyId = primary.getIdentifier(); | |
| const ciphertext = new Uint8Array(keyId.length + encryptedText.length); | |
| ciphertext.set(keyId, 0); | |
| ciphertext.set(encryptedText, keyId.length); | |
| return ciphertext; | |
| } | |
| /** | |
| */ | |
| async decrypt(ciphertext: Uint8Array, opt_associatedData?: Uint8Array|null): | |
| Promise<Uint8Array> { | |
| if (!ciphertext) { | |
| throw new SecurityException('Ciphertext has to be non-null.'); | |
| } | |
| if (ciphertext.length > CryptoFormat.NON_RAW_PREFIX_SIZE) { | |
| const keyId = ciphertext.subarray(0, CryptoFormat.NON_RAW_PREFIX_SIZE); | |
| const entries = await this.aeadSet.getPrimitives(keyId); | |
| const rawCiphertext = ciphertext.subarray( | |
| CryptoFormat.NON_RAW_PREFIX_SIZE, ciphertext.length); | |
| let decryptedText: Uint8Array|undefined; | |
| try { | |
| decryptedText = await this.tryDecryption( | |
| entries, rawCiphertext, opt_associatedData); | |
| } catch (e) { | |
| } | |
| if (decryptedText) { | |
| return decryptedText; | |
| } | |
| } | |
| const entries = await this.aeadSet.getRawPrimitives(); | |
| const decryptedText = | |
| await this.tryDecryption(entries, ciphertext, opt_associatedData); | |
| return decryptedText; | |
| } | |
| /** | |
| * Tries to decrypt the ciphertext using each entry in entriesArray and | |
| * returns the ciphertext decrypted by first primitive which succeed. It | |
| * throws an exception if no entry succeeds. | |
| * | |
| * | |
| */ | |
| private async tryDecryption( | |
| entriesArray: Array<PrimitiveSet.Entry<Aead>>, ciphertext: Uint8Array, | |
| opt_associatedData?: Uint8Array|null): Promise<Uint8Array> { | |
| const entriesArrayLength = entriesArray.length; | |
| for (let i = 0; i < entriesArrayLength; i++) { | |
| if (entriesArray[i].getKeyStatus() != PbKeyStatusType.ENABLED) { | |
| continue; | |
| } | |
| const primitive = entriesArray[i].getPrimitive(); | |
| let decryptionResult; | |
| try { | |
| decryptionResult = | |
| await primitive.decrypt(ciphertext, opt_associatedData); | |
| } catch (e) { | |
| continue; | |
| } | |
| return decryptionResult; | |
| } | |
| throw new SecurityException('Decryption failed for the given ciphertext.'); | |
| } | |
| } | |
| export class AeadWrapper implements PrimitiveWrapper<Aead> { | |
| /** | |
| */ | |
| wrap(primitiveSet: PrimitiveSet.PrimitiveSet<Aead>): Aead { | |
| return WrappedAead.newAead(primitiveSet); | |
| } | |
| /** | |
| */ | |
| getPrimitiveType(): Constructor<Aead> { | |
| return Aead; | |
| } | |
| static register() { | |
| Registry.registerPrimitiveWrapper(new AeadWrapper()); | |
| } | |
| } |