libzypp  11.13.5
Digest.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
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 
81 
83  md(NULL),
84  initialized(false),
85  finalized(false)
86  {
87  }
88 
90  {
91  cleanup();
92  }
93 
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 
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 
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 
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