xorriso  1.5.4.pl02
About: GNU xorriso creates, loads, manipulates and writes ISO 9660 filesystem images with Rock Ridge extensions. It is suitable for incremental data backup and for production of bootable ISO 9660 images. GNU xorriso is a statical compilation of the libraries libburn, libisofs, libisoburn, and libjte.
  Fossies Dox: xorriso-1.5.4.pl02.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

checksum.c
Go to the documentation of this file.
1 /*
2  * checksum.c
3  *
4  * Copyright (c) 2008-2019 Steve McIntyre <steve@einval.com>
5  *
6  * Implementation of a generic checksum interface, used in JTE.
7  *
8  * GNU GPL v2+
9  */
10 
11 #ifdef HAVE_CONFIG_H
12 #include "../config.h"
13 #endif
14 
15 #include <sys/types.h>
16 #include <regex.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <sys/stat.h>
21 
22 #ifdef HAVE_STDINT_H
23 #include <stdint.h>
24 #else
25 #ifdef HAVE_INTTYPES_H
26 #include <inttypes.h>
27 #endif
28 #endif
29 
30 #include "md5.h"
31 #include "sha1.h"
32 #include "sha256.h"
33 #include "sha512.h"
34 #include "checksum.h"
35 
36 #ifdef THREADED_CHECKSUMS
37 #include <pthread.h>
38 #endif
39 
40 static void md5_init(void *context)
41 {
42  mk_MD5Init(context);
43 }
44 static void md5_update(void *context, unsigned char const *buf, unsigned int len)
45 {
46  mk_MD5Update(context, buf, len);
47 }
48 static void md5_final(unsigned char *digest, void *context)
49 {
50  mk_MD5Final(digest, context);
51 }
52 
53 static void sha1_init(void *context)
54 {
55  sha1_init_ctx(context);
56 }
57 static void sha1_update(void *context, unsigned char const *buf, unsigned int len)
58 {
59  sha1_write(context, buf, len);
60 }
61 static void sha1_final(unsigned char *digest, void *context)
62 {
63  sha1_finish_ctx(context);
64  memcpy(digest, sha1_read(context), 20);
65 }
66 
67 static void sha256_init(void *context)
68 {
69  sha256_init_ctx(context);
70 }
71 static void sha256_update(void *context, unsigned char const *buf, unsigned int len)
72 {
73  sha256_process_bytes(buf, len, context);
74 }
75 static void sha256_final(unsigned char *digest, void *context)
76 {
77  sha256_finish_ctx(context, digest);
78 }
79 
80 static void sha512_init(void *context)
81 {
82  sha512_init_ctx(context);
83 }
84 static void sha512_update(void *context, unsigned char const *buf, unsigned int len)
85 {
86  sha512_process_bytes(buf, len, context);
87 }
88 static void sha512_final(unsigned char *digest, void *context)
89 {
90  sha512_finish_ctx(context, digest);
91 }
92 
94 {
95  char *name;
96  char *prog;
99  void (*init)(void *context);
100  void (*update)(void *context, unsigned char const *buf, unsigned int len);
101  void (*final)(unsigned char *digest, void *context);
103 };
104 
105 static const struct checksum_details algorithms[] =
106 {
107  {
108  "MD5",
109  "md5sum",
110  16,
111  sizeof(struct mk_MD5Context),
112  md5_init,
113  md5_update,
114  md5_final,
116  },
117  {
118  "SHA1",
119  "sha1sum",
120  20,
121  sizeof(SHA1_CONTEXT),
122  sha1_init,
123  sha1_update,
124  sha1_final,
126  },
127  {
128  "SHA256",
129  "sha256sum",
130  32,
131  sizeof(struct sha256_ctx),
132  sha256_init,
134  sha256_final,
136  },
137  {
138  "SHA512",
139  "sha512sum",
140  64,
141  sizeof(struct sha512_ctx),
142  sha512_init,
144  sha512_final,
146  }
147 };
148 
150 {
151  void *context;
152  unsigned char *digest;
153  int enabled;
155  char *hexdump;
156 #ifdef THREADED_CHECKSUMS
157  unsigned char const *buf;
158  unsigned int len;
159  int which;
160  pthread_t thread;
161  struct _checksum_context *parent;
162  pthread_mutex_t start_mutex;
163  pthread_cond_t start_cv;
164 #endif
165 };
166 
168 {
169 #ifdef THREADED_CHECKSUMS
170  unsigned int index;
171  unsigned int threads_running;
172  unsigned int threads_desired;
173  pthread_mutex_t done_mutex;
174  pthread_cond_t done_cv;
175 #endif
176  char *owner;
177  struct algo_context algo[NUM_CHECKSUMS];
178 };
179 
181 {
182  return (struct checksum_info *)&algorithms[which];
183 }
184 
185 /* Dump a buffer in hex */
186 static void hex_dump_to_buffer(char *output_buffer, unsigned char *buf, size_t buf_size)
187 {
188  unsigned int i;
189  char *p = output_buffer;
190 
191  memset(output_buffer, 0, 1 + (2*buf_size));
192  for (i = 0; i < buf_size ; i++)
193  p += sprintf(p, "%2.2x", buf[i]);
194 }
195 
196 #ifdef THREADED_CHECKSUMS
197 static void *checksum_thread(void *arg)
198 {
199  struct algo_context *a = arg;
200  struct _checksum_context *c = a->parent;
201  int num_blocks_summed = 0;
202 
203  while (1)
204  {
205  /* wait to be given some work to do */
206  pthread_mutex_lock(&a->start_mutex);
207  while (a->buf == NULL)
208  {
209  pthread_cond_wait(&a->start_cv, &a->start_mutex);
210  }
211  pthread_mutex_unlock(&a->start_mutex);
212 
213  /* if we're given a zero-length buffer, then that means we're
214  * done */
215  if (a->len == 0)
216  break;
217 
218  /* actually do the checksum on the supplied buffer */
219  algorithms[a->which].update(a->context, a->buf, a->len);
220  num_blocks_summed++;
221  a->buf = NULL;
222 
223  /* and tell the main thread that we're done with that
224  * buffer */
225  pthread_mutex_lock(&c->done_mutex);
226  c->threads_running--;
227  if (c->threads_running == 0)
228  pthread_cond_signal(&c->done_cv);
229  pthread_mutex_unlock(&c->done_mutex);
230  }
231 
232  pthread_exit(NULL);
233 }
234 #endif
235 
236 checksum_context_t *checksum_init_context(int checksums, const char *owner)
237 {
238  int i = 0;
239 #ifdef THREADED_CHECKSUMS
240  int ret = 0;
241 #endif
242 
243  struct _checksum_context *context = calloc(1, sizeof(struct _checksum_context));
244 
245  if (!context)
246  return NULL;
247 
248  context->owner = strdup(owner);
249  if (!context->owner)
250  {
251  free(context);
252  return NULL;
253  }
254 
255 #ifdef THREADED_CHECKSUMS
256  pthread_mutex_init(&context->done_mutex, NULL);
257  pthread_cond_init(&context->done_cv, NULL);
258  context->index = 0;
259  context->threads_running = 0;
260  context->threads_desired = 0;
261 
262  for (i = 0; i < NUM_CHECKSUMS; i++)
263  if ( (1 << i) & checksums)
264  context->threads_desired++;
265 #endif
266 
267  for (i = 0; i < NUM_CHECKSUMS; i++)
268  {
269  struct algo_context *a = &context->algo[i];
270  if ( (1 << i) & checksums)
271  {
272  a->context = malloc(algorithms[i].context_size);
273  if (!a->context)
274  {
276  return NULL;
277  }
278  a->digest = malloc(algorithms[i].digest_size);
279  if (!a->digest)
280  {
282  return NULL;
283  }
284  a->hexdump = malloc(1 + (2*algorithms[i].digest_size));
285  if (!a->hexdump)
286  {
288  return NULL;
289  }
290  algorithms[i].init(a->context);
291  a->enabled = 1;
292  a->finalised = 0;
293 #ifdef THREADED_CHECKSUMS
294  a->which = i;
295  a->parent = context;
296  a->buf = NULL;
297  a->len = 0;
298  pthread_mutex_init(&a->start_mutex, NULL);
299  pthread_cond_init(&a->start_cv, NULL);
300  ret = pthread_create(&a->thread, NULL, checksum_thread, a);
301  if (ret != 0)
302  {
303  /* libjte issues an own message:
304  fprintf(stderr, "failed to create new thread: %d\n", ret);
305  */
307  return NULL;
308  }
309 #endif
310  }
311  else
312  a->enabled = 0;
313  }
314 
315  return context;
316 }
317 
319 {
320  int i = 0;
321  struct _checksum_context *c = context;
322 
323  for (i = 0; i < NUM_CHECKSUMS; i++)
324  {
325  struct algo_context *a = &c->algo[i];
326 
327 #ifdef THREADED_CHECKSUMS
328  if (a->thread)
329  {
330  void *ret;
331  pthread_cancel(a->thread);
332  pthread_join(a->thread, &ret);
333  a->thread = 0;
334  }
335 #endif
336  free(a->context);
337  free(a->digest);
338  free(a->hexdump);
339  }
340  free(c->owner);
341  free(c);
342 }
343 
344 #ifdef THREADED_CHECKSUMS
346  unsigned char const *buf, unsigned int len)
347 {
348  int i = 0;
349  struct _checksum_context *c = context;
350 
351  /* >>> TODO : Find out for what purpose index shall serve.
352  It is defined here and incremented. Not more.
353  */
354  static int index = 0;
355 
356  index++;
357 
358  c->threads_running = c->threads_desired;
359  for (i = 0; i < NUM_CHECKSUMS; i++)
360  {
361  if (c->algo[i].enabled)
362  {
363  struct algo_context *a = &c->algo[i];
364  pthread_mutex_lock(&a->start_mutex);
365  a->len = len;
366  a->buf = buf;
367  pthread_cond_signal(&a->start_cv);
368  pthread_mutex_unlock(&a->start_mutex);
369  }
370  }
371 
372  /* Should now all be running, wait on them all to return */
373  pthread_mutex_lock(&c->done_mutex);
374  while (c->threads_running > 0)
375  {
376  pthread_cond_wait(&c->done_cv, &c->done_mutex);
377  }
378  pthread_mutex_unlock(&c->done_mutex);
379 }
380 
381 #else /* THREADED_CHECKSUMS */
382 
384  unsigned char const *buf, unsigned int len)
385 {
386  int i = 0;
387  struct _checksum_context *c = context;
388 
389  for (i = 0; i < NUM_CHECKSUMS; i++)
390  {
391  if (c->algo[i].enabled)
392  {
393  struct algo_context *a = &c->algo[i];
394  algorithms[i].update(a->context, buf, len);
395  }
396  }
397 }
398 
399 #endif /* THREADED_CHECKSUMS */
400 
402 {
403  int i = 0;
404  struct _checksum_context *c = context;
405 
406 #ifdef THREADED_CHECKSUMS
407  /* Clean up the threads */
408  c->threads_running = c->threads_desired;
409 
410  for (i = 0; i < NUM_CHECKSUMS; i++)
411  {
412  if (c->algo[i].enabled)
413  {
414  void *ret = NULL;
415  struct algo_context *a = &c->algo[i];
416 
417  pthread_mutex_lock(&a->start_mutex);
418  a->len = 0;
419  a->buf = (unsigned char *)-1;
420  pthread_cond_signal(&a->start_cv);
421  pthread_mutex_unlock(&a->start_mutex);
422  pthread_join(a->thread, &ret);
423  a->thread = 0;
424  }
425  }
426 #endif
427 
428  for (i = 0; i < NUM_CHECKSUMS; i++)
429  {
430  struct algo_context *a = &c->algo[i];
431  if (a->enabled)
432  {
433  algorithms[i].final(a->digest, a->context);
435  a->finalised = 1;
436  }
437  }
438 }
439 
441  enum checksum_types which,
442  unsigned char *digest)
443 {
444  struct _checksum_context *c = context;
445 
446  if (c->algo[which].enabled)
447  {
448  if (c->algo[which].finalised)
449  memcpy(digest, c->algo[which].digest, algorithms[which].digest_size);
450  else
451  memset(digest, 0, algorithms[which].digest_size);
452  }
453 
454  else
455  /* >>> TODO : ??? Can this happen ? Why print and then go on ? */
456  fprintf(stderr, "Asked for %s checksum, not enabled!\n",
457  algorithms[which].name);
458 }
459 
460 const char *checksum_hex(checksum_context_t *context,
461  enum checksum_types which)
462 {
463  struct _checksum_context *c = context;
464 
465  if (c->algo[which].enabled && c->algo[which].finalised)
466  return c->algo[which].hexdump;
467 
468  /* else */
469  return NULL;
470 }
471 
472 
473 /* Parse the command line options for which checksums to use */
474 int parse_checksum_algo(char *arg, int *algo)
475 {
476  int i = 0;
477  char *start_ptr = arg;
478  int len = 0;
479 
480  (*algo) |= CHECK_MD5_USED;
481 
482  if (!strcasecmp(arg, "all"))
483  {
484  *algo = 0xFF;
485  return 0;
486  }
487 
488  while (*start_ptr != 0)
489  {
490  int match = 0;
491  len = 0;
492 
493  while (start_ptr[len] != ',' && start_ptr[len] != 0)
494  len++;
495 
496  if (len)
497  {
498  for (i = 0; i < NUM_CHECKSUMS; i++)
499  {
500  if (len == (int) strlen(algorithms[i].name) &&
501  !strncasecmp(start_ptr, algorithms[i].name, len))
502  {
503  match = 1;
505  }
506  }
507 
508  if (!match)
509  {
510  return EINVAL;
511  }
512  }
513 
514  if (start_ptr[len] == 0)
515  break;
516 
517  start_ptr += len + 1;
518  }
519 
520  return 0;
521 }
522 
523 /* Helper function: Simply calculate the checksum of the first "size"
524  * bytes of a file using the specified algorithm. If size == -1,
525  * calculate the checksum for the whole of the file. The caller is
526  * responsible for passing in a large enough buffer as "digest", based
527  * on their choice of algorithm. */
528 int checksum_calculate(char *filename,
529  int64_t size,
530  unsigned char *out,
531  enum checksum_types which)
532 {
533  char buffer[32768];
534  FILE *infile = NULL;
535  int64_t remain = 0;
536  int use;
537  struct checksum_context_t *context;
538 
539  context = checksum_init_context(1 << which, "misc");
540  if (!context)
541  {
542  errno = ENOMEM;
543  return -1;
544  }
545 
546  infile = fopen(filename, "rb");
547  if (!infile)
548  return -1;
549 
550  if (-1 == size)
551  {
552  struct stat st;
553  stat(filename, &st);
554  size = st.st_size;
555  }
556 
557  remain = size;
558  while (remain > 0)
559  {
560  use = (remain > (int) sizeof(buffer) ? (int) sizeof(buffer)
561  : remain);
562  if (fread(buffer, 1, use, infile) == 0)
563  return -1;
564  /* Update the checksum */
565  checksum_update(context, (unsigned char *)buffer, use);
566  remain -= use;
567  }
568  fclose(infile);
569  checksum_final(context);
570  checksum_copy(context, which, out);
571  checksum_free_context(context);
572  return 0;
573 }
574 
575 /* Read in a hex-dumped checksum and parse it */
576 int checksum_parse_hex(char *in, unsigned char *out, int size)
577 {
578  int i = 0;
579 
580  if (size % 2) /* odd number */
581  return EINVAL;
582 
583  for (i = 0; i < size / 2; i++)
584  {
585  if (in[2*i] >= '0' && in[2*i] <= '9')
586  in[2*i] -= '0';
587  else if (in[2*i] >= 'A' && in[2*i] <= 'F')
588  in[2*i] += 10 - 'A';
589  else if (in[2*i] >= 'a' && in[2*i] <= 'f')
590  in[2*i] += 10 - 'a';
591  else
592  return 1;
593  if (in[1+(2*i)] >= '0' && in[1+(2*i)] <= '9')
594  in[1+(2*i)] -= '0';
595  else if (in[1+(2*i)] >= 'A' && in[1+(2*i)] <= 'F')
596  in[1+(2*i)] += 10 - 'A';
597  else if (in[1+(2*i)] >= 'a' && in[1+(2*i)] <= 'f')
598  in[1+(2*i)] += 10 - 'a';
599  else
600  return 1;
601  out[i] = in[2*i] << 4 | in[1+(2*i)];
602  }
603  return 0;
604 }
605 
606 #ifdef CHECKSUM_SELF_TEST
607 #include <sys/types.h>
608 #include <sys/stat.h>
609 #include <fcntl.h>
610 #include <unistd.h>
611 #include <errno.h>
612 #include <stdlib.h>
613 
614 int main(int argc, char **argv)
615 {
616  char buf[1024];
617  int fd = -1;
618  char *filename;
619  int err = 0;
620  static checksum_context_t *test_context = NULL;
621  int i = 0;
622 
623  if (argc != 2)
624  {
625  fprintf(stderr, "Need a filename to act on!\n");
626  return 1;
627  }
628 
629  filename = argv[1];
630  fd = open(filename, O_RDONLY);
631  if (fd < 0)
632  {
633  fprintf(stderr, "Unable to open file %s, errno %d\n", filename, errno);
634  return 1;
635  }
636 
637  test_context = checksum_init_context(CHECK_ALL_USED, "test");
638  if (!test_context)
639  {
640  fprintf(stderr, "Unable to initialise checksum context\n");
641  close(fd);
642  return 1;
643  }
644 
645  while(1)
646  {
647  err = read(fd, buf, sizeof(buf));
648  if (err < 0)
649  {
650  fprintf(stderr, "Failed to read from file, errno %d\n", errno);
651  return 1;
652  }
653 
654  if (err == 0)
655  break; /* EOF */
656 
657  /* else */
658  checksum_update(test_context, buf, err);
659  }
660  close(fd);
661  checksum_final(test_context);
662 
663  for (i = 0; i < NUM_CHECKSUMS; i++)
664  {
665  struct checksum_info *info;
666  unsigned char r[64];
667  int j = 0;
668 
669  info = checksum_information(i);
670  memset(r, 0, sizeof(r));
671 
672  checksum_copy(test_context, i, r);
673 
674  printf("OUR %s:\n", info->name);
675  for (j = 0; j < info->digest_size; j++)
676  printf("%2.2x", r[j]);
677  printf(" %s\n", filename);
678  printf("system checksum program (%s):\n", info->prog);
679  sprintf(buf, "%s %s", info->prog, filename);
680  system(buf);
681  printf("\n");
682  }
683  return 0;
684 }
685 #endif /* CHECKSUM_SELF_TEST */
686 
int checksum_calculate(char *filename, int64_t size, unsigned char *out, enum checksum_types which)
Definition: checksum.c:528
static void sha1_final(unsigned char *digest, void *context)
Definition: checksum.c:61
static const struct checksum_details algorithms[]
Definition: checksum.c:105
checksum_context_t * checksum_init_context(int checksums, const char *owner)
Definition: checksum.c:236
static void sha1_update(void *context, unsigned char const *buf, unsigned int len)
Definition: checksum.c:57
static void sha256_update(void *context, unsigned char const *buf, unsigned int len)
Definition: checksum.c:71
const char * checksum_hex(checksum_context_t *context, enum checksum_types which)
Definition: checksum.c:460
static void sha1_init(void *context)
Definition: checksum.c:53
static void md5_update(void *context, unsigned char const *buf, unsigned int len)
Definition: checksum.c:44
static void sha256_init(void *context)
Definition: checksum.c:67
static void sha512_update(void *context, unsigned char const *buf, unsigned int len)
Definition: checksum.c:84
static void md5_init(void *context)
Definition: checksum.c:40
void checksum_update(checksum_context_t *context, unsigned char const *buf, unsigned int len)
Definition: checksum.c:383
void checksum_copy(checksum_context_t *context, enum checksum_types which, unsigned char *digest)
Definition: checksum.c:440
static void sha512_final(unsigned char *digest, void *context)
Definition: checksum.c:88
static void hex_dump_to_buffer(char *output_buffer, unsigned char *buf, size_t buf_size)
Definition: checksum.c:186
void checksum_final(checksum_context_t *context)
Definition: checksum.c:401
static void md5_final(unsigned char *digest, void *context)
Definition: checksum.c:48
static void sha256_final(unsigned char *digest, void *context)
Definition: checksum.c:75
int checksum_parse_hex(char *in, unsigned char *out, int size)
Definition: checksum.c:576
void checksum_free_context(checksum_context_t *context)
Definition: checksum.c:318
int parse_checksum_algo(char *arg, int *algo)
Definition: checksum.c:474
struct checksum_info * checksum_information(enum checksum_types which)
Definition: checksum.c:180
static void sha512_init(void *context)
Definition: checksum.c:80
void checksum_context_t
Definition: checksum.h:31
#define CHECK_SHA256_USED
Definition: checksum.h:27
checksum_types
Definition: checksum.h:17
@ NUM_CHECKSUMS
Definition: checksum.h:22
#define CHECK_MD5_USED
Definition: checksum.h:25
#define CHECK_ALL_USED
Definition: checksum.h:29
#define CHECK_SHA1_USED
Definition: checksum.h:26
#define CHECK_SHA512_USED
Definition: checksum.h:28
int main(int argc, char *argv[])
void mk_MD5Update(struct mk_MD5Context *ctx, unsigned char const *buf, unsigned len)
Definition: md5.c:108
void mk_MD5Init(struct mk_MD5Context *ctx)
Definition: md5.c:92
void mk_MD5Final(unsigned char digest[16], struct mk_MD5Context *ctx)
Definition: md5.c:156
void sha1_write(void *context, const void *inbuf_arg, size_t inlen)
Definition: sha1.c:232
void sha1_finish_ctx(void *context)
Definition: sha1.c:279
unsigned char * sha1_read(void *context)
Definition: sha1.c:343
void sha1_init_ctx(void *context)
Definition: sha1.c:65
void * sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf)
Definition: sha256.c:204
void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx)
Definition: sha256.c:236
void sha256_init_ctx(struct sha256_ctx *ctx)
Definition: sha256.c:182
void sha512_process_bytes(const void *buffer, size_t len, struct sha512_ctx *ctx)
Definition: sha512.c:351
void * sha512_finish_ctx(struct sha512_ctx *ctx, void *resbuf)
Definition: sha512.c:319
void sha512_init_ctx(struct sha512_ctx *ctx)
Definition: sha512.c:273
struct algo_context algo[NUM_CHECKSUMS]
Definition: checksum.c:177
int finalised
Definition: checksum.c:154
unsigned char * digest
Definition: checksum.c:152
void * context
Definition: checksum.c:151
char * hexdump
Definition: checksum.c:155
void(* final)(unsigned char *digest, void *context)
Definition: checksum.c:101
int check_used_value
Definition: checksum.c:102
void(* init)(void *context)
Definition: checksum.c:99
void(* update)(void *context, unsigned char const *buf, unsigned int len)
Definition: checksum.c:100
char * prog
Definition: checksum.h:36
int digest_size
Definition: checksum.h:37
char * name
Definition: checksum.h:35