/* The software in this package is distributed under the GNU General Public License version 2 (with a special exception described below). A copy of GNU General Public License (GPL) is included in this distribution, in the file COPYING.GPL. As a special exception, if other files instantiate templates or use macros or inline functions from this file, or you compile this file and link it with other works to produce a work based on this file, this file does not by itself cause the resulting work to be covered by the GNU General Public License. However the source code for this file must still be made available in accordance with section (3) of the GNU General Public License. This exception does not invalidate any other reasons why a work based on this file might be covered by the GNU General Public License. */ /** Hashing functions based upon openssl. @copyright Intra2net AG */ using namespace std; #include #include #include #include #include #include #include #include "crypto.hxx" #define buf_size (size_t)65536 using namespace I2n; namespace { const char* get_algo_name(algorithm algo) { switch (algo) { case MD5: return (char*)"md5"; case SHA1: return (char*)"sha1"; case SHA256: return (char*)"sha256"; case SHA384: return (char*)"sha384"; case SHA512: return (char*)"sha512"; default: return NULL; } } const string ERROR_MESSAGE = "Error while trying to hash the data"; } // eo anonymous namespace string I2n::encode_hex(string data) { return encode_hex((char *)data.c_str(), data.size()); } string I2n::encode_hex(char *data, unsigned int size) { ostringstream out; for (unsigned int i = 0; i < size; i++) out << hex << uppercase << setw(2) << setfill('0') << (int)(unsigned char)data[i]; return out.str(); } // output: hex encoded hash string I2n::hash_data(string data, algorithm algo) { return encode_hex(hash_data_raw(data, algo)); } // output: raw binary hash string I2n::hash_data_raw(string data, algorithm algo) { unsigned int olen; const EVP_MD *md; EVP_MD_CTX_Ptr ctx(EVP_MD_CTX_create(), EVP_MD_CTX_destroy); uchar_arr ret(new unsigned char[EVP_MAX_MD_SIZE]); OpenSSL_add_all_digests(); if(!(md = EVP_get_digestbyname(get_algo_name(algo))) || !EVP_DigestInit_ex(ctx.get(), md, NULL) || !EVP_DigestUpdate(ctx.get(), (char*)data.c_str(), data.length()) || !EVP_DigestFinal_ex(ctx.get(), ret.get(), &olen)) { throw runtime_error(ERROR_MESSAGE); } return string(reinterpret_cast(ret.get()), olen); } // hash data in 64kB blocks string I2n::hash_file(string filename, algorithm algo) { const EVP_MD *md; EVP_MD_CTX_Ptr ctx(EVP_MD_CTX_create(), EVP_MD_CTX_destroy); uchar_arr ret(new unsigned char[EVP_MAX_MD_SIZE]); unsigned int olen; OpenSSL_add_all_digests(); char_arr buf(new char[buf_size]); if (!buf) throw bad_alloc(); FILE* file = fopen (filename.c_str(), "r"); if (!file) { throw ios_base::failure("can't open file"); } if(!(md = EVP_get_digestbyname(get_algo_name(algo))) || !EVP_DigestInit_ex(ctx.get(), md, NULL)) { fclose(file); throw runtime_error(ERROR_MESSAGE); } int read_bytes; while (!feof(file)) { memset(buf.get(), 0, sizeof(char) * buf_size); read_bytes = fread (buf.get(), 1, buf_size, file); if (ferror(file)) { fclose(file); throw runtime_error("Error while reading file: " + filename); } if (read_bytes && !EVP_DigestUpdate(ctx.get(), buf.get(), read_bytes)) { fclose(file); throw runtime_error(ERROR_MESSAGE); } } if (!EVP_DigestFinal_ex(ctx.get(), ret.get(), &olen)) { fclose(file); throw runtime_error(ERROR_MESSAGE); } return string(encode_hex(reinterpret_cast(ret.get()), olen)); }