| /** |
| * @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()); |
| } |
| } |