Commit | Line | Data |
---|---|---|
69d568dd TC |
1 | /* |
2 | The software in this package is distributed under the GNU General | |
3 | Public License version 2 (with a special exception described below). | |
4 | ||
5 | A copy of GNU General Public License (GPL) is included in this distribution, | |
6 | in the file COPYING.GPL. | |
7 | ||
8 | As a special exception, if other files instantiate templates or use macros | |
9 | or inline functions from this file, or you compile this file and link it | |
10 | with other works to produce a work based on this file, this file | |
11 | does not by itself cause the resulting work to be covered | |
12 | by the GNU General Public License. | |
13 | ||
14 | However the source code for this file must still be made available | |
15 | in accordance with section (3) of the GNU General Public License. | |
16 | ||
17 | This exception does not invalidate any other reasons why a work based | |
18 | on this file might be covered by the GNU General Public License. | |
19 | */ | |
20 | /** | |
21 | Hashing functions based upon openssl. | |
22 | ||
23 | @copyright Intra2net AG | |
24 | */ | |
25 | ||
26 | using namespace std; | |
27 | ||
28 | #include <openssl/evp.h> | |
29 | #include <sstream> | |
30 | #include <iomanip> | |
31 | #include <string> | |
32 | #include <string.h> | |
33 | #include <boost/shared_ptr.hpp> | |
34 | #include <stdexcept> | |
35 | #include "crypto.hxx" | |
36 | ||
37 | #define buf_size (size_t)65536 | |
38 | ||
39 | ||
40 | using namespace I2n; | |
41 | ||
42 | namespace | |
43 | { | |
44 | const char* get_algo_name(algorithm algo) | |
45 | { | |
46 | switch (algo) | |
47 | { | |
48 | case MD5: | |
49 | return (char*)"md5"; | |
50 | case SHA1: | |
51 | return (char*)"sha1"; | |
52 | case SHA256: | |
53 | return (char*)"sha256"; | |
54 | case SHA384: | |
55 | return (char*)"sha384"; | |
56 | case SHA512: | |
57 | return (char*)"sha512"; | |
58 | default: | |
59 | return NULL; | |
60 | } | |
61 | } | |
62 | ||
63 | const string ERROR_MESSAGE = "Error while trying to hash the data"; | |
64 | } // eo anonymous namespace | |
65 | ||
66 | string I2n::encode_hex(string data) | |
67 | { | |
68 | return encode_hex((char *)data.c_str(), data.size()); | |
69 | } | |
70 | ||
71 | string I2n::encode_hex(char *data, unsigned int size) | |
72 | { | |
73 | ostringstream out; | |
74 | ||
75 | for (unsigned int i = 0; i < size; i++) | |
76 | out << hex << uppercase << setw(2) << setfill('0') << (int)(unsigned char)data[i]; | |
77 | ||
78 | return out.str(); | |
79 | } | |
80 | ||
81 | // output: hex encoded hash | |
82 | string I2n::hash_data(string data, algorithm algo) | |
83 | { | |
84 | return encode_hex(hash_data_raw(data, algo)); | |
85 | } | |
86 | ||
87 | // output: raw binary hash | |
88 | string I2n::hash_data_raw(string data, algorithm algo) | |
89 | { | |
90 | unsigned int olen; | |
91 | ||
92 | const EVP_MD *md; | |
93 | ||
94 | EVP_MD_CTX_Ptr ctx(EVP_MD_CTX_create(), EVP_MD_CTX_destroy); | |
95 | ||
96 | uchar_arr ret(new unsigned char[EVP_MAX_MD_SIZE]); | |
97 | ||
98 | OpenSSL_add_all_digests(); | |
99 | ||
100 | if(!(md = EVP_get_digestbyname(get_algo_name(algo))) || | |
101 | !EVP_DigestInit_ex(ctx.get(), md, NULL) || | |
102 | !EVP_DigestUpdate(ctx.get(), (char*)data.c_str(), data.length()) || | |
103 | !EVP_DigestFinal_ex(ctx.get(), ret.get(), &olen)) | |
104 | { | |
105 | throw runtime_error(ERROR_MESSAGE); | |
106 | } | |
107 | ||
108 | return string(reinterpret_cast<char*>(ret.get()), olen); | |
109 | } | |
110 | ||
111 | // hash data in 64kB blocks | |
112 | string I2n::hash_file(string filename, algorithm algo) | |
113 | { | |
114 | const EVP_MD *md; | |
115 | ||
116 | EVP_MD_CTX_Ptr ctx(EVP_MD_CTX_create(), EVP_MD_CTX_destroy); | |
117 | ||
118 | uchar_arr ret(new unsigned char[EVP_MAX_MD_SIZE]); | |
119 | ||
120 | unsigned int olen; | |
121 | ||
122 | OpenSSL_add_all_digests(); | |
123 | ||
124 | char_arr buf(new char[buf_size]); | |
125 | ||
126 | if (!buf) | |
127 | throw bad_alloc(); | |
128 | ||
129 | FILE* file = fopen (filename.c_str(), "r"); | |
130 | if (!file) | |
131 | { | |
132 | throw ios_base::failure("can't open file"); | |
133 | } | |
134 | ||
135 | if(!(md = EVP_get_digestbyname(get_algo_name(algo))) || | |
136 | !EVP_DigestInit_ex(ctx.get(), md, NULL)) | |
137 | { | |
138 | fclose(file); | |
139 | throw runtime_error(ERROR_MESSAGE); | |
140 | } | |
141 | ||
142 | int read_bytes; | |
143 | ||
144 | while (!feof(file)) | |
145 | { | |
146 | memset(buf.get(), 0, sizeof(char) * buf_size); | |
147 | ||
148 | read_bytes = fread (buf.get(), 1, buf_size, file); | |
149 | ||
150 | if (ferror(file)) | |
151 | { | |
152 | fclose(file); | |
153 | throw runtime_error("Error while reading file: " + filename); | |
154 | } | |
155 | ||
156 | if (read_bytes && !EVP_DigestUpdate(ctx.get(), buf.get(), read_bytes)) | |
157 | { | |
158 | fclose(file); | |
159 | throw runtime_error(ERROR_MESSAGE); | |
160 | } | |
161 | } | |
162 | ||
163 | if (!EVP_DigestFinal_ex(ctx.get(), ret.get(), &olen)) | |
164 | { | |
165 | fclose(file); | |
166 | throw runtime_error(ERROR_MESSAGE); | |
167 | } | |
168 | ||
169 | return string(encode_hex(reinterpret_cast<char*>(ret.get()), olen)); | |
170 | } |