Imported Upstream version 17.2.0
[platform/upstream/libzypp.git] / zypp / Digest.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/Digest.cc
10  *
11  * \todo replace by Blocxx
12  *
13 */
14
15 #include <cstdio> // snprintf
16 #include <openssl/evp.h>
17 #include <openssl/conf.h>
18 #include <openssl/engine.h>
19 #include <string>
20 #include <string.h>
21
22 #include <iostream>
23 #include <sstream>
24
25 #ifdef DIGEST_TESTSUITE
26 #include <fstream>
27 #endif
28
29 #include "zypp/Digest.h"
30 #include "zypp/base/PtrTypes.h"
31
32 namespace zypp {
33
34     bool DigestReport::askUserToAcceptNoDigest( const zypp::Pathname &file )
35     { return false; }
36
37     bool DigestReport::askUserToAccepUnknownDigest( const Pathname &file, const std::string &name )
38     { return false; }
39
40     bool DigestReport::askUserToAcceptWrongDigest( const Pathname &file, const std::string &requested, const std::string &found )
41     { return false; }
42
43
44     const std::string & Digest::md5()
45     { static std::string _type( "md5" ); return _type; }
46
47     const std::string & Digest::sha1()
48     { static std::string _type( "sha1" ); return _type; }
49
50     const std::string & Digest::sha224()
51     { static std::string _type( "sha224" ); return _type; }
52
53     const std::string & Digest::sha256()
54     { static std::string _type( "sha256" ); return _type; }
55
56     const std::string & Digest::sha384()
57     { static std::string _type( "sha384" ); return _type; }
58
59     const std::string & Digest::sha512()
60     { static std::string _type( "sha512" ); return _type; }
61
62     // private data
63     class Digest::P
64     {
65       P(const P& p);
66       const P& operator=(const P& p);
67
68       public:
69         typedef zypp::shared_ptr<EVP_MD_CTX> EvpDataPtr;
70         P();
71         ~P();
72
73         EvpDataPtr mdctx;
74
75         const EVP_MD *md;
76         unsigned char md_value[EVP_MAX_MD_SIZE];
77         unsigned md_len;
78
79         bool finalized : 1;
80         static bool openssl_digests_added;
81
82         std::string name;
83
84         inline bool maybeInit();
85         inline void cleanup();
86     };
87
88
89     using namespace std;
90
91     bool Digest::P::openssl_digests_added = false;
92
93     Digest::P::P() :
94       md(NULL),
95       finalized(false)
96     {
97     }
98
99     Digest::P::~P()
100     {
101       cleanup();
102     }
103
104     bool Digest::P::maybeInit()
105     {
106       if(!openssl_digests_added)
107       {
108         OPENSSL_config(NULL);
109         ENGINE_load_builtin_engines();
110         ENGINE_register_all_complete();
111         OpenSSL_add_all_digests();
112         openssl_digests_added = true;
113       }
114
115       if(!mdctx)
116       {
117         md = EVP_get_digestbyname(name.c_str());
118         if(!md)
119           return false;
120
121 #if OPENSSL_VERSION_NUMBER < 0x10100000L
122         EvpDataPtr tmp_mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_destroy);
123 #else
124         EvpDataPtr tmp_mdctx(EVP_MD_CTX_new(), EVP_MD_CTX_free);
125 #endif
126         if (!tmp_mdctx)
127           return false;
128
129         if (!EVP_DigestInit_ex(tmp_mdctx.get(), md, NULL)) {
130           return false;
131         }
132
133         md_len = 0;
134         ::memset(md_value, 0, sizeof(md_value));
135
136         mdctx.swap(tmp_mdctx);
137       }
138       return true;
139     }
140
141     void Digest::P::cleanup()
142     {
143       mdctx.reset();
144       finalized = false;
145     }
146
147     Digest::Digest() : _dp(new P())
148     {
149     }
150
151     Digest::~Digest()
152     {
153       delete _dp;
154     }
155
156     bool Digest::create(const std::string& name)
157     {
158       if(name.empty()) return false;
159
160       if(_dp->mdctx)
161         _dp->cleanup();
162
163       _dp->name = name;
164
165       return _dp->maybeInit();
166     }
167
168     const std::string& Digest::name()
169     {
170       return _dp->name;
171     }
172
173     bool Digest::reset()
174     {
175       if (!_dp->mdctx)
176         return false;
177       if(!_dp->finalized)
178       {
179         (void)EVP_DigestFinal_ex(_dp->mdctx.get(), _dp->md_value, &_dp->md_len);
180         _dp->finalized = true;
181       }
182       if(!EVP_DigestInit_ex(_dp->mdctx.get(), _dp->md, NULL))
183         return false;
184       _dp->finalized = false;
185       return true;
186     }
187
188     std::string Digest::digest()
189     {
190       if(!_dp->maybeInit())
191         return std::string();
192
193       if(!_dp->finalized)
194       {
195       if(!EVP_DigestFinal_ex(_dp->mdctx.get(), _dp->md_value, &_dp->md_len))
196             return std::string();
197
198         _dp->finalized = true;
199       }
200
201       char mdtxt[_dp->md_len*2 + 1];
202       mdtxt[_dp->md_len*2] = '\0';
203
204       for(unsigned i = 0; i < _dp->md_len; ++i)
205       {
206         ::snprintf(mdtxt + i*2, 3, "%02hhx", _dp->md_value[i]);
207       }
208
209       return std::string(mdtxt);
210     }
211
212     std::vector<unsigned char> Digest::digestVector()
213     {
214       std::vector<unsigned char> r;
215       if(!_dp->maybeInit())
216         return r;
217
218       if(!_dp->finalized)
219       {
220         if(!EVP_DigestFinal_ex(_dp->mdctx.get(), _dp->md_value, &_dp->md_len))
221             return r;
222         _dp->finalized = true;
223       }
224       r.reserve(_dp->md_len);
225       for(unsigned i = 0; i < _dp->md_len; ++i)
226         r.push_back(_dp->md_value[i]);
227       return r;
228     }
229
230     bool Digest::update(const char* bytes, size_t len)
231     {
232       if(!bytes)
233       {
234         return false;
235       }
236
237       if(!_dp->maybeInit())
238         return false;
239
240       if(_dp->finalized)
241       {
242         _dp->cleanup();
243         if(!_dp->maybeInit())
244             return false;
245
246       }
247       if(!EVP_DigestUpdate(_dp->mdctx.get(), reinterpret_cast<const unsigned char*>(bytes), len))
248         return false;
249
250       return true;
251     }
252
253     std::string Digest::digest(const std::string& name, std::istream& is, size_t bufsize)
254     {
255       if(name.empty() || !is)
256         return string();
257
258       char buf[bufsize];
259
260       Digest digest;
261       if(!digest.create(name))
262         return string();
263
264
265       while(is.good())
266       {
267         int readed;
268         is.read(buf, bufsize);
269         readed = is.gcount();
270         if(readed && !digest.update(buf, readed))
271             return string();
272       }
273
274       return digest.digest();
275     }
276
277     std::string Digest::digest( const std::string & name, const std::string & input, size_t bufsize )
278     {
279       istringstream is( input );
280       return digest( name, is, bufsize );
281     }
282
283 #ifdef DIGEST_TESTSUITE
284     int main(int argc, char *argv[])
285     {
286       bool openssl = false;
287       unsigned argpos = 1;
288
289       if(argc > 1 && string(argv[argpos]) == "--openssl")
290       {
291         openssl = true;
292         ++argpos;
293       }
294
295       if(argc - argpos < 2)
296       {
297         cerr << "Usage: " << argv[0] << " <DIGESTNAME> <FILE>" << endl;
298         return 1;
299       }
300
301       const char* digestname = argv[argpos++];
302       const char* fn = argv[argpos++];
303
304       ifstream file(fn);
305
306       string digest = Digest::digest(digestname, file);
307
308       if(openssl)
309         cout << digestname << "(" << fn << ")= " << digest << endl;
310       else
311         cout << digest << "  " << fn << endl;
312
313       return 0;
314     }
315 #endif
316
317 } // namespace zypp