Coverage Report

Created: 2024-02-29 06:05

/src/strongswan/src/libstrongswan/utils/chunk.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2008-2019 Tobias Brunner
3
 * Copyright (C) 2023 Andreas Steffen
4
 * Copyright (C) 2005-2006 Martin Willi
5
 * Copyright (C) 2005 Jan Hutter
6
 *
7
 * Copyright (C) secunet Security Networks AG
8
 *
9
 * This program is free software; you can redistribute it and/or modify it
10
 * under the terms of the GNU General Public License as published by the
11
 * Free Software Foundation; either version 2 of the License, or (at your
12
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
13
 *
14
 * This program is distributed in the hope that it will be useful, but
15
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17
 * for more details.
18
 */
19
20
#include <stdio.h>
21
#include <sys/types.h>
22
#include <sys/stat.h>
23
#ifdef HAVE_MMAP
24
# include <sys/mman.h>
25
#endif
26
#include <fcntl.h>
27
#include <unistd.h>
28
#include <errno.h>
29
#include <ctype.h>
30
#include <time.h>
31
32
#include "chunk.h"
33
34
/**
35
 * Empty chunk.
36
 */
37
chunk_t chunk_empty = { NULL, 0 };
38
39
/**
40
 * Described in header.
41
 */
42
chunk_t chunk_create_clone(u_char *ptr, chunk_t chunk)
43
23.8k
{
44
23.8k
  chunk_t clone = chunk_empty;
45
46
23.8k
  if (chunk.ptr && chunk.len > 0)
47
23.7k
  {
48
23.7k
    clone.ptr = ptr;
49
23.7k
    clone.len = chunk.len;
50
23.7k
    memcpy(clone.ptr, chunk.ptr, chunk.len);
51
23.7k
  }
52
53
23.8k
  return clone;
54
23.8k
}
55
56
/**
57
 * Described in header.
58
 */
59
size_t chunk_length(const char* mode, ...)
60
0
{
61
0
  va_list chunks;
62
0
  size_t length = 0;
63
64
0
  va_start(chunks, mode);
65
0
  while (TRUE)
66
0
  {
67
0
    switch (*mode++)
68
0
    {
69
0
      case 'm':
70
0
      case 'c':
71
0
      case 's':
72
0
      {
73
0
        chunk_t ch = va_arg(chunks, chunk_t);
74
0
        length += ch.len;
75
0
        continue;
76
0
      }
77
0
      default:
78
0
        break;
79
0
    }
80
0
    break;
81
0
  }
82
0
  va_end(chunks);
83
0
  return length;
84
0
}
85
86
/**
87
 * Described in header.
88
 */
89
chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...)
90
0
{
91
0
  va_list chunks;
92
0
  chunk_t construct = chunk_create(ptr, 0);
93
94
0
  va_start(chunks, mode);
95
0
  while (TRUE)
96
0
  {
97
0
    bool free_chunk = FALSE, clear_chunk = FALSE;
98
0
    chunk_t ch;
99
100
0
    switch (*mode++)
101
0
    {
102
0
      case 's':
103
0
        clear_chunk = TRUE;
104
        /* FALL */
105
0
      case 'm':
106
0
        free_chunk = TRUE;
107
        /* FALL */
108
0
      case 'c':
109
0
        ch = va_arg(chunks, chunk_t);
110
0
        memcpy(ptr, ch.ptr, ch.len);
111
0
        ptr += ch.len;
112
0
        construct.len += ch.len;
113
0
        if (clear_chunk)
114
0
        {
115
0
          chunk_clear(&ch);
116
0
        }
117
0
        else if (free_chunk)
118
0
        {
119
0
          free(ch.ptr);
120
0
        }
121
0
        continue;
122
0
      default:
123
0
        break;
124
0
    }
125
0
    break;
126
0
  }
127
0
  va_end(chunks);
128
129
0
  return construct;
130
0
}
131
132
/**
133
 * Described in header.
134
 */
135
void chunk_split(chunk_t chunk, const char *mode, ...)
136
0
{
137
0
  va_list chunks;
138
0
  u_int len;
139
0
  chunk_t *ch;
140
141
0
  va_start(chunks, mode);
142
0
  while (TRUE)
143
0
  {
144
0
    if (*mode == '\0')
145
0
    {
146
0
      break;
147
0
    }
148
0
    len = va_arg(chunks, u_int);
149
0
    ch = va_arg(chunks, chunk_t*);
150
    /* a null chunk means skip len bytes */
151
0
    if (ch == NULL)
152
0
    {
153
0
      chunk = chunk_skip(chunk, len);
154
0
      continue;
155
0
    }
156
0
    switch (*mode++)
157
0
    {
158
0
      case 'm':
159
0
      {
160
0
        ch->len = min(chunk.len, len);
161
0
        if (ch->len)
162
0
        {
163
0
          ch->ptr = chunk.ptr;
164
0
        }
165
0
        else
166
0
        {
167
0
          ch->ptr = NULL;
168
0
        }
169
0
        chunk = chunk_skip(chunk, ch->len);
170
0
        continue;
171
0
      }
172
0
      case 'a':
173
0
      {
174
0
        ch->len = min(chunk.len, len);
175
0
        if (ch->len)
176
0
        {
177
0
          ch->ptr = malloc(ch->len);
178
0
          memcpy(ch->ptr, chunk.ptr, ch->len);
179
0
        }
180
0
        else
181
0
        {
182
0
          ch->ptr = NULL;
183
0
        }
184
0
        chunk = chunk_skip(chunk, ch->len);
185
0
        continue;
186
0
      }
187
0
      case 'c':
188
0
      {
189
0
        ch->len = min(ch->len, chunk.len);
190
0
        ch->len = min(ch->len, len);
191
0
        if (ch->len)
192
0
        {
193
0
          memcpy(ch->ptr, chunk.ptr, ch->len);
194
0
        }
195
0
        else
196
0
        {
197
0
          ch->ptr = NULL;
198
0
        }
199
0
        chunk = chunk_skip(chunk, ch->len);
200
0
        continue;
201
0
      }
202
0
      default:
203
0
        break;
204
0
    }
205
0
    break;
206
0
  }
207
0
  va_end(chunks);
208
0
}
209
210
/**
211
 * Described in header.
212
 */
213
bool chunk_write(chunk_t chunk, char *path, mode_t mask, bool force)
214
0
{
215
0
  mode_t oldmask;
216
0
  FILE *fd;
217
0
  bool good = FALSE;
218
0
  int tmp = 0;
219
220
0
  if (!force && access(path, F_OK) == 0)
221
0
  {
222
0
    errno = EEXIST;
223
0
    return FALSE;
224
0
  }
225
0
  oldmask = umask(mask);
226
0
  fd = fopen(path,
227
#ifdef WIN32
228
        "wb"
229
#else
230
0
        "w"
231
0
#endif
232
0
  );
233
234
0
  if (fd)
235
0
  {
236
0
    if (fwrite(chunk.ptr, sizeof(u_char), chunk.len, fd) == chunk.len)
237
0
    {
238
0
      good = TRUE;
239
0
    }
240
0
    else
241
0
    {
242
0
      tmp = errno;
243
0
    }
244
0
    fclose(fd);
245
0
  }
246
0
  else
247
0
  {
248
0
    tmp = errno;
249
0
  }
250
0
  umask(oldmask);
251
0
  errno = tmp;
252
0
  return good;
253
0
}
254
255
/**
256
 * Described in header.
257
 */
258
bool chunk_from_fd(int fd, chunk_t *out)
259
0
{
260
0
  struct stat sb;
261
0
  char *buf, *tmp;
262
0
  ssize_t len, total = 0, bufsize;
263
264
0
  if (fstat(fd, &sb) == 0 && S_ISREG(sb.st_mode))
265
0
  {
266
0
    bufsize = sb.st_size;
267
0
  }
268
0
  else
269
0
  {
270
0
    bufsize = 256;
271
0
  }
272
0
  buf = malloc(bufsize);
273
0
  if (!buf)
274
0
  { /* for huge files */
275
0
    return FALSE;
276
0
  }
277
278
0
  while (TRUE)
279
0
  {
280
0
    len = read(fd, buf + total, bufsize - total);
281
#ifdef WIN32
282
    if (len == -1 && errno == EBADF)
283
    { /* operating on a Winsock socket? */
284
      len = recv(fd, buf + total, bufsize - total, 0);
285
    }
286
#endif
287
0
    if (len < 0)
288
0
    {
289
0
      free(buf);
290
0
      return FALSE;
291
0
    }
292
0
    if (len == 0)
293
0
    {
294
0
      break;
295
0
    }
296
0
    total += len;
297
0
    if (total == bufsize)
298
0
    {
299
0
      bufsize *= 2;
300
0
      tmp = realloc(buf, bufsize);
301
0
      if (!tmp)
302
0
      {
303
0
        free(buf);
304
0
        return FALSE;
305
0
      }
306
0
      buf = tmp;
307
0
    }
308
0
  }
309
0
  if (total == 0)
310
0
  {
311
0
    free(buf);
312
0
    buf = NULL;
313
0
  }
314
0
  else if (total < bufsize)
315
0
  {
316
0
    buf = realloc(buf, total);
317
0
  }
318
0
  *out = chunk_create(buf, total);
319
0
  return TRUE;
320
0
}
321
322
/**
323
 * Implementation for mmap()ed chunks
324
 */
325
typedef struct {
326
  /* public chunk interface */
327
  chunk_t public;
328
  /* FD of open file */
329
  int fd;
330
  /* mmap() address */
331
  void *map;
332
  /* size of map */
333
  size_t len;
334
  /* do we write? */
335
  bool wr;
336
} mmaped_chunk_t;
337
338
/**
339
 * See header.
340
 */
341
chunk_t *chunk_map(char *path, bool wr)
342
0
{
343
0
  mmaped_chunk_t *chunk;
344
0
  struct stat sb;
345
0
  int tmp, flags;
346
347
0
  flags = wr ? O_RDWR : O_RDONLY;
348
#ifdef WIN32
349
  flags |= O_BINARY;
350
#endif
351
352
0
  INIT(chunk,
353
0
    .fd = open(path, flags),
354
0
    .wr = wr,
355
0
  );
356
357
0
  if (chunk->fd == -1)
358
0
  {
359
0
    free(chunk);
360
0
    return NULL;
361
0
  }
362
0
  if (fstat(chunk->fd, &sb) == -1)
363
0
  {
364
0
    tmp = errno;
365
0
    chunk_unmap(&chunk->public);
366
0
    errno = tmp;
367
0
    return NULL;
368
0
  }
369
0
#ifdef HAVE_MMAP
370
0
  chunk->len = sb.st_size;
371
  /* map non-empty files only, as mmap() complains otherwise */
372
0
  if (chunk->len)
373
0
  {
374
    /* in read-only mode, we allow writes, but don't sync to disk */
375
0
    chunk->map = mmap(NULL, chunk->len, PROT_READ | PROT_WRITE,
376
0
              wr ? MAP_SHARED : MAP_PRIVATE, chunk->fd, 0);
377
0
    if (chunk->map == MAP_FAILED)
378
0
    {
379
0
      tmp = errno;
380
0
      chunk_unmap(&chunk->public);
381
0
      errno = tmp;
382
0
      return NULL;
383
0
    }
384
0
  }
385
0
  chunk->public = chunk_create(chunk->map, chunk->len);
386
#else /* !HAVE_MMAP */
387
  if (!chunk_from_fd(chunk->fd, &chunk->public))
388
  {
389
    tmp = errno;
390
    chunk_unmap(&chunk->public);
391
    errno = tmp;
392
    return NULL;
393
  }
394
  chunk->map = chunk->public.ptr;
395
  chunk->len = chunk->public.len;
396
#endif /* !HAVE_MMAP */
397
0
  return &chunk->public;
398
0
}
399
400
/**
401
 * Unmap the given chunk and optionally clear it
402
 */
403
static bool chunk_unmap_internal(chunk_t *public, bool clear)
404
0
{
405
0
  mmaped_chunk_t *chunk;
406
0
  bool ret = FALSE;
407
0
  int tmp = 0;
408
409
0
  chunk = (mmaped_chunk_t*)public;
410
0
#ifdef HAVE_MMAP
411
0
  if (chunk->map && chunk->map != MAP_FAILED)
412
0
  {
413
0
    if (!chunk->wr && clear)
414
0
    {
415
0
      memwipe(chunk->map, chunk->len);
416
0
    }
417
0
    ret = munmap(chunk->map, chunk->len) == 0;
418
0
    tmp = errno;
419
0
  }
420
#else /* !HAVE_MMAP */
421
  if (chunk->wr)
422
  {
423
    if (lseek(chunk->fd, 0, SEEK_SET) != -1)
424
    {
425
      int len, total = 0;
426
427
      ret = TRUE;
428
      while (total < chunk->len)
429
      {
430
        len = write(chunk->fd, chunk->map + total, chunk->len - total);
431
        if (len <= 0)
432
        {
433
          ret = FALSE;
434
          break;
435
        }
436
        total += len;
437
      }
438
    }
439
    tmp = errno;
440
  }
441
  else
442
  {
443
    ret = TRUE;
444
  }
445
  if (clear)
446
  {
447
    memwipe(chunk->map, chunk->len);
448
  }
449
  free(chunk->map);
450
#endif /* !HAVE_MMAP */
451
0
  close(chunk->fd);
452
0
  free(chunk);
453
0
  errno = tmp;
454
455
0
  return ret;
456
0
}
457
458
/*
459
 * Described in header
460
 */
461
bool chunk_unmap(chunk_t *public)
462
0
{
463
0
  return chunk_unmap_internal(public, FALSE);
464
0
}
465
466
/*
467
 * Described in header
468
 */
469
bool chunk_unmap_clear(chunk_t *public)
470
0
{
471
0
  return chunk_unmap_internal(public, TRUE);
472
0
}
473
474
/** hex conversion digits */
475
static char hexdig_upper[] = "0123456789ABCDEF";
476
static char hexdig_lower[] = "0123456789abcdef";
477
478
/**
479
 * Described in header.
480
 */
481
chunk_t chunk_to_hex(chunk_t chunk, char *buf, bool uppercase)
482
0
{
483
0
  int i, len;
484
0
  char *hexdig = hexdig_lower;
485
486
0
  if (uppercase)
487
0
  {
488
0
    hexdig = hexdig_upper;
489
0
  }
490
491
0
  len = chunk.len * 2;
492
0
  if (!buf)
493
0
  {
494
0
    buf = malloc(len + 1);
495
0
  }
496
0
  buf[len] = '\0';
497
498
0
  for (i = 0; i < chunk.len; i++)
499
0
  {
500
0
    buf[i*2]   = hexdig[(chunk.ptr[i] >> 4) & 0xF];
501
0
    buf[i*2+1] = hexdig[(chunk.ptr[i]     ) & 0xF];
502
0
  }
503
0
  return chunk_create(buf, len);
504
0
}
505
506
/**
507
 * convert a single hex character to its binary value
508
 */
509
static char hex2bin(char hex)
510
42.6k
{
511
42.6k
  switch (hex)
512
42.6k
  {
513
10.7k
    case '0' ... '9':
514
10.7k
      return hex - '0';
515
9.90k
    case 'A' ... 'F':
516
9.90k
      return hex - 'A' + 10;
517
8.15k
    case 'a' ... 'f':
518
8.15k
      return hex - 'a' + 10;
519
13.8k
    default:
520
13.8k
      return 0;
521
42.6k
  }
522
42.6k
}
523
524
/**
525
 * Described in header.
526
 */
527
chunk_t chunk_from_hex(chunk_t hex, char *buf)
528
3.19k
{
529
3.19k
  int i, len;
530
3.19k
  u_char *ptr;
531
3.19k
  bool odd = FALSE;
532
533
  /* skip an optional 0x prefix */
534
3.19k
  if (hex.len > 1 && hex.ptr[1] == 'x' && hex.ptr[0] == '0')
535
448
  {
536
448
    hex = chunk_skip(hex, 2);
537
448
  }
538
539
  /* subtract the number of optional ':' separation characters */
540
3.19k
  len = hex.len;
541
3.19k
  ptr = hex.ptr;
542
46.6k
  for (i = 0; i < hex.len; i++)
543
43.4k
  {
544
43.4k
    if (*ptr++ == ':')
545
813
    {
546
813
      len--;
547
813
    }
548
43.4k
  }
549
550
  /* compute the number of binary bytes */
551
3.19k
  if (len % 2)
552
1.22k
  {
553
1.22k
    odd = TRUE;
554
1.22k
    len++;
555
1.22k
  }
556
3.19k
  len /= 2;
557
558
  /* allocate buffer memory unless provided by caller */
559
3.19k
  if (!buf)
560
0
  {
561
0
    buf = malloc(len);
562
0
  }
563
564
  /* buffer is filled from the right */
565
3.19k
  memset(buf, 0, len);
566
3.19k
  hex.ptr += hex.len;
567
568
25.1k
  for (i = len - 1; i >= 0; i--)
569
21.9k
  {
570
    /* skip separation characters */
571
21.9k
    if (*(--hex.ptr) == ':')
572
286
    {
573
286
      --hex.ptr;
574
286
    }
575
21.9k
    buf[i] = hex2bin(*hex.ptr);
576
21.9k
    if (i > 0 || !odd)
577
20.7k
    {
578
20.7k
      buf[i] |= hex2bin(*(--hex.ptr)) << 4;
579
20.7k
    }
580
21.9k
  }
581
3.19k
  return chunk_create(buf, len);
582
3.19k
}
583
584
/** base 64 conversion digits */
585
static char b64digits[] =
586
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
587
588
/**
589
 * Described in header.
590
 */
591
chunk_t chunk_to_base64(chunk_t chunk, char *buf)
592
0
{
593
0
  int i, len;
594
0
  char *pos;
595
596
0
  len = chunk.len + ((3 - chunk.len % 3) % 3);
597
0
  if (!buf)
598
0
  {
599
0
    buf = malloc(len * 4 / 3 + 1);
600
0
  }
601
0
  pos = buf;
602
0
  for (i = 0; i < len; i+=3)
603
0
  {
604
0
    *pos++ = b64digits[chunk.ptr[i] >> 2];
605
0
    if (i+1 >= chunk.len)
606
0
    {
607
0
      *pos++ = b64digits[(chunk.ptr[i] & 0x03) << 4];
608
0
      *pos++ = '=';
609
0
      *pos++ = '=';
610
0
      break;
611
0
    }
612
0
    *pos++ = b64digits[((chunk.ptr[i] & 0x03) << 4) | (chunk.ptr[i+1] >> 4)];
613
0
    if (i+2 >= chunk.len)
614
0
    {
615
0
      *pos++ = b64digits[(chunk.ptr[i+1] & 0x0F) << 2];
616
0
      *pos++ = '=';
617
0
      break;
618
0
    }
619
0
    *pos++ = b64digits[((chunk.ptr[i+1] & 0x0F) << 2) | (chunk.ptr[i+2] >> 6)];
620
0
    *pos++ = b64digits[chunk.ptr[i+2] & 0x3F];
621
0
  }
622
0
  *pos = '\0';
623
0
  return chunk_create(buf, len * 4 / 3);
624
0
}
625
626
/**
627
 * convert a base 64 digit to its binary form (inversion of b64digits array)
628
 */
629
static int b642bin(char b64)
630
15.0M
{
631
15.0M
  switch (b64)
632
15.0M
  {
633
198k
    case 'A' ... 'Z':
634
198k
      return b64 - 'A';
635
1.56M
    case 'a' ... 'z':
636
1.56M
      return ('Z' - 'A' + 1) + b64 - 'a';
637
2.31M
    case '0' ... '9':
638
2.31M
      return ('Z' - 'A' + 1) + ('z' - 'a' + 1) + b64 - '0';
639
3.09k
    case '+':
640
31.2k
    case '-':
641
31.2k
      return 62;
642
2.45k
    case '/':
643
6.63k
    case '_':
644
6.63k
      return 63;
645
6.10k
    case '=':
646
6.10k
      return 0;
647
10.8M
    default:
648
10.8M
      return -1;
649
15.0M
  }
650
15.0M
}
651
652
/**
653
 * Described in header.
654
 */
655
chunk_t chunk_from_base64(chunk_t base64, char *buf)
656
103k
{
657
103k
  u_char *pos, byte[4];
658
103k
  int i, j, len, outlen;
659
660
103k
  len = base64.len / 4 * 3;
661
103k
  if (!buf)
662
0
  {
663
0
    buf = malloc(len);
664
0
  }
665
103k
  pos = base64.ptr;
666
103k
  outlen = 0;
667
3.85M
  for (i = 0; i < len; i+=3)
668
3.75M
  {
669
3.75M
    outlen += 3;
670
18.7M
    for (j = 0; j < 4; j++)
671
15.0M
    {
672
15.0M
      if (*pos == '=' && outlen > 0)
673
5.80k
      {
674
5.80k
        outlen--;
675
5.80k
      }
676
15.0M
      byte[j] = b642bin(*pos++);
677
15.0M
    }
678
3.75M
    buf[i] = (byte[0] << 2) | (byte[1] >> 4);
679
3.75M
    buf[i+1] = (byte[1] << 4) | (byte[2] >> 2);
680
3.75M
    buf[i+2] = (byte[2] << 6) | (byte[3]);
681
3.75M
  }
682
103k
  return chunk_create(buf, outlen);
683
103k
}
684
685
/** base 32 conversion digits */
686
static char b32digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
687
688
/**
689
 * Described in header.
690
 */
691
chunk_t chunk_to_base32(chunk_t chunk, char *buf)
692
0
{
693
0
  int i, len;
694
0
  char *pos;
695
696
0
  len = chunk.len + ((5 - chunk.len % 5) % 5);
697
0
  if (!buf)
698
0
  {
699
0
    buf = malloc(len * 8 / 5 + 1);
700
0
  }
701
0
  pos = buf;
702
0
  for (i = 0; i < len; i+=5)
703
0
  {
704
0
    *pos++ = b32digits[chunk.ptr[i] >> 3];
705
0
    if (i+1 >= chunk.len)
706
0
    {
707
0
      *pos++ = b32digits[(chunk.ptr[i] & 0x07) << 2];
708
0
      memset(pos, '=', 6);
709
0
      pos += 6;
710
0
      break;
711
0
    }
712
0
    *pos++ = b32digits[((chunk.ptr[i] & 0x07) << 2) |
713
0
               (chunk.ptr[i+1] >> 6)];
714
0
    *pos++ = b32digits[(chunk.ptr[i+1] & 0x3E) >> 1];
715
0
    if (i+2 >= chunk.len)
716
0
    {
717
0
      *pos++ = b32digits[(chunk.ptr[i+1] & 0x01) << 4];
718
0
      memset(pos, '=', 4);
719
0
      pos += 4;
720
0
      break;
721
0
    }
722
0
    *pos++ = b32digits[((chunk.ptr[i+1] & 0x01) << 4) |
723
0
               (chunk.ptr[i+2] >> 4)];
724
0
    if (i+3 >= chunk.len)
725
0
    {
726
0
      *pos++ = b32digits[(chunk.ptr[i+2] & 0x0F) << 1];
727
0
      memset(pos, '=', 3);
728
0
      pos += 3;
729
0
      break;
730
0
    }
731
0
    *pos++ = b32digits[((chunk.ptr[i+2] & 0x0F) << 1) |
732
0
               (chunk.ptr[i+3] >> 7)];
733
0
    *pos++ = b32digits[(chunk.ptr[i+3] & 0x7F) >> 2];
734
0
    if (i+4 >= chunk.len)
735
0
    {
736
0
      *pos++ = b32digits[(chunk.ptr[i+3] & 0x03) << 3];
737
0
      *pos++ = '=';
738
0
      break;
739
0
    }
740
0
    *pos++ = b32digits[((chunk.ptr[i+3] & 0x03) << 3) |
741
0
               (chunk.ptr[i+4] >> 5)];
742
0
    *pos++ = b32digits[chunk.ptr[i+4] & 0x1F];
743
0
  }
744
0
  *pos = '\0';
745
0
  return chunk_create(buf, len * 8 / 5);
746
0
}
747
748
/**
749
 * Described in header.
750
 */
751
chunk_t chunk_to_dec(chunk_t chunk, char *buf)
752
0
{
753
0
  int len, i, i_buf, i_bin = 0;
754
0
  uint16_t remainder;
755
0
  chunk_t bin;
756
757
  /* Determine the number of needed decimal digits:
758
   * 10^len > 2^(8*chunk.len)       =>
759
   *    len > log(256) * chunk.len  =>
760
   *    len >   2.4083 * chunk.len
761
   */
762
0
  len = (int)(2.4083 * (double)chunk.len) + 1;
763
764
0
  if (!buf)
765
0
  {
766
0
    buf = malloc(len + 1);
767
0
  }
768
0
  i_buf = len;
769
0
  buf[i_buf] = '\0';
770
0
  bin = chunk_clone(chunk);
771
0
  while (i_bin < bin.len)
772
0
  {
773
0
    remainder = 0;
774
0
    for (i = i_bin; i < bin.len; i++)
775
0
    {
776
0
      remainder = bin.ptr[i] + (remainder << 8);
777
0
      if (remainder < 10)
778
0
      {
779
0
        remainder = bin.ptr[i];
780
0
        bin.ptr[i] = 0;
781
0
        if (i == i_bin)
782
0
        {
783
0
          i_bin++;
784
0
        }
785
0
      }
786
0
      else
787
0
      {
788
0
        bin.ptr[i] = remainder / 10;
789
0
        remainder %= 10;
790
0
      }
791
0
    }
792
0
    if (i_buf > 0)
793
0
    {
794
0
      buf[--i_buf] = 0x30 + remainder;
795
0
    }
796
0
  }
797
0
  chunk_free(&bin);
798
799
  /* align decimal number to the start of the string */
800
0
  if (i_buf > 0)
801
0
  {
802
0
    len -= i_buf;
803
804
0
    for (i = 0; i <= len; i++)
805
0
    {
806
0
      buf[i] = buf[i + i_buf];
807
0
    }
808
0
  }
809
810
0
  return chunk_create(buf, len);
811
0
}
812
813
/**
814
 * Described in header.
815
 */
816
int chunk_compare(chunk_t a, chunk_t b)
817
0
{
818
0
  int compare_len = a.len - b.len;
819
0
  int len = (compare_len < 0)? a.len : b.len;
820
821
0
  if (compare_len != 0 || len == 0)
822
0
  {
823
0
    return compare_len;
824
0
  }
825
0
  return memcmp(a.ptr, b.ptr, len);
826
0
};
827
828
829
/**
830
 * Described in header.
831
 */
832
bool chunk_increment(chunk_t chunk)
833
0
{
834
0
  int i;
835
836
0
  for (i = chunk.len - 1; i >= 0; i--)
837
0
  {
838
0
    if (++chunk.ptr[i] != 0)
839
0
    {
840
0
      return FALSE;
841
0
    }
842
0
  }
843
0
  return TRUE;
844
0
}
845
846
/*
847
 * Described in header
848
 */
849
chunk_t chunk_copy_pad(chunk_t dst, chunk_t src, u_char chr)
850
0
{
851
0
  if (dst.ptr)
852
0
  {
853
0
    if (dst.len > src.len)
854
0
    {
855
0
      memcpy(dst.ptr + dst.len - src.len, src.ptr, src.len);
856
0
      memset(dst.ptr, chr, dst.len - src.len);
857
0
    }
858
0
    else
859
0
    {
860
0
      memcpy(dst.ptr, src.ptr + src.len - dst.len, dst.len);
861
0
    }
862
0
  }
863
0
  return dst;
864
0
}
865
866
/**
867
 * Remove non-printable characters from a chunk.
868
 */
869
bool chunk_printable(chunk_t chunk, chunk_t *sane, char replace)
870
0
{
871
0
  bool printable = TRUE;
872
0
  int i;
873
874
0
  if (sane)
875
0
  {
876
0
    *sane = chunk_clone(chunk);
877
0
  }
878
0
  for (i = 0; i < chunk.len; i++)
879
0
  {
880
0
    if (!isprint(chunk.ptr[i]))
881
0
    {
882
0
      if (sane)
883
0
      {
884
0
        sane->ptr[i] = replace;
885
0
      }
886
0
      printable = FALSE;
887
0
    }
888
0
  }
889
0
  return printable;
890
0
}
891
892
/**
893
 * Helper functions for chunk_mac()
894
 */
895
static inline uint64_t sipget(u_char *in)
896
8.54M
{
897
8.54M
  uint64_t v = 0;
898
8.54M
  int i;
899
900
76.9M
  for (i = 0; i < 64; i += 8, ++in)
901
68.3M
  {
902
68.3M
    v |= ((uint64_t)*in) << i;
903
68.3M
  }
904
8.54M
  return v;
905
8.54M
}
906
907
static inline uint64_t siprotate(uint64_t v, int shift)
908
179M
{
909
179M
        return (v << shift) | (v >> (64 - shift));
910
179M
}
911
912
static inline void sipround(uint64_t *v0, uint64_t *v1, uint64_t *v2,
913
              uint64_t *v3)
914
29.8M
{
915
29.8M
  *v0 += *v1;
916
29.8M
  *v1 = siprotate(*v1, 13);
917
29.8M
  *v1 ^= *v0;
918
29.8M
  *v0 = siprotate(*v0, 32);
919
920
29.8M
  *v2 += *v3;
921
29.8M
  *v3 = siprotate(*v3, 16);
922
29.8M
  *v3 ^= *v2;
923
924
29.8M
  *v2 += *v1;
925
29.8M
  *v1 = siprotate(*v1, 17);
926
29.8M
  *v1 ^= *v2;
927
29.8M
  *v2 = siprotate(*v2, 32);
928
929
29.8M
  *v0 += *v3;
930
29.8M
  *v3 = siprotate(*v3, 21);
931
29.8M
  *v3 ^= *v0;
932
29.8M
}
933
934
static inline void sipcompress(uint64_t *v0, uint64_t *v1, uint64_t *v2,
935
                 uint64_t *v3, uint64_t m)
936
6.39M
{
937
6.39M
  *v3 ^= m;
938
6.39M
  sipround(v0, v1, v2, v3);
939
6.39M
  sipround(v0, v1, v2, v3);
940
6.39M
  *v0 ^= m;
941
6.39M
}
942
943
static inline uint64_t siplast(size_t len, u_char *pos)
944
4.27M
{
945
4.27M
  uint64_t b;
946
4.27M
  int rem = len & 7;
947
948
4.27M
  b = ((uint64_t)len) << 56;
949
4.27M
  switch (rem)
950
4.27M
  {
951
0
    case 7:
952
0
      b |= ((uint64_t)pos[6]) << 48;
953
3.52k
    case 6:
954
3.52k
      b |= ((uint64_t)pos[5]) << 40;
955
7.04k
    case 5:
956
7.04k
      b |= ((uint64_t)pos[4]) << 32;
957
4.09M
    case 4:
958
4.09M
      b |= ((uint64_t)pos[3]) << 24;
959
4.10M
    case 3:
960
4.10M
      b |= ((uint64_t)pos[2]) << 16;
961
4.10M
    case 2:
962
4.10M
      b |= ((uint64_t)pos[1]) <<  8;
963
4.10M
    case 1:
964
4.10M
      b |= ((uint64_t)pos[0]);
965
4.10M
      break;
966
168k
    case 0:
967
168k
      break;
968
4.27M
  }
969
4.27M
  return b;
970
4.27M
}
971
972
/**
973
 * Calculate SipHash-2-4 with an optional first block given as argument.
974
 */
975
static uint64_t chunk_mac_inc(chunk_t chunk, u_char *key, uint64_t m)
976
4.27M
{
977
4.27M
  uint64_t v0, v1, v2, v3, k0, k1;
978
4.27M
  size_t len = chunk.len;
979
4.27M
  u_char *pos = chunk.ptr, *end;
980
981
4.27M
  end = chunk.ptr + len - (len % 8);
982
983
4.27M
  k0 = sipget(key);
984
4.27M
  k1 = sipget(key + 8);
985
986
4.27M
  v0 = k0 ^ 0x736f6d6570736575ULL;
987
4.27M
  v1 = k1 ^ 0x646f72616e646f6dULL;
988
4.27M
  v2 = k0 ^ 0x6c7967656e657261ULL;
989
4.27M
  v3 = k1 ^ 0x7465646279746573ULL;
990
991
4.27M
  if (m)
992
2.12M
  {
993
2.12M
    sipcompress(&v0, &v1, &v2, &v3, m);
994
2.12M
  }
995
996
  /* compression with c = 2 */
997
4.27M
  for (; pos != end; pos += 8)
998
68
  {
999
68
    m = sipget(pos);
1000
68
    sipcompress(&v0, &v1, &v2, &v3, m);
1001
68
  }
1002
4.27M
  sipcompress(&v0, &v1, &v2, &v3, siplast(len, pos));
1003
1004
  /* finalization with d = 4 */
1005
4.27M
  v2 ^= 0xff;
1006
4.27M
  sipround(&v0, &v1, &v2, &v3);
1007
4.27M
  sipround(&v0, &v1, &v2, &v3);
1008
4.27M
  sipround(&v0, &v1, &v2, &v3);
1009
4.27M
  sipround(&v0, &v1, &v2, &v3);
1010
4.27M
  return v0 ^ v1 ^ v2  ^ v3;
1011
4.27M
}
1012
1013
/**
1014
 * Described in header.
1015
 */
1016
uint64_t chunk_mac(chunk_t chunk, u_char *key)
1017
2.15M
{
1018
2.15M
  return chunk_mac_inc(chunk, key, 0);
1019
2.15M
}
1020
1021
/**
1022
 * Secret key allocated randomly with chunk_hash_seed().
1023
 */
1024
static u_char hash_key[16] = {};
1025
1026
/**
1027
 * Static key used in case predictable hash values are required.
1028
 */
1029
static u_char static_key[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1030
                0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
1031
1032
/**
1033
 * See header
1034
 */
1035
void chunk_hash_seed()
1036
3.51k
{
1037
3.51k
  static bool seeded = FALSE;
1038
3.51k
  ssize_t len;
1039
3.51k
  size_t done = 0;
1040
3.51k
  int fd;
1041
1042
3.51k
  if (seeded)
1043
3.51k
  {
1044
    /* just once to have the same seed during the whole process lifetimes */
1045
3.51k
    return;
1046
3.51k
  }
1047
1048
2
  fd = open("/dev/urandom", O_RDONLY);
1049
2
  if (fd >= 0)
1050
2
  {
1051
4
    while (done < sizeof(hash_key))
1052
2
    {
1053
2
      len = read(fd, hash_key + done, sizeof(hash_key) - done);
1054
2
      if (len < 0)
1055
0
      {
1056
0
        break;
1057
0
      }
1058
2
      done += len;
1059
2
    }
1060
2
    close(fd);
1061
2
  }
1062
  /* on error we use random() to generate the key (better than nothing) */
1063
2
  if (done < sizeof(hash_key))
1064
0
  {
1065
0
    srandom(time(NULL) + getpid());
1066
0
    for (; done < sizeof(hash_key); done++)
1067
0
    {
1068
0
      hash_key[done] = (u_char)random();
1069
0
    }
1070
0
  }
1071
2
  seeded = TRUE;
1072
2
}
1073
1074
/**
1075
 * Described in header.
1076
 */
1077
uint32_t chunk_hash_inc(chunk_t chunk, uint32_t hash)
1078
2.12M
{
1079
  /* we could use a mac of the previous hash, but this is faster */
1080
2.12M
  return chunk_mac_inc(chunk, hash_key, ((uint64_t)hash) << 32 | hash);
1081
2.12M
}
1082
1083
/**
1084
 * Described in header.
1085
 */
1086
uint32_t chunk_hash(chunk_t chunk)
1087
2.15M
{
1088
2.15M
  return chunk_mac(chunk, hash_key);
1089
2.15M
}
1090
1091
/*
1092
 * Described in header.
1093
 */
1094
uint32_t chunk_hash_ptr(chunk_t *chunk)
1095
0
{
1096
0
  return chunk_hash(*chunk);
1097
0
}
1098
1099
/**
1100
 * Described in header.
1101
 */
1102
uint32_t chunk_hash_static_inc(chunk_t chunk, uint32_t hash)
1103
0
{ /* we could use a mac of the previous hash, but this is faster */
1104
0
  return chunk_mac_inc(chunk, static_key, ((uint64_t)hash) << 32 | hash);
1105
0
}
1106
1107
/**
1108
 * Described in header.
1109
 */
1110
uint32_t chunk_hash_static(chunk_t chunk)
1111
0
{
1112
0
  return chunk_mac(chunk, static_key);
1113
0
}
1114
1115
/**
1116
 * Described in header.
1117
 */
1118
uint16_t chunk_internet_checksum_inc(chunk_t data, uint16_t checksum)
1119
0
{
1120
0
  uint32_t sum = ntohs((uint16_t)~checksum);
1121
1122
0
  while (data.len > 1)
1123
0
  {
1124
0
    sum += untoh16(data.ptr);
1125
0
    data = chunk_skip(data, 2);
1126
0
  }
1127
0
  if (data.len)
1128
0
  {
1129
0
    sum += (uint16_t)*data.ptr << 8;
1130
0
  }
1131
0
  while (sum >> 16)
1132
0
  {
1133
0
    sum = (sum & 0xffff) + (sum >> 16);
1134
0
  }
1135
0
  return htons(~sum);
1136
0
}
1137
1138
/**
1139
 * Described in header.
1140
 */
1141
uint16_t chunk_internet_checksum(chunk_t data)
1142
0
{
1143
0
  return chunk_internet_checksum_inc(data, 0xffff);
1144
0
}
1145
1146
/**
1147
 * Described in header.
1148
 */
1149
int chunk_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
1150
            const void *const *args)
1151
0
{
1152
0
  chunk_t *chunk = *((chunk_t**)(args[0]));
1153
0
  bool first = TRUE;
1154
0
  chunk_t copy = *chunk;
1155
0
  int written = 0;
1156
1157
0
  if (!spec->hash && !spec->plus)
1158
0
  {
1159
0
    u_int chunk_len = chunk->len;
1160
0
    const void *new_args[] = {&chunk->ptr, &chunk_len};
1161
0
    return mem_printf_hook(data, spec, new_args);
1162
0
  }
1163
1164
0
  while (copy.len > 0)
1165
0
  {
1166
0
    if (first)
1167
0
    {
1168
0
      first = FALSE;
1169
0
    }
1170
0
    else if (!spec->plus)
1171
0
    {
1172
0
      written += print_in_hook(data, ":");
1173
0
    }
1174
0
    written += print_in_hook(data, "%02x", *copy.ptr++);
1175
0
    copy.len--;
1176
0
  }
1177
0
  return written;
1178
0
}