int aws_cryptosdk_serialize_frame()

in source/framefmt.c [298:359]


int aws_cryptosdk_serialize_frame(
    /* out */
    struct aws_cryptosdk_frame *frame,
    size_t *ciphertext_size,
    /* in */
    size_t plaintext_size,
    struct aws_byte_buf *ciphertext_buf,
    const struct aws_cryptosdk_alg_properties *alg_props) {
    AWS_PRECONDITION(aws_cryptosdk_frame_has_valid_type(frame));
    AWS_PRECONDITION(aws_byte_buf_is_valid(ciphertext_buf));
    AWS_PRECONDITION(aws_cryptosdk_alg_properties_is_valid(alg_props));
    struct aws_cryptosdk_framestate state;

    // The plaintext_size should be bound to prevent arithmetic
    // overflows due to addition
    if ((frame->type == FRAME_TYPE_SINGLE && plaintext_size > MAX_UNFRAMED_PLAINTEXT_SIZE) ||
        (frame->type != FRAME_TYPE_SINGLE && plaintext_size > MAX_FRAME_SIZE)) {
        // Clear the ciphertext buffer
        aws_byte_buf_secure_zero(ciphertext_buf);
        return aws_raise_error(AWS_CRYPTOSDK_ERR_LIMIT_EXCEEDED);
    }

    // We assume that the max frame size is equal to the plaintext size. This
    // lets us avoid having to pass in a redundant argument, avoids needing to
    // take a branch in serde_framed, and does not impact the serialized
    // output.
    state.max_frame_size = plaintext_size;
    state.plaintext_size = plaintext_size;
    // Currently all supported algorithms have plaintext = ciphertext size
    state.ciphertext_size = 0;

    state.alg_props = alg_props;
    state.u.buffer  = *ciphertext_buf;

    state.writing   = true;
    state.too_small = false;

    int result;
    if (frame->type == FRAME_TYPE_SINGLE) {
        result = serde_nonframed(&state, frame);
    } else {
        result = serde_framed(&state, frame);
    }

    if (result == AWS_ERROR_SUCCESS && state.too_small) {
        result = AWS_ERROR_SHORT_BUFFER;
    }

    *ciphertext_size = state.ciphertext_size;

    if (result != AWS_ERROR_SUCCESS) {
        // Clear any garbage we wrote
        aws_byte_buf_secure_zero(ciphertext_buf);
        return aws_raise_error(result);
    } else {
        *ciphertext_buf = state.u.buffer;
        AWS_POSTCONDITION(aws_cryptosdk_frame_is_valid(frame));
        AWS_POSTCONDITION(aws_cryptosdk_alg_properties_is_valid(alg_props));
        AWS_POSTCONDITION(aws_cryptosdk_frame_serialized(frame, alg_props, plaintext_size));
        return AWS_OP_SUCCESS;
    }
}