static void
_sol_message_digest_md5_init(struct sol_message_digest *handle)
{
    md5_ctx_t *ctx = sol_message_digest_common_get_context(handle);

    md5_init(ctx);
}
static void
_sol_message_digest_sha256_init(struct sol_message_digest *handle)
{
    sha256_context_t *ctx = sol_message_digest_common_get_context(handle);

    sha256_init(ctx);
}
static void
_sol_message_digest_evp_reset(struct sol_message_digest *handle)
{
    EVP_MD_CTX *ctx = sol_message_digest_common_get_context(handle);

    EVP_MD_CTX_reset(ctx);
}
static void
_sol_message_digest_hmac_reset(struct sol_message_digest *handle)
{
    HMAC_CTX *ctx = sol_message_digest_common_get_context(handle);

    HMAC_CTX_reset(ctx);
}
static ssize_t
_sol_message_digest_md5_feed(struct sol_message_digest *handle, const void *mem, size_t len, bool is_last)
{
    md5_ctx_t *ctx = sol_message_digest_common_get_context(handle);

    md5_update(ctx, mem, len);
    return len;
}
static ssize_t
_sol_message_digest_evp_feed(struct sol_message_digest *handle, const void *mem, size_t len, bool is_last)
{
    EVP_MD_CTX *ctx = sol_message_digest_common_get_context(handle);

    if (EVP_DigestUpdate(ctx, mem, len))
        return len;

    return -EIO;
}
static int
_sol_message_digest_evp_init(struct sol_message_digest *handle, const EVP_MD *md, const struct sol_str_slice key)
{
    EVP_MD_CTX *ctx = sol_message_digest_common_get_context(handle);

    if (EVP_DigestInit_ex(ctx, md, NULL))
        return 0;

    return -EINVAL;
}
static int
_sol_message_digest_hmac_init(struct sol_message_digest *handle, const EVP_MD *md, const struct sol_str_slice key)
{
    HMAC_CTX *ctx = sol_message_digest_common_get_context(handle);

    if (HMAC_Init(ctx, key.data, key.len, md))
        return 0;

    return -EINVAL;
}
static ssize_t
_sol_message_digest_sha256_read_digest(struct sol_message_digest *handle, void *mem, size_t len)
{
    sha256_context_t *ctx = sol_message_digest_common_get_context(handle);

    if (len < SHA256_DIGEST_LENGTH)
        return -EINVAL;

    sha256_final(mem, ctx);
    return len;
}
static ssize_t
_sol_message_digest_md5_read_digest(struct sol_message_digest *handle, void *mem, size_t len)
{
    md5_ctx_t *ctx = sol_message_digest_common_get_context(handle);

    if (len < MD5_DIGEST_LENGTH)
        return -EINVAL;

    md5_final(ctx, mem);
    return len;
}
static ssize_t
_sol_message_digest_evp_read_digest(struct sol_message_digest *handle, void *mem, size_t len)
{
    EVP_MD_CTX *ctx = sol_message_digest_common_get_context(handle);
    unsigned int rlen = len;

    if (EVP_DigestFinal_ex(ctx, mem, &rlen)) {
        if (rlen != len)
            SOL_WRN("Wanted %zd digest bytes, got %u", len, rlen);
        return rlen;
    }

    return -EIO;
}