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 | ||
e613cd71 | 94 | # if (OPENSSL_VERSION_NUMBER < 0x10100000L) |
69d568dd | 95 | EVP_MD_CTX_Ptr ctx(EVP_MD_CTX_create(), EVP_MD_CTX_destroy); |
e613cd71 PG |
96 | # else |
97 | EVP_MD_CTX_Ptr ctx(EVP_MD_CTX_new(), EVP_MD_CTX_free); | |
98 | # endif | |
69d568dd TC |
99 | |
100 | uchar_arr ret(new unsigned char[EVP_MAX_MD_SIZE]); | |
101 | ||
102 | OpenSSL_add_all_digests(); | |
103 | ||
104 | if(!(md = EVP_get_digestbyname(get_algo_name(algo))) || | |
105 | !EVP_DigestInit_ex(ctx.get(), md, NULL) || | |
106 | !EVP_DigestUpdate(ctx.get(), (char*)data.c_str(), data.length()) || | |
107 | !EVP_DigestFinal_ex(ctx.get(), ret.get(), &olen)) | |
108 | { | |
109 | throw runtime_error(ERROR_MESSAGE); | |
110 | } | |
111 | ||
112 | return string(reinterpret_cast<char*>(ret.get()), olen); | |
113 | } | |
114 | ||
115 | // hash data in 64kB blocks | |
116 | string I2n::hash_file(string filename, algorithm algo) | |
117 | { | |
118 | const EVP_MD *md; | |
119 | ||
e613cd71 | 120 | # if (OPENSSL_VERSION_NUMBER < 0x10100000L) |
69d568dd | 121 | EVP_MD_CTX_Ptr ctx(EVP_MD_CTX_create(), EVP_MD_CTX_destroy); |
e613cd71 PG |
122 | # else |
123 | EVP_MD_CTX_Ptr ctx(EVP_MD_CTX_new(), EVP_MD_CTX_free); | |
124 | # endif | |
69d568dd TC |
125 | |
126 | uchar_arr ret(new unsigned char[EVP_MAX_MD_SIZE]); | |
127 | ||
128 | unsigned int olen; | |
129 | ||
130 | OpenSSL_add_all_digests(); | |
131 | ||
132 | char_arr buf(new char[buf_size]); | |
133 | ||
134 | if (!buf) | |
135 | throw bad_alloc(); | |
136 | ||
137 | FILE* file = fopen (filename.c_str(), "r"); | |
138 | if (!file) | |
139 | { | |
140 | throw ios_base::failure("can't open file"); | |
141 | } | |
142 | ||
143 | if(!(md = EVP_get_digestbyname(get_algo_name(algo))) || | |
144 | !EVP_DigestInit_ex(ctx.get(), md, NULL)) | |
145 | { | |
146 | fclose(file); | |
147 | throw runtime_error(ERROR_MESSAGE); | |
148 | } | |
149 | ||
150 | int read_bytes; | |
151 | ||
152 | while (!feof(file)) | |
153 | { | |
154 | memset(buf.get(), 0, sizeof(char) * buf_size); | |
155 | ||
156 | read_bytes = fread (buf.get(), 1, buf_size, file); | |
157 | ||
158 | if (ferror(file)) | |
159 | { | |
160 | fclose(file); | |
161 | throw runtime_error("Error while reading file: " + filename); | |
162 | } | |
163 | ||
164 | if (read_bytes && !EVP_DigestUpdate(ctx.get(), buf.get(), read_bytes)) | |
165 | { | |
166 | fclose(file); | |
167 | throw runtime_error(ERROR_MESSAGE); | |
168 | } | |
169 | } | |
170 | ||
4cefaf51 PG |
171 | fclose(file); |
172 | ||
69d568dd TC |
173 | if (!EVP_DigestFinal_ex(ctx.get(), ret.get(), &olen)) |
174 | { | |
69d568dd TC |
175 | throw runtime_error(ERROR_MESSAGE); |
176 | } | |
177 | ||
178 | return string(encode_hex(reinterpret_cast<char*>(ret.get()), olen)); | |
179 | } |