int aws_cryptosdk_verify_header()

in source/cipher.c [563:613]


int aws_cryptosdk_verify_header(
    const struct aws_cryptosdk_alg_properties *props,
    const struct content_key *content_key,
    const struct aws_byte_buf *authtag,
    const struct aws_byte_buf *header) {
    /*
     * Note: We don't delegate to sign_header here, as we want to leave the
     * GCM tag comparison (which needs to be constant-time) to openssl.
     */

    const uint8_t *iv, *tag;

    AWS_PRECONDITION(aws_cryptosdk_alg_properties_is_valid(props));

    if (props->msg_format_version == AWS_CRYPTOSDK_HEADER_VERSION_1_0) {
        if (authtag->len != props->iv_len + props->tag_len) {
            return aws_raise_error(AWS_CRYPTOSDK_ERR_BAD_CIPHERTEXT);
        }
        iv  = authtag->buffer;
        tag = authtag->buffer + props->iv_len;
    } else if (props->msg_format_version == AWS_CRYPTOSDK_HEADER_VERSION_2_0) {
        static const uint8_t ZERO_IV[12] = { 0 };

        if (authtag->len != props->tag_len) {
            return aws_raise_error(AWS_CRYPTOSDK_ERR_BAD_CIPHERTEXT);
        }

        iv  = ZERO_IV;
        tag = authtag->buffer;
    } else {
        return aws_raise_error(AWS_CRYPTOSDK_ERR_CRYPTO_UNKNOWN);
    }

    int result = AWS_CRYPTOSDK_ERR_CRYPTO_UNKNOWN;

    EVP_CIPHER_CTX *ctx = evp_gcm_cipher_init(props, content_key, iv, false);
    if (!ctx) goto out;

    int outlen;
    if (!EVP_DecryptUpdate(ctx, NULL, &outlen, header->buffer, header->len)) goto out;

    result = evp_gcm_decrypt_final(props, ctx, tag);
out:
    if (ctx) EVP_CIPHER_CTX_free(ctx);

    if (result == AWS_ERROR_SUCCESS) {
        return AWS_OP_SUCCESS;
    } else {
        return aws_raise_error(result);
    }
}