GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/crypto/hash.h
Date: 2026-08-09 02:40:25
Exec Total Coverage
Lines: 178 193 92.2%
Branches: 99 146 67.8%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 *
4 * Provides a bit syntactic sugar around the hash algorithms.
5 * In particular, hashes can easily be created by constructors.
6 * Also, we have a little to-string-from-string conversion.
7 *
8 * The complexity is due to the need to avoid dynamically allocated memory
9 * for the hashes. Almost everything happens on the stack.
10 */
11
12 #ifndef CVMFS_CRYPTO_HASH_H_
13 #define CVMFS_CRYPTO_HASH_H_
14
15 #include <arpa/inet.h>
16 #include <stdint.h>
17
18 #include <cassert>
19 #include <cctype>
20 #include <cstdlib>
21 #include <cstring>
22 #include <string>
23
24 #include "util/export.h"
25 #include "util/logging.h"
26 #include "util/prng.h"
27 #include "util/smalloc.h"
28
29 #ifdef CVMFS_NAMESPACE_GUARD
30 namespace CVMFS_NAMESPACE_GUARD {
31 #endif
32
33 namespace shash {
34
35 /**
36 * Don't change order! The integer value of the enum constants is used
37 * as file catalog flags and as flags in communication with the cache manager.
38 * If algorithms are added, the protocol definition for external cache managers
39 * needs to be updated, too.
40 */
41 enum Algorithms {
42 kMd5 = 0,
43 kSha1,
44 kRmd160,
45 kShake128, // with 160 output bits
46 kAny,
47 };
48
49 /**
50 * NOTE: when adding a suffix here, one must edit `cvmfs_swissknife scrub`
51 * accordingly, that checks for invalid hash suffixes
52 */
53 const char kSuffixNone = 0;
54 const char kSuffixCatalog = 'C';
55 const char kSuffixHistory = 'H';
56 const char kSuffixMicroCatalog = 'L'; // currently unused
57 const char kSuffixPartial = 'P';
58 const char kSuffixTemporary = 'T';
59 const char kSuffixCertificate = 'X';
60 const char kSuffixMetainfo = 'M';
61
62
63 /**
64 * Corresponds to Algorithms. "Any" is the maximum of all the other
65 * digest sizes.
66 * When the maximum digest size changes, the memory layout of DirectoryEntry and
67 * PosixQuotaManager::LruCommand changes, too!
68 */
69 const unsigned kDigestSizes[] = {16, 20, 20, 20, 20};
70 // Md5 Sha1 Rmd160 Shake128 Any
71 const unsigned kMaxDigestSize = 20;
72
73 /**
74 * The maximum of GetContextSize()
75 * Nettle v3.x has a larger context size for sha3.
76 * When using v4 exclusively, this could be reset to 256 bytes.
77 */
78 const unsigned kMaxContextSize = 384;
79
80 /**
81 * Hex representations of hashes with the same length need a suffix
82 * to be distinguished from each other. They should all have one but
83 * for backwards compatibility MD5 and SHA-1 have none. Initialized in hash.cc
84 * like const char *kAlgorithmIds[] = {"", "", "-rmd160", ...
85 */
86 CVMFS_EXPORT extern const char *kAlgorithmIds[];
87 const unsigned kAlgorithmIdSizes[] = {0, 0, 7, 9, 0};
88 // Md5 Sha1 -rmd160 -shake128 Any
89 const unsigned kMaxAlgorithmIdentifierSize = 9;
90
91 /**
92 * Corresponds to Algorithms. There is no block size for Any.
93 * Is an HMAC for SHAKE well-defined?
94 */
95 const unsigned kBlockSizes[] = {64, 64, 64, 168};
96 // Md5 Sha1 Rmd160 Shake128
97
98 /**
99 * Distinguishes between interpreting a string as hex hash and hashing over
100 * the contents of a string.
101 */
102 struct CVMFS_EXPORT HexPtr {
103 const std::string *str;
104 1407703 explicit HexPtr(const std::string &s) { str = &s; }
105 bool IsValid() const;
106 };
107
108 struct CVMFS_EXPORT AsciiPtr {
109 const std::string *str;
110 53610 explicit AsciiPtr(const std::string &s) { str = &s; }
111 };
112
113 typedef char Suffix;
114
115 /**
116 * Holds a hash digest and provides from string / to string conversion and
117 * comparison. The kAny algorithm may not be used in functions! The algorithm
118 * has to be changed beforehand.
119 * This class is not used directly, but used as base clase of Md5, Sha1, ...
120 */
121 template<unsigned digest_size_, Algorithms algorithm_>
122 struct CVMFS_EXPORT Digest {
123 unsigned char digest[digest_size_];
124 Algorithms algorithm;
125 Suffix suffix;
126
127 class Hex {
128 public:
129 22628028 explicit Hex(const Digest<digest_size_, algorithm_> *digest)
130 22628028 : digest_(*digest)
131 22628028 , hash_length_(2 * kDigestSizes[digest_.algorithm])
132 22628028 , algo_id_length_(kAlgorithmIdSizes[digest_.algorithm]) { }
133
134 1847604730 unsigned int length() const { return hash_length_ + algo_id_length_; }
135
136 901226323 char operator[](const unsigned int position) const {
137
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 901102296 times.
901226323 assert(position < length());
138
2/2
✓ Branch 0 taken 901077156 times.
✓ Branch 1 taken 25140 times.
901178904 return (position < hash_length_) ? GetHashChar(position)
139 901278333 : GetAlgorithmIdentifierChar(position);
140 }
141
142 protected:
143 901176192 char GetHashChar(const unsigned int position) const {
144
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 901099584 times.
901176192 assert(position < hash_length_);
145
2/2
✓ Branch 0 taken 450833197 times.
✓ Branch 1 taken 450266387 times.
901176192 const char digit = (position % 2 == 0)
146 450871501 ? digest_.digest[position / 2] / 16
147 450304691 : digest_.digest[position / 2] % 16;
148 901176192 return ToHex(digit);
149 }
150
151 25140 char GetAlgorithmIdentifierChar(const unsigned int position) const {
152
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25140 times.
25140 assert(position >= hash_length_);
153 25140 return kAlgorithmIds[digest_.algorithm][position - hash_length_];
154 }
155
156 901252301 static char ToHex(const char c) {
157
2/2
✓ Branch 0 taken 647243632 times.
✓ Branch 1 taken 253932061 times.
901252301 return static_cast<char>(c + ((c <= 9) ? '0' : 'a' - 10));
158 }
159
160 private:
161 const Digest<digest_size_, algorithm_> &digest_;
162 const unsigned int hash_length_;
163 const unsigned int algo_id_length_;
164 };
165
166 53775014 unsigned GetDigestSize() const { return kDigestSizes[algorithm]; }
167 1997 unsigned GetHexSize() const {
168 1997 return 2 * kDigestSizes[algorithm] + kAlgorithmIdSizes[algorithm];
169 }
170
171 961316606 Digest() : algorithm(algorithm_), suffix(kSuffixNone) { SetNull(); }
172
173 219889 explicit Digest(const Algorithms a, const HexPtr hex, const char s = 0)
174 219889 : algorithm(a), suffix(s) {
175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1029 times.
1029 assert((algorithm_ == kAny) || (a == algorithm_));
176 219889 const unsigned char_size = 2 * kDigestSizes[a];
177
178 219889 const std::string *str = hex.str;
179 219889 const unsigned length = str->length();
180
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 219889 times.
219889 assert(length >= char_size); // A suffix won't hurt
181
182
2/2
✓ Branch 0 taken 4211948 times.
✓ Branch 1 taken 219889 times.
4431837 for (unsigned i = 0; i < char_size; i += 2) {
183 7297285 this->digest[i / 2] = ((*str)[i] <= '9' ? (*str)[i] - '0'
184 1126611 : (*str)[i] - 'a' + 10)
185 * 16
186
4/4
✓ Branch 0 taken 3085337 times.
✓ Branch 1 taken 1126611 times.
✓ Branch 3 taken 2996285 times.
✓ Branch 4 taken 1215663 times.
9639559 + ((*str)[i + 1] <= '9' ? (*str)[i + 1] - '0'
187 1215663 : (*str)[i + 1] - 'a' + 10);
188 }
189 219889 }
190
191 9063 Digest(const Algorithms a,
192 const unsigned char *digest_buffer,
193 const Suffix s = kSuffixNone)
194 9063 : algorithm(a), suffix(s) {
195 9063 memcpy(digest, digest_buffer, kDigestSizes[a]);
196 9063 }
197
198 /**
199 * Generates a purely random hash
200 * Only used for testing purposes
201 */
202 4048 void Randomize() {
203 4048 Prng prng;
204 4048 prng.InitLocaltime();
205
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4048 Randomize(&prng);
206 4048 }
207
208 /**
209 * Generates a purely random hash
210 * Only used for testing purposes
211 *
212 * @param seed random number generator seed (for reproducibility)
213 */
214 30007946 void Randomize(const uint64_t seed) {
215 30007946 Prng prng;
216 30007946 prng.InitSeed(seed);
217
1/2
✓ Branch 1 taken 30003973 times.
✗ Branch 2 not taken.
30007946 Randomize(&prng);
218 30007946 }
219
220 /**
221 * Generates a purely random hash
222 * Only used for testing purposes
223 *
224 * @param prng random number generator object (for external reproducibility)
225 */
226 49231755 void Randomize(Prng *prng) {
227 49231755 const unsigned bytes = GetDigestSize();
228
2/2
✓ Branch 0 taken 847258564 times.
✓ Branch 1 taken 49231716 times.
896491099 for (unsigned i = 0; i < bytes; ++i) {
229 847259344 digest[i] = prng->Next(256);
230 }
231 49231755 }
232
233 358790 bool HasSuffix() const { return suffix != kSuffixNone; }
234 5959232 void set_suffix(const Suffix s) { suffix = s; }
235
236 /**
237 * Generates a hexified representation of the digest including the identifier
238 * string for newly added hashes.
239 *
240 * @param with_suffix append the hash suffix (C,H,X, ...) to the result
241 * @return a string representation of the digest
242 */
243 21834525 std::string ToString(const bool with_suffix = false) const {
244 21834525 Hex hex(this);
245
4/4
✓ Branch 0 taken 353459 times.
✓ Branch 1 taken 21478016 times.
✓ Branch 3 taken 2821 times.
✓ Branch 4 taken 350163 times.
21833869 const bool use_suffix = with_suffix && HasSuffix();
246 21833394 const unsigned string_length = hex.length() + use_suffix;
247
1/2
✓ Branch 2 taken 21832569 times.
✗ Branch 3 not taken.
21833441 std::string result(string_length, 0);
248
249
2/2
✓ Branch 1 taken 869438029 times.
✓ Branch 2 taken 21699932 times.
891330391 for (unsigned int i = 0; i < hex.length(); ++i) {
250
2/4
✓ Branch 1 taken 869471389 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 869418703 times.
✗ Branch 5 not taken.
869514637 result[i] = hex[i];
251 }
252
253
2/2
✓ Branch 0 taken 2821 times.
✓ Branch 1 taken 21697111 times.
21702326 if (use_suffix) {
254
1/2
✓ Branch 1 taken 2821 times.
✗ Branch 2 not taken.
2821 result[string_length - 1] = suffix;
255 }
256
257
2/2
✓ Branch 1 taken 387 times.
✓ Branch 2 taken 21830733 times.
21702326 assert(result.length() == string_length);
258 43666254 return result;
259 }
260
261 /**
262 * Generates a hexified representation of the digest including the identifier
263 * string for newly added hashes. Output is in the form of
264 * 'openssl x509 fingerprint', e.g. 00:AA:BB:...-SHAKE128
265 *
266 * @param with_suffix append the hash suffix (C,H,X, ...) to the result
267 * @return a string representation of the digest
268 */
269 312 std::string ToFingerprint(const bool with_suffix = false) const {
270 312 Hex hex(this);
271
3/4
✓ Branch 0 taken 156 times.
✓ Branch 1 taken 156 times.
✓ Branch 3 taken 156 times.
✗ Branch 4 not taken.
312 const bool use_suffix = with_suffix && HasSuffix();
272 312 const unsigned string_length = hex.length() + kDigestSizes[algorithm] - 1
273 312 + use_suffix;
274
1/2
✓ Branch 2 taken 312 times.
✗ Branch 3 not taken.
312 std::string result(string_length, 0);
275
276 312 unsigned l = hex.length();
277
2/2
✓ Branch 0 taken 13104 times.
✓ Branch 1 taken 312 times.
13416 for (unsigned int hex_i = 0, result_i = 0; hex_i < l; ++hex_i, ++result_i) {
278
2/4
✓ Branch 1 taken 13104 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13104 times.
✗ Branch 5 not taken.
13104 result[result_i] = toupper(hex[hex_i]);
279
4/4
✓ Branch 0 taken 11544 times.
✓ Branch 1 taken 1560 times.
✓ Branch 2 taken 5616 times.
✓ Branch 3 taken 5928 times.
13104 if ((hex_i < 2 * kDigestSizes[algorithm] - 1) && (hex_i % 2 == 1)) {
280
1/2
✓ Branch 1 taken 5616 times.
✗ Branch 2 not taken.
5616 result[++result_i] = ':';
281 }
282 }
283
284
2/2
✓ Branch 0 taken 156 times.
✓ Branch 1 taken 156 times.
312 if (use_suffix) {
285
1/2
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
156 result[string_length - 1] = suffix;
286 }
287
288
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 312 times.
312 assert(result.length() == string_length);
289 624 return result;
290 }
291
292 /**
293 * Convenience method to generate a string representation of the digest.
294 * See Digest<>::ToString() for details
295 *
296 * @return a string representation including the hash suffix of the digest
297 */
298 5350 std::string ToStringWithSuffix() const { return ToString(true); }
299
300 /**
301 * Generate the standard relative path from the hexified digest to be used in
302 * CAS areas or cache directories. Throughout the entire system we use one
303 * directory level (first to hex digest characters) for namespace splitting.
304 * Note: This method appends the internal hash suffix to the path.
305 *
306 * @return a relative path representation of the digest including the suffix
307 */
308 31530 std::string MakePath() const { return MakePathExplicit(1, 2, suffix); }
309
310 /**
311 * The alternative path is used to symlink the root catalog from the webserver
312 * root to the data directory. This way, the data directory can be protected
313 * while the root catalog remains accessible.
314 */
315 342 std::string MakeAlternativePath() const {
316
1/2
✓ Branch 2 taken 342 times.
✗ Branch 3 not taken.
342 return ".cvmfsalt-" + ToStringWithSuffix();
317 }
318
319 /**
320 * Produces a relative path representation of the digest without appending the
321 * hash suffix. See Digest<>::MakePath() for more details.
322 *
323 * @return a relative path representation of the digest without the suffix
324 */
325 761996 std::string MakePathWithoutSuffix() const {
326 761996 return MakePathExplicit(1, 2, kSuffixNone);
327 }
328
329 /**
330 * Generates an arbitrary path representation of the digest. Both number of
331 * directory levels and the hash-digits per level can be customized. Further-
332 * more an arbitrary hash suffix can be provided.
333 * Note: This method is mainly meant for internal usage but stays public for
334 * historical reasons.
335 *
336 * @param dir_levels the number of namespace splitting directory levels
337 * @param digits_per_level each directory level's number of hex-digits
338 * @param hash_suffix the hash suffix character to be appended
339 * @return a relative path representation of the digest
340 */
341 794150 std::string MakePathExplicit(const unsigned dir_levels,
342 const unsigned digits_per_level,
343 const Suffix hash_suffix = kSuffixNone) const {
344 794150 Hex hex(this);
345
346 // figure out how big the output string needs to be
347 794150 const bool use_suffix = (hash_suffix != kSuffixNone);
348 794150 const unsigned string_length = hex.length() + dir_levels + use_suffix;
349 794150 std::string result;
350
1/2
✓ Branch 1 taken 794150 times.
✗ Branch 2 not taken.
794150 result.resize(string_length);
351
352 // build hexified hash and path delimiters
353 794150 unsigned i = 0;
354 794150 unsigned pos = 0;
355
2/2
✓ Branch 1 taken 31717859 times.
✓ Branch 2 taken 794150 times.
32512009 for (; i < hex.length(); ++i) {
356
4/4
✓ Branch 0 taken 30923709 times.
✓ Branch 1 taken 794150 times.
✓ Branch 2 taken 15066338 times.
✓ Branch 3 taken 15857371 times.
31717859 if (i > 0 && (i % digits_per_level == 0)
357
2/2
✓ Branch 0 taken 794462 times.
✓ Branch 1 taken 14271876 times.
15066338 && (i / digits_per_level <= dir_levels)) {
358
1/2
✓ Branch 1 taken 794462 times.
✗ Branch 2 not taken.
794462 result[pos++] = '/';
359 }
360
2/4
✓ Branch 1 taken 31717859 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 31717859 times.
✗ Branch 5 not taken.
31717859 result[pos++] = hex[i];
361 }
362
363 // (optionally) add hash hint suffix
364
2/2
✓ Branch 0 taken 17456 times.
✓ Branch 1 taken 776694 times.
794150 if (use_suffix) {
365
1/2
✓ Branch 1 taken 17456 times.
✗ Branch 2 not taken.
17456 result[pos++] = hash_suffix;
366 }
367
368
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 794150 times.
794150 assert(i == hex.length());
369
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 794150 times.
794150 assert(pos == string_length);
370 1588300 return result;
371 }
372
373 33668745 bool IsNull() const {
374
2/2
✓ Branch 0 taken 147959234 times.
✓ Branch 1 taken 6004478 times.
153963712 for (unsigned i = 0; i < kDigestSizes[algorithm]; ++i) {
375
2/2
✓ Branch 0 taken 27664267 times.
✓ Branch 1 taken 120294967 times.
147959234 if (digest[i] != 0)
376 27664267 return false;
377 }
378 6004478 return true;
379 }
380
381 /**
382 * Get a partial digest for use when only 32 bits are required
383 */
384 1061 uint32_t Partial32() const {
385 1061 const uint32_t *partial = (const uint32_t *)digest;
386 1061 return ntohl(*partial);
387 }
388
389
390 961327824 void SetNull() { memset(digest, 0, digest_size_); }
391
392
393 860305226 bool operator==(const Digest<digest_size_, algorithm_> &other) const {
394
2/2
✓ Branch 0 taken 70269926 times.
✓ Branch 1 taken 359883667 times.
860305226 if (this->algorithm != other.algorithm)
395 140538274 return false;
396
2/2
✓ Branch 0 taken 3058818712 times.
✓ Branch 1 taken 167033449 times.
6451696300 for (unsigned i = 0; i < kDigestSizes[algorithm]; ++i) {
397
2/2
✓ Branch 0 taken 192850218 times.
✓ Branch 1 taken 2865968494 times.
6117629784 if (this->digest[i] != other.digest[i])
398 385700436 return false;
399 }
400 334066516 return true;
401 }
402
403 97649016 bool operator!=(const Digest<digest_size_, algorithm_> &other) const {
404 97649016 return !(*this == other);
405 }
406
407 653684555 bool operator<(const Digest<digest_size_, algorithm_> &other) const {
408
2/2
✓ Branch 0 taken 14393340 times.
✓ Branch 1 taken 639291215 times.
653684555 if (this->algorithm != other.algorithm)
409 14393340 return (this->algorithm < other.algorithm);
410
1/2
✓ Branch 0 taken 1782328854 times.
✗ Branch 1 not taken.
1715035008 for (unsigned i = 0; i < kDigestSizes[algorithm]; ++i) {
411
2/2
✓ Branch 0 taken 335114526 times.
✓ Branch 1 taken 1447214328 times.
1782328854 if (this->digest[i] > other.digest[i])
412 335114526 return false;
413
2/2
✓ Branch 0 taken 371470535 times.
✓ Branch 1 taken 1075743793 times.
1447214328 if (this->digest[i] < other.digest[i])
414 371470535 return true;
415 }
416 94 return false;
417 }
418
419 384336 bool operator>(const Digest<digest_size_, algorithm_> &other) const {
420
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 384336 times.
384336 if (this->algorithm != other.algorithm)
421 return (this->algorithm > other.algorithm);
422
2/2
✓ Branch 0 taken 452226 times.
✓ Branch 1 taken 576 times.
452802 for (unsigned i = 0; i < kDigestSizes[algorithm]; ++i) {
423
2/2
✓ Branch 0 taken 145652 times.
✓ Branch 1 taken 306574 times.
452226 if (this->digest[i] < other.digest[i])
424 145652 return false;
425
2/2
✓ Branch 0 taken 238108 times.
✓ Branch 1 taken 68466 times.
306574 if (this->digest[i] > other.digest[i])
426 238108 return true;
427 }
428 576 return false;
429 }
430 };
431
432
433 struct CVMFS_EXPORT Md5 : public Digest<16, kMd5> {
434 202608506 Md5() : Digest<16, kMd5>() { }
435 explicit Md5(const AsciiPtr ascii);
436 1029 explicit Md5(const HexPtr hex) : Digest<16, kMd5>(kMd5, hex) { }
437 Md5(const char *chars, const unsigned length);
438
439 /**
440 * An MD5 hash can be seen as two 64bit integers.
441 */
442 Md5(const uint64_t lo, const uint64_t hi);
443 void ToIntPair(uint64_t *lo, uint64_t *hi) const;
444 };
445
446 struct CVMFS_EXPORT Sha1 : public Digest<20, kSha1> { };
447 struct CVMFS_EXPORT Rmd160 : public Digest<20, kRmd160> { };
448 struct CVMFS_EXPORT Shake128 : public Digest<20, kShake128> { };
449
450 /**
451 * Any as such must not be used except for digest storage.
452 * To do real work, the class has to be "blessed" to be a real hash by
453 * setting the algorithm field accordingly.
454 */
455 struct CVMFS_EXPORT Any : public Digest<kMaxDigestSize, kAny> {
456 222742562 Any() : Digest<kMaxDigestSize, kAny>() { }
457
458 50828373 explicit Any(const Algorithms a, const char s = kSuffixNone)
459 50828373 : Digest<kMaxDigestSize, kAny>() {
460 50828373 algorithm = a;
461 50828373 suffix = s;
462 50828373 }
463
464 9063 Any(const Algorithms a,
465 const unsigned char *digest_buffer,
466 const Suffix suffix = kSuffixNone)
467 9063 : Digest<kMaxDigestSize, kAny>(a, digest_buffer, suffix) { }
468
469 218860 explicit Any(const Algorithms a,
470 const HexPtr hex,
471 const char suffix = kSuffixNone)
472 218860 : Digest<kMaxDigestSize, kAny>(a, hex, suffix) { }
473
474 Md5 CastToMd5();
475 };
476
477 const size_t kShortDigestSize = kMaxDigestSize;
478 struct CVMFS_EXPORT Short : public Digest<kShortDigestSize, kAny> {
479 39 explicit Short(const Any &full) : Digest<kShortDigestSize, kAny>() {
480 39 algorithm = full.algorithm;
481 39 suffix = full.suffix;
482 39 digest_size_ = kShortDigestSize / 4;
483 39 hex_size_ = 2 * digest_size_ + kAlgorithmIdSizes[algorithm];
484 39 memcpy(digest, full.digest, kShortDigestSize);
485 39 }
486
487 bool operator==(const Short &other) const {
488 if (this->algorithm != other.algorithm) {
489 return false;
490 }
491 if (this->digest_size_ != other.digest_size_) {
492 return false;
493 }
494 for (unsigned i = 0; i < digest_size_; ++i) {
495 if (this->digest[i] != other.digest[i])
496 return false;
497 }
498 return true;
499 }
500
501 std::string ToString(const bool with_suffix = false) {
502 const Hex hex(this);
503 const bool use_suffix = with_suffix && HasSuffix();
504 const unsigned string_length = hex_size_ + use_suffix;
505 std::string result(string_length, 0);
506
507 for (unsigned int i = 0; i < hex_size_; ++i) {
508 result[i] = hex[i];
509 }
510
511 if (use_suffix) {
512 result[string_length - 1] = suffix;
513 }
514
515 assert(result.length() == string_length);
516 return result;
517 }
518
519 78 bool Collide(const Any &other) const {
520
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
78 if (this->algorithm != other.algorithm) {
521 return false;
522 }
523
2/2
✓ Branch 0 taken 234 times.
✓ Branch 1 taken 39 times.
273 for (unsigned i = 0; i < digest_size_; ++i) {
524
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 195 times.
234 if (this->digest[i] != other.digest[i])
525 39 return false;
526 }
527 39 return true;
528 }
529
530 private:
531 size_t digest_size_;
532 size_t hex_size_;
533 };
534 /**
535 * Actual operations on digests, like "hash a file", "hash a buffer", or
536 * iterative operations.
537 */
538 CVMFS_EXPORT unsigned GetContextSize(const Algorithms algorithm);
539
540 /**
541 * Holds an OpenSSL context, only required for hash operations. Allows to
542 * deferr the storage allocation for the context to alloca.
543 */
544 class CVMFS_EXPORT ContextPtr {
545 public:
546 Algorithms algorithm;
547 void *buffer;
548 unsigned size;
549
550 9982405 ContextPtr() : algorithm(kAny), buffer(NULL), size(0) { }
551
552 633165 explicit ContextPtr(const Algorithms a)
553 633165 : algorithm(a), buffer(NULL), size(GetContextSize(a)) { }
554 ContextPtr(const Algorithms a, void *b)
555 : algorithm(a), buffer(b), size(GetContextSize(a)) { }
556 };
557
558 CVMFS_EXPORT void Init(ContextPtr context);
559 CVMFS_EXPORT void Update(const unsigned char *buffer,
560 const unsigned buffer_size,
561 ContextPtr context);
562 CVMFS_EXPORT void Final(ContextPtr context, Any *any_digest);
563 CVMFS_EXPORT bool HashFile(const std::string &filename, Any *any_digest);
564 CVMFS_EXPORT bool HashFd(int fd, Any *any_digest);
565 CVMFS_EXPORT void HashMem(const unsigned char *buffer,
566 const unsigned buffer_size,
567 Any *any_digest);
568 CVMFS_EXPORT void HashString(const std::string &content, Any *any_digest);
569 CVMFS_EXPORT void Hmac(const std::string &key,
570 const unsigned char *buffer,
571 const unsigned buffer_size,
572 Any *any_digest);
573 39 inline void HmacString(const std::string &key, const std::string &content,
574 Any *any_digest) {
575 39 Hmac(key,
576 39 reinterpret_cast<const unsigned char *>(content.data()),
577 39 content.size(),
578 any_digest);
579 39 }
580
581 /**
582 * Only used for AWS4 signature.
583 *
584 * Adding SHA-256 to the standard hash infrastructure would generally bloat the
585 * digets size to 32 bytes and require client data structure transformation
586 * during hotpatch.
587 */
588 CVMFS_EXPORT std::string Hmac256(const std::string &key,
589 const std::string &content,
590 bool raw_output = false);
591 CVMFS_EXPORT std::string Sha256File(const std::string &filename);
592 CVMFS_EXPORT std::string Sha256Mem(const unsigned char *buffer,
593 const unsigned buffer_size);
594 CVMFS_EXPORT std::string Sha256String(const std::string &content);
595
596 CVMFS_EXPORT
597 Algorithms ParseHashAlgorithm(const std::string &algorithm_option);
598 CVMFS_EXPORT
599 Any MkFromHexPtr(const HexPtr hex, const Suffix suffix = kSuffixNone);
600 CVMFS_EXPORT Any MkFromSuffixedHexPtr(const HexPtr hex);
601
602 } // namespace shash
603
604 #ifdef CVMFS_NAMESPACE_GUARD
605 } // namespace CVMFS_NAMESPACE_GUARD
606 #endif
607
608 #endif // CVMFS_CRYPTO_HASH_H_
609
610