/*
 * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"). You may not use
 * this file except in compliance with the License. A copy of the License is
 * located at
 *
 *     http://aws.amazon.com/apache2.0/
 *
 * or in the "license" file accompanying this file. This file 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.
 */

#ifndef AWS_CRYPTOSDK_EDK_H
#define AWS_CRYPTOSDK_EDK_H

#include <aws/common/array_list.h>
#include <aws/common/byte_buf.h>

#include <aws/cryptosdk/exports.h>

/*
 * This public interface to the encrypted data key (EDK) objects is provided for
 * developers of CMMs and keyrings only. If you are a user of the AWS Encryption
 * SDK for C and you are not developing your own CMMs and/or keyrings, you do not
 * need to use it and you should not do so.
 */

/**
 * @addtogroup cmm_kr_lowlevel
 * @{
 */

/**
 * A structure representing a single encrypted data key.
 */
struct aws_cryptosdk_edk {
    struct aws_byte_buf provider_id;
    struct aws_byte_buf provider_info;
    struct aws_byte_buf ciphertext;
};

#ifdef __cplusplus
extern "C" {
#endif

/**
 * Evaluates the set of properties that define the shape of all valid aws_cryptosdk_edk structures.
 * It is also a cheap check, in the sense it run in constant time (i.e., no loops or recursion).
 */
AWS_CRYPTOSDK_API
bool aws_cryptosdk_edk_is_valid(const struct aws_cryptosdk_edk *const edk);

/**
 * Evaluates the set of properties that define the shape of a valid edk_list.
 * if (AWS_DEEP_CHECKS == 1), loops through all elements of the list;
 * otherwise, it completes in constant time.
 */
AWS_CRYPTOSDK_API
bool aws_cryptosdk_edk_list_is_valid(const struct aws_array_list *edk_list);

/**
 * Evaluates the set of properties that define the shape of a valid empty edk_list.
 */
AWS_CRYPTOSDK_API
bool aws_cryptosdk_empty_edk_list_is_valid(const struct aws_array_list *edk_list);

/**
 * Evaluates the set of properties that define the shape of a valid edk_list.
 * Takes time O(list->length) as it loops through all elements of the list;
 */
bool aws_cryptosdk_edk_list_elements_are_valid(const struct aws_array_list *edk_list);

/**
 * Deallocates all memory associated with an EDK. Setting all bytes of an EDK to
 * zero when you declare it will make this safe to call even if some buffers are unused.
 */
AWS_CRYPTOSDK_API
void aws_cryptosdk_edk_clean_up(struct aws_cryptosdk_edk *edk);

/**
 * Allocates an empty list of EDKs.
 */
AWS_CRYPTOSDK_API
int aws_cryptosdk_edk_list_init(struct aws_allocator *alloc, struct aws_array_list *edk_list);

/**
 * Deallocates all memory associated with all EDKs in the list and then deallocates the list.
 */
AWS_CRYPTOSDK_API
void aws_cryptosdk_edk_list_clean_up(struct aws_array_list *edk_list);

/**
 * Deallocates all memory associated with all EDKs in the list and then clears the list.
 * The array list itself remains allocated but empty.
 */
AWS_CRYPTOSDK_API
void aws_cryptosdk_edk_list_clear(struct aws_array_list *edk_list);

/**
 * Copies the EDK data in src to dest.
 */
AWS_CRYPTOSDK_API
int aws_cryptosdk_edk_init_clone(
    struct aws_allocator *alloc, struct aws_cryptosdk_edk *dest, const struct aws_cryptosdk_edk *src);

/**
 * Returns true if the contents of all EDK byte buffers are identical, false otherwise.
 */
AWS_CRYPTOSDK_STATIC_INLINE bool aws_cryptosdk_edk_eq(
    const struct aws_cryptosdk_edk *a, const struct aws_cryptosdk_edk *b) {
    return aws_byte_buf_eq(&a->ciphertext, &b->ciphertext) && aws_byte_buf_eq(&a->provider_info, &b->provider_info) &&
           aws_byte_buf_eq(&a->provider_id, &b->provider_id);
}

#ifdef __cplusplus
}
#endif

/** @} */  // doxygen group cmm_kr_lowlevel

#endif  // AWS_CRYPTOSDK_EDK_H