"use strict";
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
Object.defineProperty(exports, "__esModule", { value: true });
exports.deserializeHeaderV1Factory = void 0;
/*
 * This public interface for parsing the AWS Encryption SDK Message Header Format
 * is provided for the use of the Encryption SDK for JavaScript only.  It can be used
 * as a reference but is not intended to be use by any packages other than the
 * Encryption SDK for JavaScript.
 *
 * See: https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/message-format.html#header-structure
 */
const material_management_1 = require("@aws-crypto/material-management");
// To deal with Browser and Node.js I inject a function to handle utf8 encoding.
function deserializeHeaderV1Factory({ decodeEncryptionContext, deserializeEncryptedDataKeys, SdkSuite, }) {
    return deserializeMessageHeaderV1;
    /**
     * deserializeMessageHeaderV1
     *
     * I need to be able to parse the MessageHeader, but since the data may be streamed
     * I may not have all the data yet.  The caller is expected to maintain and append
     * to the buffer and call this function with the same readPos until the function
     * returns a HeaderInfo.
     *
     * @param messageBuffer
     * @param deserializeOptions
     * @returns HeaderInfo|undefined
     */
    function deserializeMessageHeaderV1(messageBuffer, deserializeOptions = { maxEncryptedDataKeys: false }) {
        /* Uint8Array is a view on top of the underlying ArrayBuffer.
         * This means that raw underlying memory stored in the ArrayBuffer
         * may be larger than the Uint8Array.  This is especially true of
         * the Node.js Buffer object.  The offset and length *must* be
         * passed to the DataView otherwise I will get unexpected results.
         */
        const dataView = new DataView(messageBuffer.buffer, messageBuffer.byteOffset, messageBuffer.byteLength);
        /* Check for early return (Postcondition): Not Enough Data. Need to have at least 22 bytes of data to begin parsing.
         * The first 22 bytes of the header are fixed length.  After that
         * there are 2 variable length sections.
         */
        if (dataView.byteLength < 22)
            return false; // not enough data
        const version = dataView.getUint8(0);
        const type = dataView.getUint8(1);
        /* Precondition: version and type must be the required values. */
        (0, material_management_1.needs)(version === material_management_1.MessageFormat.V1 && type === 128, version === 65 && type === 89
            ? 'Malformed Header: This blob may be base64 encoded.'
            : 'Malformed Header.');
        const suiteId = dataView.getUint16(2, false); // big endian
        /* Precondition: suiteId must be a non-committing algorithm suite. */
        (0, material_management_1.needs)(material_management_1.NonCommittingAlgorithmSuiteIdentifier[suiteId], 'Unsupported algorithm suite.');
        const messageId = messageBuffer.slice(4, 20);
        const contextLength = dataView.getUint16(20, false); // big endian
        /* Check for early return (Postcondition): Not Enough Data. Need to have all of the context in bytes before we can parse the next section.
         * This is the first variable length section.
         */
        if (22 + contextLength > dataView.byteLength)
            return false; // not enough data
        const encryptionContext = decodeEncryptionContext(messageBuffer.slice(22, 22 + contextLength));
        const dataKeyInfo = deserializeEncryptedDataKeys(messageBuffer, 22 + contextLength, deserializeOptions);
        /* Check for early return (Postcondition): Not Enough Data. deserializeEncryptedDataKeys will return false if it does not have enough data.
         * This is the second variable length section.
         */
        if (!dataKeyInfo)
            return false; // not enough data
        const { encryptedDataKeys, readPos } = dataKeyInfo;
        /* I'm doing this here, after decodeEncryptionContext and deserializeEncryptedDataKeys
         * because they are the bulk of the header section.
         */
        const algorithmSuite = new SdkSuite(suiteId);
        const { ivLength, tagLength } = algorithmSuite;
        const tagLengthBytes = tagLength / 8;
        const headerLength = readPos + 1 + 4 + 1 + 4;
        /* Check for early return (Postcondition): Not Enough Data. Need to have the remaining fixed length data to parse. */
        if (headerLength + ivLength + tagLengthBytes > dataView.byteLength)
            return false; // not enough data
        const contentType = dataView.getUint8(readPos);
        const reservedBytes = dataView.getUint32(readPos + 1, false); // big endian
        /* Postcondition: reservedBytes are defined as 0,0,0,0
         * See: https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/message-format.html#header-reserved
         */
        (0, material_management_1.needs)(reservedBytes === 0, 'Malformed Header');
        const headerIvLength = dataView.getUint8(readPos + 1 + 4);
        /* Postcondition: The headerIvLength must match the algorithm suite specification. */
        (0, material_management_1.needs)(headerIvLength === ivLength, 'Malformed Header');
        const frameLength = dataView.getUint32(readPos + 1 + 4 + 1, false); // big endian
        const rawHeader = messageBuffer.slice(0, headerLength);
        const messageHeader = {
            version,
            type,
            suiteId,
            messageId,
            encryptionContext,
            encryptedDataKeys,
            contentType,
            headerIvLength,
            frameLength,
        };
        const headerIv = messageBuffer.slice(headerLength, headerLength + ivLength);
        const headerAuthTag = messageBuffer.slice(headerLength + ivLength, headerLength + ivLength + tagLengthBytes);
        return {
            messageHeader,
            headerLength,
            rawHeader,
            algorithmSuite,
            headerAuth: {
                headerIv,
                headerAuthTag,
                headerAuthLength: headerIv.byteLength + headerAuthTag.byteLength,
            },
        };
    }
}
exports.deserializeHeaderV1Factory = deserializeHeaderV1Factory;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVzZXJpYWxpemVfaGVhZGVyX3YxLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2Rlc2VyaWFsaXplX2hlYWRlcl92MS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsb0VBQW9FO0FBQ3BFLHNDQUFzQzs7O0FBRXRDOzs7Ozs7O0dBT0c7QUFFSCx5RUFRd0M7QUFReEMsZ0ZBQWdGO0FBQ2hGLFNBQWdCLDBCQUEwQixDQUErQixFQUN2RSx1QkFBdUIsRUFDdkIsNEJBQTRCLEVBQzVCLFFBQVEsR0FnQlQ7SUFDQyxPQUFPLDBCQUEwQixDQUFBO0lBRWpDOzs7Ozs7Ozs7OztPQVdHO0lBQ0gsU0FBUywwQkFBMEIsQ0FDakMsYUFBeUIsRUFDekIscUJBQXlDLEVBQUUsb0JBQW9CLEVBQUUsS0FBSyxFQUFFO1FBRXhFOzs7OztXQUtHO1FBQ0gsTUFBTSxRQUFRLEdBQUcsSUFBSSxRQUFRLENBQzNCLGFBQWEsQ0FBQyxNQUFNLEVBQ3BCLGFBQWEsQ0FBQyxVQUFVLEVBQ3hCLGFBQWEsQ0FBQyxVQUFVLENBQ3pCLENBQUE7UUFFRDs7O1dBR0c7UUFDSCxJQUFJLFFBQVEsQ0FBQyxVQUFVLEdBQUcsRUFBRTtZQUFFLE9BQU8sS0FBSyxDQUFBLENBQUMsa0JBQWtCO1FBRTdELE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUE7UUFDcEMsTUFBTSxJQUFJLEdBQUcsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQTtRQUNqQyxpRUFBaUU7UUFDakUsSUFBQSwyQkFBSyxFQUNILE9BQU8sS0FBSyxtQ0FBYSxDQUFDLEVBQUUsSUFBSSxJQUFJLEtBQUssR0FBRyxFQUM1QyxPQUFPLEtBQUssRUFBRSxJQUFJLElBQUksS0FBSyxFQUFFO1lBQzNCLENBQUMsQ0FBQyxvREFBb0Q7WUFDdEQsQ0FBQyxDQUFDLG1CQUFtQixDQUN4QixDQUFBO1FBRUQsTUFBTSxPQUFPLEdBQUcsUUFB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