view modules/hash/hash.hpp @ 548:f48bb09bccc7

Misc: huge cleanup, switch to spaces
author David Demelier <markand@malikania.fr>
date Wed, 15 Jun 2016 13:13:26 +0200
parents b698e591b43a
children 4df397257d44
line wrap: on
line source

/*
 * hash.hpp -- hash functions
 *
 * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef HASH_HPP
#define HASH_HPP

/**
 * \file hash.hpp
 * \brief Hash functions.
 * \author David Demelier <markand\malikania.fr>
 */

/**
 * \brief Define buffer size.
 */
#if !defined(HASH_BUFFER_SIZE)
#  define HASH_BUFFER_SIZE 2048
#endif

#include <cassert>
#include <istream>
#include <iterator>
#include <sstream>
#include <string>

#include <openssl/sha.h>
#include <openssl/md5.h>

/**
 * \brief Hash namespace.
 */
namespace hash {

/**
 * \cond HASH_HIDDEN_SYMBOLS
 */

namespace detail {

template <typename Context>
using Init = int (*)(Context *);

template <typename Context>
using Update = int (*)(Context *, const void *, size_t);

template <typename Context>
using Final = int (*)(unsigned char *, Context *);

template <typename Context, size_t Length, typename InputIt>
inline std::string convert(InputIt it, InputIt end, Init<Context> init, Update<Context> update, Final<Context> finalize)
{
    unsigned char digest[Length] = { 0 };
    char hash[Length * 2 + 1];
    char buf[HASH_BUFFER_SIZE];

    Context ctx;
    init(&ctx);

    while (it != end) {
        unsigned i;

        for (i = 0; it != end && i < HASH_BUFFER_SIZE; ++i)
            buf[i] = *it++;

        update(&ctx, buf, i);
    }

    finalize(digest, &ctx);

    for (unsigned long i = 0; i < Length; i++)
        std::snprintf(&hash[i * 2], 2 + 1, "%02x", (unsigned int)digest[i]);

    return std::string(hash);
}

} // !namespace

/**
 * \endcond
 */

/**
 * \enum Scheme
 * \brief The scheme to use.
 */
enum Scheme {
    Md5,        //!< MD5
    Sha1,       //!< SHA-1
    Sha256,     //!< SHA-256
    Sha512      //!< SHA-512
};

/**
 * Generic function.
 *
 * \param scheme the scheme to use
 * \param it the first character
 * \param end the last character
 * \return the string
 */
template <typename InputIt>
inline std::string toString(Scheme scheme, InputIt it, InputIt end)
{
    assert(scheme >= Scheme::Md5 && scheme <= Scheme::Sha512);

    std::string result;

    switch (scheme) {
    case Scheme::Md5:
        result = detail::convert<MD5_CTX, MD5_DIGEST_LENGTH>(it, end, MD5_Init, MD5_Update, MD5_Final);
        break;
    case Scheme::Sha1:
        result = detail::convert<SHA_CTX, SHA_DIGEST_LENGTH>(it, end, SHA1_Init, SHA1_Update, SHA1_Final);;
        break;
    case Scheme::Sha256:
        result = detail::convert<SHA256_CTX, SHA256_DIGEST_LENGTH>(it, end, SHA256_Init, SHA256_Update, SHA256_Final);
        break;
    case Scheme::Sha512:
        result = detail::convert<SHA512_CTX, SHA512_DIGEST_LENGTH>(it, end, SHA512_Init, SHA512_Update, SHA512_Final);
        break;
    default:
        break;
    }

    return result;
}

/**
 * Overload for std::istream.
 *
 * \param scheme the scheme to use
 * \param input the input stream
 * \return the string
 */
inline std::string toString(Scheme scheme, std::istream &input)
{
    return toString(scheme, std::istreambuf_iterator<char>(input), std::istreambuf_iterator<char>());
}

/**
 * Overload for std::string.
 *
 * \param scheme the scheme to use
 * \param input the input stream
 * \return the string
 */
inline std::string toString(Scheme scheme, const std::string &input)
{
    return toString(scheme, input.begin(), input.end());
}

/**
 * Hash using MD5.
 *
 * \param input the input string
 * \return the hashed string
 */
inline std::string md5(const std::string &input)
{
    return toString(Scheme::Md5, input);
}

/**
 * Hash using MD5.
 *
 * \param input the input stream
 * \return the hashed string
 */
inline std::string md5(std::istream &input)
{
    return toString(Scheme::Md5, input);
}

/**
 * Hash using SHA1.
 *
 * \param input the input string
 * \return the hashed string
 */
inline std::string sha1(const std::string &input)
{
    return toString(Scheme::Sha1, input);
}

/**
 * Hash using SHA1.
 *
 * \param input the input stream
 * \return the hashed string
 */
inline std::string sha1(std::istream &input)
{
    return toString(Scheme::Sha1, input);
}

/**
 * Hash using SHA256.
 *
 * \param input the input string
 * \return the hashed string
 */
inline std::string sha256(const std::string &input)
{
    return toString(Scheme::Sha256, input);
}

/**
 * Hash using SHA256.
 *
 * \param input the input stream
 * \return the hashed string
 */
inline std::string sha256(std::istream &input)
{
    return toString(Scheme::Sha256, input);
}

/**
 * Hash using SHA512.
 *
 * \param input the input string
 * \return the hashed string
 */
inline std::string sha512(const std::string &input)
{
    return toString(Scheme::Sha512, input);
}

/**
 * Hash using SHA512.
 *
 * \param input the input stream
 * \return the hashed string
 */
inline std::string sha512(std::istream &input)
{
    return toString(Scheme::Sha512, input);
}

} // !hash

#endif // !HASH_HPP