blob: 664c5f0116423f4480f80f712686aa8349ed9a02 [file] [log] [blame]
/**
* @license
* Copyright 2020 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {SecurityException} from '../exception/security_exception';
import * as Bytes from './bytes';
import * as EllipticCurves from './elliptic_curves';
import * as Hkdf from './hkdf';
/**
* HKDF-based ECIES-KEM (key encapsulation mechanism) for ECIES sender.
*/
export class EciesHkdfKemSender {
private readonly publicKey: CryptoKey;
constructor(recipientPublicKey: CryptoKey) {
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.');
}
this.publicKey = recipientPublicKey;
}
/**
* @param 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 pointFormat The format of the
* public ephemeral point.
* @param hkdfHash the name of the hash function. Accepted names are
* SHA-1, SHA-256 and SHA-512.
* @param hkdfInfo Context and application specific
* information (can be a zero-length array).
* @param opt_hkdfSalt Salt value (a non-secret random
* value). If not provided, it is set to a string of hash length zeros.
* @return The KEM key and
* token.
*/
async encapsulate(
keySizeInBytes: number, pointFormat: EllipticCurves.PointFormatType,
hkdfHash: string, hkdfInfo: Uint8Array, opt_hkdfSalt?: Uint8Array):
Promise<{key: Uint8Array, token: Uint8Array}> {
const {namedCurve}: Partial<EcKeyAlgorithm> = this.publicKey.algorithm;
if (!namedCurve) {
throw new SecurityException('Curve has to be defined.');
}
const ephemeralKeyPair =
await EllipticCurves.generateKeyPair('ECDH', namedCurve);
const sharedSecret = await EllipticCurves.computeEcdhSharedSecret(
ephemeralKeyPair.privateKey!, this.publicKey);
const jwk =
await EllipticCurves.exportCryptoKey(ephemeralKeyPair.publicKey!);
const {crv} = jwk;
if (!crv) {
throw new SecurityException('Curve has to be defined.');
}
const kemToken = EllipticCurves.pointEncode(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};
}
}
export async function fromJsonWebKey(jwk: JsonWebKey):
Promise<EciesHkdfKemSender> {
const publicKey = await EllipticCurves.importPublicKey('ECDH', jwk);
return new EciesHkdfKemSender(publicKey);
}