GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/crypto/hash.cc
Date: 2026-10-04 02:40:33
Exec Total Coverage
Lines: 278 307 90.6%
Branches: 159 246 64.6%

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 5078042 void Md5Digest(md5_ctx *ctx, uint8_t *digest) {
55 5078042 nettle_md5_digest(ctx, MD5_DIGEST_SIZE, digest);
56 5078042 }
57
58 767651 void Sha1Digest(sha1_ctx *ctx, uint8_t *digest) {
59 767651 nettle_sha1_digest(ctx, SHA1_DIGEST_SIZE, digest);
60 767732 }
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 499 void Shake128Digest(sha3_128_ctx *ctx, uint8_t *digest) {
73 499 nettle_sha3_128_shake(ctx, kDigestSizes[kShake128], digest);
74 499 }
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 323746 Any MkFromHexPtr(const HexPtr hex, const char suffix) {
131 323746 Any result;
132
133 323746 const unsigned length = hex.str->length();
134
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 323743 times.
323746 if (length == 2 * kDigestSizes[kMd5])
135 3 result = Any(kMd5, hex);
136
2/2
✓ Branch 0 taken 323516 times.
✓ Branch 1 taken 230 times.
323746 if (length == 2 * kDigestSizes[kSha1])
137 323516 result = Any(kSha1, hex);
138 // TODO(jblomer) compare -rmd160, -shake128
139
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 323731 times.
323746 if ((length == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160]))
140 15 result = Any(kRmd160, hex);
141
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 323739 times.
323746 if ((length == 2 * kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128]))
142 7 result = Any(kShake128, hex);
143
144 323746 result.suffix = suffix;
145 323746 return result;
146 }
147
148
149 /**
150 * Similar to MkFromHexPtr but the suffix is deducted from the HexPtr string.
151 */
152 23507 Any MkFromSuffixedHexPtr(const HexPtr hex) {
153 23507 Any result;
154
155 23507 const unsigned length = hex.str->length();
156
2/2
✓ Branch 0 taken 1511 times.
✓ Branch 1 taken 21996 times.
23507 if ((length == 2 * kDigestSizes[kMd5])
157
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1508 times.
1511 || (length == 2 * kDigestSizes[kMd5] + 1)) {
158 21999 const Suffix suffix = (length == 2 * kDigestSizes[kMd5] + 1)
159
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 21996 times.
21999 ? *(hex.str->rbegin())
160 21999 : kSuffixNone;
161 21999 result = Any(kMd5, hex, suffix);
162 }
163
2/2
✓ Branch 0 taken 22695 times.
✓ Branch 1 taken 812 times.
23507 if ((length == 2 * kDigestSizes[kSha1])
164
2/2
✓ Branch 0 taken 675 times.
✓ Branch 1 taken 22020 times.
22695 || (length == 2 * kDigestSizes[kSha1] + 1)) {
165 1487 const Suffix suffix = (length == 2 * kDigestSizes[kSha1] + 1)
166
2/2
✓ Branch 0 taken 675 times.
✓ Branch 1 taken 812 times.
1487 ? *(hex.str->rbegin())
167 1487 : kSuffixNone;
168 1487 result = Any(kSha1, hex, suffix);
169 }
170
2/2
✓ Branch 0 taken 23504 times.
✓ Branch 1 taken 3 times.
23507 if ((length == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160])
171 23504 || (length
172
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 23495 times.
23504 == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160] + 1)) {
173 const Suffix suffix = (length
174 12 == 2 * kDigestSizes[kRmd160]
175 12 + kAlgorithmIdSizes[kRmd160] + 1)
176
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 3 times.
12 ? *(hex.str->rbegin())
177 12 : kSuffixNone;
178 12 result = Any(kRmd160, hex, suffix);
179 }
180
2/2
✓ Branch 0 taken 23504 times.
✓ Branch 1 taken 3 times.
23507 if ((length == 2 * kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128])
181 23504 || (length
182
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 23501 times.
23504 == 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 23507 return result;
192 }
193
194
195 /**
196 * Allows the caller to create the context on the stack.
197 */
198 1390405 unsigned GetContextSize(const Algorithms algorithm) {
199
4/5
✓ Branch 0 taken 607682 times.
✓ Branch 1 taken 782189 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 499 times.
✗ Branch 4 not taken.
1390405 switch (algorithm) {
200 607682 case kMd5:
201 607682 return sizeof(md5_ctx);
202 782189 case kSha1:
203 782189 return sizeof(sha1_ctx);
204 38 case kRmd160:
205 38 return sizeof(ripemd160_ctx);
206 499 case kShake128:
207 499 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 1390700 void Init(ContextPtr context) {
215
4/5
✓ Branch 0 taken 607691 times.
✓ Branch 1 taken 782496 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 499 times.
✗ Branch 4 not taken.
1390700 switch (context.algorithm) {
216 607691 case kMd5:
217 607691 md5_init(reinterpret_cast<md5_ctx *>(context.buffer));
218 607691 break;
219 782496 case kSha1:
220 782496 sha1_init(reinterpret_cast<sha1_ctx *>(context.buffer));
221 782301 break;
222 38 case kRmd160:
223 38 ripemd160_init(reinterpret_cast<ripemd160_ctx *>(context.buffer));
224 38 break;
225 499 case kShake128:
226 499 sha3_128_init(reinterpret_cast<sha3_128_ctx *>(context.buffer));
227 499 break;
228 ✗ default:
229 ✗ PANIC(NULL); // Undefined hash
230 }
231 1390529 }
232
233 281064089 void Update(const unsigned char *buffer, const unsigned buffer_length,
234 ContextPtr context) {
235
4/5
✓ Branch 0 taken 72209239 times.
✓ Branch 1 taken 70442287 times.
✓ Branch 2 taken 69206060 times.
✓ Branch 3 taken 69206506 times.
✗ Branch 4 not taken.
281064089 switch (context.algorithm) {
236 72209239 case kMd5:
237 72209239 md5_update(reinterpret_cast<md5_ctx *>(context.buffer),
238 buffer_length, buffer);
239 72209239 break;
240 70442287 case kSha1:
241 70442287 sha1_update(reinterpret_cast<sha1_ctx *>(context.buffer),
242 buffer_length, buffer);
243 70442686 break;
244 69206060 case kRmd160:
245 69206060 ripemd160_update(reinterpret_cast<ripemd160_ctx *>(context.buffer),
246 buffer_length, buffer);
247 69206060 break;
248 69206506 case kShake128:
249 69206506 sha3_128_update(reinterpret_cast<sha3_128_ctx *>(context.buffer),
250 buffer_length, buffer);
251 69206506 break;
252 ✗ default:
253 ✗ PANIC(NULL); // Undefined hash
254 }
255 281064491 }
256
257 1375858 void Final(ContextPtr context, Any *any_digest) {
258
5/5
✓ Branch 0 taken 607679 times.
✓ Branch 1 taken 767639 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 499 times.
✓ Branch 4 taken 3 times.
1375858 switch (context.algorithm) {
259 607679 case kMd5:
260 607679 Md5Digest(reinterpret_cast<md5_ctx *>(context.buffer), any_digest->digest);
261 607679 break;
262 767639 case kSha1:
263 767639 Sha1Digest(reinterpret_cast<sha1_ctx *>(context.buffer),
264 767639 any_digest->digest);
265 767687 break;
266 38 case kRmd160:
267 38 Ripemd160Digest(reinterpret_cast<ripemd160_ctx *>(context.buffer),
268 38 any_digest->digest);
269 38 break;
270 499 case kShake128:
271 499 Shake128Digest(reinterpret_cast<sha3_128_ctx *>(context.buffer),
272 499 any_digest->digest);
273 499 break;
274 3 default:
275 3 PANIC(NULL); // Undefined hash
276 }
277 1375903 any_digest->algorithm = context.algorithm;
278 1375903 }
279
280
281 11074 void HashMem(const unsigned char *buffer, const unsigned buffer_size,
282 Any *any_digest) {
283 11074 const Algorithms algorithm = any_digest->algorithm;
284
1/2
✓ Branch 1 taken 11074 times.
✗ Branch 2 not taken.
11074 ContextPtr context(algorithm);
285 11074 context.buffer = alloca(context.size);
286
287
1/2
✓ Branch 1 taken 11074 times.
✗ Branch 2 not taken.
11074 Init(context);
288
1/2
✓ Branch 1 taken 11074 times.
✗ Branch 2 not taken.
11074 Update(buffer, buffer_size, context);
289
1/2
✓ Branch 1 taken 11074 times.
✗ Branch 2 not taken.
11074 Final(context, any_digest);
290 11074 }
291
292
293 669 void HashString(const std::string &content, Any *any_digest) {
294 669 HashMem(reinterpret_cast<const unsigned char *>(content.data()),
295 669 content.length(), any_digest);
296 669 }
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 4583 bool HashFd(int fd, Any *any_digest) {
345 4583 const Algorithms algorithm = any_digest->algorithm;
346
1/2
✓ Branch 1 taken 4583 times.
✗ Branch 2 not taken.
4583 ContextPtr context(algorithm);
347 4583 context.buffer = alloca(context.size);
348
349
1/2
✓ Branch 1 taken 4583 times.
✗ Branch 2 not taken.
4583 Init(context);
350 unsigned char io_buffer[4096];
351 int actual_bytes;
352
3/4
✓ Branch 1 taken 1856231 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1851648 times.
✓ Branch 4 taken 4583 times.
1856231 while ((actual_bytes = read(fd, io_buffer, 4096)) != 0) {
353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1851648 times.
1851648 if (actual_bytes == -1) {
354 ✗ if (errno == EINTR)
355 ✗ continue;
356 ✗ return false;
357 }
358
1/2
✓ Branch 1 taken 1851648 times.
✗ Branch 2 not taken.
1851648 Update(io_buffer, actual_bytes, context);
359 }
360
1/2
✓ Branch 1 taken 4583 times.
✗ Branch 2 not taken.
4583 Final(context, any_digest);
361 4583 return true;
362 }
363
364
365 4583 bool HashFile(const std::string &filename, Any *any_digest) {
366 4583 const int fd = open(filename.c_str(), O_RDONLY);
367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4583 times.
4583 if (fd == -1)
368 ✗ return false;
369
370 4583 const bool result = HashFd(fd, any_digest);
371 4583 close(fd);
372 4583 return result;
373 }
374
375
376 /**
377 * Fast constructor for hashing path names.
378 */
379 6546 Md5::Md5(const AsciiPtr ascii) {
380 6546 algorithm = kMd5;
381 6546 const string *str = ascii.str;
382
383 md5_ctx md5_state;
384
1/2
✓ Branch 1 taken 6546 times.
✗ Branch 2 not taken.
6546 md5_init(&md5_state);
385
1/2
✓ Branch 2 taken 6546 times.
✗ Branch 3 not taken.
6546 md5_update(&md5_state, str->length(),
386 6546 reinterpret_cast<const uint8_t *>(&(*str)[0]));
387
1/2
✓ Branch 1 taken 6546 times.
✗ Branch 2 not taken.
6546 Md5Digest(&md5_state, digest);
388 6546 }
389
390
391 4463817 Md5::Md5(const char *chars, const unsigned length) {
392 4463817 algorithm = kMd5;
393
394 md5_ctx md5_state;
395
1/2
✓ Branch 1 taken 4463817 times.
✗ Branch 2 not taken.
4463817 md5_init(&md5_state);
396
1/2
✓ Branch 1 taken 4463817 times.
✗ Branch 2 not taken.
4463817 md5_update(&md5_state, length, reinterpret_cast<const uint8_t *>(chars));
397
1/2
✓ Branch 1 taken 4463817 times.
✗ Branch 2 not taken.
4463817 Md5Digest(&md5_state, digest);
398 4463817 }
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 8140 void Md5::ToIntPair(uint64_t *lo, uint64_t *hi) const {
408 8140 memcpy(lo, digest, 8);
409 8140 memcpy(hi, digest + 8, 8);
410 8140 }
411
412
413 300063 Md5 Any::CastToMd5() {
414
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 300063 times.
300063 assert(algorithm == kMd5);
415 300063 Md5 result;
416 300063 memcpy(result.digest, digest, kDigestSizes[kMd5]);
417 300063 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