blob: caf4bf552dc1aa8fb526f257209e5bbf37f70e4f [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.EciesHkdfKemSender');
const Bytes = goog.require('tink.subtle.Bytes');
const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
const Hkdf = goog.require('tink.subtle.Hkdf');
const SecurityException = goog.require('tink.exception.SecurityException');
/**
* HKDF-based ECIES-KEM (key encapsulation mechanism) for ECIES sender.
*/
class EciesHkdfKemSender {
/**
* @param {!webCrypto.CryptoKey} recipientPublicKey
*/
constructor(recipientPublicKey) {
if (!recipientPublicKey) {
throw new SecurityException('Recipient public key has to be non-null.');
}
// CryptoKey should have the properties type and algorithm.
if (recipientPublicKey.type !== 'public' || !recipientPublicKey.algorithm) {
throw new SecurityException('Expected Crypto key of type: public.');
}
/** @const @private {!webCrypto.CryptoKey} */
this.publicKey_ = recipientPublicKey;
}
/**
* @param {!webCrypto.JsonWebKey} jwk
* @return {!Promise.<!EciesHkdfKemSender>}
* @static
*/
static async newInstance(jwk) {
const publicKey = await EllipticCurves.importPublicKey('ECDH', jwk);
return new EciesHkdfKemSender(publicKey);
}
/**
* @param {number} keySizeInBytes The length of the generated pseudorandom
* string in bytes. The maximal size is 255 * DigestSize, where DigestSize
* is the size of the underlying HMAC.
* @param {!EllipticCurves.PointFormatType} pointFormat The format of the
* public ephemeral point.
* @param {string} hkdfHash the name of the hash function. Accepted names are
* SHA-1, SHA-256 and SHA-512.
* @param {!Uint8Array} hkdfInfo Context and application specific
* information (can be a zero-length array).
* @param {!Uint8Array=} opt_hkdfSalt Salt value (a non-secret random
* value). If not provided, it is set to a string of hash length zeros.
* @return {!Promise.<{key:!Uint8Array, token:!Uint8Array}>} The KEM key and
* token.
*/
async encapsulate(
keySizeInBytes, pointFormat, hkdfHash, hkdfInfo, opt_hkdfSalt) {
const ephemeralKeyPair = await EllipticCurves.generateKeyPair(
'ECDH', this.publicKey_.algorithm['namedCurve']);
const sharedSecret = await EllipticCurves.computeEcdhSharedSecret(
/** @type {?} */ (ephemeralKeyPair).privateKey, this.publicKey_);
const jwk = await EllipticCurves.exportCryptoKey(
/** @type {?} */ (ephemeralKeyPair).publicKey);
const kemToken = EllipticCurves.pointEncode(jwk.crv, pointFormat, jwk);
const hkdfIkm = Bytes.concat(kemToken, sharedSecret);
const kemKey = await Hkdf.compute(
keySizeInBytes, hkdfHash, hkdfIkm, hkdfInfo, opt_hkdfSalt);
return {'key': kemKey, 'token': kemToken};
}
}
exports = EciesHkdfKemSender;