UNPKG

pooja-docucomb-tink-crypto

Version:

A multi-language, cross-platform library that provides cryptographic APIs that are secure, easy to use correctly, and hard(er) to misuse.

132 lines (121 loc) 4.26 kB
/** * @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()); } }