GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/crypto/hash.cc
Date: 2026-08-30 02:40:36
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 2751648 void Md5Digest(md5_ctx *ctx, uint8_t *digest) {
55 2751648 nettle_md5_digest(ctx, MD5_DIGEST_SIZE, digest);
56 2751648 }
57
58 1010944 void Sha1Digest(sha1_ctx *ctx, uint8_t *digest) {
59 1010944 nettle_sha1_digest(ctx, SHA1_DIGEST_SIZE, digest);
60 1010960 }
61
62 72 void Sha256Digest(sha256_ctx *ctx, uint8_t *digest) {
63 72 nettle_sha256_digest(ctx, SHA256_DIGEST_SIZE, digest);
64 72 }
65
66 50 void Ripemd160Digest(ripemd160_ctx *ctx, uint8_t *digest) {
67 50 nettle_ripemd160_digest(ctx, RIPEMD160_DIGEST_SIZE, digest);
68 50 }
69
70 #endif
71
72 929 void Shake128Digest(sha3_128_ctx *ctx, uint8_t *digest) {
73 929 nettle_sha3_128_shake(ctx, kDigestSizes[kShake128], digest);
74 929 }
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 88 bool HexPtr::IsValid() const {
85 88 const unsigned l = str->length();
86
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 84 times.
88 if (l == 0)
87 4 return false;
88 84 const char *c = str->data(); // Walks through the string
89 84 unsigned i = 0; // String position of *c
90
91
2/2
✓ Branch 0 taken 3280 times.
✓ Branch 1 taken 20 times.
3300 for (; i < l; ++i, ++c) {
92
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 3224 times.
3280 if (*c == '-')
93 56 break;
94
6/8
✓ Branch 0 taken 3224 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3224 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1308 times.
✓ Branch 5 taken 1916 times.
✓ Branch 6 taken 8 times.
✓ Branch 7 taken 1300 times.
3224 if ((*c < '0') || (*c > 'f') || ((*c > '9') && (*c < 'a')))
95 8 return false;
96 }
97
98 // Walk through all algorithms
99
2/2
✓ Branch 0 taken 280 times.
✓ Branch 1 taken 60 times.
340 for (unsigned j = 0; j < kAny; ++j) {
100 280 const unsigned hex_length = 2 * kDigestSizes[j];
101 280 const unsigned algo_id_length = kAlgorithmIdSizes[j];
102
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 192 times.
280 if (i == hex_length) {
103 // Right suffix?
104
4/4
✓ Branch 0 taken 244 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 212 times.
✓ Branch 3 taken 32 times.
260 for (; (i < l) && (i - hex_length < algo_id_length); ++i, ++c) {
105
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 172 times.
212 if (*c != kAlgorithmIds[j][i - hex_length])
106 40 break;
107 }
108
3/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 72 times.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
88 if ((i == l) && (l == hex_length + algo_id_length))
109 16 return true;
110 72 i = hex_length;
111 72 c = str->data() + i;
112 }
113 }
114
115 60 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 161308 Any MkFromHexPtr(const HexPtr hex, const char suffix) {
131 161308 Any result;
132
133 161308 const unsigned length = hex.str->length();
134
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 161304 times.
161308 if (length == 2 * kDigestSizes[kMd5])
135 4 result = Any(kMd5, hex);
136
2/2
✓ Branch 0 taken 160911 times.
✓ Branch 1 taken 397 times.
161308 if (length == 2 * kDigestSizes[kSha1])
137 160911 result = Any(kSha1, hex);
138 // TODO(jblomer) compare -rmd160, -shake128
139
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 161301 times.
161308 if ((length == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160]))
140 7 result = Any(kRmd160, hex);
141
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 161288 times.
161308 if ((length == 2 * kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128]))
142 20 result = Any(kShake128, hex);
143
144 161308 result.suffix = suffix;
145 161308 return result;
146 }
147
148
149 /**
150 * Similar to MkFromHexPtr but the suffix is deducted from the HexPtr string.
151 */
152 42446 Any MkFromSuffixedHexPtr(const HexPtr hex) {
153 42446 Any result;
154
155 42446 const unsigned length = hex.str->length();
156
2/2
✓ Branch 0 taken 1360 times.
✓ Branch 1 taken 41086 times.
42446 if ((length == 2 * kDigestSizes[kMd5])
157
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1356 times.
1360 || (length == 2 * kDigestSizes[kMd5] + 1)) {
158 41090 const Suffix suffix = (length == 2 * kDigestSizes[kMd5] + 1)
159
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 41086 times.
41090 ? *(hex.str->rbegin())
160 41090 : kSuffixNone;
161 41090 result = Any(kMd5, hex, suffix);
162 }
163
2/2
✓ Branch 0 taken 41714 times.
✓ Branch 1 taken 732 times.
42446 if ((length == 2 * kDigestSizes[kSha1])
164
2/2
✓ Branch 0 taken 592 times.
✓ Branch 1 taken 41122 times.
41714 || (length == 2 * kDigestSizes[kSha1] + 1)) {
165 1324 const Suffix suffix = (length == 2 * kDigestSizes[kSha1] + 1)
166
2/2
✓ Branch 0 taken 592 times.
✓ Branch 1 taken 732 times.
1324 ? *(hex.str->rbegin())
167 1324 : kSuffixNone;
168 1324 result = Any(kSha1, hex, suffix);
169 }
170
2/2
✓ Branch 0 taken 42442 times.
✓ Branch 1 taken 4 times.
42446 if ((length == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160])
171 42442 || (length
172
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 42426 times.
42442 == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160] + 1)) {
173 const Suffix suffix = (length
174 20 == 2 * kDigestSizes[kRmd160]
175 20 + kAlgorithmIdSizes[kRmd160] + 1)
176
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 4 times.
20 ? *(hex.str->rbegin())
177 20 : kSuffixNone;
178 20 result = Any(kRmd160, hex, suffix);
179 }
180
2/2
✓ Branch 0 taken 42442 times.
✓ Branch 1 taken 4 times.
42446 if ((length == 2 * kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128])
181 42442 || (length
182
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 42438 times.
42442 == 2 * kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128] + 1)) {
183 const Suffix suffix = (length
184 8 == 2 * kDigestSizes[kShake128]
185 8 + kAlgorithmIdSizes[kShake128] + 1)
186
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 ? *(hex.str->rbegin())
187 8 : kSuffixNone;
188 8 result = Any(kShake128, hex, suffix);
189 }
190
191 42446 return result;
192 }
193
194
195 /**
196 * Allows the caller to create the context on the stack.
197 */
198 2227104 unsigned GetContextSize(const Algorithms algorithm) {
199
4/5
✓ Branch 0 taken 1210902 times.
✓ Branch 1 taken 1015247 times.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 929 times.
✗ Branch 4 not taken.
2227104 switch (algorithm) {
200 1210902 case kMd5:
201 1210902 return sizeof(md5_ctx);
202 1015247 case kSha1:
203 1015247 return sizeof(sha1_ctx);
204 50 case kRmd160:
205 50 return sizeof(ripemd160_ctx);
206 929 case kShake128:
207 929 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 2227450 void Init(ContextPtr context) {
215
4/5
✓ Branch 0 taken 1210905 times.
✓ Branch 1 taken 1015594 times.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 929 times.
✗ Branch 4 not taken.
2227450 switch (context.algorithm) {
216 1210905 case kMd5:
217 1210905 md5_init(reinterpret_cast<md5_ctx *>(context.buffer));
218 1210905 break;
219 1015594 case kSha1:
220 1015594 sha1_init(reinterpret_cast<sha1_ctx *>(context.buffer));
221 1015410 break;
222 50 case kRmd160:
223 50 ripemd160_init(reinterpret_cast<ripemd160_ctx *>(context.buffer));
224 50 break;
225 929 case kShake128:
226 929 sha3_128_init(reinterpret_cast<sha3_128_ctx *>(context.buffer));
227 929 break;
228 default:
229 PANIC(NULL); // Undefined hash
230 }
231 2227294 }
232
233 376445204 void Update(const unsigned char *buffer, const unsigned buffer_length,
234 ContextPtr context) {
235
4/5
✓ Branch 0 taken 97844973 times.
✓ Branch 1 taken 94049881 times.
✓ Branch 2 taken 92274746 times.
✓ Branch 3 taken 92275608 times.
✗ Branch 4 not taken.
376445204 switch (context.algorithm) {
236 97844973 case kMd5:
237 97844973 md5_update(reinterpret_cast<md5_ctx *>(context.buffer),
238 buffer_length, buffer);
239 97844973 break;
240 94049881 case kSha1:
241 94049881 sha1_update(reinterpret_cast<sha1_ctx *>(context.buffer),
242 buffer_length, buffer);
243 94050329 break;
244 92274746 case kRmd160:
245 92274746 ripemd160_update(reinterpret_cast<ripemd160_ctx *>(context.buffer),
246 buffer_length, buffer);
247 92274746 break;
248 92275608 case kShake128:
249 92275608 sha3_128_update(reinterpret_cast<sha3_128_ctx *>(context.buffer),
250 buffer_length, buffer);
251 92275608 break;
252 default:
253 PANIC(NULL); // Undefined hash
254 }
255 376445656 }
256
257 2222812 void Final(ContextPtr context, Any *any_digest) {
258
4/5
✓ Branch 0 taken 1210901 times.
✓ Branch 1 taken 1010940 times.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 929 times.
✗ Branch 4 not taken.
2222812 switch (context.algorithm) {
259 1210901 case kMd5:
260 1210901 Md5Digest(reinterpret_cast<md5_ctx *>(context.buffer), any_digest->digest);
261 1210901 break;
262 1010940 case kSha1:
263 1010940 Sha1Digest(reinterpret_cast<sha1_ctx *>(context.buffer),
264 1010940 any_digest->digest);
265 1010932 break;
266 50 case kRmd160:
267 50 Ripemd160Digest(reinterpret_cast<ripemd160_ctx *>(context.buffer),
268 50 any_digest->digest);
269 50 break;
270 929 case kShake128:
271 929 Shake128Digest(reinterpret_cast<sha3_128_ctx *>(context.buffer),
272 929 any_digest->digest);
273 929 break;
274 default:
275 PANIC(NULL); // Undefined hash
276 }
277 2222812 any_digest->algorithm = context.algorithm;
278 2222812 }
279
280
281 8887 void HashMem(const unsigned char *buffer, const unsigned buffer_size,
282 Any *any_digest) {
283 8887 const Algorithms algorithm = any_digest->algorithm;
284
1/2
✓ Branch 1 taken 8887 times.
✗ Branch 2 not taken.
8887 ContextPtr context(algorithm);
285 8887 context.buffer = alloca(context.size);
286
287
1/2
✓ Branch 1 taken 8887 times.
✗ Branch 2 not taken.
8887 Init(context);
288
1/2
✓ Branch 1 taken 8887 times.
✗ Branch 2 not taken.
8887 Update(buffer, buffer_size, context);
289
1/2
✓ Branch 1 taken 8887 times.
✗ Branch 2 not taken.
8887 Final(context, any_digest);
290 8887 }
291
292
293 1146 void HashString(const std::string &content, Any *any_digest) {
294 1146 HashMem(reinterpret_cast<const unsigned char *>(content.data()),
295 1146 content.length(), any_digest);
296 1146 }
297
298
299 601312 void Hmac(const string &key,
300 const unsigned char *buffer,
301 const unsigned buffer_size,
302 Any *any_digest) {
303 601312 const Algorithms algorithm = any_digest->algorithm;
304
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 601312 times.
601312 assert(algorithm != kAny);
305
306 601312 const unsigned block_size = kBlockSizes[algorithm];
307 601312 unsigned char key_block[block_size];
308 601312 memset(key_block, 0, block_size);
309
2/2
✓ Branch 1 taken 1228 times.
✓ Branch 2 taken 600084 times.
601312 if (key.length() > block_size) {
310
1/2
✓ Branch 1 taken 1228 times.
✗ Branch 2 not taken.
1228 Any hash_key(algorithm);
311
1/2
✓ Branch 3 taken 1228 times.
✗ Branch 4 not taken.
1228 HashMem(reinterpret_cast<const unsigned char *>(key.data()), key.length(),
312 &hash_key);
313 1228 memcpy(key_block, hash_key.digest, kDigestSizes[algorithm]);
314 } else {
315
2/2
✓ Branch 1 taken 600072 times.
✓ Branch 2 taken 12 times.
600084 if (key.length() > 0)
316 600072 memcpy(key_block, key.data(), key.length());
317 }
318
319 601312 unsigned char pad_block[block_size];
320 // Inner hash
321
1/2
✓ Branch 1 taken 601312 times.
✗ Branch 2 not taken.
601312 Any hash_inner(algorithm);
322
1/2
✓ Branch 1 taken 601312 times.
✗ Branch 2 not taken.
601312 ContextPtr context_inner(algorithm);
323 601312 context_inner.buffer = alloca(context_inner.size);
324
1/2
✓ Branch 1 taken 601312 times.
✗ Branch 2 not taken.
601312 Init(context_inner);
325
2/2
✓ Branch 0 taken 38483968 times.
✓ Branch 1 taken 601312 times.
39085280 for (unsigned i = 0; i < block_size; ++i)
326 38483968 pad_block[i] = key_block[i] ^ 0x36;
327
1/2
✓ Branch 1 taken 601312 times.
✗ Branch 2 not taken.
601312 Update(pad_block, block_size, context_inner);
328
1/2
✓ Branch 1 taken 601312 times.
✗ Branch 2 not taken.
601312 Update(buffer, buffer_size, context_inner);
329
1/2
✓ Branch 1 taken 601312 times.
✗ Branch 2 not taken.
601312 Final(context_inner, &hash_inner);
330
331 // Outer hash
332
1/2
✓ Branch 1 taken 601312 times.
✗ Branch 2 not taken.
601312 ContextPtr context_outer(algorithm);
333 601312 context_outer.buffer = alloca(context_outer.size);
334
1/2
✓ Branch 1 taken 601312 times.
✗ Branch 2 not taken.
601312 Init(context_outer);
335
2/2
✓ Branch 0 taken 38483968 times.
✓ Branch 1 taken 601312 times.
39085280 for (unsigned i = 0; i < block_size; ++i)
336 38483968 pad_block[i] = key_block[i] ^ 0x5c;
337
1/2
✓ Branch 1 taken 601312 times.
✗ Branch 2 not taken.
601312 Update(pad_block, block_size, context_outer);
338
1/2
✓ Branch 1 taken 601312 times.
✗ Branch 2 not taken.
601312 Update(hash_inner.digest, kDigestSizes[algorithm], context_outer);
339
340
1/2
✓ Branch 1 taken 601312 times.
✗ Branch 2 not taken.
601312 Final(context_outer, any_digest);
341 601312 }
342
343
344 7984 bool HashFd(int fd, Any *any_digest) {
345 7984 const Algorithms algorithm = any_digest->algorithm;
346
1/2
✓ Branch 1 taken 7984 times.
✗ Branch 2 not taken.
7984 ContextPtr context(algorithm);
347 7984 context.buffer = alloca(context.size);
348
349
1/2
✓ Branch 1 taken 7984 times.
✗ Branch 2 not taken.
7984 Init(context);
350 unsigned char io_buffer[4096];
351 int actual_bytes;
352
3/4
✓ Branch 1 taken 3389777 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3381793 times.
✓ Branch 4 taken 7984 times.
3389777 while ((actual_bytes = read(fd, io_buffer, 4096)) != 0) {
353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3381793 times.
3381793 if (actual_bytes == -1) {
354 if (errno == EINTR)
355 continue;
356 return false;
357 }
358
1/2
✓ Branch 1 taken 3381793 times.
✗ Branch 2 not taken.
3381793 Update(io_buffer, actual_bytes, context);
359 }
360
1/2
✓ Branch 1 taken 7984 times.
✗ Branch 2 not taken.
7984 Final(context, any_digest);
361 7984 return true;
362 }
363
364
365 7984 bool HashFile(const std::string &filename, Any *any_digest) {
366 7984 const int fd = open(filename.c_str(), O_RDONLY);
367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7984 times.
7984 if (fd == -1)
368 return false;
369
370 7984 const bool result = HashFd(fd, any_digest);
371 7984 close(fd);
372 7984 return result;
373 }
374
375
376 /**
377 * Fast constructor for hashing path names.
378 */
379 5337 Md5::Md5(const AsciiPtr ascii) {
380 5337 algorithm = kMd5;
381 5337 const string *str = ascii.str;
382
383 md5_ctx md5_state;
384
1/2
✓ Branch 1 taken 5337 times.
✗ Branch 2 not taken.
5337 md5_init(&md5_state);
385
1/2
✓ Branch 2 taken 5337 times.
✗ Branch 3 not taken.
5337 md5_update(&md5_state, str->length(),
386 5337 reinterpret_cast<const uint8_t *>(&(*str)[0]));
387
1/2
✓ Branch 1 taken 5337 times.
✗ Branch 2 not taken.
5337 Md5Digest(&md5_state, digest);
388 5337 }
389
390
391 1535410 Md5::Md5(const char *chars, const unsigned length) {
392 1535410 algorithm = kMd5;
393
394 md5_ctx md5_state;
395
1/2
✓ Branch 1 taken 1535410 times.
✗ Branch 2 not taken.
1535410 md5_init(&md5_state);
396
1/2
✓ Branch 1 taken 1535410 times.
✗ Branch 2 not taken.
1535410 md5_update(&md5_state, length, reinterpret_cast<const uint8_t *>(chars));
397
1/2
✓ Branch 1 taken 1535410 times.
✗ Branch 2 not taken.
1535410 Md5Digest(&md5_state, digest);
398 1535410 }
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 5780 void Md5::ToIntPair(uint64_t *lo, uint64_t *hi) const {
408 5780 memcpy(lo, digest, 8);
409 5780 memcpy(hi, digest + 8, 8);
410 5780 }
411
412
413 600084 Md5 Any::CastToMd5() {
414
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 600084 times.
600084 assert(algorithm == kMd5);
415 600084 Md5 result;
416 600084 memcpy(result.digest, digest, kDigestSizes[kMd5]);
417 600084 return result;
418 }
419
420 24 static string HexFromSha256(unsigned char digest[SHA256_DIGEST_SIZE]) {
421 24 string result;
422
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 result.reserve(2 * SHA256_DIGEST_SIZE);
423
2/2
✓ Branch 0 taken 768 times.
✓ Branch 1 taken 24 times.
792 for (unsigned i = 0; i < SHA256_DIGEST_SIZE; ++i) {
424 768 const char d1 = digest[i] / 16;
425 768 const char d2 = digest[i] % 16;
426
3/4
✓ Branch 0 taken 444 times.
✓ Branch 1 taken 324 times.
✓ Branch 3 taken 768 times.
✗ Branch 4 not taken.
768 result.push_back(d1 + ((d1 <= 9) ? '0' : 'a' - 10));
427
3/4
✓ Branch 0 taken 532 times.
✓ Branch 1 taken 236 times.
✓ Branch 3 taken 768 times.
✗ Branch 4 not taken.
768 result.push_back(d2 + ((d2 <= 9) ? '0' : 'a' - 10));
428 }
429 24 return result;
430 }
431
432 4 string Sha256File(const string &filename) {
433
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 const int fd = open(filename.c_str(), O_RDONLY);
434
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (fd < 0)
435 return "";
436
437 sha256_ctx ctx;
438
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 sha256_init(&ctx);
439
440 unsigned char io_buffer[4096];
441 int actual_bytes;
442
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
4 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 4 times.
✗ Branch 2 not taken.
4 close(fd);
452
453 unsigned char digest[SHA256_DIGEST_SIZE];
454
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 Sha256Digest(&ctx, digest);
455
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 return HexFromSha256(digest);
456 }
457
458 8 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 8 times.
✗ Branch 2 not taken.
8 sha256_init(&ctx);
462
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 sha256_update(&ctx, buffer_size, buffer);
463
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 Sha256Digest(&ctx, digest);
464
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
16 return HexFromSha256(digest);
465 }
466
467 4 string Sha256String(const string &content) {
468 4 return Sha256Mem(reinterpret_cast<const unsigned char *>(content.data()),
469 4 content.length());
470 }
471
472
473 28 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 28 const unsigned block_size = 64;
479 28 const unsigned key_length = key.length();
480 unsigned char key_block[block_size];
481 28 memset(key_block, 0, block_size);
482
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 24 times.
28 if (key_length > block_size) {
483
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 sha256_init(&ctx);
484
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 sha256_update(&ctx, key_length,
485 4 reinterpret_cast<const unsigned char *>(key.data()));
486
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 Sha256Digest(&ctx, key_block);
487 } else {
488
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 if (key.length() > 0)
489 24 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 28 times.
✗ Branch 2 not taken.
28 sha256_init(&ctx);
496
2/2
✓ Branch 0 taken 1792 times.
✓ Branch 1 taken 28 times.
1820 for (unsigned i = 0; i < block_size; ++i)
497 1792 pad_block[i] = key_block[i] ^ 0x36;
498
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 sha256_update(&ctx, block_size, pad_block);
499
1/2
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
28 sha256_update(&ctx, content.length(),
500 28 reinterpret_cast<const unsigned char *>(content.data()));
501
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 Sha256Digest(&ctx, digest_inner);
502
503 // Outer hash
504
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 sha256_init(&ctx);
505
2/2
✓ Branch 0 taken 1792 times.
✓ Branch 1 taken 28 times.
1820 for (unsigned i = 0; i < block_size; ++i)
506 1792 pad_block[i] = key_block[i] ^ 0x5c;
507
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 sha256_update(&ctx, block_size, pad_block);
508
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 sha256_update(&ctx, SHA256_DIGEST_SIZE, digest_inner);
509
510
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 Sha256Digest(&ctx, digest);
511
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 12 times.
28 if (raw_output)
512
1/2
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
16 return string(reinterpret_cast<const char *>(digest), SHA256_DIGEST_SIZE);
513
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 return HexFromSha256(digest);
514 }
515
516 } // namespace shash
517
518 #ifdef CVMFS_NAMESPACE_GUARD
519 } // namespace CVMFS_NAMESPACE_GUARD
520 #endif
521