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