GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/crypto/hash.cc
Date: 2026-09-20 02:39:58
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 2336678 void Md5Digest(md5_ctx *ctx, uint8_t *digest) {
55 2336678 nettle_md5_digest(ctx, MD5_DIGEST_SIZE, digest);
56 2336678 }
57
58 1512834 void Sha1Digest(sha1_ctx *ctx, uint8_t *digest) {
59 1512834 nettle_sha1_digest(ctx, SHA1_DIGEST_SIZE, digest);
60 1513176 }
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 657 void Shake128Digest(sha3_128_ctx *ctx, uint8_t *digest) {
73 657 nettle_sha3_128_shake(ctx, kDigestSizes[kShake128], digest);
74 657 }
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 118839 Any MkFromHexPtr(const HexPtr hex, const char suffix) {
131 118839 Any result;
132
133 118839 const unsigned length = hex.str->length();
134
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 118835 times.
118839 if (length == 2 * kDigestSizes[kMd5])
135 4 result = Any(kMd5, hex);
136
2/2
✓ Branch 0 taken 118656 times.
✓ Branch 1 taken 183 times.
118839 if (length == 2 * kDigestSizes[kSha1])
137 118656 result = Any(kSha1, hex);
138 // TODO(jblomer) compare -rmd160, -shake128
139
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 118823 times.
118839 if ((length == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160]))
140 16 result = Any(kRmd160, hex);
141
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 118827 times.
118839 if ((length == 2 * kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128]))
142 12 result = Any(kShake128, hex);
143
144 118839 result.suffix = suffix;
145 118839 return result;
146 }
147
148
149 /**
150 * Similar to MkFromHexPtr but the suffix is deducted from the HexPtr string.
151 */
152 29405 Any MkFromSuffixedHexPtr(const HexPtr hex) {
153 29405 Any result;
154
155 29405 const unsigned length = hex.str->length();
156
2/2
✓ Branch 0 taken 1345 times.
✓ Branch 1 taken 28060 times.
29405 if ((length == 2 * kDigestSizes[kMd5])
157
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1341 times.
1345 || (length == 2 * kDigestSizes[kMd5] + 1)) {
158 28064 const Suffix suffix = (length == 2 * kDigestSizes[kMd5] + 1)
159
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 28060 times.
28064 ? *(hex.str->rbegin())
160 28064 : kSuffixNone;
161 28064 result = Any(kMd5, hex, suffix);
162 }
163
2/2
✓ Branch 0 taken 28684 times.
✓ Branch 1 taken 721 times.
29405 if ((length == 2 * kDigestSizes[kSha1])
164
2/2
✓ Branch 0 taken 592 times.
✓ Branch 1 taken 28092 times.
28684 || (length == 2 * kDigestSizes[kSha1] + 1)) {
165 1313 const Suffix suffix = (length == 2 * kDigestSizes[kSha1] + 1)
166
2/2
✓ Branch 0 taken 592 times.
✓ Branch 1 taken 721 times.
1313 ? *(hex.str->rbegin())
167 1313 : kSuffixNone;
168 1313 result = Any(kSha1, hex, suffix);
169 }
170
2/2
✓ Branch 0 taken 29401 times.
✓ Branch 1 taken 4 times.
29405 if ((length == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160])
171 29401 || (length
172
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 29389 times.
29401 == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160] + 1)) {
173 const Suffix suffix = (length
174 16 == 2 * kDigestSizes[kRmd160]
175 16 + kAlgorithmIdSizes[kRmd160] + 1)
176
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
16 ? *(hex.str->rbegin())
177 16 : kSuffixNone;
178 16 result = Any(kRmd160, hex, suffix);
179 }
180
2/2
✓ Branch 0 taken 29401 times.
✓ Branch 1 taken 4 times.
29405 if ((length == 2 * kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128])
181 29401 || (length
182
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 29397 times.
29401 == 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 29405 return result;
192 }
193
194
195 /**
196 * Allows the caller to create the context on the stack.
197 */
198 2340630 unsigned GetContextSize(const Algorithms algorithm) {
199
5/5
✓ Branch 0 taken 807973 times.
✓ Branch 1 taken 1531936 times.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 657 times.
✓ Branch 4 taken 14 times.
2340630 switch (algorithm) {
200 807973 case kMd5:
201 807973 return sizeof(md5_ctx);
202 1531936 case kSha1:
203 1531936 return sizeof(sha1_ctx);
204 50 case kRmd160:
205 50 return sizeof(ripemd160_ctx);
206 657 case kShake128:
207 657 return sizeof(sha3_128_ctx);
208 14 default:
209 14 PANIC(kLogDebug | kLogSyslogErr,
210 "tried to generate hash context for unspecified hash. Aborting...");
211 }
212 }
213
214 2341150 void Init(ContextPtr context) {
215
4/5
✓ Branch 0 taken 807979 times.
✓ Branch 1 taken 1532530 times.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 657 times.
✗ Branch 4 not taken.
2341150 switch (context.algorithm) {
216 807979 case kMd5:
217 807979 md5_init(reinterpret_cast<md5_ctx *>(context.buffer));
218 807979 break;
219 1532530 case kSha1:
220 1532530 sha1_init(reinterpret_cast<sha1_ctx *>(context.buffer));
221 1532142 break;
222 50 case kRmd160:
223 50 ripemd160_init(reinterpret_cast<ripemd160_ctx *>(context.buffer));
224 50 break;
225 657 case kShake128:
226 657 sha3_128_init(reinterpret_cast<sha3_128_ctx *>(context.buffer));
227 657 break;
228 default:
229 PANIC(NULL); // Undefined hash
230 }
231 2340828 }
232
233 375509276 void Update(const unsigned char *buffer, const unsigned buffer_length,
234 ContextPtr context) {
235
4/5
✓ Branch 0 taken 96138250 times.
✓ Branch 1 taken 94820947 times.
✓ Branch 2 taken 92274746 times.
✓ Branch 3 taken 92275333 times.
✗ Branch 4 not taken.
375509276 switch (context.algorithm) {
236 96138250 case kMd5:
237 96138250 md5_update(reinterpret_cast<md5_ctx *>(context.buffer),
238 buffer_length, buffer);
239 96138250 break;
240 94820947 case kSha1:
241 94820947 sha1_update(reinterpret_cast<sha1_ctx *>(context.buffer),
242 buffer_length, buffer);
243 94821709 break;
244 92274746 case kRmd160:
245 92274746 ripemd160_update(reinterpret_cast<ripemd160_ctx *>(context.buffer),
246 buffer_length, buffer);
247 92274746 break;
248 92275333 case kShake128:
249 92275333 sha3_128_update(reinterpret_cast<sha3_128_ctx *>(context.buffer),
250 buffer_length, buffer);
251 92275333 break;
252 default:
253 PANIC(NULL); // Undefined hash
254 }
255 375510038 }
256
257 2321524 void Final(ContextPtr context, Any *any_digest) {
258
4/5
✓ Branch 0 taken 807971 times.
✓ Branch 1 taken 1512852 times.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 657 times.
✗ Branch 4 not taken.
2321524 switch (context.algorithm) {
259 807971 case kMd5:
260 807971 Md5Digest(reinterpret_cast<md5_ctx *>(context.buffer), any_digest->digest);
261 807971 break;
262 1512852 case kSha1:
263 1512852 Sha1Digest(reinterpret_cast<sha1_ctx *>(context.buffer),
264 1512852 any_digest->digest);
265 1513074 break;
266 50 case kRmd160:
267 50 Ripemd160Digest(reinterpret_cast<ripemd160_ctx *>(context.buffer),
268 50 any_digest->digest);
269 50 break;
270 657 case kShake128:
271 657 Shake128Digest(reinterpret_cast<sha3_128_ctx *>(context.buffer),
272 657 any_digest->digest);
273 657 break;
274 default:
275 PANIC(NULL); // Undefined hash
276 }
277 2321752 any_digest->algorithm = context.algorithm;
278 2321752 }
279
280
281 9379 void HashMem(const unsigned char *buffer, const unsigned buffer_size,
282 Any *any_digest) {
283 9379 const Algorithms algorithm = any_digest->algorithm;
284
1/2
✓ Branch 1 taken 9379 times.
✗ Branch 2 not taken.
9379 ContextPtr context(algorithm);
285 9379 context.buffer = alloca(context.size);
286
287
1/2
✓ Branch 1 taken 9379 times.
✗ Branch 2 not taken.
9379 Init(context);
288
1/2
✓ Branch 1 taken 9379 times.
✗ Branch 2 not taken.
9379 Update(buffer, buffer_size, context);
289
1/2
✓ Branch 1 taken 9379 times.
✗ Branch 2 not taken.
9379 Final(context, any_digest);
290 9379 }
291
292
293 855 void HashString(const std::string &content, Any *any_digest) {
294 855 HashMem(reinterpret_cast<const unsigned char *>(content.data()),
295 855 content.length(), any_digest);
296 855 }
297
298
299 401304 void Hmac(const string &key,
300 const unsigned char *buffer,
301 const unsigned buffer_size,
302 Any *any_digest) {
303 401304 const Algorithms algorithm = any_digest->algorithm;
304
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 401304 times.
401304 assert(algorithm != kAny);
305
306 401304 const unsigned block_size = kBlockSizes[algorithm];
307 401304 unsigned char key_block[block_size];
308 401304 memset(key_block, 0, block_size);
309
2/2
✓ Branch 1 taken 1228 times.
✓ Branch 2 taken 400076 times.
401304 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 400064 times.
✓ Branch 2 taken 12 times.
400076 if (key.length() > 0)
316 400064 memcpy(key_block, key.data(), key.length());
317 }
318
319 401304 unsigned char pad_block[block_size];
320 // Inner hash
321
1/2
✓ Branch 1 taken 401304 times.
✗ Branch 2 not taken.
401304 Any hash_inner(algorithm);
322
1/2
✓ Branch 1 taken 401304 times.
✗ Branch 2 not taken.
401304 ContextPtr context_inner(algorithm);
323 401304 context_inner.buffer = alloca(context_inner.size);
324
1/2
✓ Branch 1 taken 401304 times.
✗ Branch 2 not taken.
401304 Init(context_inner);
325
2/2
✓ Branch 0 taken 25683456 times.
✓ Branch 1 taken 401304 times.
26084760 for (unsigned i = 0; i < block_size; ++i)
326 25683456 pad_block[i] = key_block[i] ^ 0x36;
327
1/2
✓ Branch 1 taken 401304 times.
✗ Branch 2 not taken.
401304 Update(pad_block, block_size, context_inner);
328
1/2
✓ Branch 1 taken 401304 times.
✗ Branch 2 not taken.
401304 Update(buffer, buffer_size, context_inner);
329
1/2
✓ Branch 1 taken 401304 times.
✗ Branch 2 not taken.
401304 Final(context_inner, &hash_inner);
330
331 // Outer hash
332
1/2
✓ Branch 1 taken 401304 times.
✗ Branch 2 not taken.
401304 ContextPtr context_outer(algorithm);
333 401304 context_outer.buffer = alloca(context_outer.size);
334
1/2
✓ Branch 1 taken 401304 times.
✗ Branch 2 not taken.
401304 Init(context_outer);
335
2/2
✓ Branch 0 taken 25683456 times.
✓ Branch 1 taken 401304 times.
26084760 for (unsigned i = 0; i < block_size; ++i)
336 25683456 pad_block[i] = key_block[i] ^ 0x5c;
337
1/2
✓ Branch 1 taken 401304 times.
✗ Branch 2 not taken.
401304 Update(pad_block, block_size, context_outer);
338
1/2
✓ Branch 1 taken 401304 times.
✗ Branch 2 not taken.
401304 Update(hash_inner.digest, kDigestSizes[algorithm], context_outer);
339
340
1/2
✓ Branch 1 taken 401304 times.
✗ Branch 2 not taken.
401304 Final(context_outer, any_digest);
341 401304 }
342
343
344 5739 bool HashFd(int fd, Any *any_digest) {
345 5739 const Algorithms algorithm = any_digest->algorithm;
346
1/2
✓ Branch 1 taken 5739 times.
✗ Branch 2 not taken.
5739 ContextPtr context(algorithm);
347 5739 context.buffer = alloca(context.size);
348
349
1/2
✓ Branch 1 taken 5739 times.
✗ Branch 2 not taken.
5739 Init(context);
350 unsigned char io_buffer[4096];
351 int actual_bytes;
352
3/4
✓ Branch 1 taken 2480740 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2475001 times.
✓ Branch 4 taken 5739 times.
2480740 while ((actual_bytes = read(fd, io_buffer, 4096)) != 0) {
353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2475001 times.
2475001 if (actual_bytes == -1) {
354 if (errno == EINTR)
355 continue;
356 return false;
357 }
358
1/2
✓ Branch 1 taken 2475001 times.
✗ Branch 2 not taken.
2475001 Update(io_buffer, actual_bytes, context);
359 }
360
1/2
✓ Branch 1 taken 5739 times.
✗ Branch 2 not taken.
5739 Final(context, any_digest);
361 5739 return true;
362 }
363
364
365 5739 bool HashFile(const std::string &filename, Any *any_digest) {
366 5739 const int fd = open(filename.c_str(), O_RDONLY);
367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5739 times.
5739 if (fd == -1)
368 return false;
369
370 5739 const bool result = HashFd(fd, any_digest);
371 5739 close(fd);
372 5739 return result;
373 }
374
375
376 /**
377 * Fast constructor for hashing path names.
378 */
379 4937 Md5::Md5(const AsciiPtr ascii) {
380 4937 algorithm = kMd5;
381 4937 const string *str = ascii.str;
382
383 md5_ctx md5_state;
384
1/2
✓ Branch 1 taken 4937 times.
✗ Branch 2 not taken.
4937 md5_init(&md5_state);
385
1/2
✓ Branch 2 taken 4937 times.
✗ Branch 3 not taken.
4937 md5_update(&md5_state, str->length(),
386 4937 reinterpret_cast<const uint8_t *>(&(*str)[0]));
387
1/2
✓ Branch 1 taken 4937 times.
✗ Branch 2 not taken.
4937 Md5Digest(&md5_state, digest);
388 4937 }
389
390
391 1523770 Md5::Md5(const char *chars, const unsigned length) {
392 1523770 algorithm = kMd5;
393
394 md5_ctx md5_state;
395
1/2
✓ Branch 1 taken 1523770 times.
✗ Branch 2 not taken.
1523770 md5_init(&md5_state);
396
1/2
✓ Branch 1 taken 1523770 times.
✗ Branch 2 not taken.
1523770 md5_update(&md5_state, length, reinterpret_cast<const uint8_t *>(chars));
397
1/2
✓ Branch 1 taken 1523770 times.
✗ Branch 2 not taken.
1523770 Md5Digest(&md5_state, digest);
398 1523770 }
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 5785 void Md5::ToIntPair(uint64_t *lo, uint64_t *hi) const {
408 5785 memcpy(lo, digest, 8);
409 5785 memcpy(hi, digest + 8, 8);
410 5785 }
411
412
413 400064 Md5 Any::CastToMd5() {
414
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 400064 times.
400064 assert(algorithm == kMd5);
415 400064 Md5 result;
416 400064 memcpy(result.digest, digest, kDigestSizes[kMd5]);
417 400064 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