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