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