GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/hash.cc Lines: 240 268 89.6 %
Date: 2019-02-03 02:48:13 Branches: 129 178 72.5 %

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