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