changeset 520:b698e591b43a

Hash: resurrection
author David Demelier <markand@malikania.fr>
date Wed, 01 Jun 2016 16:42:14 +0200
parents d6dad57e9e6b
children b604d3dd45b7
files CMakeLists.txt modules/hash/CMakeLists.txt modules/hash/doc/mainpage.cpp modules/hash/hash.hpp modules/hash/test/main.cpp
diffstat 5 files changed, 381 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Wed Jun 01 16:35:01 2016 +0200
+++ b/CMakeLists.txt	Wed Jun 01 16:42:14 2016 +0200
@@ -45,4 +45,5 @@
 add_subdirectory(modules/base64)
 add_subdirectory(modules/dynlib)
 add_subdirectory(modules/fs)
+add_subdirectory(modules/hash)
 add_subdirectory(modules/options)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/hash/CMakeLists.txt	Wed Jun 01 16:42:14 2016 +0200
@@ -0,0 +1,28 @@
+#
+# CMakeLists.txt -- code building for common code
+#
+# 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.
+#
+
+find_package(OpenSSL)
+
+if (OPENSSL_FOUND)
+	code_define_module(
+		NAME hash
+		SOURCES hash.hpp
+		LIBRARIES ${OPENSSL_LIBRARIES}
+		INCLUDES ${OPENSSL_INCLUDE_DIR}
+	)
+endif ()
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/hash/doc/mainpage.cpp	Wed Jun 01 16:42:14 2016 +0200
@@ -0,0 +1,31 @@
+/**
+ * \mainpage
+ *
+ * Welcome to the hash library.
+ *
+ * ## Introduction
+ *
+ * With the hash functions you can easily hash any string with OpenSSL.
+ *
+ * ## Requirements
+ * 
+ *   - C++11,
+ *   - [OpenSSL](http://openssl.org).
+ * 
+ * ## Installation
+ * 
+ * Just copy file hash.hpp and add it to your project.
+ *
+ * ## Overview
+ *
+ * ````
+ * #include "hash.hpp"
+ * 
+ * int main(void)
+ * {
+ *     hash::sha1("Hello World!");
+ * 
+ *     return 0;
+ * }
+ * ````
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/hash/hash.hpp	Wed Jun 01 16:42:14 2016 +0200
@@ -0,0 +1,257 @@
+/*
+ * 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/hash/test/main.cpp	Wed Jun 01 16:42:14 2016 +0200
@@ -0,0 +1,64 @@
+/*
+ * main.cpp -- test the hash cryptographic 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <hash.hpp>
+
+/*
+ * We test the "Hello World" message in all cryptographic functions.
+ */
+
+TEST(Hash, md5)
+{
+	std::string expected = "b10a8db164e0754105b7a99be72e3fe5";
+	std::string output = hash::md5("Hello World");
+
+	ASSERT_EQ(expected, output);
+}
+
+TEST(Hash, sha1)
+{
+	std::string expected = "0a4d55a8d778e5022fab701977c5d840bbc486d0";
+	std::string output = hash::sha1("Hello World");
+
+	ASSERT_EQ(expected, output);
+}
+
+TEST(Hash, sha256)
+{
+	std::string expected = "a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e";
+	std::string output = hash::sha256("Hello World");
+
+	ASSERT_EQ(expected, output);
+}
+
+TEST(Hash, sha512)
+{
+	std::string expected = "2c74fd17edafd80e8447b0d46741ee243b7eb74dd2149a0ab1b9246fb30382f27e853d8585719e0e67cbda0daa8f51671064615d645ae27acb15bfb1447f459b";
+	std::string output = hash::sha512("Hello World");
+
+	ASSERT_EQ(expected, output);
+}
+
+int main(int argc, char **argv)
+{
+	testing::InitGoogleTest(&argc, argv);
+
+	return RUN_ALL_TESTS();
+}