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