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