int aws_cryptosdk_session_process()

in source/session.c [244:329]


int aws_cryptosdk_session_process(
    struct aws_cryptosdk_session *session,
    uint8_t *outp,
    size_t outlen,
    size_t *out_bytes_written,
    const uint8_t *inp,
    size_t inlen,
    size_t *in_bytes_read) {
    struct aws_byte_buf output   = { .buffer = outp, .capacity = outlen, .len = 0 };
    struct aws_byte_cursor input = { .ptr = (uint8_t *)inp, .len = inlen };
    int result;

    enum session_state prior_state;
    const uint8_t *old_inp;
    bool made_progress;

    *out_bytes_written = 0;

    do {
        prior_state = session->state;
        old_inp     = input.ptr;

        struct aws_byte_buf remaining_space =
            aws_byte_buf_from_empty_array(output.buffer + output.len, output.capacity - output.len);

        switch (session->state) {
            case ST_CONFIG:
                if (!session->cmm || !aws_cryptosdk_commitment_policy_is_valid(session->commitment_policy)) {
                    // TODO - is this the right error?
                    result = aws_raise_error(AWS_CRYPTOSDK_ERR_BAD_STATE);
                    break;
                }

                if (session->mode == AWS_CRYPTOSDK_ENCRYPT) {
                    aws_cryptosdk_priv_session_change_state(session, ST_GEN_KEY);
                } else {
                    aws_cryptosdk_priv_session_change_state(session, ST_READ_HEADER);
                }
                result = AWS_OP_SUCCESS;
                break;

            case ST_READ_HEADER: result = aws_cryptosdk_priv_try_parse_header(session, &input); break;
            case ST_UNWRAP_KEY: result = aws_cryptosdk_priv_unwrap_keys(session); break;
            case ST_DECRYPT_BODY:
                result = aws_cryptosdk_priv_try_decrypt_body(session, &remaining_space, &input);
                break;
            case ST_CHECK_TRAILER: result = aws_cryptosdk_priv_check_trailer(session, &input); break;

            case ST_GEN_KEY: result = aws_cryptosdk_priv_try_gen_key(session); break;
            case ST_WRITE_HEADER: result = aws_cryptosdk_priv_try_write_header(session, &remaining_space); break;
            case ST_ENCRYPT_BODY:
                result = aws_cryptosdk_priv_try_encrypt_body(session, &remaining_space, &input);
                break;
            case ST_WRITE_TRAILER: result = aws_cryptosdk_priv_write_trailer(session, &remaining_space); break;

            case ST_DONE: result = AWS_OP_SUCCESS; break;
            default: result = aws_raise_error(AWS_ERROR_UNKNOWN); break;
            case ST_ERROR: result = aws_raise_error(session->error); break;
        }

        made_progress = (remaining_space.len) || (input.ptr != old_inp) || (prior_state != session->state);

        output.len += remaining_space.len;
    } while (result == AWS_OP_SUCCESS && made_progress);

    *out_bytes_written = output.len;
    *in_bytes_read     = input.ptr - inp;

    if (result != AWS_OP_SUCCESS) {
        // Destroy any incomplete (and possibly corrupt) plaintext
        aws_byte_buf_secure_zero(&output);
        *out_bytes_written = 0;

        if (session->state != ST_ERROR) {
            session->error = aws_last_error();
            aws_cryptosdk_priv_session_change_state(session, ST_ERROR);
        }
    }

    if (session->state == ST_ERROR) {
        // (Re-)raise any stored error
        result = aws_raise_error(session->error);
    }

    return result;
}