6b7cbdac7132fe6bfe41380f260318cd00ec5f44
[bpdyndnsd] / src / util.cpp
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         EVP_cleanup();  /*lint !e534 */
51         throw std::invalid_argument("Could not set up digest context correctly");
52     }
53
54     // Test if data is empty.
55     if ( data.empty() )
56     {
57         EVP_MD_CTX_cleanup(&mdctx); /*lint !e534 */
58         EVP_cleanup();  /*lint !e534 */
59         throw std::invalid_argument("Passed data is empty");
60     }
61
62     // Hash the data. At this point data is not empty and &mdctx is initialized.
63     if ( EVP_DigestUpdate(&mdctx, data.c_str(), data.size()) == 0 )
64     {
65         EVP_MD_CTX_cleanup(&mdctx); /*lint !e534 */
66         EVP_cleanup();  /*lint !e534 */
67         throw std::invalid_argument("Could not hash data into digest context");
68     }
69
70     // Retrieve the digest value from &mdctx and place it in md_value.
71     if ( EVP_DigestFinal_ex(&mdctx, md_value, &md_len) == 0 )
72     {
73         EVP_MD_CTX_cleanup(&mdctx); /*lint !e534 */
74         EVP_cleanup();  /*lint !e534 */
75         throw std::invalid_argument("Could not retrieve digest value");
76     }
77
78     // Test if md_value is filled correctly and md_len is not zero.
79     if ( (md_len == 0) || (EVP_MD_CTX_size(&mdctx) == 0) )
80     {
81         EVP_MD_CTX_cleanup(&mdctx); /*lint !e534 */
82         EVP_cleanup();  /*lint !e534 */
83         throw std::invalid_argument("Retrieved invalid digest value");
84     }
85
86     // Internal cleanup of the digest content.
87     EVP_MD_CTX_cleanup(&mdctx); /*lint !e534 */
88     EVP_cleanup();  /*lint !e534 */
89
90     // Convert md5 digest C string to hex.
91     std::ostringstream oss_digest_md5_hex;
92     for(unsigned int i = 0; i < md_len; ++i)
93     {
94         // We have to do a static cast to an decimal representation, cause otherwise ostringstream would interpret
95         // the stream as a character and output the character representation of the hex value.
96         oss_digest_md5_hex << std::nouppercase << std::setw(2) << std::setfill('0')
97                            << std::hex << static_cast<int>(static_cast<unsigned char>(md_value[i]));
98     }
99
100     return oss_digest_md5_hex.str();
101 }
102
103
104 /**
105  * Get the status code from the given data.
106  * @param data The data containing the status code at front, limited by delimiter.
107  * @param delimiter The delimiter to use.
108  * @return The parsed status code
109  */
110 std::string parse_status_code(std::string data, std::string delimiter)
111 {
112     std::list<std::string> tokens;
113     boost::algorithm::split(tokens,data,boost::is_any_of(delimiter));
114     if ( tokens.empty() )
115         return "";
116     return tokens.front();
117 }
118
119 }