Merge branch 'redirect-urlauth'
[libi2ncommon] / src / crypto.cpp
CommitLineData
69d568dd
TC
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on 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
26using 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
40using namespace I2n;
41
42namespace
43{
44const 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
63const string ERROR_MESSAGE = "Error while trying to hash the data";
64} // eo anonymous namespace
65
66string I2n::encode_hex(string data)
67{
68 return encode_hex((char *)data.c_str(), data.size());
69}
70
71string 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
82string I2n::hash_data(string data, algorithm algo)
83{
84 return encode_hex(hash_data_raw(data, algo));
85}
86
87// output: raw binary hash
88string 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
112string 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}