int aws_cryptosdk_priv_try_decrypt_body()

in source/session_decrypt.c [231:305]


int aws_cryptosdk_priv_try_decrypt_body(
    struct aws_cryptosdk_session *AWS_RESTRICT session,
    struct aws_byte_buf *AWS_RESTRICT poutput,
    struct aws_byte_cursor *AWS_RESTRICT pinput) {
    struct aws_cryptosdk_frame frame;
    // We'll save the original cursor state; if we don't have enough plaintext buffer we'll
    // need to roll back and un-consume the ciphertext.
    struct aws_byte_cursor input_rollback = *pinput;

    if (aws_cryptosdk_deserialize_frame(
            &frame,
            &session->input_size_estimate,
            &session->output_size_estimate,
            pinput,
            session->alg_props,
            session->frame_size)) {
        if (aws_last_error() == AWS_ERROR_SHORT_BUFFER) {
            // Not actually an error. We've updated the estimates, so move on.
            return AWS_OP_SUCCESS;
        } else {
            // Frame format was malformed. Propagate the error up the chain.
            return AWS_OP_ERR;
        }
    }

    // The frame is structurally sound. Now we just need to do some validation of its
    // contents and decrypt.

    if (session->frame_seqno != frame.sequence_number) {
        return aws_raise_error(AWS_CRYPTOSDK_ERR_BAD_CIPHERTEXT);
    }

    // Before we go further, do we have enough room to place the plaintext?
    struct aws_byte_buf output = { .buffer = 0, .len = 0, .capacity = 0, .allocator = NULL };
    if (!aws_byte_buf_advance(poutput, &output, session->output_size_estimate)) {
        *pinput = input_rollback;
        // No progress due to not enough plaintext output space.
        return AWS_OP_SUCCESS;
    }

    // We have everything we need, try to decrypt
    struct aws_byte_cursor ciphertext_cursor =
        aws_byte_cursor_from_array(frame.ciphertext.buffer, frame.ciphertext.len);

    int rv = aws_cryptosdk_decrypt_body(
        session->alg_props,
        &output,
        &ciphertext_cursor,
        &session->header.message_id,
        frame.sequence_number,
        frame.iv.buffer,
        &session->content_key,
        frame.authtag.buffer,
        frame.type);

    if (rv == AWS_ERROR_SUCCESS) {
        session->frame_seqno++;

        if (session->signctx) {
            struct aws_byte_cursor frame = { .ptr = input_rollback.ptr, .len = pinput->ptr - input_rollback.ptr };
            if (aws_cryptosdk_sig_update(session->signctx, frame)) {
                return AWS_OP_ERR;
            }
        }

        if (frame.type != FRAME_TYPE_FRAME) {
            aws_cryptosdk_priv_session_change_state(session, ST_CHECK_TRAILER);
        }

        return rv;
    }

    // An error was encountered; the top level loop will transition to the error state
    return rv;
}