// Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //////////////////////////////////////////////////////////////////////////////// goog.module('tink.aead.AeadWrapper'); const Aead = goog.require('tink.Aead'); const CryptoFormat = goog.require('tink.CryptoFormat'); const PbKeyStatusType = goog.require('proto.google.crypto.tink.KeyStatusType'); const PrimitiveSet = goog.require('tink.PrimitiveSet'); const PrimitiveWrapper = goog.require('tink.PrimitiveWrapper'); const SecurityException = goog.require('tink.exception.SecurityException'); /** * @implements {Aead} * @final */ class WrappedAead { /** * @param {!PrimitiveSet.PrimitiveSet} aeadSet */ // The constructor should be @private, but it is not supported by Closure // (see https://github.com/google/closure-compiler/issues/2761). constructor(aeadSet) { /** @private @const {!PrimitiveSet.PrimitiveSet} */ this.aeadSet_ = aeadSet; } /** * @param {!PrimitiveSet.PrimitiveSet} aeadSet * * @return {!Aead} */ static newAead(aeadSet) { 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); } /** * @override */ async encrypt(plaintext, opt_associatedData) { if (!plaintext) { throw new SecurityException('Plaintext has to be non-null.'); } const primitive = this.aeadSet_.getPrimary().getPrimitive(); const encryptedText = await primitive.encrypt(plaintext, opt_associatedData); const keyId = this.aeadSet_.getPrimary().getIdentifier(); const ciphertext = new Uint8Array(keyId.length + encryptedText.length); ciphertext.set(keyId, 0); ciphertext.set(encryptedText, keyId.length); return ciphertext; } /** * @override */ async decrypt(ciphertext, opt_associatedData) { 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 /** @type {!Uint8Array} */ decryptedText; 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 * @param {!Array<!PrimitiveSet.Entry>} entriesArray * @param {!Uint8Array} ciphertext * @param {?Uint8Array=} opt_associatedData * * @return {!Promise<!Uint8Array>} */ async tryDecryption_(entriesArray, ciphertext, opt_associatedData) { 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.'); } } /** * @implements {PrimitiveWrapper<Aead>} */ class AeadWrapper { // The constructor should be @private, but it is not supported by Closure // (see https://github.com/google/closure-compiler/issues/2761). constructor() {} /** * @override */ wrap(primitiveSet) { return WrappedAead.newAead(primitiveSet); } /** * @override */ getPrimitiveType() { return Aead; } } goog.exportSymbol('tink.aead.AeadWrapper', AeadWrapper); exports = AeadWrapper;