libzypp 17.31.28
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
37using std::endl;
38
39namespace 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
72 AutoDispose<EVP_MD *> md;
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
93 Digest::P::P() :
94 md(NULL),
95 finalized(false)
96 {
97 }
98
99 Digest::P::~P()
100 {
101 cleanup();
102 }
103
104 bool Digest::P::maybeInit()
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
169 void Digest::P::cleanup()
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
186 Digest &Digest::operator=(Digest &&other)
187 {
188 _dp = std::move( other._dp );
189 return *this;
190 }
191
192 Digest::~Digest()
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
212 bool Digest::reset()
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
228 Digest Digest::clone() const
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 {
238 return digestVectorToString( digestVector() );
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
291 UByteArray Digest::digestVector()
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
352 ByteCount Digest::bytesHashed() const
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
Store and operate with byte count.
Definition: ByteCount.h:31
EvpDataPtr mdctx
Definition: Digest.cc:70
const EVP_MD * md
Definition: Digest.cc:74
const P & operator=(const P &p)
unsigned char md_value[EVP_MAX_MD_SIZE]
Definition: Digest.cc:76
static bool openssl_digests_added
Definition: Digest.cc:81
zypp::ByteCount bytesHashed
Definition: Digest.cc:78
unsigned md_len
Definition: Digest.cc:77
zypp::shared_ptr< EVP_MD_CTX > EvpDataPtr
Definition: Digest.cc:66
void cleanup()
Definition: Digest.cc:169
bool maybeInit()
Definition: Digest.cc:104
std::string name
Definition: Digest.cc:83
bool finalized
Definition: Digest.cc:80
static const std::string & md5()
md5
Definition: Digest.cc:41
static const std::string & sha384()
sha384
Definition: Digest.cc:53
static const std::string & sha512()
sha512
Definition: Digest.cc:56
static const std::string & sha1()
sha1
Definition: Digest.cc:44
static const std::string & sha256()
sha256
Definition: Digest.cc:50
static const std::string & sha224()
sha224
Definition: Digest.cc:47
Definition: Arch.h:364
String related utilities and Regular expression matching.
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:2
#define c2h(c)
#define ERR
Definition: Logger.h:98