// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { createHmac, createHash } from 'crypto';
import { UnsupportedAlgorithm, KeyLengthError } from './errors';
/**
 * Factory function to curry the hash algorithm
 *
 * @param algorithm [String] The name of the hash algorithm to use
 * @return [Function] The extract function decorated with expand and verify functions
 */
export function HKDF(algorithm = 'sha256') {
    // Check the length and support
    const hashLength = (function () {
        try {
            return createHash(algorithm).digest().length;
        }
        catch (ex) {
            throw new UnsupportedAlgorithm(algorithm);
        }
    })();
    // (<= 255*HashLen) from https://tools.ietf.org/html/rfc5869
    const maxLength = 255 * hashLength;
    // decorate the return function
    extractExpand.extract = extract;
    extractExpand.expand = expand;
    return extractExpand;
    // implementation
    /**
     * Extracts a prk and returns a function to expand the given initial key
     *
     * @param ikm [String|Buffer] The initial key
     * @param salt [String|Buffer] Optional salt for the extraction
     * @return [Function] expand function with the extracted key curried onto it
     */
    function extractExpand(ikm, salt) {
        const prk = extract(ikm, salt);
        return (length, info) => expand(prk, length, info);
    }
    /**
     * Extracts a prk and returns a function to expand the given initial key
     *
     * @param ikm [String|Buffer] The initial key
     * @param salt [String|Buffer] Optional salt for the extraction
     * @return [Buffer] the expanded key
     */
    function extract(ikm, salt) {
        const _salt = salt || Buffer.alloc(hashLength, 0).toString();
        return createHmac(algorithm, _salt).update(ikm).digest();
    }
    /**
     * Expands a given key
     *
     * @param prk [Buffer] The key to expand from
     * @param length [Number] The length of the expanded key
     * @param info [Buffer] Data to bind the expanded key to application/context specific information
     * @return [Buffer] the expanded
     */
    function expand(prk, length, info) {
        if (length > maxLength) {
            throw new KeyLengthError(maxLength, algorithm);
        }
        info = info || Buffer.alloc(0);
        const N = Math.ceil(length / hashLength);
        const memo = [];
        /* L/length octets are returned from T(1)...T(N), and T(0) is definitionally empty/zero length.
         * Elide T(0) into the Buffer.alloc(0) case and then return L octets of T indexed 0...L-1.
         */
        for (let i = 0; i < N; i++) {
            memo[i] = createHmac(algorithm, prk)
                .update(memo[i - 1] || Buffer.alloc(0))
                .update(info)
                .update(Buffer.alloc(1, i + 1))
                .digest();
        }
        return Buffer.concat(memo, length);
    }
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGtkZi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9oa2RmLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLG9FQUFvRTtBQUNwRSxzQ0FBc0M7QUFFdEMsT0FBTyxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsTUFBTSxRQUFRLENBQUE7QUFDL0MsT0FBTyxFQUFFLG9CQUFvQixFQUFFLGNBQWMsRUFBRSxNQUFNLFVBQVUsQ0FBQTtBQUUvRDs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxJQUFJLENBQUMsU0FBUyxHQUFHLFFBQVE7SUFDdkMsK0JBQStCO0lBQy9CLE1BQU0sVUFBVSxHQUFHLENBQUM7UUFDbEIsSUFBSTtZQUNGLE9BQU8sVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLE1BQU0sQ0FBQTtTQUM3QztRQUFDLE9BQU8sRUFBRSxFQUFFO1lBQ1gsTUFBTSxJQUFJLG9CQUFvQixDQUFDLFNBQVMsQ0FBQyxDQUFBO1NBQzFDO0lBQ0gsQ0FBQyxDQUFDLEVBQUUsQ0FBQTtJQUVKLDREQUE0RDtJQUM1RCxNQUFNLFNBQVMsR0FBRyxHQUFHLEdBQUcsVUFBVSxDQUFBO0lBRWxDLCtCQUErQjtJQUMvQixhQUFhLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQTtJQUMvQixhQUFhLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQTtJQUU3QixPQUFPLGFBQWEsQ0FBQTtJQUVwQixpQkFBaUI7SUFFakI7Ozs7OztPQU1HO0lBQ0gsU0FBUyxhQUFhLENBQ3BCLEdBQXdCLEVBQ3hCLElBQWtDO1FBRWxDLE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUE7UUFDOUIsT0FBTyxDQUFDLE1BQWMsRUFBRSxJQUFpQixFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsR0FBRyxFQUFFLE1BQU0sRUFBRSxJQUFJLENBQUMsQ0FBQTtJQUN6RSxDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0gsU0FBUyxPQUFPLENBQ2QsR0FBd0IsRUFDeEIsSUFBa0M7UUFFbEMsTUFBTSxLQUFLLEdBQUcsSUFBSSxJQUFJLE1BQU0sQ0FBQyxLQUFLLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFBO1FBQzVELE9BQU8sVUFBVSxDQUFDLFNBQVMsRUFBRSxLQUFLLENBQUMsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUE7SUFDMUQsQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSCxTQUFTLE1BQU0sQ0FBQyxHQUFlLEVBQUUsTUFBYyxFQUFFLElBQWlCO1FBQ2hFLElBQUksTUFBTSxHQUFHLFNBQVMsRUFBRTtZQUN0QixNQUFNLElBQUksY0FBYyxDQUFDLFNBQVMsRUFBRSxTQUFTLENBQUMsQ0FBQTtTQUMvQztRQUVELElBQUksR0FBRyxJQUFJLElBQUksTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQTtRQUM5QixNQUFNLENBQUMsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxVQUFVLENBQUMsQ0FBQTtRQUN4QyxNQUFNLElBQUksR0FBYSxFQUFFLENBQUE7UUFFekI7O1dBRUc7UUFDSCxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQzFCLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxVQUFVLENBQUMsU0FBUyxFQUFFLEdBQUcsQ0FBQztpQkFDakMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztpQkFDdEMsTUFBTSxDQUFDLElBQUksQ0FBQztpQkFDWixNQUFNLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO2lCQUM5QixNQUFNLEVBQUUsQ0FBQTtTQUNaO1FBQ0QsT0FBTyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxNQUFNLENBQUMsQ0FBQTtJQUNwQyxDQUFDO0FBQ0gsQ0FBQyJ9