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