CernVM-FS  2.13.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
hash.cc
Go to the documentation of this file.
1 
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 bool HexPtr::IsValid() const {
37  const unsigned l = str->length();
38  if (l == 0)
39  return false;
40  const char *c = str->data(); // Walks through the string
41  unsigned i = 0; // String position of *c
42 
43  for (; i < l; ++i, ++c) {
44  if (*c == '-')
45  break;
46  if ((*c < '0') || (*c > 'f') || ((*c > '9') && (*c < 'a')))
47  return false;
48  }
49 
50  // Walk through all algorithms
51  for (unsigned j = 0; j < kAny; ++j) {
52  const unsigned hex_length = 2 * kDigestSizes[j];
53  const unsigned algo_id_length = kAlgorithmIdSizes[j];
54  if (i == hex_length) {
55  // Right suffix?
56  for (; (i < l) && (i - hex_length < algo_id_length); ++i, ++c) {
57  if (*c != kAlgorithmIds[j][i - hex_length])
58  break;
59  }
60  if ((i == l) && (l == hex_length + algo_id_length))
61  return true;
62  i = hex_length;
63  c = str->data() + i;
64  }
65  }
66 
67  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 Any MkFromHexPtr(const HexPtr hex, const char suffix) {
83  Any result;
84 
85  const unsigned length = hex.str->length();
86  if (length == 2 * kDigestSizes[kMd5])
87  result = Any(kMd5, hex);
88  if (length == 2 * kDigestSizes[kSha1])
89  result = Any(kSha1, hex);
90  // TODO(jblomer) compare -rmd160, -shake128
91  if ((length == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160]))
92  result = Any(kRmd160, hex);
93  if ((length == 2 * kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128]))
94  result = Any(kShake128, hex);
95 
96  result.suffix = suffix;
97  return result;
98 }
99 
100 
105  Any result;
106 
107  const unsigned length = hex.str->length();
108  if ((length == 2 * kDigestSizes[kMd5])
109  || (length == 2 * kDigestSizes[kMd5] + 1)) {
110  Suffix suffix = (length == 2 * kDigestSizes[kMd5] + 1)
111  ? *(hex.str->rbegin())
112  : kSuffixNone;
113  result = Any(kMd5, hex, suffix);
114  }
115  if ((length == 2 * kDigestSizes[kSha1])
116  || (length == 2 * kDigestSizes[kSha1] + 1)) {
117  Suffix suffix = (length == 2 * kDigestSizes[kSha1] + 1)
118  ? *(hex.str->rbegin())
119  : kSuffixNone;
120  result = Any(kSha1, hex, suffix);
121  }
122  if ((length == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160])
123  || (length
124  == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160] + 1)) {
125  Suffix suffix = (length
127  + 1)
128  ? *(hex.str->rbegin())
129  : kSuffixNone;
130  result = Any(kRmd160, hex, suffix);
131  }
132  if ((length == 2 * kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128])
133  || (length
134  == 2 * kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128] + 1)) {
135  Suffix suffix = (length
136  == 2 * kDigestSizes[kShake128]
138  ? *(hex.str->rbegin())
139  : kSuffixNone;
140  result = Any(kShake128, hex, suffix);
141  }
142 
143  return result;
144 }
145 
146 
151  switch (algorithm) {
152  case kMd5:
153  return sizeof(MD5_CTX);
154  case kSha1:
155  return sizeof(SHA_CTX);
156  case kRmd160:
157  return sizeof(RIPEMD160_CTX);
158  case kShake128:
159  return sizeof(Keccak_HashInstance);
160  default:
162  "tried to generate hash context for unspecified hash. Aborting...");
163  }
164 }
165 
166 void Init(ContextPtr context) {
167  HashReturn keccak_result;
168  switch (context.algorithm) {
169  case kMd5:
170  assert(context.size == sizeof(MD5_CTX));
171  MD5_Init(reinterpret_cast<MD5_CTX *>(context.buffer));
172  break;
173  case kSha1:
174  assert(context.size == sizeof(SHA_CTX));
175  SHA1_Init(reinterpret_cast<SHA_CTX *>(context.buffer));
176  break;
177  case kRmd160:
178  assert(context.size == sizeof(RIPEMD160_CTX));
179  RIPEMD160_Init(reinterpret_cast<RIPEMD160_CTX *>(context.buffer));
180  break;
181  case kShake128:
182  assert(context.size == sizeof(Keccak_HashInstance));
183  keccak_result = Keccak_HashInitialize_SHAKE128(
184  reinterpret_cast<Keccak_HashInstance *>(context.buffer));
185  assert(keccak_result == SUCCESS);
186  break;
187  default:
188  PANIC(NULL); // Undefined hash
189  }
190 }
191 
192 void Update(const unsigned char *buffer, const unsigned buffer_length,
193  ContextPtr context) {
194  HashReturn keccak_result;
195  switch (context.algorithm) {
196  case kMd5:
197  assert(context.size == sizeof(MD5_CTX));
198  MD5_Update(reinterpret_cast<MD5_CTX *>(context.buffer), buffer,
199  buffer_length);
200  break;
201  case kSha1:
202  assert(context.size == sizeof(SHA_CTX));
203  SHA1_Update(reinterpret_cast<SHA_CTX *>(context.buffer), buffer,
204  buffer_length);
205  break;
206  case kRmd160:
207  assert(context.size == sizeof(RIPEMD160_CTX));
208  RIPEMD160_Update(reinterpret_cast<RIPEMD160_CTX *>(context.buffer),
209  buffer, buffer_length);
210  break;
211  case kShake128:
212  assert(context.size == sizeof(Keccak_HashInstance));
213  keccak_result = Keccak_HashUpdate(
214  reinterpret_cast<Keccak_HashInstance *>(context.buffer), buffer,
215  buffer_length * 8);
216  assert(keccak_result == SUCCESS);
217  break;
218  default:
219  PANIC(NULL); // Undefined hash
220  }
221 }
222 
223 void Final(ContextPtr context, Any *any_digest) {
224  HashReturn keccak_result;
225  switch (context.algorithm) {
226  case kMd5:
227  assert(context.size == sizeof(MD5_CTX));
228  MD5_Final(any_digest->digest,
229  reinterpret_cast<MD5_CTX *>(context.buffer));
230  break;
231  case kSha1:
232  assert(context.size == sizeof(SHA_CTX));
233  SHA1_Final(any_digest->digest,
234  reinterpret_cast<SHA_CTX *>(context.buffer));
235  break;
236  case kRmd160:
237  assert(context.size == sizeof(RIPEMD160_CTX));
238  RIPEMD160_Final(any_digest->digest,
239  reinterpret_cast<RIPEMD160_CTX *>(context.buffer));
240  break;
241  case kShake128:
242  assert(context.size == sizeof(Keccak_HashInstance));
243  keccak_result = Keccak_HashFinal(
244  reinterpret_cast<Keccak_HashInstance *>(context.buffer), NULL);
245  assert(keccak_result == SUCCESS);
246  keccak_result = Keccak_HashSqueeze(
247  reinterpret_cast<Keccak_HashInstance *>(context.buffer),
248  any_digest->digest, kDigestSizes[kShake128] * 8);
249  break;
250  default:
251  PANIC(NULL); // Undefined hash
252  }
253  any_digest->algorithm = context.algorithm;
254 }
255 
256 
257 void HashMem(const unsigned char *buffer, const unsigned buffer_size,
258  Any *any_digest) {
259  Algorithms algorithm = any_digest->algorithm;
260  ContextPtr context(algorithm);
261  context.buffer = alloca(context.size);
262 
263  Init(context);
264  Update(buffer, buffer_size, context);
265  Final(context, any_digest);
266 }
267 
268 
269 void HashString(const std::string &content, Any *any_digest) {
270  HashMem(reinterpret_cast<const unsigned char *>(content.data()),
271  content.length(), any_digest);
272 }
273 
274 
275 void Hmac(const string &key,
276  const unsigned char *buffer,
277  const unsigned buffer_size,
278  Any *any_digest) {
279  Algorithms algorithm = any_digest->algorithm;
280  assert(algorithm != kAny);
281 
282  const unsigned block_size = kBlockSizes[algorithm];
283  unsigned char key_block[block_size];
284  memset(key_block, 0, block_size);
285  if (key.length() > block_size) {
286  Any hash_key(algorithm);
287  HashMem(reinterpret_cast<const unsigned char *>(key.data()), key.length(),
288  &hash_key);
289  memcpy(key_block, hash_key.digest, kDigestSizes[algorithm]);
290  } else {
291  if (key.length() > 0)
292  memcpy(key_block, key.data(), key.length());
293  }
294 
295  unsigned char pad_block[block_size];
296  // Inner hash
297  Any hash_inner(algorithm);
298  ContextPtr context_inner(algorithm);
299  context_inner.buffer = alloca(context_inner.size);
300  Init(context_inner);
301  for (unsigned i = 0; i < block_size; ++i)
302  pad_block[i] = key_block[i] ^ 0x36;
303  Update(pad_block, block_size, context_inner);
304  Update(buffer, buffer_size, context_inner);
305  Final(context_inner, &hash_inner);
306 
307  // Outer hash
308  ContextPtr context_outer(algorithm);
309  context_outer.buffer = alloca(context_outer.size);
310  Init(context_outer);
311  for (unsigned i = 0; i < block_size; ++i)
312  pad_block[i] = key_block[i] ^ 0x5c;
313  Update(pad_block, block_size, context_outer);
314  Update(hash_inner.digest, kDigestSizes[algorithm], context_outer);
315 
316  Final(context_outer, any_digest);
317 }
318 
319 
320 bool HashFd(int fd, Any *any_digest) {
321  Algorithms algorithm = any_digest->algorithm;
322  ContextPtr context(algorithm);
323  context.buffer = alloca(context.size);
324 
325  Init(context);
326  unsigned char io_buffer[4096];
327  int actual_bytes;
328  while ((actual_bytes = read(fd, io_buffer, 4096)) != 0) {
329  if (actual_bytes == -1) {
330  if (errno == EINTR)
331  continue;
332  return false;
333  }
334  Update(io_buffer, actual_bytes, context);
335  }
336  Final(context, any_digest);
337  return true;
338 }
339 
340 
341 bool HashFile(const std::string &filename, Any *any_digest) {
342  int fd = open(filename.c_str(), O_RDONLY);
343  if (fd == -1)
344  return false;
345 
346  bool result = HashFd(fd, any_digest);
347  close(fd);
348  return result;
349 }
350 
351 
355 Md5::Md5(const AsciiPtr ascii) {
356  algorithm = kMd5;
357  const string *str = ascii.str;
358 
359  MD5_CTX md5_state;
360  MD5_Init(&md5_state);
361  MD5_Update(&md5_state, reinterpret_cast<const unsigned char *>(&(*str)[0]),
362  str->length());
363  MD5_Final(digest, &md5_state);
364 }
365 
366 
367 Md5::Md5(const char *chars, const unsigned length) {
368  algorithm = kMd5;
369 
370  MD5_CTX md5_state;
371  MD5_Init(&md5_state);
372  MD5_Update(&md5_state, reinterpret_cast<const unsigned char *>(chars),
373  length);
374  MD5_Final(digest, &md5_state);
375 }
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 void Md5::ToIntPair(uint64_t *lo, uint64_t *hi) const {
385  memcpy(lo, digest, 8);
386  memcpy(hi, digest + 8, 8);
387 }
388 
389 
390 Md5 Any::CastToMd5() {
391  assert(algorithm == kMd5);
392  Md5 result;
393  memcpy(result.digest, digest, kDigestSizes[kMd5]);
394  return result;
395 }
396 
397 #ifndef OPENSSL_API_INTERFACE_V09
398 static string HexFromSha256(unsigned char digest[SHA256_DIGEST_LENGTH]) {
399  string result;
400  result.reserve(2 * SHA256_DIGEST_LENGTH);
401  for (unsigned i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
402  const char d1 = digest[i] / 16;
403  const char d2 = digest[i] % 16;
404  result.push_back(d1 + ((d1 <= 9) ? '0' : 'a' - 10));
405  result.push_back(d2 + ((d2 <= 9) ? '0' : 'a' - 10));
406  }
407  return result;
408 }
409 #endif
410 
411 string Sha256File(const string &filename) {
412 #ifdef OPENSSL_API_INTERFACE_V09
413  PANIC(NULL);
414 #else
415  int fd = open(filename.c_str(), O_RDONLY);
416  if (fd < 0)
417  return "";
418 
419  SHA256_CTX ctx;
420  SHA256_Init(&ctx);
421 
422  unsigned char io_buffer[4096];
423  int actual_bytes;
424  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  close(fd);
434 
435  unsigned char digest[SHA256_DIGEST_LENGTH];
436  SHA256_Final(digest, &ctx);
437  return HexFromSha256(digest);
438 #endif
439 }
440 
441 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  SHA256(buffer, buffer_size, digest);
447  return HexFromSha256(digest);
448 #endif
449 }
450 
451 string Sha256String(const string &content) {
452  return Sha256Mem(reinterpret_cast<const unsigned char *>(content.data()),
453  content.length());
454 }
455 
456 
457 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  const unsigned block_size = 64;
465  const unsigned key_length = key.length();
466  unsigned char key_block[block_size];
467  memset(key_block, 0, block_size);
468  if (key_length > block_size) {
469  SHA256(reinterpret_cast<const unsigned char *>(key.data()), key_length,
470  key_block);
471  } else {
472  if (key.length() > 0)
473  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  SHA256_Init(&ctx_inner);
481  for (unsigned i = 0; i < block_size; ++i)
482  pad_block[i] = key_block[i] ^ 0x36;
483  SHA256_Update(&ctx_inner, pad_block, block_size);
484  SHA256_Update(&ctx_inner, content.data(), content.length());
485  SHA256_Final(digest_inner, &ctx_inner);
486 
487  // Outer hash
488  SHA256_CTX ctx_outer;
489  SHA256_Init(&ctx_outer);
490  for (unsigned i = 0; i < block_size; ++i)
491  pad_block[i] = key_block[i] ^ 0x5c;
492  SHA256_Update(&ctx_outer, pad_block, block_size);
493  SHA256_Update(&ctx_outer, digest_inner, SHA256_DIGEST_LENGTH);
494 
495  SHA256_Final(digest, &ctx_outer);
496  if (raw_output)
497  return string(reinterpret_cast<const char *>(digest), SHA256_DIGEST_LENGTH);
498  return HexFromSha256(digest);
499 #endif
500 }
501 
502 } // namespace shash
503 
504 #ifdef CVMFS_NAMESPACE_GUARD
505 } // namespace CVMFS_NAMESPACE_GUARD
506 #endif
void HashString(const std::string &content, Any *any_digest)
Definition: hash.cc:269
const char kSuffixNone
Definition: compat.h:162
struct cvmcache_context * ctx
const std::string * str
Definition: hash.h:101
bool HashFile(const std::string &filename, Any *any_digest)
Definition: hash.cc:341
string Sha256String(const string &content)
Definition: hash.cc:451
#define PANIC(...)
Definition: exception.h:29
const unsigned kAlgorithmIdSizes[]
Definition: compat.h:159
void Hmac(const string &key, const unsigned char *buffer, const unsigned buffer_size, Any *any_digest)
Definition: hash.cc:275
assert((mem||(size==0))&&"Out Of Memory")
string Sha256File(const string &filename)
Definition: hash.cc:411
static string HexFromSha256(unsigned char digest[SHA256_DIGEST_LENGTH])
Definition: hash.cc:398
Algorithms algorithm
Definition: hash.h:122
unsigned char digest[digest_size_]
Definition: hash.h:121
char algorithm
Algorithms
Definition: hash.h:41
const unsigned kBlockSizes[]
Definition: hash.h:93
const unsigned kDigestSizes[]
Definition: compat.h:37
const std::string * str
Definition: hash.h:107
string Sha256Mem(const unsigned char *buffer, const unsigned buffer_size)
Definition: hash.cc:441
Algorithms algorithm
Definition: hash.h:488
unsigned char digest[20]
static int Init(const loader::LoaderExports *loader_exports)
Definition: cvmfs.cc:2309
void Final(ContextPtr context, Any *any_digest)
Definition: hash.cc:223
void * buffer
Definition: hash.h:489
const char * kAlgorithmIds[]
Definition: hash.cc:33
char Suffix
Definition: hash.h:111
void HashMem(const unsigned char *buffer, const unsigned buffer_size, Any *any_digest)
Definition: hash.cc:257
unsigned GetContextSize(const Algorithms algorithm)
Definition: hash.cc:150
void Update(const unsigned char *buffer, const unsigned buffer_length, ContextPtr context)
Definition: hash.cc:192
Any MkFromSuffixedHexPtr(const HexPtr hex)
Definition: hash.cc:104
Algorithms ParseHashAlgorithm(const string &algorithm_option)
Definition: hash.cc:71
bool HashFd(int fd, Any *any_digest)
Definition: hash.cc:320
Any MkFromHexPtr(const HexPtr hex, const char suffix)
Definition: hash.cc:82
std::string Hmac256(const std::string &key, const std::string &content, bool raw_output)
Definition: hash.cc:457
Suffix suffix
Definition: hash.h:123
unsigned size
Definition: hash.h:490