libzypp  17.31.31
Digest.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
15 #include <cstdio> // snprintf
16 
17 #include <openssl/evp.h>
18 #include <openssl/conf.h>
19 #include <optional>
20 #if OPENSSL_API_LEVEL < 30000
21 #include <openssl/engine.h>
22 #else
23 #include <openssl/provider.h>
24 #endif
25 
26 #include <string>
27 #include <string.h>
28 
29 #include <iostream>
30 #include <sstream>
31 
32 #include <zypp-core/AutoDispose.h>
33 #include <zypp-core/Digest.h>
34 #include <zypp-core/base/Logger.h>
35 #include <zypp-core/base/PtrTypes.h>
36 
37 using std::endl;
38 
39 namespace zypp {
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::sha224()
48  { static std::string _type( "sha224" ); return _type; }
49 
50  const std::string & Digest::sha256()
51  { static std::string _type( "sha256" ); return _type; }
52 
53  const std::string & Digest::sha384()
54  { static std::string _type( "sha384" ); return _type; }
55 
56  const std::string & Digest::sha512()
57  { static std::string _type( "sha512" ); return _type; }
58 
59  // private data
60  class Digest::P
61  {
62  P(const P& p);
63  const P& operator=(const P& p);
64 
65  public:
66  typedef zypp::shared_ptr<EVP_MD_CTX> EvpDataPtr;
67  P();
68  ~P();
69 
71 #if OPENSSL_API_LEVEL >= 30000
73 #else
74  const EVP_MD *md;
75 #endif
76  unsigned char md_value[EVP_MAX_MD_SIZE];
77  unsigned md_len;
79 
80  bool finalized : 1;
81  static bool openssl_digests_added;
82 
83  std::string name;
84 
85  inline bool maybeInit();
86  inline void cleanup();
87  };
88 
89 
90 
92 
94  md(NULL),
95  finalized(false)
96  {
97  }
98 
100  {
101  cleanup();
102  }
103 
105  {
106  if(!openssl_digests_added)
107  {
108 #if OPENSSL_API_LEVEL >= 30000
109  // openssl 3.0 does not use engines anymore, instead we fetch algorithms via a new API
110  // also it seems initialization is implicit, i'm not sure if that call here is even required.
111  OPENSSL_init_crypto( OPENSSL_INIT_LOAD_CONFIG, nullptr );
112 
113  // md4 was moved to legacy, we need this for zsync
114  if ( !OSSL_PROVIDER_load( nullptr, "legacy" ) ) {
115  ERR << "Failed to load legacy openssl provider" << std::endl;
116  }
117  if ( !OSSL_PROVIDER_load( nullptr, "default") ) {
118  ERR << "Failed to load default openssl provider" << std::endl;
119  }
120 
121  OPENSSL_init_crypto( OPENSSL_INIT_ADD_ALL_DIGESTS, nullptr );
122 #else
123 # if OPENSSL_API_LEVEL >= 10100
124  OPENSSL_init_crypto( OPENSSL_INIT_LOAD_CONFIG, nullptr );
125 # else
126  OPENSSL_config(NULL);
127 # endif
128  ENGINE_load_builtin_engines();
129  ENGINE_register_all_complete();
130  OpenSSL_add_all_digests();
131 #endif
132  openssl_digests_added = true;
133  }
134 
135  if(!mdctx)
136  {
137 #if OPENSSL_API_LEVEL >= 30000
138  // this fetches the new provider based algorithms, returned objects have to be free'd
139  // i wonder if we could cache the providers instead of querying them for every Digest instance....
140  md = AutoDispose<EVP_MD *>( EVP_MD_fetch (nullptr, name.c_str(), nullptr), EVP_MD_free );
141 #else
142  md = EVP_get_digestbyname(name.c_str());
143 #endif
144  if(!md)
145  return false;
146 
147 #if OPENSSL_VERSION_NUMBER < 0x10100000L
148  EvpDataPtr tmp_mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_destroy);
149 #else
150  EvpDataPtr tmp_mdctx(EVP_MD_CTX_new(), EVP_MD_CTX_free);
151 #endif
152  if (!tmp_mdctx)
153  return false;
154 
155  if (!EVP_DigestInit_ex(tmp_mdctx.get(), md, NULL)) {
156  return false;
157  }
158 
159  md_len = 0;
160  ::memset(md_value, 0, sizeof(md_value));
161 
162  bytesHashed = 0;
163 
164  mdctx.swap(tmp_mdctx);
165  }
166  return true;
167  }
168 
170  {
171 #if OPENSSL_API_LEVEL >= 30000
172  md.reset();
173 #endif
174  mdctx.reset();
175  finalized = false;
176  }
177 
178  Digest::Digest() : _dp( std::make_unique<P>() )
179  {
180  }
181 
182  Digest::Digest(Digest &&other) : _dp( std::move(other._dp) )
183  {
184  }
185 
187  {
188  _dp = std::move( other._dp );
189  return *this;
190  }
191 
193  { }
194 
195  bool Digest::create(const std::string& name)
196  {
197  if(name.empty()) return false;
198 
199  if(_dp->mdctx)
200  _dp->cleanup();
201 
202  _dp->name = name;
203 
204  return _dp->maybeInit();
205  }
206 
207  const std::string& Digest::name()
208  {
209  return _dp->name;
210  }
211 
213  {
214  if (!_dp->mdctx)
215  return false;
216  if(!_dp->finalized)
217  {
218  (void)EVP_DigestFinal_ex(_dp->mdctx.get(), _dp->md_value, &_dp->md_len);
219  _dp->finalized = true;
220  }
221  if(!EVP_DigestInit_ex(_dp->mdctx.get(), _dp->md, NULL))
222  return false;
223  _dp->finalized = false;
224  _dp->bytesHashed = 0;
225  return true;
226  }
227 
229  {
230  Digest d;
231  if ( !_dp->name.empty () )
232  d.create ( _dp->name );
233  return d;
234  }
235 
236  std::string Digest::digest()
237  {
239  }
240 
241  std::string Digest::digestVectorToString(const UByteArray &vec)
242  {
243  if ( vec.empty() )
244  return std::string();
245 
246  std::vector<char> resData ( vec.size()*2 + 1, '\0' );
247  char *mdtxt = &resData[0];
248  for(unsigned i = 0; i < vec.size(); ++i)
249  {
250  ::snprintf( mdtxt+(i*2), 3, "%02hhx", vec[i]);
251  }
252  return std::string( resData.data() );
253  }
254 
255 #ifdef __cpp_lib_string_view
256  namespace {
257  template <typename BArr>
258  BArr hexStrToBArr ( std::string_view &&str ) {
259  BArr bytes;
260  for ( std::string::size_type i = 0; i < str.length(); i+=2 )
261  {
262  #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
263  : ((c)>='a' && (c)<='f') ? ((c)-('a'-10)) \
264  : ((c)>='A' && (c)<='F') ? ((c)-('A'-10)) \
265  : -1)
266  int v = c2h(str[i]);
267  if (v < 0)
268  return {};
269  bytes.push_back(v);
270  v = c2h(str[i+1]);
271  if (v < 0)
272  return {};
273  bytes.back() = (bytes.back() << 4) | v;
274  #undef c2h
275  }
276  return bytes;
277  }
278  } // namespace
279 
280  ByteArray Digest::hexStringToByteArray(std::string_view str)
281  {
282  return hexStrToBArr<ByteArray>( std::move(str) );
283  }
284 
285  UByteArray Digest::hexStringToUByteArray( std::string_view str )
286  {
287  return hexStrToBArr<UByteArray>( std::move(str) );
288  }
289 #endif
290 
292  {
293  UByteArray r;
294  if(!_dp->maybeInit())
295  return r;
296 
297  if(!_dp->finalized)
298  {
299  if(!EVP_DigestFinal_ex(_dp->mdctx.get(), _dp->md_value, &_dp->md_len))
300  return r;
301  _dp->finalized = true;
302  }
303  r.reserve(_dp->md_len);
304  for(unsigned i = 0; i < _dp->md_len; ++i)
305  r.push_back(_dp->md_value[i]);
306  return r;
307  }
308 
309  bool Digest::update(const char* bytes, size_t len)
310  {
311  if(!bytes)
312  {
313  return false;
314  }
315 
316  if(!_dp->maybeInit())
317  return false;
318 
319  if(_dp->finalized)
320  {
321  _dp->cleanup();
322  if(!_dp->maybeInit())
323  return false;
324 
325  }
326  if(!EVP_DigestUpdate(_dp->mdctx.get(), reinterpret_cast<const unsigned char*>(bytes), len))
327  return false;
328 
329  _dp->bytesHashed += len;
330  return true;
331  }
332 
333  bool Digest::update(std::istream &is, size_t bufsize)
334  {
335  if( !is )
336  return false;
337 
338  char buf[bufsize];
339 
340  while(is.good())
341  {
342  size_t readed;
343  is.read(buf, bufsize);
344  readed = is.gcount();
345  if(readed && !update(buf, readed))
346  return false;
347  }
348 
349  return true;
350  }
351 
353  {
354  return _dp->bytesHashed;
355  }
356 
357  std::string Digest::digest(const std::string& name, std::istream& is, size_t bufsize)
358  {
359  if(name.empty() || !is)
360  return std::string();
361 
362  Digest digest;
363  if(!digest.create(name))
364  return std::string();
365 
366  if ( !digest.update( is, bufsize ))
367  return std::string();
368 
369  return digest.digest();
370  }
371 
372  std::string Digest::digest( const std::string & name, const std::string & input, size_t bufsize )
373  {
374  std::istringstream is( input );
375  return digest( name, is, bufsize );
376  }
377 
378 } // namespace zypp
UByteArray digestVector()
get vector of unsigned char representation of the digest
Definition: Digest.cc:291
static const std::string & sha256()
sha256
Definition: Digest.cc:50
static const std::string & sha1()
sha1
Definition: Digest.cc:44
unsigned md_len
Definition: Digest.cc:77
std::string digest()
get hex string representation of the digest
Definition: Digest.cc:236
Compute Message Digests (MD5, SHA1 etc)
Definition: Digest.h:37
zypp::shared_ptr< EVP_MD_CTX > EvpDataPtr
Definition: Digest.cc:66
Store and operate with byte count.
Definition: ByteCount.h:30
#define c2h(c)
EvpDataPtr mdctx
Definition: Digest.cc:70
String related utilities and Regular expression matching.
const std::string & name()
get the name of the current digest algorithm
Definition: Digest.cc:207
Definition: Arch.h:363
bool maybeInit()
Definition: Digest.cc:104
zypp::ByteCount bytesHashed
Definition: Digest.cc:78
const Digest & operator=(const Digest &d)=delete
bool reset()
reset internal digest state
Definition: Digest.cc:212
#define ERR
Definition: Logger.h:98
static std::string digestVectorToString(const UByteArray &vec)
get hex string representation of the digest vector given as parameter
Definition: Digest.cc:241
std::unique_ptr< P > _dp
Definition: Digest.h:40
static const std::string & sha512()
sha512
Definition: Digest.cc:56
unsigned char md_value[EVP_MAX_MD_SIZE]
Definition: Digest.cc:76
zypp::ByteCount bytesHashed() const
Returns the number of input bytes that have been added to the hash.
Definition: Digest.cc:352
static bool openssl_digests_added
Definition: Digest.cc:81
bool create(const std::string &name)
initialize creation of a new message digest
Definition: Digest.cc:195
SolvableIdType size_type
Definition: PoolMember.h:126
const EVP_MD * md
Definition: Digest.cc:74
static const std::string & md5()
md5
Definition: Digest.cc:41
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition: AutoDispose.h:93
static const std::string & sha224()
sha224
Definition: Digest.cc:47
Digest clone() const
Returns a clone of the current Digest and returns it.
Definition: Digest.cc:228
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
void cleanup()
Definition: Digest.cc:169
bool update(const char *bytes, size_t len)
feed data into digest computation algorithm
Definition: Digest.cc:309
const P & operator=(const P &p)
bool finalized
Definition: Digest.cc:80
static const std::string & sha384()
sha384
Definition: Digest.cc:53
std::string name
Definition: Digest.cc:83