GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/crypto/hash.cc
Date: 2025-12-21 02:39:23
Exec Total Coverage
Lines: 275 306 89.9%
Branches: 169 268 63.1%

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 <openssl/hmac.h>
12 #include <openssl/md5.h>
13 #include <openssl/ripemd.h>
14 #include <openssl/sha.h>
15 #include <unistd.h>
16
17 #include <cstdio>
18 #include <cstring>
19
20 #include "KeccakHash.h"
21 #include "crypto/openssl_version.h"
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 const char *kAlgorithmIds[] = {"", "", "-rmd160", "-shake128", ""};
34
35
36 88 bool HexPtr::IsValid() const {
37 88 const unsigned l = str->length();
38
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 84 times.
88 if (l == 0)
39 4 return false;
40 84 const char *c = str->data(); // Walks through the string
41 84 unsigned i = 0; // String position of *c
42
43
2/2
✓ Branch 0 taken 3280 times.
✓ Branch 1 taken 20 times.
3300 for (; i < l; ++i, ++c) {
44
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 3224 times.
3280 if (*c == '-')
45 56 break;
46
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')))
47 8 return false;
48 }
49
50 // Walk through all algorithms
51
2/2
✓ Branch 0 taken 280 times.
✓ Branch 1 taken 60 times.
340 for (unsigned j = 0; j < kAny; ++j) {
52 280 const unsigned hex_length = 2 * kDigestSizes[j];
53 280 const unsigned algo_id_length = kAlgorithmIdSizes[j];
54
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 192 times.
280 if (i == hex_length) {
55 // Right suffix?
56
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) {
57
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 172 times.
212 if (*c != kAlgorithmIds[j][i - hex_length])
58 40 break;
59 }
60
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))
61 16 return true;
62 72 i = hex_length;
63 72 c = str->data() + i;
64 }
65 }
66
67 60 return false;
68 }
69
70
71 Algorithms ParseHashAlgorithm(const string &algorithm_option) {
72 if (algorithm_option == "sha1")
73 return kSha1;
74 if (algorithm_option == "rmd160")
75 return kRmd160;
76 if (algorithm_option == "shake128")
77 return kShake128;
78 return kAny;
79 }
80
81
82 223676 Any MkFromHexPtr(const HexPtr hex, const char suffix) {
83 223676 Any result;
84
85 223676 const unsigned length = hex.str->length();
86
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 223672 times.
223676 if (length == 2 * kDigestSizes[kMd5])
87 4 result = Any(kMd5, hex);
88
2/2
✓ Branch 0 taken 223416 times.
✓ Branch 1 taken 260 times.
223676 if (length == 2 * kDigestSizes[kSha1])
89 223416 result = Any(kSha1, hex);
90 // TODO(jblomer) compare -rmd160, -shake128
91
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 223666 times.
223676 if ((length == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160]))
92 10 result = Any(kRmd160, hex);
93
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 223656 times.
223676 if ((length == 2 * kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128]))
94 20 result = Any(kShake128, hex);
95
96 223676 result.suffix = suffix;
97 223676 return result;
98 }
99
100
101 /**
102 * Similar to MkFromHexPtr but the suffix is deducted from the HexPtr string.
103 */
104 40612 Any MkFromSuffixedHexPtr(const HexPtr hex) {
105 40612 Any result;
106
107 40612 const unsigned length = hex.str->length();
108
2/2
✓ Branch 0 taken 1908 times.
✓ Branch 1 taken 38704 times.
40612 if ((length == 2 * kDigestSizes[kMd5])
109
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1904 times.
1908 || (length == 2 * kDigestSizes[kMd5] + 1)) {
110 38708 const Suffix suffix = (length == 2 * kDigestSizes[kMd5] + 1)
111
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 38704 times.
38708 ? *(hex.str->rbegin())
112 38708 : kSuffixNone;
113 38708 result = Any(kMd5, hex, suffix);
114 }
115
2/2
✓ Branch 0 taken 39584 times.
✓ Branch 1 taken 1028 times.
40612 if ((length == 2 * kDigestSizes[kSha1])
116
2/2
✓ Branch 0 taken 844 times.
✓ Branch 1 taken 38740 times.
39584 || (length == 2 * kDigestSizes[kSha1] + 1)) {
117 1872 const Suffix suffix = (length == 2 * kDigestSizes[kSha1] + 1)
118
2/2
✓ Branch 0 taken 844 times.
✓ Branch 1 taken 1028 times.
1872 ? *(hex.str->rbegin())
119 1872 : kSuffixNone;
120 1872 result = Any(kSha1, hex, suffix);
121 }
122
2/2
✓ Branch 0 taken 40608 times.
✓ Branch 1 taken 4 times.
40612 if ((length == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160])
123 40608 || (length
124
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 40592 times.
40608 == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160] + 1)) {
125 const Suffix suffix = (length
126 20 == 2 * kDigestSizes[kRmd160]
127 20 + kAlgorithmIdSizes[kRmd160] + 1)
128
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 4 times.
20 ? *(hex.str->rbegin())
129 20 : kSuffixNone;
130 20 result = Any(kRmd160, hex, suffix);
131 }
132
2/2
✓ Branch 0 taken 40608 times.
✓ Branch 1 taken 4 times.
40612 if ((length == 2 * kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128])
133 40608 || (length
134
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 40604 times.
40608 == 2 * kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128] + 1)) {
135 const Suffix suffix = (length
136 8 == 2 * kDigestSizes[kShake128]
137 8 + kAlgorithmIdSizes[kShake128] + 1)
138
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 ? *(hex.str->rbegin())
139 8 : kSuffixNone;
140 8 result = Any(kShake128, hex, suffix);
141 }
142
143 40612 return result;
144 }
145
146
147 /**
148 * Allows the caller to create the context on the stack.
149 */
150 2266514 unsigned GetContextSize(const Algorithms algorithm) {
151
4/5
✓ Branch 0 taken 1213936 times.
✓ Branch 1 taken 1051587 times.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 961 times.
✗ Branch 4 not taken.
2266514 switch (algorithm) {
152 1213936 case kMd5:
153 1213936 return sizeof(MD5_CTX);
154 1051587 case kSha1:
155 1051587 return sizeof(SHA_CTX);
156 50 case kRmd160:
157 50 return sizeof(RIPEMD160_CTX);
158 961 case kShake128:
159 961 return sizeof(Keccak_HashInstance);
160 default:
161 PANIC(kLogDebug | kLogSyslogErr,
162 "tried to generate hash context for unspecified hash. Aborting...");
163 }
164 }
165
166 2266420 void Init(ContextPtr context) {
167 HashReturn keccak_result;
168
4/5
✓ Branch 0 taken 1213954 times.
✓ Branch 1 taken 1051467 times.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 961 times.
✗ Branch 4 not taken.
2266420 switch (context.algorithm) {
169 1213954 case kMd5:
170
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1213954 times.
1213954 assert(context.size == sizeof(MD5_CTX));
171 1213954 MD5_Init(reinterpret_cast<MD5_CTX *>(context.buffer));
172 1213954 break;
173 1051467 case kSha1:
174
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1051467 times.
1051467 assert(context.size == sizeof(SHA_CTX));
175 1051467 SHA1_Init(reinterpret_cast<SHA_CTX *>(context.buffer));
176 1051379 break;
177 50 case kRmd160:
178
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 assert(context.size == sizeof(RIPEMD160_CTX));
179 50 RIPEMD160_Init(reinterpret_cast<RIPEMD160_CTX *>(context.buffer));
180 50 break;
181 961 case kShake128:
182
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 961 times.
961 assert(context.size == sizeof(Keccak_HashInstance));
183 961 keccak_result = Keccak_HashInitialize_SHAKE128(
184 reinterpret_cast<Keccak_HashInstance *>(context.buffer));
185
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 961 times.
961 assert(keccak_result == SUCCESS);
186 961 break;
187 default:
188 PANIC(NULL); // Undefined hash
189 }
190 2266344 }
191
192 377007024 void Update(const unsigned char *buffer, const unsigned buffer_length,
193 ContextPtr context) {
194 HashReturn keccak_result;
195
4/5
✓ Branch 0 taken 98287712 times.
✓ Branch 1 taken 94168959 times.
✓ Branch 2 taken 92274746 times.
✓ Branch 3 taken 92275635 times.
✗ Branch 4 not taken.
377007024 switch (context.algorithm) {
196 98287712 case kMd5:
197
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98287712 times.
98287712 assert(context.size == sizeof(MD5_CTX));
198 98287712 MD5_Update(reinterpret_cast<MD5_CTX *>(context.buffer), buffer,
199 buffer_length);
200 98287712 break;
201 94168959 case kSha1:
202
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 94168959 times.
94168959 assert(context.size == sizeof(SHA_CTX));
203 94168959 SHA1_Update(reinterpret_cast<SHA_CTX *>(context.buffer), buffer,
204 buffer_length);
205 94173131 break;
206 92274746 case kRmd160:
207
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 92274746 times.
92274746 assert(context.size == sizeof(RIPEMD160_CTX));
208 92274746 RIPEMD160_Update(reinterpret_cast<RIPEMD160_CTX *>(context.buffer),
209 buffer, buffer_length);
210 92274746 break;
211 92275635 case kShake128:
212
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 92275635 times.
92275635 assert(context.size == sizeof(Keccak_HashInstance));
213 184551270 keccak_result = Keccak_HashUpdate(
214 92275635 reinterpret_cast<Keccak_HashInstance *>(context.buffer), buffer,
215 92275635 buffer_length * 8);
216
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 92275635 times.
92275635 assert(keccak_result == SUCCESS);
217 92275635 break;
218 default:
219 PANIC(NULL); // Undefined hash
220 }
221 377011224 }
222
223 2232318 void Final(ContextPtr context, Any *any_digest) {
224 HashReturn keccak_result;
225
4/5
✓ Branch 0 taken 1213930 times.
✓ Branch 1 taken 1017485 times.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 961 times.
✗ Branch 4 not taken.
2232318 switch (context.algorithm) {
226 1213930 case kMd5:
227
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1213930 times.
1213930 assert(context.size == sizeof(MD5_CTX));
228 1213930 MD5_Final(any_digest->digest,
229 1213930 reinterpret_cast<MD5_CTX *>(context.buffer));
230 1213930 break;
231 1017485 case kSha1:
232
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1017485 times.
1017485 assert(context.size == sizeof(SHA_CTX));
233 1017485 SHA1_Final(any_digest->digest,
234 1017485 reinterpret_cast<SHA_CTX *>(context.buffer));
235 1022537 break;
236 50 case kRmd160:
237
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 assert(context.size == sizeof(RIPEMD160_CTX));
238 50 RIPEMD160_Final(any_digest->digest,
239 50 reinterpret_cast<RIPEMD160_CTX *>(context.buffer));
240 50 break;
241 961 case kShake128:
242
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 961 times.
961 assert(context.size == sizeof(Keccak_HashInstance));
243 1922 keccak_result = Keccak_HashFinal(
244 961 reinterpret_cast<Keccak_HashInstance *>(context.buffer), NULL);
245
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 961 times.
961 assert(keccak_result == SUCCESS);
246 1922 keccak_result = Keccak_HashSqueeze(
247 961 reinterpret_cast<Keccak_HashInstance *>(context.buffer),
248 961 any_digest->digest, kDigestSizes[kShake128] * 8);
249 961 break;
250 default:
251 PANIC(NULL); // Undefined hash
252 }
253 2237478 any_digest->algorithm = context.algorithm;
254 2237478 }
255
256
257 14886 void HashMem(const unsigned char *buffer, const unsigned buffer_size,
258 Any *any_digest) {
259 14886 const Algorithms algorithm = any_digest->algorithm;
260
1/2
✓ Branch 1 taken 14886 times.
✗ Branch 2 not taken.
14886 ContextPtr context(algorithm);
261 14886 context.buffer = alloca(context.size);
262
263
1/2
✓ Branch 1 taken 14886 times.
✗ Branch 2 not taken.
14886 Init(context);
264
1/2
✓ Branch 1 taken 14886 times.
✗ Branch 2 not taken.
14886 Update(buffer, buffer_size, context);
265
1/2
✓ Branch 1 taken 14886 times.
✗ Branch 2 not taken.
14886 Final(context, any_digest);
266 14886 }
267
268
269 1203 void HashString(const std::string &content, Any *any_digest) {
270 1203 HashMem(reinterpret_cast<const unsigned char *>(content.data()),
271 1203 content.length(), any_digest);
272 1203 }
273
274
275 604968 void Hmac(const string &key,
276 const unsigned char *buffer,
277 const unsigned buffer_size,
278 Any *any_digest) {
279 604968 const Algorithms algorithm = any_digest->algorithm;
280
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 604968 times.
604968 assert(algorithm != kAny);
281
282 604968 const unsigned block_size = kBlockSizes[algorithm];
283 604968 unsigned char key_block[block_size];
284 604968 memset(key_block, 0, block_size);
285
2/2
✓ Branch 1 taken 4888 times.
✓ Branch 2 taken 600080 times.
604968 if (key.length() > block_size) {
286
1/2
✓ Branch 1 taken 4888 times.
✗ Branch 2 not taken.
4888 Any hash_key(algorithm);
287
1/2
✓ Branch 3 taken 4888 times.
✗ Branch 4 not taken.
4888 HashMem(reinterpret_cast<const unsigned char *>(key.data()), key.length(),
288 &hash_key);
289 4888 memcpy(key_block, hash_key.digest, kDigestSizes[algorithm]);
290 } else {
291
2/2
✓ Branch 1 taken 600068 times.
✓ Branch 2 taken 12 times.
600080 if (key.length() > 0)
292 600068 memcpy(key_block, key.data(), key.length());
293 }
294
295 604968 unsigned char pad_block[block_size];
296 // Inner hash
297
1/2
✓ Branch 1 taken 604968 times.
✗ Branch 2 not taken.
604968 Any hash_inner(algorithm);
298
1/2
✓ Branch 1 taken 604968 times.
✗ Branch 2 not taken.
604968 ContextPtr context_inner(algorithm);
299 604968 context_inner.buffer = alloca(context_inner.size);
300
1/2
✓ Branch 1 taken 604968 times.
✗ Branch 2 not taken.
604968 Init(context_inner);
301
2/2
✓ Branch 0 taken 38717952 times.
✓ Branch 1 taken 604968 times.
39322920 for (unsigned i = 0; i < block_size; ++i)
302 38717952 pad_block[i] = key_block[i] ^ 0x36;
303
1/2
✓ Branch 1 taken 604968 times.
✗ Branch 2 not taken.
604968 Update(pad_block, block_size, context_inner);
304
1/2
✓ Branch 1 taken 604968 times.
✗ Branch 2 not taken.
604968 Update(buffer, buffer_size, context_inner);
305
1/2
✓ Branch 1 taken 604968 times.
✗ Branch 2 not taken.
604968 Final(context_inner, &hash_inner);
306
307 // Outer hash
308
1/2
✓ Branch 1 taken 604968 times.
✗ Branch 2 not taken.
604968 ContextPtr context_outer(algorithm);
309 604968 context_outer.buffer = alloca(context_outer.size);
310
1/2
✓ Branch 1 taken 604968 times.
✗ Branch 2 not taken.
604968 Init(context_outer);
311
2/2
✓ Branch 0 taken 38717952 times.
✓ Branch 1 taken 604968 times.
39322920 for (unsigned i = 0; i < block_size; ++i)
312 38717952 pad_block[i] = key_block[i] ^ 0x5c;
313
1/2
✓ Branch 1 taken 604968 times.
✗ Branch 2 not taken.
604968 Update(pad_block, block_size, context_outer);
314
1/2
✓ Branch 1 taken 604968 times.
✗ Branch 2 not taken.
604968 Update(hash_inner.digest, kDigestSizes[algorithm], context_outer);
315
316
1/2
✓ Branch 1 taken 604968 times.
✗ Branch 2 not taken.
604968 Final(context_outer, any_digest);
317 604968 }
318
319
320 9086 bool HashFd(int fd, Any *any_digest) {
321 9086 const Algorithms algorithm = any_digest->algorithm;
322
1/2
✓ Branch 1 taken 9086 times.
✗ Branch 2 not taken.
9086 ContextPtr context(algorithm);
323 9086 context.buffer = alloca(context.size);
324
325
1/2
✓ Branch 1 taken 9086 times.
✗ Branch 2 not taken.
9086 Init(context);
326 unsigned char io_buffer[4096];
327 int actual_bytes;
328
3/4
✓ Branch 1 taken 3935382 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3926296 times.
✓ Branch 4 taken 9086 times.
3935382 while ((actual_bytes = read(fd, io_buffer, 4096)) != 0) {
329
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3926296 times.
3926296 if (actual_bytes == -1) {
330 if (errno == EINTR)
331 continue;
332 return false;
333 }
334
1/2
✓ Branch 1 taken 3926296 times.
✗ Branch 2 not taken.
3926296 Update(io_buffer, actual_bytes, context);
335 }
336
1/2
✓ Branch 1 taken 9086 times.
✗ Branch 2 not taken.
9086 Final(context, any_digest);
337 9086 return true;
338 }
339
340
341 9086 bool HashFile(const std::string &filename, Any *any_digest) {
342 9086 const int fd = open(filename.c_str(), O_RDONLY);
343
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9086 times.
9086 if (fd == -1)
344 return false;
345
346 9086 const bool result = HashFd(fd, any_digest);
347 9086 close(fd);
348 9086 return result;
349 }
350
351
352 /**
353 * Fast constructor for hashing path names.
354 */
355 8528 Md5::Md5(const AsciiPtr ascii) {
356 8528 algorithm = kMd5;
357 8528 const string *str = ascii.str;
358
359 MD5_CTX md5_state;
360
1/2
✓ Branch 1 taken 8528 times.
✗ Branch 2 not taken.
8528 MD5_Init(&md5_state);
361
1/2
✓ Branch 3 taken 8528 times.
✗ Branch 4 not taken.
8528 MD5_Update(&md5_state, reinterpret_cast<const unsigned char *>(&(*str)[0]),
362 str->length());
363
1/2
✓ Branch 1 taken 8528 times.
✗ Branch 2 not taken.
8528 MD5_Final(digest, &md5_state);
364 8528 }
365
366
367 5962605 Md5::Md5(const char *chars, const unsigned length) {
368 5962605 algorithm = kMd5;
369
370 MD5_CTX md5_state;
371
1/2
✓ Branch 1 taken 5962605 times.
✗ Branch 2 not taken.
5962605 MD5_Init(&md5_state);
372
1/2
✓ Branch 1 taken 5962605 times.
✗ Branch 2 not taken.
5962605 MD5_Update(&md5_state, reinterpret_cast<const unsigned char *>(chars),
373 length);
374
1/2
✓ Branch 1 taken 5962605 times.
✗ Branch 2 not taken.
5962605 MD5_Final(digest, &md5_state);
375 5962605 }
376
377
378 Md5::Md5(const uint64_t lo, const uint64_t hi) {
379 algorithm = kMd5;
380 memcpy(digest, &lo, 8);
381 memcpy(digest + 8, &hi, 8);
382 }
383
384 10599 void Md5::ToIntPair(uint64_t *lo, uint64_t *hi) const {
385 10599 memcpy(lo, digest, 8);
386 10599 memcpy(hi, digest + 8, 8);
387 10599 }
388
389
390 600092 Md5 Any::CastToMd5() {
391
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 600092 times.
600092 assert(algorithm == kMd5);
392 600092 Md5 result;
393 600092 memcpy(result.digest, digest, kDigestSizes[kMd5]);
394 600092 return result;
395 }
396
397 #ifndef OPENSSL_API_INTERFACE_V09
398 24 static string HexFromSha256(unsigned char digest[SHA256_DIGEST_LENGTH]) {
399 24 string result;
400
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 result.reserve(2 * SHA256_DIGEST_LENGTH);
401
2/2
✓ Branch 0 taken 768 times.
✓ Branch 1 taken 24 times.
792 for (unsigned i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
402 768 const char d1 = digest[i] / 16;
403 768 const char d2 = digest[i] % 16;
404
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));
405
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));
406 }
407 24 return result;
408 }
409 #endif
410
411 4 string Sha256File(const string &filename) {
412 #ifdef OPENSSL_API_INTERFACE_V09
413 PANIC(NULL);
414 #else
415
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 const int fd = open(filename.c_str(), O_RDONLY);
416
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (fd < 0)
417 return "";
418
419 SHA256_CTX ctx;
420
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 SHA256_Init(&ctx);
421
422 unsigned char io_buffer[4096];
423 int actual_bytes;
424
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) {
425 if (actual_bytes == -1) {
426 if (errno == EINTR)
427 continue;
428 close(fd);
429 return "";
430 }
431 SHA256_Update(&ctx, io_buffer, actual_bytes);
432 }
433
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 close(fd);
434
435 unsigned char digest[SHA256_DIGEST_LENGTH];
436
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 SHA256_Final(digest, &ctx);
437
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 return HexFromSha256(digest);
438 #endif
439 }
440
441 8 string Sha256Mem(const unsigned char *buffer, const unsigned buffer_size) {
442 #ifdef OPENSSL_API_INTERFACE_V09
443 PANIC(NULL);
444 #else
445 unsigned char digest[SHA256_DIGEST_LENGTH];
446
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 SHA256(buffer, buffer_size, digest);
447
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
16 return HexFromSha256(digest);
448 #endif
449 }
450
451 4 string Sha256String(const string &content) {
452 4 return Sha256Mem(reinterpret_cast<const unsigned char *>(content.data()),
453 4 content.length());
454 }
455
456
457 28 std::string Hmac256(const std::string &key,
458 const std::string &content,
459 bool raw_output) {
460 #ifdef OPENSSL_API_INTERFACE_V09
461 PANIC(NULL);
462 #else
463 unsigned char digest[SHA256_DIGEST_LENGTH];
464 28 const unsigned block_size = 64;
465 28 const unsigned key_length = key.length();
466 unsigned char key_block[block_size];
467 28 memset(key_block, 0, block_size);
468
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 24 times.
28 if (key_length > block_size) {
469
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 SHA256(reinterpret_cast<const unsigned char *>(key.data()), key_length,
470 key_block);
471 } else {
472
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 if (key.length() > 0)
473 24 memcpy(key_block, key.data(), key_length);
474 }
475
476 unsigned char pad_block[block_size];
477 // Inner hash
478 SHA256_CTX ctx_inner;
479 unsigned char digest_inner[SHA256_DIGEST_LENGTH];
480
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 SHA256_Init(&ctx_inner);
481
2/2
✓ Branch 0 taken 1792 times.
✓ Branch 1 taken 28 times.
1820 for (unsigned i = 0; i < block_size; ++i)
482 1792 pad_block[i] = key_block[i] ^ 0x36;
483
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 SHA256_Update(&ctx_inner, pad_block, block_size);
484
1/2
✓ Branch 3 taken 28 times.
✗ Branch 4 not taken.
28 SHA256_Update(&ctx_inner, content.data(), content.length());
485
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 SHA256_Final(digest_inner, &ctx_inner);
486
487 // Outer hash
488 SHA256_CTX ctx_outer;
489
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 SHA256_Init(&ctx_outer);
490
2/2
✓ Branch 0 taken 1792 times.
✓ Branch 1 taken 28 times.
1820 for (unsigned i = 0; i < block_size; ++i)
491 1792 pad_block[i] = key_block[i] ^ 0x5c;
492
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 SHA256_Update(&ctx_outer, pad_block, block_size);
493
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 SHA256_Update(&ctx_outer, digest_inner, SHA256_DIGEST_LENGTH);
494
495
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 SHA256_Final(digest, &ctx_outer);
496
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 12 times.
28 if (raw_output)
497
1/2
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
16 return string(reinterpret_cast<const char *>(digest), SHA256_DIGEST_LENGTH);
498
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 return HexFromSha256(digest);
499 #endif
500 }
501
502 } // namespace shash
503
504 #ifdef CVMFS_NAMESPACE_GUARD
505 } // namespace CVMFS_NAMESPACE_GUARD
506 #endif
507