cfengine  3.15.4
About: CFEngine is a configuration management system for configuring and maintaining Unix-like computers (using an own high level policy language). Community version.
  Fossies Dox: cfengine-3.15.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

hash.c
Go to the documentation of this file.
1 /*
2  Copyright 2020 Northern.tech AS
3 
4  This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5 
6  This program is free software; you can redistribute it and/or modify it
7  under the terms of the GNU General Public License as published by the
8  Free Software Foundation; version 3.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18 
19  To the extent this program is licensed as part of the Enterprise
20  versions of CFEngine, the applicable Commercial Open Source License
21  (COSL) may apply to this file if you as a licensee so wish it. See
22  included file COSL.txt.
23 */
24 
25 #include <platform.h>
26 
27 #include <openssl/evp.h> /* EVP_* */
28 #include <openssl/bn.h> /* BN_bn2bin */
29 #include <libcrypto-compat.h>
30 
31 #include <alloc.h>
32 #include <logging.h>
33 #include <hash.h>
34 #include <misc_lib.h>
35 #include <file_lib.h>
36 #include <string_lib.h>
37 
38 
39 static const char *const CF_DIGEST_TYPES[10] =
40 {
41  "md5",
42  "sha224",
43  "sha256",
44  "sha384",
45  "sha512",
46  "sha1",
47  "sha",
48  "best",
49  "crypt",
50  NULL
51 };
52 
53 static const int CF_DIGEST_SIZES[10] =
54 {
55  CF_MD5_LEN,
61  CF_SHA_LEN,
65 };
66 
67 struct Hash {
68  unsigned char digest[EVP_MAX_MD_SIZE];
69  char printable[EVP_MAX_MD_SIZE * 4];
72 };
73 
74 /*
75  * These methods are not exported through the public API.
76  * These are internal methods used by the constructors of a
77  * Hash object. Do not export them since they have very little
78  * meaning outside of the constructors.
79  */
81 {
82  Hash *hash = xcalloc (1, sizeof(Hash));
83  hash->size = CF_DIGEST_SIZES[method];
84  hash->method = method;
85  return hash;
86 }
87 
89 {
90  switch (hash->method)
91  {
92  case HASH_METHOD_MD5:
93  strcpy(hash->printable, "MD5=");
94  break;
95  case HASH_METHOD_SHA224:
96  case HASH_METHOD_SHA256:
97  case HASH_METHOD_SHA384:
98  case HASH_METHOD_SHA512:
99  case HASH_METHOD_SHA:
100  case HASH_METHOD_SHA1:
101  strcpy(hash->printable, "SHA=");
102  break;
103  default:
104  strcpy(hash->printable, "UNK=");
105  break;
106  }
107 
108  unsigned int i;
109  for (i = 0; i < hash->size; i++)
110  {
111  snprintf(hash->printable + 4 + 2 * i,
112  sizeof(hash->printable) - (4 + 2 * i), "%02x",
113  hash->digest[i]);
114  }
115  hash->printable[4 + 2 * hash->size] = '\0';
116 }
117 
118 /*
119  * Constructors
120  * All constructors call two common methods: HashBasicInit(...) and HashCalculatePrintableRepresentation(...).
121  * Each constructor reads the data to create the Hash from different sources so after the basic
122  * initialization and up to the point where the hash is computed, each follows its own path.
123  */
124 Hash *HashNew(const char *data, const unsigned int length, HashMethod method)
125 {
126  if (!data || (length == 0))
127  {
128  return NULL;
129  }
130  if (method >= HASH_METHOD_NONE)
131  {
132  return NULL;
133  }
134  /*
135  * OpenSSL documentation marked EVP_DigestInit and EVP_DigestFinal functions as deprecated and
136  * recommends moving to EVP_DigestInit_ex and EVP_DigestFinal_ex.
137  */
138  const EVP_MD *md = NULL;
139  md = EVP_get_digestbyname(CF_DIGEST_TYPES[method]);
140  if (md == NULL)
141  {
142  Log(LOG_LEVEL_INFO, "Digest type %s not supported by OpenSSL library", CF_DIGEST_TYPES[method]);
143  return NULL;
144  }
145 
146  EVP_MD_CTX *const context = EVP_MD_CTX_create();
147  if (context == NULL)
148  {
149  Log(LOG_LEVEL_ERR, "Could not allocate openssl hash context");
150  return NULL;
151  }
152  Hash *hash = HashBasicInit(method);
153  EVP_DigestInit_ex(context, md, NULL);
154  EVP_DigestUpdate(context, data, (size_t) length);
155  unsigned int digest_length;
156  EVP_DigestFinal_ex(context, hash->digest, &digest_length);
157  EVP_MD_CTX_destroy(context);
158  /* Update the printable representation */
160 
161  return hash;
162 }
163 
164 Hash *HashNewFromDescriptor(const int descriptor, HashMethod method)
165 {
166  if (descriptor < 0)
167  {
168  return NULL;
169  }
170  if (method >= HASH_METHOD_NONE)
171  {
172  return NULL;
173  }
174 
175  const EVP_MD *const md = HashDigestFromId(method);
176  if (md == NULL)
177  {
178  Log(LOG_LEVEL_INFO, "Digest (type=%d) not supported by OpenSSL library", method);
179  return NULL;
180  }
181  EVP_MD_CTX *const context = EVP_MD_CTX_create();
182  if (context == NULL)
183  {
184  Log(LOG_LEVEL_ERR, "Could not allocate openssl hash context");
185  return NULL;
186  }
187 
188  if (EVP_DigestInit_ex(context, md, NULL) != 1)
189  {
190  Log(LOG_LEVEL_ERR, "Could not initialize openssl hash context");
191  EVP_MD_CTX_destroy(context);
192  return NULL;
193  }
194 
195  ssize_t read_count = 0;
196  char buffer[1024];
197  do
198  {
199  read_count = read(descriptor, buffer, 1024);
200  EVP_DigestUpdate(context, buffer, (size_t) read_count);
201  } while (read_count > 0);
202 
203  Hash *const hash = HashBasicInit(method); // xcalloc, cannot be NULL
204  unsigned int md_len;
205  EVP_DigestFinal_ex(context, hash->digest, &md_len);
206 
207  /* Update the printable representation */
209 
210  EVP_MD_CTX_destroy(context);
211  return hash;
212 }
213 
214 Hash *HashNewFromKey(const RSA *rsa, HashMethod method)
215 {
216  if (rsa == NULL)
217  {
218  return NULL;
219  }
220  if (method >= HASH_METHOD_NONE)
221  {
222  return NULL;
223  }
224 
225  const BIGNUM *n, *e;
226  RSA_get0_key(rsa, &n, &e, NULL);
227 
228  size_t n_len = (n == NULL) ? 0 : (size_t) BN_num_bytes(n);
229  size_t e_len = (e == NULL) ? 0 : (size_t) BN_num_bytes(e);
230  size_t buf_len = MAX(n_len, e_len);
231 
232  if (buf_len <= 0)
233  {
234  // Should never happen
235  Log(LOG_LEVEL_ERR, "Invalid RSA key, internal OpenSSL related error");
236  return NULL;
237  }
238 
239  const EVP_MD *md = EVP_get_digestbyname(CF_DIGEST_TYPES[method]);
240  if (md == NULL)
241  {
242  Log(LOG_LEVEL_INFO, "Digest type %s not supported by OpenSSL library", CF_DIGEST_TYPES[method]);
243  return NULL;
244  }
245 
246  EVP_MD_CTX *context = EVP_MD_CTX_new();
247  if (context == NULL)
248  {
249  Log(LOG_LEVEL_ERR, "Failed to allocate openssl hashing context");
250  return NULL;
251  }
252 
253  if (EVP_DigestInit_ex(context, md, NULL) != 1)
254  {
255  EVP_MD_CTX_free(context);
256  return NULL;
257  }
258 
259  unsigned char buffer[buf_len];
260  int actlen;
261 
262  actlen = BN_bn2bin(n, buffer);
263  CF_ASSERT(actlen <= buf_len, "Buffer overflow n, %d > %zu!",
264  actlen, buf_len);
265  EVP_DigestUpdate(context, buffer, actlen);
266 
267  actlen = BN_bn2bin(e, buffer);
268  CF_ASSERT(actlen <= buf_len, "Buffer overflow e, %d > %zu!",
269  actlen, buf_len);
270  EVP_DigestUpdate(context, buffer, actlen);
271 
272  Hash *hash = HashBasicInit(method);
273  unsigned int digest_length;
274  EVP_DigestFinal_ex(context, hash->digest, &digest_length);
275 
276  EVP_MD_CTX_free(context);
277 
278  /* Update the printable representation */
279  HashCalculatePrintableRepresentation(hash);
280 
281  return hash;
282 }
283 
284 void HashDestroy(Hash **hash)
285 {
286  if (!hash || !*hash)
287  {
288  return;
289  }
290  free (*hash);
291  *hash = NULL;
292 }
293 
294 int HashCopy(Hash *origin, Hash **destination)
295 {
296  if (!origin || !destination)
297  {
298  return -1;
299  }
300  *destination = xmalloc(sizeof(Hash));
301  memcpy((*destination)->digest, origin->digest, origin->size);
302  strlcpy((*destination)->printable, origin->printable, (EVP_MAX_MD_SIZE * 4));
303  (*destination)->method = origin->method;
304  (*destination)->size = origin->size;
305  return 0;
306 }
307 
308 bool HashEqual(const Hash *a, const Hash *b)
309 {
310  if (!a && !b)
311  {
312  return true;
313  }
314  if (!a && b)
315  {
316  return false;
317  }
318  if (a && !b)
319  {
320  return false;
321  }
322  if (a->method != b->method)
323  {
324  return false;
325  }
326  int i = 0;
327  for (i = 0; i < a->size; ++i)
328  {
329  if (a->digest[i] != b->digest[i])
330  {
331  return false;
332  }
333  }
334  return true;
335 }
336 
337 const unsigned char *HashData(const Hash *hash, unsigned int *length)
338 {
339  if (!hash || !length)
340  {
341  return NULL;
342  }
343  *length = hash->size;
344  return hash->digest;
345 }
346 
347 const char *HashPrintable(const Hash *hash)
348 {
349  return hash ? hash->printable : NULL;
350 }
351 
352 HashMethod HashType(const Hash *hash)
353 {
354  return hash ? hash->method : HASH_METHOD_NONE;
355 }
356 
357 HashSize HashLength(const Hash *hash)
358 {
359  return hash ? hash->size : CF_NO_HASH;
360 }
361 
362 /* Class methods */
363 HashMethod HashIdFromName(const char *hash_name)
364 {
365  int i;
366  for (i = 0; CF_DIGEST_TYPES[i] != NULL; i++)
367  {
368  if (hash_name && (strcmp(hash_name, CF_DIGEST_TYPES[i]) == 0))
369  {
370  return (HashMethod) i;
371  }
372  }
373 
374  return HASH_METHOD_NONE;
375 }
376 
377 const char *HashNameFromId(HashMethod hash_id)
378 {
379  assert(hash_id >= 0);
380  return (hash_id >= HASH_METHOD_NONE) ? NULL : CF_DIGEST_TYPES[hash_id];
381 }
382 
383 const EVP_MD *HashDigestFromId(HashMethod type)
384 {
385  const char *const name = HashNameFromId(type);
386  if (name == NULL)
387  {
388  return NULL;
389  }
390  return EVP_get_digestbyname(name);
391 }
392 
393 
394 HashSize HashSizeFromId(HashMethod hash_id)
395 {
396  assert(hash_id >= 0);
397  return (hash_id >= HASH_METHOD_NONE) ? CF_NO_HASH : CF_DIGEST_SIZES[hash_id];
398 }
399 
400 static void HashFile_Stream(
401  FILE *const file,
402  unsigned char digest[EVP_MAX_MD_SIZE + 1],
403  const HashMethod type)
404 {
405  assert(file != NULL);
406  const EVP_MD *const md = HashDigestFromId(type);
407  if (md == NULL)
408  {
409  Log(LOG_LEVEL_ERR,
410  "Could not determine function for file hashing (type=%d)",
411  (int) type);
412  return;
413  }
414 
415  EVP_MD_CTX *const context = EVP_MD_CTX_new();
416  if (context == NULL)
417  {
418  Log(LOG_LEVEL_ERR, "Failed to allocate openssl hashing context");
419  return;
420  }
421 
422  if (EVP_DigestInit(context, md) == 1)
423  {
424  unsigned char buffer[1024];
425  size_t len;
426  while ((len = fread(buffer, 1, 1024, file)))
427  {
428  EVP_DigestUpdate(context, buffer, len);
429  }
430 
431  unsigned int digest_length;
432  EVP_DigestFinal(context, digest, &digest_length);
433  }
434 
435  EVP_MD_CTX_free(context);
436 }
437 
438 /**
439  * @param text_mode whether to read the file in text mode or not (binary mode)
440  * @note Reading/writing file in text mode on Windows changes Unix newlines
441  * into Windows newlines.
442  */
443 void HashFile(
444  const char *const filename,
445  unsigned char digest[EVP_MAX_MD_SIZE + 1],
446  HashMethod type,
447  bool text_mode)
448 {
449  assert(filename != NULL);
450  assert(digest != NULL);
451 
452  memset(digest, 0, EVP_MAX_MD_SIZE + 1);
453 
454  FILE *file = NULL;
455  if (text_mode)
456  {
457  file = safe_fopen(filename, "rt");
458  }
459  else
460  {
461  file = safe_fopen(filename, "rb");
462  }
463  if (file == NULL)
464  {
465  Log(LOG_LEVEL_INFO,
466  "Cannot open file for hashing '%s'. (fopen: %s)",
467  filename,
468  GetErrorStr());
469  return;
470  }
471 
472  HashFile_Stream(file, digest, type);
473  fclose(file);
474 }
475 
476 /*******************************************************************/
477 
478 void HashString(
479  const char *const buffer,
480  const int len,
481  unsigned char digest[EVP_MAX_MD_SIZE + 1],
482  HashMethod type)
483 {
484  assert(buffer != NULL);
485  assert(digest != NULL);
486  assert(type != HASH_METHOD_CRYPT);
487 
488  memset(digest, 0, EVP_MAX_MD_SIZE + 1);
489 
490  if (type == HASH_METHOD_CRYPT)
491  {
492  Log(LOG_LEVEL_ERR,
493  "The crypt support is not presently implemented, please use another algorithm instead");
494  return;
495  }
496 
497  const EVP_MD *const md = HashDigestFromId(type);
498  if (md == NULL)
499  {
500  Log(LOG_LEVEL_ERR,
501  "Could not determine function for file hashing (type=%d)",
502  (int) type);
503  return;
504  }
505 
506  EVP_MD_CTX *const context = EVP_MD_CTX_new();
507  if (context == NULL)
508  {
509  Log(LOG_LEVEL_ERR, "Failed to allocate openssl hashing context");
510  return;
511  }
512 
513  if (EVP_DigestInit(context, md) == 1)
514  {
515  EVP_DigestUpdate(context, buffer, len);
516  EVP_DigestFinal(context, digest, NULL);
517  }
518  else
519  {
520  Log(LOG_LEVEL_ERR,
521  "Failed to initialize digest for hashing: '%s'",
522  buffer);
523  }
524 
525  EVP_MD_CTX_free(context);
526 }
527 
528 /*******************************************************************/
529 
530 void HashPubKey(
531  const RSA *const key,
532  unsigned char digest[EVP_MAX_MD_SIZE + 1],
533  const HashMethod type)
534 {
535  assert(key != NULL);
536  assert(type != HASH_METHOD_CRYPT);
537 
538  memset(digest, 0, EVP_MAX_MD_SIZE + 1);
539 
540  if (type == HASH_METHOD_CRYPT)
541  {
542  Log(LOG_LEVEL_ERR,
543  "The crypt support is not presently implemented, please use sha256 instead");
544  return;
545  }
546 
547  const EVP_MD *const md = HashDigestFromId(type);
548  if (md == NULL)
549  {
550  Log(LOG_LEVEL_ERR,
551  "Could not determine function for file hashing (type=%d)",
552  (int) type);
553  return;
554  }
555 
556  EVP_MD_CTX *const context = EVP_MD_CTX_new();
557  if (context == NULL)
558  {
559  Log(LOG_LEVEL_ERR, "Failed to allocate openssl hashing context");
560  return;
561  }
562 
563 
564  if (EVP_DigestInit(context, md) == 1)
565  {
566  const BIGNUM *n, *e;
567  RSA_get0_key(key, &n, &e, NULL);
568 
569  const size_t n_len = (n == NULL) ? 0 : (size_t) BN_num_bytes(n);
570  const size_t e_len = (e == NULL) ? 0 : (size_t) BN_num_bytes(e);
571  const size_t buf_len = MAX(n_len, e_len);
572 
573  unsigned char buffer[buf_len];
574  int actlen;
575  actlen = BN_bn2bin(n, buffer);
576  CF_ASSERT(actlen <= buf_len, "Buffer overflow n, %d > %zu!",
577  actlen, buf_len);
578  EVP_DigestUpdate(context, buffer, actlen);
579 
580  actlen = BN_bn2bin(e, buffer);
581  CF_ASSERT(actlen <= buf_len, "Buffer overflow e, %d > %zu!",
582  actlen, buf_len);
583  EVP_DigestUpdate(context, buffer, actlen);
584 
585  unsigned int digest_length;
586  EVP_DigestFinal(context, digest, &digest_length);
587  }
588 
589  EVP_MD_CTX_free(context);
590 }
591 
592 /*******************************************************************/
593 
594 bool HashesMatch(
595  const unsigned char digest1[EVP_MAX_MD_SIZE + 1],
596  const unsigned char digest2[EVP_MAX_MD_SIZE + 1],
597  HashMethod type)
598 {
599  const HashSize size = HashSizeFromId(type);
600  if (size <= 0) // HashSize is an enum (so int)
601  {
602  return false;
603  }
604 
605  return (memcmp(digest1, digest2, size) == 0);
606 }
607 
608 /* TODO rewrite this ugliness, currently it's not safe, it truncates! */
609 /**
610  * @WARNING #dst must have enough space to hold the result!
611  */
612 char *HashPrintSafe(char *dst, size_t dst_size, const unsigned char *digest,
613  HashMethod type, bool use_prefix)
614 {
615  const char *prefix;
616 
617  if (use_prefix)
618  {
619  prefix = type == HASH_METHOD_MD5 ? "MD5=" : "SHA=";
620  }
621  else
622  {
623  prefix = "";
624  }
625 
626  size_t dst_len = MIN(dst_size - 1, strlen(prefix));
627  memcpy(dst, prefix, dst_len);
628 
629  size_t digest_len = HashSizeFromId(type);
630  assert(dst_size >= strlen(prefix) + digest_len*2 + 1);
631 
632 #ifndef NDEBUG // Avoids warning.
633  size_t ret =
634 #endif
635  StringBytesToHex(&dst[dst_len], dst_size - dst_len,
636  digest, digest_len);
637  assert(ret == 2 * digest_len);
638 
639 #if 0 /* TODO return proper exit status and check it in the callers */
640  if (ret < 2 * digest_len)
641  {
642  return NULL;
643  }
644 #endif
645 
646  return dst;
647 }
648 
649 
650 char *SkipHashType(char *hash)
651 {
652  char *str = hash;
653 
654  if(STARTSWITH(hash, "MD5=") || STARTSWITH(hash, "SHA="))
655  {
656  str = hash + 4;
657  }
658 
659  return str;
660 }
661 
662 size_t StringCopyTruncateAndHashIfNecessary(
663  const char *const src, char *const dst, size_t dst_size)
664 {
665  assert(src != NULL);
666  assert(dst != NULL);
667  assert(dst_size > (32 + 5)); // Must be big enough for MD5 hex and prefix
668 
669  const size_t length = StringCopy(src, dst, dst_size);
670  if (length < dst_size)
671  {
672  // String length smaller than destination buffer size
673  // safe to return, no truncation/hashing necessary
674  return length;
675  }
676  assert(length == dst_size);
677 
678  const char md5_prefix[] = "#MD5=";
679  const size_t md5_prefix_length = sizeof(md5_prefix) - 1;
680  const size_t md5_hex_length = 32;
681  const size_t md5_string_length = md5_hex_length + md5_prefix_length;
682  assert(dst_size > md5_string_length);
683  assert(md5_prefix_length == strlen(md5_prefix));
684 
685  // Hash the original string using MD5:
686  unsigned char digest[EVP_MAX_MD_SIZE + 1];
687  HashString(src, strlen(src), digest, HASH_METHOD_MD5);
688 
689  // Calculate where the hash should start:
690  char *const terminator = dst + dst_size - 1;
691  assert(*terminator == '\0');
692  char *const hash_prefix_start = terminator - md5_string_length;
693  assert(hash_prefix_start >= dst);
694  char *const hash_start = hash_prefix_start + sizeof(md5_prefix) - 1;
695  assert(hash_start > hash_prefix_start);
696 
697  // Insert the "#MD5=" part into dst;
698  memcpy(hash_prefix_start, md5_prefix, md5_prefix_length);
699 
700  // Produce the hex string representation of MD5 hash:
701  // (Overwrite the last part of dst)
702  const char lookup[]="0123456789abcdef";
703  assert((md5_hex_length % 2) == 0);
704  for (int i = 0; i < md5_hex_length / 2; i++)
705  {
706  hash_start[i * 2] = lookup[digest[i] >> 4];
707  hash_start[i * 2 + 1] = lookup[digest[i] & 0xf];
708  }
709  assert(hash_start[md5_hex_length] == '\0');
710  assert(hash_start + md5_hex_length == terminator);
711 
712  return dst_size;
713 }
void * xcalloc(size_t nmemb, size_t size)
Definition: alloc-mini.c:51
#define NULL
Definition: getopt1.c:56
Hash * HashNewFromDescriptor(const int descriptor, HashMethod method)
Creates a new structure of type Hash.
Definition: hash.c:164
Hash * HashNew(const char *data, const unsigned int length, HashMethod method)
Creates a new structure of type Hash.
Definition: hash.c:124
const EVP_MD * HashDigestFromId(HashMethod type)
Returns pointer to an openssl digest struct.
Definition: hash.c:383
Hash * HashNewFromKey(const RSA *rsa, HashMethod method)
Creates a new structure of type Hash.
Definition: hash.c:214
static const int CF_DIGEST_SIZES[10]
Definition: hash.c:53
void HashCalculatePrintableRepresentation(Hash *hash)
Definition: hash.c:88
static const char *const CF_DIGEST_TYPES[10]
Definition: hash.c:39
Hash * HashBasicInit(HashMethod method)
Definition: hash.c:80
HashMethod
Definition: hash_method.h:36
@ HASH_METHOD_MD5
Definition: hash_method.h:37
@ HASH_METHOD_SHA
Definition: hash_method.h:43
@ HASH_METHOD_SHA512
Definition: hash_method.h:41
@ HASH_METHOD_SHA384
Definition: hash_method.h:40
@ HASH_METHOD_SHA1
Definition: hash_method.h:42
@ HASH_METHOD_SHA224
Definition: hash_method.h:38
@ HASH_METHOD_NONE
Definition: hash_method.h:46
@ HASH_METHOD_SHA256
Definition: hash_method.h:39
HashSize
Definition: hash_method.h:49
@ CF_SHA1_LEN
Definition: hash_method.h:55
@ CF_SHA224_LEN
Definition: hash_method.h:51
@ CF_SHA384_LEN
Definition: hash_method.h:53
@ CF_SHA_LEN
Definition: hash_method.h:56
@ CF_SHA256_LEN
Definition: hash_method.h:52
@ CF_SHA512_LEN
Definition: hash_method.h:54
@ CF_MD5_LEN
Definition: hash_method.h:50
@ CF_BEST_LEN
Definition: hash_method.h:57
@ CF_CRYPT_LEN
Definition: hash_method.h:58
@ CF_NO_HASH
Definition: hash_method.h:59
void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
EVP_MD_CTX * EVP_MD_CTX_new(void)
void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
void Log(LogLevel level, const char *fmt,...)
Definition: logging.c:409
@ LOG_LEVEL_ERR
Definition: logging.h:42
@ LOG_LEVEL_INFO
Definition: logging.h:45
#define CF_ASSERT(condition,...)
Definition: misc_lib.h:51
#define MAX(x, y)
Definition: snprintf.c:500
Definition: buffer.h:50
Definition: hash.c:67
char printable[EVP_MAX_MD_SIZE *4]
Definition: hash.c:69
HashSize size
Definition: hash.c:71
HashMethod method
Definition: hash.c:70
unsigned char digest[EVP_MAX_MD_SIZE]
Definition: hash.c:68