GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/crypto/hash.cc
Date: 2026-08-09 02:40:25
Exec Total Coverage
Lines: 276 307 89.9%
Branches: 158 246 64.2%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5
6 #include "crypto/hash.h"
7
8 #include <alloca.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <nettle/md5.h>
12 #include <nettle/ripemd160.h>
13 #include <nettle/sha1.h>
14 #include <nettle/sha2.h>
15 #include <nettle/sha3.h>
16 #include <nettle/version.h>
17 #include <unistd.h>
18
19 #include <cstdio>
20 #include <cstring>
21
22 #include "util/exception.h"
23
24
25 using namespace std; // NOLINT
26
27 #ifdef CVMFS_NAMESPACE_GUARD
28 namespace CVMFS_NAMESPACE_GUARD {
29 #endif
30
31 namespace shash {
32
33 namespace {
34
35 // nettle 4 dropped the digest_size parameter from the *_digest() functions.
36 #if defined(NETTLE_VERSION_MAJOR) && (NETTLE_VERSION_MAJOR >= 4)
37 void Md5Digest(md5_ctx *ctx, uint8_t *digest) {
38 nettle_md5_digest(ctx, digest);
39 }
40
41 void Sha1Digest(sha1_ctx *ctx, uint8_t *digest) {
42 nettle_sha1_digest(ctx, digest);
43 }
44
45 void Sha256Digest(sha256_ctx *ctx, uint8_t *digest) {
46 nettle_sha256_digest(ctx, digest);
47 }
48
49 void Ripemd160Digest(ripemd160_ctx *ctx, uint8_t *digest) {
50 nettle_ripemd160_digest(ctx, digest);
51 }
52
53 #else // nettle 3.x takes digest size as 2nd arg
54 5097806 void Md5Digest(md5_ctx *ctx, uint8_t *digest) {
55 5097806 nettle_md5_digest(ctx, MD5_DIGEST_SIZE, digest);
56 5097806 }
57
58 767962 void Sha1Digest(sha1_ctx *ctx, uint8_t *digest) {
59 767962 nettle_sha1_digest(ctx, SHA1_DIGEST_SIZE, digest);
60 767989 }
61
62 54 void Sha256Digest(sha256_ctx *ctx, uint8_t *digest) {
63 54 nettle_sha256_digest(ctx, SHA256_DIGEST_SIZE, digest);
64 54 }
65
66 38 void Ripemd160Digest(ripemd160_ctx *ctx, uint8_t *digest) {
67 38 nettle_ripemd160_digest(ctx, RIPEMD160_DIGEST_SIZE, digest);
68 38 }
69
70 #endif
71
72 968 void Shake128Digest(sha3_128_ctx *ctx, uint8_t *digest) {
73 968 nettle_sha3_128_shake(ctx, kDigestSizes[kShake128], digest);
74 968 }
75
76 static_assert(sizeof(sha3_128_ctx) <= kMaxContextSize,
77 "SHAKE128 context exceeds allocated buffers");
78
79 } // namespace
80
81 const char *kAlgorithmIds[] = {"", "", "-rmd160", "-shake128", ""};
82
83
84 66 bool HexPtr::IsValid() const {
85 66 const unsigned l = str->length();
86
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 63 times.
66 if (l == 0)
87 3 return false;
88 63 const char *c = str->data(); // Walks through the string
89 63 unsigned i = 0; // String position of *c
90
91
2/2
✓ Branch 0 taken 2460 times.
✓ Branch 1 taken 15 times.
2475 for (; i < l; ++i, ++c) {
92
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 2418 times.
2460 if (*c == '-')
93 42 break;
94
6/8
✓ Branch 0 taken 2418 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2418 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 981 times.
✓ Branch 5 taken 1437 times.
✓ Branch 6 taken 6 times.
✓ Branch 7 taken 975 times.
2418 if ((*c < '0') || (*c > 'f') || ((*c > '9') && (*c < 'a')))
95 6 return false;
96 }
97
98 // Walk through all algorithms
99
2/2
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 45 times.
255 for (unsigned j = 0; j < kAny; ++j) {
100 210 const unsigned hex_length = 2 * kDigestSizes[j];
101 210 const unsigned algo_id_length = kAlgorithmIdSizes[j];
102
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 144 times.
210 if (i == hex_length) {
103 // Right suffix?
104
4/4
✓ Branch 0 taken 183 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 159 times.
✓ Branch 3 taken 24 times.
195 for (; (i < l) && (i - hex_length < algo_id_length); ++i, ++c) {
105
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 129 times.
159 if (*c != kAlgorithmIds[j][i - hex_length])
106 30 break;
107 }
108
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 54 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
66 if ((i == l) && (l == hex_length + algo_id_length))
109 12 return true;
110 54 i = hex_length;
111 54 c = str->data() + i;
112 }
113 }
114
115 45 return false;
116 }
117
118
119 Algorithms ParseHashAlgorithm(const string &algorithm_option) {
120 if (algorithm_option == "sha1")
121 return kSha1;
122 if (algorithm_option == "rmd160")
123 return kRmd160;
124 if (algorithm_option == "shake128")
125 return kShake128;
126 return kAny;
127 }
128
129
130 73409 Any MkFromHexPtr(const HexPtr hex, const char suffix) {
131 73409 Any result;
132
133 73409 const unsigned length = hex.str->length();
134
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 73406 times.
73409 if (length == 2 * kDigestSizes[kMd5])
135 3 result = Any(kMd5, hex);
136
2/2
✓ Branch 0 taken 73250 times.
✓ Branch 1 taken 159 times.
73409 if (length == 2 * kDigestSizes[kSha1])
137 73250 result = Any(kSha1, hex);
138 // TODO(jblomer) compare -rmd160, -shake128
139
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 73388 times.
73409 if ((length == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160]))
140 21 result = Any(kRmd160, hex);
141
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 73382 times.
73409 if ((length == 2 * kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128]))
142 27 result = Any(kShake128, hex);
143
144 73409 result.suffix = suffix;
145 73409 return result;
146 }
147
148
149 /**
150 * Similar to MkFromHexPtr but the suffix is deducted from the HexPtr string.
151 */
152 44263 Any MkFromSuffixedHexPtr(const HexPtr hex) {
153 44263 Any result;
154
155 44263 const unsigned length = hex.str->length();
156
2/2
✓ Branch 0 taken 1174 times.
✓ Branch 1 taken 43089 times.
44263 if ((length == 2 * kDigestSizes[kMd5])
157
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1171 times.
1174 || (length == 2 * kDigestSizes[kMd5] + 1)) {
158 43092 const Suffix suffix = (length == 2 * kDigestSizes[kMd5] + 1)
159
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 43089 times.
43092 ? *(hex.str->rbegin())
160 43092 : kSuffixNone;
161 43092 result = Any(kMd5, hex, suffix);
162 }
163
2/2
✓ Branch 0 taken 43626 times.
✓ Branch 1 taken 637 times.
44263 if ((length == 2 * kDigestSizes[kSha1])
164
2/2
✓ Branch 0 taken 507 times.
✓ Branch 1 taken 43119 times.
43626 || (length == 2 * kDigestSizes[kSha1] + 1)) {
165 1144 const Suffix suffix = (length == 2 * kDigestSizes[kSha1] + 1)
166
2/2
✓ Branch 0 taken 507 times.
✓ Branch 1 taken 637 times.
1144 ? *(hex.str->rbegin())
167 1144 : kSuffixNone;
168 1144 result = Any(kSha1, hex, suffix);
169 }
170
2/2
✓ Branch 0 taken 44260 times.
✓ Branch 1 taken 3 times.
44263 if ((length == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160])
171 44260 || (length
172
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 44245 times.
44260 == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160] + 1)) {
173 const Suffix suffix = (length
174 18 == 2 * kDigestSizes[kRmd160]
175 18 + kAlgorithmIdSizes[kRmd160] + 1)
176
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
18 ? *(hex.str->rbegin())
177 18 : kSuffixNone;
178 18 result = Any(kRmd160, hex, suffix);
179 }
180
2/2
✓ Branch 0 taken 44260 times.
✓ Branch 1 taken 3 times.
44263 if ((length == 2 * kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128])
181 44260 || (length
182
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 44257 times.
44260 == 2 * kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128] + 1)) {
183 const Suffix suffix = (length
184 6 == 2 * kDigestSizes[kShake128]
185 6 + kAlgorithmIdSizes[kShake128] + 1)
186
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 ? *(hex.str->rbegin())
187 6 : kSuffixNone;
188 6 result = Any(kShake128, hex, suffix);
189 }
190
191 44263 return result;
192 }
193
194
195 /**
196 * Allows the caller to create the context on the stack.
197 */
198 1402012 unsigned GetContextSize(const Algorithms algorithm) {
199
4/5
✓ Branch 0 taken 608559 times.
✓ Branch 1 taken 792459 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 968 times.
✗ Branch 4 not taken.
1402012 switch (algorithm) {
200 608559 case kMd5:
201 608559 return sizeof(md5_ctx);
202 792459 case kSha1:
203 792459 return sizeof(sha1_ctx);
204 38 case kRmd160:
205 38 return sizeof(ripemd160_ctx);
206 968 case kShake128:
207 968 return sizeof(sha3_128_ctx);
208 default:
209 PANIC(kLogDebug | kLogSyslogErr,
210 "tried to generate hash context for unspecified hash. Aborting...");
211 }
212 }
213
214 1402368 void Init(ContextPtr context) {
215
4/5
✓ Branch 0 taken 608577 times.
✓ Branch 1 taken 792791 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 968 times.
✗ Branch 4 not taken.
1402368 switch (context.algorithm) {
216 608577 case kMd5:
217 608577 md5_init(reinterpret_cast<md5_ctx *>(context.buffer));
218 608577 break;
219 792791 case kSha1:
220 792791 sha1_init(reinterpret_cast<sha1_ctx *>(context.buffer));
221 792779 break;
222 38 case kRmd160:
223 38 ripemd160_init(reinterpret_cast<ripemd160_ctx *>(context.buffer));
224 38 break;
225 968 case kShake128:
226 968 sha3_128_init(reinterpret_cast<sha3_128_ctx *>(context.buffer));
227 968 break;
228 default:
229 PANIC(NULL); // Undefined hash
230 }
231 1402362 }
232
233 281331878 void Update(const unsigned char *buffer, const unsigned buffer_length,
234 ContextPtr context) {
235
4/5
✓ Branch 0 taken 72210084 times.
✓ Branch 1 taken 70708767 times.
✓ Branch 2 taken 69206060 times.
✓ Branch 3 taken 69206973 times.
✗ Branch 4 not taken.
281331878 switch (context.algorithm) {
236 72210084 case kMd5:
237 72210084 md5_update(reinterpret_cast<md5_ctx *>(context.buffer),
238 buffer_length, buffer);
239 72210084 break;
240 70708767 case kSha1:
241 70708767 sha1_update(reinterpret_cast<sha1_ctx *>(context.buffer),
242 buffer_length, buffer);
243 70709187 break;
244 69206060 case kRmd160:
245 69206060 ripemd160_update(reinterpret_cast<ripemd160_ctx *>(context.buffer),
246 buffer_length, buffer);
247 69206060 break;
248 69206973 case kShake128:
249 69206973 sha3_128_update(reinterpret_cast<sha3_128_ctx *>(context.buffer),
250 buffer_length, buffer);
251 69206973 break;
252 default:
253 PANIC(NULL); // Undefined hash
254 }
255 281332304 }
256
257 1377515 void Final(ContextPtr context, Any *any_digest) {
258
4/5
✓ Branch 0 taken 608553 times.
✓ Branch 1 taken 767956 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 968 times.
✗ Branch 4 not taken.
1377515 switch (context.algorithm) {
259 608553 case kMd5:
260 608553 Md5Digest(reinterpret_cast<md5_ctx *>(context.buffer), any_digest->digest);
261 608553 break;
262 767956 case kSha1:
263 767956 Sha1Digest(reinterpret_cast<sha1_ctx *>(context.buffer),
264 767956 any_digest->digest);
265 767977 break;
266 38 case kRmd160:
267 38 Ripemd160Digest(reinterpret_cast<ripemd160_ctx *>(context.buffer),
268 38 any_digest->digest);
269 38 break;
270 968 case kShake128:
271 968 Shake128Digest(reinterpret_cast<sha3_128_ctx *>(context.buffer),
272 968 any_digest->digest);
273 968 break;
274 default:
275 PANIC(NULL); // Undefined hash
276 }
277 1377536 any_digest->algorithm = context.algorithm;
278 1377536 }
279
280
281 12610 void HashMem(const unsigned char *buffer, const unsigned buffer_size,
282 Any *any_digest) {
283 12610 const Algorithms algorithm = any_digest->algorithm;
284
1/2
✓ Branch 1 taken 12610 times.
✗ Branch 2 not taken.
12610 ContextPtr context(algorithm);
285 12610 context.buffer = alloca(context.size);
286
287
1/2
✓ Branch 1 taken 12610 times.
✗ Branch 2 not taken.
12610 Init(context);
288
1/2
✓ Branch 1 taken 12610 times.
✗ Branch 2 not taken.
12610 Update(buffer, buffer_size, context);
289
1/2
✓ Branch 1 taken 12610 times.
✗ Branch 2 not taken.
12610 Final(context, any_digest);
290 12610 }
291
292
293 1114 void HashString(const std::string &content, Any *any_digest) {
294 1114 HashMem(reinterpret_cast<const unsigned char *>(content.data()),
295 1114 content.length(), any_digest);
296 1114 }
297
298
299 303744 void Hmac(const string &key,
300 const unsigned char *buffer,
301 const unsigned buffer_size,
302 Any *any_digest) {
303 303744 const Algorithms algorithm = any_digest->algorithm;
304
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 303744 times.
303744 assert(algorithm != kAny);
305
306 303744 const unsigned block_size = kBlockSizes[algorithm];
307 303744 unsigned char key_block[block_size];
308 303744 memset(key_block, 0, block_size);
309
2/2
✓ Branch 1 taken 3684 times.
✓ Branch 2 taken 300060 times.
303744 if (key.length() > block_size) {
310
1/2
✓ Branch 1 taken 3684 times.
✗ Branch 2 not taken.
3684 Any hash_key(algorithm);
311
1/2
✓ Branch 3 taken 3684 times.
✗ Branch 4 not taken.
3684 HashMem(reinterpret_cast<const unsigned char *>(key.data()), key.length(),
312 &hash_key);
313 3684 memcpy(key_block, hash_key.digest, kDigestSizes[algorithm]);
314 } else {
315
2/2
✓ Branch 1 taken 300051 times.
✓ Branch 2 taken 9 times.
300060 if (key.length() > 0)
316 300051 memcpy(key_block, key.data(), key.length());
317 }
318
319 303744 unsigned char pad_block[block_size];
320 // Inner hash
321
1/2
✓ Branch 1 taken 303744 times.
✗ Branch 2 not taken.
303744 Any hash_inner(algorithm);
322
1/2
✓ Branch 1 taken 303744 times.
✗ Branch 2 not taken.
303744 ContextPtr context_inner(algorithm);
323 303744 context_inner.buffer = alloca(context_inner.size);
324
1/2
✓ Branch 1 taken 303744 times.
✗ Branch 2 not taken.
303744 Init(context_inner);
325
2/2
✓ Branch 0 taken 19439616 times.
✓ Branch 1 taken 303744 times.
19743360 for (unsigned i = 0; i < block_size; ++i)
326 19439616 pad_block[i] = key_block[i] ^ 0x36;
327
1/2
✓ Branch 1 taken 303744 times.
✗ Branch 2 not taken.
303744 Update(pad_block, block_size, context_inner);
328
1/2
✓ Branch 1 taken 303744 times.
✗ Branch 2 not taken.
303744 Update(buffer, buffer_size, context_inner);
329
1/2
✓ Branch 1 taken 303744 times.
✗ Branch 2 not taken.
303744 Final(context_inner, &hash_inner);
330
331 // Outer hash
332
1/2
✓ Branch 1 taken 303744 times.
✗ Branch 2 not taken.
303744 ContextPtr context_outer(algorithm);
333 303744 context_outer.buffer = alloca(context_outer.size);
334
1/2
✓ Branch 1 taken 303744 times.
✗ Branch 2 not taken.
303744 Init(context_outer);
335
2/2
✓ Branch 0 taken 19439616 times.
✓ Branch 1 taken 303744 times.
19743360 for (unsigned i = 0; i < block_size; ++i)
336 19439616 pad_block[i] = key_block[i] ^ 0x5c;
337
1/2
✓ Branch 1 taken 303744 times.
✗ Branch 2 not taken.
303744 Update(pad_block, block_size, context_outer);
338
1/2
✓ Branch 1 taken 303744 times.
✗ Branch 2 not taken.
303744 Update(hash_inner.digest, kDigestSizes[algorithm], context_outer);
339
340
1/2
✓ Branch 1 taken 303744 times.
✗ Branch 2 not taken.
303744 Final(context_outer, any_digest);
341 303744 }
342
343
344 4602 bool HashFd(int fd, Any *any_digest) {
345 4602 const Algorithms algorithm = any_digest->algorithm;
346
1/2
✓ Branch 1 taken 4602 times.
✗ Branch 2 not taken.
4602 ContextPtr context(algorithm);
347 4602 context.buffer = alloca(context.size);
348
349
1/2
✓ Branch 1 taken 4602 times.
✗ Branch 2 not taken.
4602 Init(context);
350 unsigned char io_buffer[4096];
351 int actual_bytes;
352
3/4
✓ Branch 1 taken 2122550 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2117948 times.
✓ Branch 4 taken 4602 times.
2122550 while ((actual_bytes = read(fd, io_buffer, 4096)) != 0) {
353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2117948 times.
2117948 if (actual_bytes == -1) {
354 if (errno == EINTR)
355 continue;
356 return false;
357 }
358
1/2
✓ Branch 1 taken 2117948 times.
✗ Branch 2 not taken.
2117948 Update(io_buffer, actual_bytes, context);
359 }
360
1/2
✓ Branch 1 taken 4602 times.
✗ Branch 2 not taken.
4602 Final(context, any_digest);
361 4602 return true;
362 }
363
364
365 4602 bool HashFile(const std::string &filename, Any *any_digest) {
366 4602 const int fd = open(filename.c_str(), O_RDONLY);
367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4602 times.
4602 if (fd == -1)
368 return false;
369
370 4602 const bool result = HashFd(fd, any_digest);
371 4602 close(fd);
372 4602 return result;
373 }
374
375
376 /**
377 * Fast constructor for hashing path names.
378 */
379 6503 Md5::Md5(const AsciiPtr ascii) {
380 6503 algorithm = kMd5;
381 6503 const string *str = ascii.str;
382
383 md5_ctx md5_state;
384
1/2
✓ Branch 1 taken 6503 times.
✗ Branch 2 not taken.
6503 md5_init(&md5_state);
385
1/2
✓ Branch 2 taken 6503 times.
✗ Branch 3 not taken.
6503 md5_update(&md5_state, str->length(),
386 6503 reinterpret_cast<const uint8_t *>(&(*str)[0]));
387
1/2
✓ Branch 1 taken 6503 times.
✗ Branch 2 not taken.
6503 Md5Digest(&md5_state, digest);
388 6503 }
389
390
391 4482750 Md5::Md5(const char *chars, const unsigned length) {
392 4482750 algorithm = kMd5;
393
394 md5_ctx md5_state;
395
1/2
✓ Branch 1 taken 4482750 times.
✗ Branch 2 not taken.
4482750 md5_init(&md5_state);
396
1/2
✓ Branch 1 taken 4482750 times.
✗ Branch 2 not taken.
4482750 md5_update(&md5_state, length, reinterpret_cast<const uint8_t *>(chars));
397
1/2
✓ Branch 1 taken 4482750 times.
✗ Branch 2 not taken.
4482750 Md5Digest(&md5_state, digest);
398 4482750 }
399
400
401 Md5::Md5(const uint64_t lo, const uint64_t hi) {
402 algorithm = kMd5;
403 memcpy(digest, &lo, 8);
404 memcpy(digest + 8, &hi, 8);
405 }
406
407 8383 void Md5::ToIntPair(uint64_t *lo, uint64_t *hi) const {
408 8383 memcpy(lo, digest, 8);
409 8383 memcpy(hi, digest + 8, 8);
410 8383 }
411
412
413 300067 Md5 Any::CastToMd5() {
414
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 300067 times.
300067 assert(algorithm == kMd5);
415 300067 Md5 result;
416 300067 memcpy(result.digest, digest, kDigestSizes[kMd5]);
417 300067 return result;
418 }
419
420 18 static string HexFromSha256(unsigned char digest[SHA256_DIGEST_SIZE]) {
421 18 string result;
422
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 result.reserve(2 * SHA256_DIGEST_SIZE);
423
2/2
✓ Branch 0 taken 576 times.
✓ Branch 1 taken 18 times.
594 for (unsigned i = 0; i < SHA256_DIGEST_SIZE; ++i) {
424 576 const char d1 = digest[i] / 16;
425 576 const char d2 = digest[i] % 16;
426
3/4
✓ Branch 0 taken 333 times.
✓ Branch 1 taken 243 times.
✓ Branch 3 taken 576 times.
✗ Branch 4 not taken.
576 result.push_back(d1 + ((d1 <= 9) ? '0' : 'a' - 10));
427
3/4
✓ Branch 0 taken 399 times.
✓ Branch 1 taken 177 times.
✓ Branch 3 taken 576 times.
✗ Branch 4 not taken.
576 result.push_back(d2 + ((d2 <= 9) ? '0' : 'a' - 10));
428 }
429 18 return result;
430 }
431
432 3 string Sha256File(const string &filename) {
433
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 const int fd = open(filename.c_str(), O_RDONLY);
434
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (fd < 0)
435 return "";
436
437 sha256_ctx ctx;
438
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 sha256_init(&ctx);
439
440 unsigned char io_buffer[4096];
441 int actual_bytes;
442
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
3 while ((actual_bytes = read(fd, io_buffer, 4096)) != 0) {
443 if (actual_bytes == -1) {
444 if (errno == EINTR)
445 continue;
446 close(fd);
447 return "";
448 }
449 sha256_update(&ctx, actual_bytes, io_buffer);
450 }
451
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 close(fd);
452
453 unsigned char digest[SHA256_DIGEST_SIZE];
454
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 Sha256Digest(&ctx, digest);
455
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 return HexFromSha256(digest);
456 }
457
458 6 string Sha256Mem(const unsigned char *buffer, const unsigned buffer_size) {
459 unsigned char digest[SHA256_DIGEST_SIZE];
460 sha256_ctx ctx;
461
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 sha256_init(&ctx);
462
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 sha256_update(&ctx, buffer_size, buffer);
463
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 Sha256Digest(&ctx, digest);
464
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
12 return HexFromSha256(digest);
465 }
466
467 3 string Sha256String(const string &content) {
468 3 return Sha256Mem(reinterpret_cast<const unsigned char *>(content.data()),
469 3 content.length());
470 }
471
472
473 21 std::string Hmac256(const std::string &key,
474 const std::string &content,
475 bool raw_output) {
476 sha256_ctx ctx;
477 unsigned char digest[SHA256_DIGEST_SIZE];
478 21 const unsigned block_size = 64;
479 21 const unsigned key_length = key.length();
480 unsigned char key_block[block_size];
481 21 memset(key_block, 0, block_size);
482
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 18 times.
21 if (key_length > block_size) {
483
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 sha256_init(&ctx);
484
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 sha256_update(&ctx, key_length,
485 3 reinterpret_cast<const unsigned char *>(key.data()));
486
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 Sha256Digest(&ctx, key_block);
487 } else {
488
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 if (key.length() > 0)
489 18 memcpy(key_block, key.data(), key_length);
490 }
491
492 unsigned char pad_block[block_size];
493 // Inner hash
494 unsigned char digest_inner[SHA256_DIGEST_SIZE];
495
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
21 sha256_init(&ctx);
496
2/2
✓ Branch 0 taken 1344 times.
✓ Branch 1 taken 21 times.
1365 for (unsigned i = 0; i < block_size; ++i)
497 1344 pad_block[i] = key_block[i] ^ 0x36;
498
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
21 sha256_update(&ctx, block_size, pad_block);
499
1/2
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
21 sha256_update(&ctx, content.length(),
500 21 reinterpret_cast<const unsigned char *>(content.data()));
501
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
21 Sha256Digest(&ctx, digest_inner);
502
503 // Outer hash
504
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
21 sha256_init(&ctx);
505
2/2
✓ Branch 0 taken 1344 times.
✓ Branch 1 taken 21 times.
1365 for (unsigned i = 0; i < block_size; ++i)
506 1344 pad_block[i] = key_block[i] ^ 0x5c;
507
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
21 sha256_update(&ctx, block_size, pad_block);
508
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
21 sha256_update(&ctx, SHA256_DIGEST_SIZE, digest_inner);
509
510
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
21 Sha256Digest(&ctx, digest);
511
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 9 times.
21 if (raw_output)
512
1/2
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 return string(reinterpret_cast<const char *>(digest), SHA256_DIGEST_SIZE);
513
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 return HexFromSha256(digest);
514 }
515
516 } // namespace shash
517
518 #ifdef CVMFS_NAMESPACE_GUARD
519 } // namespace CVMFS_NAMESPACE_GUARD
520 #endif
521