in source/header.c [479:575]
int aws_cryptosdk_hdr_write(
const struct aws_cryptosdk_hdr *hdr, size_t *bytes_written, uint8_t *outbuf, size_t outlen) {
AWS_PRECONDITION(aws_cryptosdk_hdr_is_valid(hdr));
AWS_PRECONDITION(hdr->iv.len <= UINT8_MAX); // uint8_t max value
AWS_PRECONDITION(outlen == 0 || AWS_MEM_IS_READABLE(outbuf, outlen));
AWS_PRECONDITION(bytes_written != NULL);
struct aws_byte_buf output = aws_byte_buf_from_array(outbuf, outlen);
output.len = 0;
const struct aws_cryptosdk_alg_properties *alg_props = aws_cryptosdk_alg_props(hdr->alg_id);
if (!alg_props) goto INVALID_HEADER;
enum aws_cryptosdk_hdr_version header_version = alg_props->msg_format_version;
if (!aws_byte_buf_write_u8(&output, header_version)) goto WRITE_ERR;
if (header_version == AWS_CRYPTOSDK_HEADER_VERSION_1_0) {
if (!aws_byte_buf_write_u8(&output, AWS_CRYPTOSDK_HEADER_TYPE_CUSTOMER_AED)) goto WRITE_ERR;
}
if (!aws_byte_buf_write_be16(&output, hdr->alg_id)) goto WRITE_ERR;
if (!aws_byte_buf_write_from_whole_cursor(
&output, aws_byte_cursor_from_array(hdr->message_id.buffer, hdr->message_id.len)))
goto WRITE_ERR;
// TODO - unify everything on byte_bufs when the aws-c-common refactor lands
// See: https://github.com/awslabs/aws-c-common/pull/130
struct aws_byte_buf aad_length_field;
init_aws_byte_buf_raw(&aad_length_field);
if (!aws_byte_buf_advance(&output, &aad_length_field, 2)) goto WRITE_ERR;
size_t old_len = output.len;
if (aws_cryptosdk_enc_ctx_serialize(aws_default_allocator(), &output, &hdr->enc_ctx)) goto WRITE_ERR;
if (!aws_byte_buf_write_be16(&aad_length_field, (uint16_t)(output.len - old_len))) goto WRITE_ERR;
size_t edk_count = aws_array_list_length(&hdr->edk_list);
if (!aws_byte_buf_write_be16(&output, (uint16_t)edk_count)) goto WRITE_ERR;
for (size_t idx = 0; idx < edk_count; ++idx) {
void *vp_edk = NULL;
aws_array_list_get_at_ptr(&hdr->edk_list, &vp_edk, idx);
assert(vp_edk);
const struct aws_cryptosdk_edk *edk = vp_edk;
if (!aws_byte_buf_write_be16(&output, (uint16_t)edk->provider_id.len)) goto WRITE_ERR;
if (!aws_byte_buf_write_from_whole_cursor(
&output, aws_byte_cursor_from_array(edk->provider_id.buffer, edk->provider_id.len)))
goto WRITE_ERR;
if (!aws_byte_buf_write_be16(&output, (uint16_t)edk->provider_info.len)) goto WRITE_ERR;
if (!aws_byte_buf_write_from_whole_cursor(
&output, aws_byte_cursor_from_array(edk->provider_info.buffer, edk->provider_info.len)))
goto WRITE_ERR;
if (!aws_byte_buf_write_be16(&output, (uint16_t)edk->ciphertext.len)) goto WRITE_ERR;
if (!aws_byte_buf_write_from_whole_cursor(
&output, aws_byte_cursor_from_array(edk->ciphertext.buffer, edk->ciphertext.len)))
goto WRITE_ERR;
}
if (!aws_byte_buf_write_u8(
&output, hdr->frame_len ? AWS_CRYPTOSDK_HEADER_CTYPE_FRAMED : AWS_CRYPTOSDK_HEADER_CTYPE_NONFRAMED))
goto WRITE_ERR;
if (header_version == AWS_CRYPTOSDK_HEADER_VERSION_1_0) {
if (!aws_byte_buf_write(&output, zero.bytes, 4)) goto WRITE_ERR; // v01 reserved field
if (!aws_byte_buf_write_u8(&output, (uint8_t)hdr->iv.len)) goto WRITE_ERR;
}
if (!aws_byte_buf_write_be32(&output, hdr->frame_len)) goto WRITE_ERR;
if (!aws_byte_buf_write_from_whole_cursor(
&output, aws_byte_cursor_from_array(hdr->alg_suite_data.buffer, hdr->alg_suite_data.len)))
goto WRITE_ERR;
if (header_version == AWS_CRYPTOSDK_HEADER_VERSION_1_0) {
if (!aws_byte_buf_write_from_whole_cursor(&output, aws_byte_cursor_from_array(hdr->iv.buffer, hdr->iv.len)))
goto WRITE_ERR;
}
if (!aws_byte_buf_write_from_whole_cursor(
&output, aws_byte_cursor_from_array(hdr->auth_tag.buffer, hdr->auth_tag.len)))
goto WRITE_ERR;
*bytes_written = output.len;
return AWS_OP_SUCCESS;
INVALID_HEADER:
aws_secure_zero(outbuf, outlen);
*bytes_written = 0;
return aws_raise_error(AWS_CRYPTOSDK_ERR_BAD_STATE);
WRITE_ERR:
aws_secure_zero(outbuf, outlen);
*bytes_written = 0;
return aws_raise_error(AWS_ERROR_SHORT_BUFFER);
}