blob: 9964fe892bcc291a1034d3b176ef289012a2d7d1 [file] [log] [blame]
// 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.subtle.EciesAeadHkdfHybridEncrypt');
const Bytes = goog.require('tink.subtle.Bytes');
const EciesAeadHkdfDemHelper = goog.require('tink.subtle.EciesAeadHkdfDemHelper');
const EciesHkdfKemSender = goog.require('tink.subtle.EciesHkdfKemSender');
const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
const HybridEncrypt = goog.require('tink.HybridEncrypt');
const SecurityException = goog.require('tink.exception.SecurityException');
/**
* Implementation of ECIES AEAD HKDF hybrid encryption.
*
* @implements {HybridEncrypt}
* @protected
* @final
*/
class EciesAeadHkdfHybridEncrypt {
/**
* @param {!EciesHkdfKemSender} kemSender
* @param {string} hkdfHash the name of the HMAC algorithm, accepted names
* are: SHA-1, SHA-256 and SHA-512.
* @param {!EllipticCurves.PointFormatType} pointFormat
* @param {!EciesAeadHkdfDemHelper} demHelper
* @param {!Uint8Array=} opt_hkdfSalt
*/
constructor(kemSender, hkdfHash, pointFormat, demHelper, opt_hkdfSalt) {
// TODO(thaidn): do we actually need these null checks?
if (!kemSender) {
throw new SecurityException('KEM sender has to be non-null.');
}
if (!hkdfHash) {
throw new SecurityException('HMAC algorithm has to be non-null.');
}
if (!pointFormat) {
throw new SecurityException('Point format has to be non-null.');
}
if (!demHelper) {
throw new SecurityException('DEM helper has to be non-null.');
}
/** @private @const {!EciesHkdfKemSender} */
this.kemSender_ = kemSender;
/** @private @const {string} */
this.hkdfHash_ = hkdfHash;
/** @private @const {!EllipticCurves.PointFormatType} */
this.pointFormat_ = pointFormat;
/** @private @const {!EciesAeadHkdfDemHelper} */
this.demHelper_ = demHelper;
/** @private @const {!Uint8Array|undefined} */
this.hkdfSalt_ = opt_hkdfSalt;
}
/**
* @param {!webCrypto.JsonWebKey} recipientPublicKey
* @param {string} hkdfHash the name of the HMAC algorithm, accepted names
* are: SHA-1, SHA-256 and SHA-512.
* @param {!EllipticCurves.PointFormatType} pointFormat
* @param {!EciesAeadHkdfDemHelper} demHelper
* @param {!Uint8Array=} opt_hkdfSalt
*
* @return {!Promise.<!HybridEncrypt>}
*/
static async newInstance(
recipientPublicKey, hkdfHash, pointFormat, demHelper, opt_hkdfSalt) {
if (!recipientPublicKey) {
throw new SecurityException('Recipient public key has to be non-null.');
}
if (!hkdfHash) {
throw new SecurityException('HMAC algorithm has to be non-null.');
}
if (!pointFormat) {
throw new SecurityException('Point format has to be non-null.');
}
if (!demHelper) {
throw new SecurityException('DEM helper has to be non-null.');
}
const kemSender = await EciesHkdfKemSender.newInstance(recipientPublicKey);
return new EciesAeadHkdfHybridEncrypt(
kemSender, hkdfHash, pointFormat, demHelper, opt_hkdfSalt);
}
/**
* Encrypts plaintext using opt_contextInfo as info parameter of the
* underlying HKDF.
*
* @override
*/
async encrypt(plaintext, opt_contextInfo) {
// Variable hkdfInfo is not optional for encapsulate method. Thus it
// should be an empty array in case that it is not defined by caller of this
// method.
if (!opt_contextInfo) {
opt_contextInfo = new Uint8Array(0);
}
const keySizeInBytes = this.demHelper_.getDemKeySizeInBytes();
const kemKey = await this.kemSender_.encapsulate(
keySizeInBytes, this.pointFormat_, this.hkdfHash_, opt_contextInfo,
this.hkdfSalt_);
const aead = await this.demHelper_.getAead(kemKey['key']);
const ciphertextBody = await aead.encrypt(plaintext);
const header = kemKey['token'];
return Bytes.concat(header, ciphertextBody);
}
}
exports = EciesAeadHkdfHybridEncrypt;