// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.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
 */
import { needs, NonCommittingAlgorithmSuiteIdentifier, MessageFormat, } from '@aws-crypto/material-management';
// To deal with Browser and Node.js I inject a function to handle utf8 encoding.
export 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. */
        needs(version === 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. */
        needs(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
         */
        needs(reservedBytes === 0, 'Malformed Header');
        const headerIvLength = dataView.getUint8(readPos + 1 + 4);
        /* Postcondition: The headerIvLength must match the algorithm suite specification. */
        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,
            },
        };
    }
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVzZXJpYWxpemVfaGVhZGVyX3YxLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2Rlc2VyaWFsaXplX2hlYWRlcl92MS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxvRUFBb0U7QUFDcEUsc0NBQXNDO0FBRXRDOzs7Ozs7O0dBT0c7QUFFSCxPQUFPLEVBS0wsS0FBSyxFQUNMLHFDQUFxQyxFQUNyQyxhQUFhLEdBQ2QsTUFBTSxpQ0FBaUMsQ0FBQTtBQVF4QyxnRkFBZ0Y7QUFDaEYsTUFBTSxVQUFVLDBCQUEwQixDQUErQixFQUN2RSx1QkFBdUIsRUFDdkIsNEJBQTRCLEVBQzVCLFFBQVEsR0FnQlQ7SUFDQyxPQUFPLDBCQUEwQixDQUFBO0lBRWpDOzs7Ozs7Ozs7OztPQVdHO0lBQ0gsU0FBUywwQkFBMEIsQ0FDakMsYUFBeUIsRUFDekIscUJBQXlDLEVBQUUsb0JBQW9CLEVBQUUsS0FBSyxFQUFFO1FBRXhFOzs7OztXQUtHO1FBQ0gsTUFBTSxRQUFRLEdBQUcsSUFBSSxRQUFRLENBQzNCLGFBQWEsQ0FBQyxNQUFNLEVBQ3BCLGFBQWEsQ0FBQyxVQUFVLEVBQ3hCLGFBQWEsQ0FBQyxVQUFVLENBQ3pCLENBQUE7UUFFRDs7O1dBR0c7UUFDSCxJQUFJLFFBQVEsQ0FBQyxVQUFVLEdBQUcsRUFBRTtZQUFFLE9BQU8sS0FBSyxDQUFBLENBQUMsa0JBQWtCO1FBRTdELE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUE7UUFDcEMsTUFBTSxJQUFJLEdBQUcsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQTtRQUNqQyxpRUFBaUU7UUFDakUsS0FBSyxDQUNILE9BQU8sS0FBSyxhQUFhLENBQUMsRUFBRSxJQUFJLElBQUksS0FBSyxHQUFHLEVBQzVDLE9BQU8sS0FBSyxFQUFFLElBQUksSUFBSSxLQUFLLEVBQUU7WUFDM0IsQ0FBQyxDQUFDLG9EQUFvRDtZQUN0RCxDQUFD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