GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/crypto/hash.cc
Date: 2024-04-28 02:33:07
Exec Total Coverage
Lines: 267 298 89.6%
Branches: 169 268 63.1%

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