| 1 | /** @file |
| 2 | * @brief Util namespace header. |
| 3 | * |
| 4 | * |
| 5 | * |
| 6 | * @copyright Intra2net AG |
| 7 | * @license GPLv2 |
| 8 | */ |
| 9 | |
| 10 | #include "util.hpp" |
| 11 | |
| 12 | #include <sstream> |
| 13 | #include <iomanip> |
| 14 | #include <openssl/evp.h> |
| 15 | #include <boost/algorithm/string.hpp> |
| 16 | |
| 17 | namespace Util |
| 18 | { |
| 19 | /** |
| 20 | * Computes a MD5 Digest from the given string and returns the HEX representation |
| 21 | * @param data The string to compute the md5 for |
| 22 | * @return The computed md5 in hex |
| 23 | */ |
| 24 | std::string compute_md5_digest(std::string data) |
| 25 | { |
| 26 | // compute an MD5 digest. |
| 27 | |
| 28 | EVP_MD_CTX mdctx; |
| 29 | const EVP_MD *md; |
| 30 | unsigned char md_value[EVP_MAX_MD_SIZE]; |
| 31 | unsigned int md_len = 0; |
| 32 | |
| 33 | // Add all digest algorithms to the internal table. |
| 34 | OpenSSL_add_all_digests(); |
| 35 | |
| 36 | // Get the md5 digest algorithm from the internal table. |
| 37 | md = EVP_get_digestbyname("md5"); |
| 38 | |
| 39 | // Test if md is initialized. |
| 40 | if ( (md == NULL) || (EVP_MD_size(md) == 0) ) |
| 41 | throw std::invalid_argument("NULL pointer: md"); |
| 42 | |
| 43 | // Initalize digest content mdctx. |
| 44 | EVP_MD_CTX_init(&mdctx); |
| 45 | |
| 46 | // Now we can call init_ex. |
| 47 | if ( EVP_DigestInit_ex(&mdctx, md, NULL) == 0 ) |
| 48 | { |
| 49 | EVP_MD_CTX_cleanup(&mdctx); /*lint !e534 */ |
| 50 | throw std::invalid_argument("Could not set up digest context correctly"); |
| 51 | } |
| 52 | |
| 53 | // Test if data is empty. |
| 54 | if ( data.empty() ) |
| 55 | { |
| 56 | EVP_MD_CTX_cleanup(&mdctx); /*lint !e534 */ |
| 57 | throw std::invalid_argument("Passed data is empty"); |
| 58 | } |
| 59 | |
| 60 | // Hash the data. At this point data is not empty and &mdctx is initialized. |
| 61 | if ( EVP_DigestUpdate(&mdctx, data.c_str(), data.size()) == 0 ) |
| 62 | { |
| 63 | EVP_MD_CTX_cleanup(&mdctx); /*lint !e534 */ |
| 64 | throw std::invalid_argument("Could not hash data into digest context"); |
| 65 | } |
| 66 | |
| 67 | // Retrieve the digest value from &mdctx and place it in md_value. |
| 68 | if ( EVP_DigestFinal_ex(&mdctx, md_value, &md_len) == 0 ) |
| 69 | { |
| 70 | EVP_MD_CTX_cleanup(&mdctx); /*lint !e534 */ |
| 71 | throw std::invalid_argument("Could not retrieve digest value"); |
| 72 | } |
| 73 | |
| 74 | // Test if md_value is filled correctly and md_len is not zero. |
| 75 | if ( (md_len == 0) || (EVP_MD_CTX_size(&mdctx) == 0) ) |
| 76 | { |
| 77 | EVP_MD_CTX_cleanup(&mdctx); /*lint !e534 */ |
| 78 | throw std::invalid_argument("Retrieved invalid digest value"); |
| 79 | } |
| 80 | |
| 81 | // Internal cleanup of the digest content. |
| 82 | EVP_MD_CTX_cleanup(&mdctx); /*lint !e534 */ |
| 83 | |
| 84 | // Convert md5 digest C string to hex. |
| 85 | std::ostringstream oss_digest_md5_hex; |
| 86 | for(unsigned int i = 0; i < md_len; ++i) |
| 87 | { |
| 88 | // We have to do a static cast to an decimal representation, cause otherwise ostringstream would interpret |
| 89 | // the stream as a character and output the character representation of the hex value. |
| 90 | oss_digest_md5_hex << std::nouppercase << std::setw(2) << std::setfill('0') |
| 91 | << std::hex << static_cast<int>(static_cast<unsigned char>(md_value[i])); |
| 92 | } |
| 93 | |
| 94 | return oss_digest_md5_hex.str(); |
| 95 | } |
| 96 | |
| 97 | |
| 98 | /** |
| 99 | * Get the status code from the given data. |
| 100 | * @param data The data containing the status code at front, limited by delimiter. |
| 101 | * @param delimiter The delimiter to use. |
| 102 | * @return The parsed status code |
| 103 | */ |
| 104 | std::string parse_status_code(std::string data, std::string delimiter) |
| 105 | { |
| 106 | std::list<std::string> tokens; |
| 107 | boost::algorithm::split(tokens,data,boost::is_any_of(delimiter)); |
| 108 | if ( tokens.empty() ) |
| 109 | return ""; |
| 110 | return tokens.front(); |
| 111 | } |
| 112 | |
| 113 | } |