libzypp: zypp-core/Digest.cc Source File

libzypp 17.36.6

Digest.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
14
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) = 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
72 EvpDataPtr mdctx;
73#if OPENSSL_API_LEVEL >= 30000
74 AutoDispose<EVP_MD *> md;
75#else
76 const EVP_MD *md;
77#endif
78 unsigned char md_value[EVP_MAX_MD_SIZE];
79 unsigned md_len;
80 zypp::ByteCount bytesHashed;
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
93 bool Digest::P::openssl_digests_added = false;
94
95 Digest::P::P() :
96 md(nullptr),
97 finalized(false)
98 {
99 }
100
101 Digest::P::~P()
102 {
103 cleanup();
104 }
105
106 bool Digest::P::maybeInit()
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
171 void Digest::P::cleanup()
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
194 Digest::~Digest()
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
214 bool Digest::reset()
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
230 Digest Digest::clone() const
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 {
240 return digestVectorToString( digestVector() );
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
293 UByteArray Digest::digestVector()
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
354 ByteCount Digest::bytesHashed() const
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::AutoDispose
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition AutoDispose.h:95
zypp::ByteArray
Definition ByteArray.h:19
zypp::ByteCount
Store and operate with byte count.
Definition ByteCount.h:32
zypp::Digest::P
Definition Digest.cc:61
zypp::Digest::P::mdctx
EvpDataPtr mdctx
Definition Digest.cc:72
zypp::Digest::P::md
const EVP_MD * md
Definition Digest.cc:76
zypp::Digest::P::P
P(P &&)=delete
zypp::Digest::P::P
P(const P &p)=delete
zypp::Digest::P::~P
~P()
Definition Digest.cc:101
zypp::Digest::P::md_value
unsigned char md_value[EVP_MAX_MD_SIZE]
Definition Digest.cc:78
zypp::Digest::P::openssl_digests_added
static bool openssl_digests_added
Definition Digest.cc:83
zypp::Digest::P::operator=
const P & operator=(const P &p)=delete
zypp::Digest::P::bytesHashed
zypp::ByteCount bytesHashed
Definition Digest.cc:80
zypp::Digest::P::md_len
unsigned md_len
Definition Digest.cc:79
zypp::Digest::P::EvpDataPtr
zypp::shared_ptr< EVP_MD_CTX > EvpDataPtr
Definition Digest.cc:68
zypp::Digest::P::operator=
P & operator=(P &&)=delete
zypp::Digest::P::cleanup
void cleanup()
Definition Digest.cc:171
zypp::Digest::P::P
P()
Definition Digest.cc:95
zypp::Digest::P::maybeInit
bool maybeInit()
Definition Digest.cc:106
zypp::Digest::P::name
std::string name
Definition Digest.cc:85
zypp::Digest::P::finalized
bool finalized
Definition Digest.cc:82
zypp::Digest::md5
static const std::string & md5()
md5
Definition Digest.cc:41
zypp::Digest::sha384
static const std::string & sha384()
sha384
Definition Digest.cc:53
zypp::Digest::digest
std::string digest()
get hex string representation of the digest
Definition Digest.cc:238
zypp::Digest::~Digest
~Digest()
Definition Digest.cc:194
zypp::Digest::Digest
Digest()
Definition Digest.cc:180
zypp::Digest::sha512
static const std::string & sha512()
sha512
Definition Digest.cc:56
zypp::Digest::digestVector
UByteArray digestVector()
get vector of unsigned char representation of the digest
Definition Digest.cc:293
zypp::Digest::sha1
static const std::string & sha1()
sha1
Definition Digest.cc:44
zypp::Digest::Digest
Digest(const Digest &d)=delete
zypp::Digest::update
bool update(const char *bytes, size_t len)
feed data into digest computation algorithm
Definition Digest.cc:311
zypp::Digest::clone
Digest clone() const
Returns a clone of the current Digest and returns it.
Definition Digest.cc:230
zypp::Digest::bytesHashed
zypp::ByteCount bytesHashed() const
Returns the number of input bytes that have been added to the hash.
Definition Digest.cc:354
zypp::Digest::_dp
std::unique_ptr< P > _dp
Definition Digest.h:41
zypp::Digest::sha256
static const std::string & sha256()
sha256
Definition Digest.cc:50
zypp::Digest::operator=
const Digest & operator=(const Digest &d)=delete
zypp::Digest::sha224
static const std::string & sha224()
sha224
Definition Digest.cc:47
zypp::Digest::digestVectorToString
static std::string digestVectorToString(const UByteArray &vec)
get hex string representation of the digest vector given as parameter
Definition Digest.cc:243
zypp::Digest::reset
bool reset()
reset internal digest state
Definition Digest.cc:214
zypp::Digest::name
const std::string & name()
get the name of the current digest algorithm
Definition Digest.cc:209
zypp::Digest::create
bool create(const std::string &name)
initialize creation of a new message digest
Definition Digest.cc:197
zypp::UByteArray
Definition ByteArray.h:46
std
Definition Arch.h:364
str
String related utilities and Regular expression matching.
zypp::str
String related utilities and Regular expression matching.
Definition PurgeKernels.h:19
zypp
Easy-to use interface to the ZYPP dependency resolver.
Definition Application.cc:20
string.h
c2h
#define c2h(c)
AutoDispose.h
Digest.h
Logger.h
ERR
#define ERR
Definition Logger.h:102
PtrTypes.h