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