libzypp 17.37.10

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/String.h>
35#include <zypp-core/base/Logger.h>
36#include <zypp-core/base/PtrTypes.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
73 EvpDataPtr mdctx;
74#if OPENSSL_API_LEVEL >= 30000
75 AutoDispose<EVP_MD *> md;
76#else
77 const EVP_MD *md;
78#endif
79 unsigned char md_value[EVP_MAX_MD_SIZE];
80 unsigned md_len;
81 zypp::ByteCount bytesHashed;
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
94 bool Digest::P::openssl_digests_added = false;
95
96 Digest::P::P() :
97 md(nullptr),
98 finalized(false)
99 {
100 }
101
102 Digest::P::~P()
103 {
104 cleanup();
105 }
106
107 bool Digest::P::maybeInit()
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
172 void Digest::P::cleanup()
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
195 Digest::~Digest()
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
215 bool Digest::reset()
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
231 Digest Digest::clone() const
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 {
241 return digestVectorToString( digestVector() );
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
270 UByteArray Digest::digestVector()
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
331 ByteCount Digest::bytesHashed() const
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::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:62
zypp::Digest::P::mdctx
EvpDataPtr mdctx
Definition Digest.cc:73
zypp::Digest::P::md
const EVP_MD * md
Definition Digest.cc:77
zypp::Digest::P::P
P(P &&)=delete
zypp::Digest::P::P
P(const P &p)=delete
zypp::Digest::P::~P
~P()
Definition Digest.cc:102
zypp::Digest::P::md_value
unsigned char md_value[EVP_MAX_MD_SIZE]
Definition Digest.cc:79
zypp::Digest::P::openssl_digests_added
static bool openssl_digests_added
Definition Digest.cc:84
zypp::Digest::P::operator=
const P & operator=(const P &p)=delete
zypp::Digest::P::bytesHashed
zypp::ByteCount bytesHashed
Definition Digest.cc:81
zypp::Digest::P::md_len
unsigned md_len
Definition Digest.cc:80
zypp::Digest::P::EvpDataPtr
zypp::shared_ptr< EVP_MD_CTX > EvpDataPtr
Definition Digest.cc:69
zypp::Digest::P::operator=
P & operator=(P &&)=delete
zypp::Digest::P::cleanup
void cleanup()
Definition Digest.cc:172
zypp::Digest::P::P
P()
Definition Digest.cc:96
zypp::Digest::P::maybeInit
bool maybeInit()
Definition Digest.cc:107
zypp::Digest::P::name
std::string name
Definition Digest.cc:86
zypp::Digest::P::finalized
bool finalized
Definition Digest.cc:83
zypp::Digest::md5
static const std::string & md5()
md5
Definition Digest.cc:42
zypp::Digest::sha384
static const std::string & sha384()
sha384
Definition Digest.cc:54
zypp::Digest::digest
std::string digest()
get hex string representation of the digest
Definition Digest.cc:239
zypp::Digest::~Digest
~Digest()
Definition Digest.cc:195
zypp::Digest::Digest
Digest()
Definition Digest.cc:181
zypp::Digest::sha512
static const std::string & sha512()
sha512
Definition Digest.cc:57
zypp::Digest::digestVector
UByteArray digestVector()
get vector of unsigned char representation of the digest
Definition Digest.cc:270
zypp::Digest::sha1
static const std::string & sha1()
sha1
Definition Digest.cc:45
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:288
zypp::Digest::clone
Digest clone() const
Returns a clone of the current Digest and returns it.
Definition Digest.cc:231
zypp::Digest::bytesHashed
zypp::ByteCount bytesHashed() const
Returns the number of input bytes that have been added to the hash.
Definition Digest.cc:331
zypp::Digest::_dp
std::unique_ptr< P > _dp
Definition Digest.h:41
zypp::Digest::sha256
static const std::string & sha256()
sha256
Definition Digest.cc:51
zypp::Digest::operator=
const Digest & operator=(const Digest &d)=delete
zypp::Digest::sha224
static const std::string & sha224()
sha224
Definition Digest.cc:48
zypp::Digest::digestVectorToString
static std::string digestVectorToString(const UByteArray &vec)
get hex string representation of the digest vector given as parameter
Definition Digest.cc:244
zypp::Digest::reset
bool reset()
reset internal digest state
Definition Digest.cc:215
zypp::Digest::name
const std::string & name()
get the name of the current digest algorithm
Definition Digest.cc:210
zypp::Digest::create
bool create(const std::string &name)
initialize creation of a new message digest
Definition Digest.cc:198
zypp::UByteArray
Definition ByteArray.h:46
std
Definition Arch.h:364
str
String related utilities and Regular expression matching.
zypp
Easy-to use interface to the ZYPP dependency resolver.
Definition Application.cc:20
string.h
AutoDispose.h
Digest.h
Logger.h
ERR
#define ERR
Definition Logger.h:102
PtrTypes.h
String.h