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