chunk: Add functions to map file contents to a chunk
[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 chunk_t chunk_from_fd(int fd)
251 {
252 char buf[8096];
253 char *pos = buf;
254 ssize_t len, total = 0;
255
256 while (TRUE)
257 {
258 len = read(fd, pos, buf + sizeof(buf) - pos);
259 if (len < 0)
260 {
261 DBG1(DBG_LIB, "reading from file descriptor failed: %s",
262 strerror(errno));
263 return chunk_empty;
264 }
265 if (len == 0)
266 {
267 break;
268 }
269 total += len;
270 if (total == sizeof(buf))
271 {
272 DBG1(DBG_LIB, "buffer too small to read from file descriptor");
273 return chunk_empty;
274 }
275 }
276 return chunk_clone(chunk_create(buf, total));
277 }
278
279 /**
280 * Implementation for mmap()ed chunks
281 */
282 typedef struct {
283 /* public chunk interface */
284 chunk_t public;
285 /* FD of open file */
286 int fd;
287 /* mmap() address */
288 void *map;
289 /* size of map */
290 size_t len;
291 } mmaped_chunk_t;
292
293 /**
294 * See header.
295 */
296 chunk_t *chunk_map(char *path, bool wr)
297 {
298 mmaped_chunk_t *chunk;
299 struct stat sb;
300 int tmp;
301
302 INIT(chunk,
303 .fd = open(path, wr ? O_RDWR : O_RDONLY),
304 );
305
306 if (chunk->fd == -1)
307 {
308 free(chunk);
309 return NULL;
310 }
311 if (fstat(chunk->fd, &sb) == -1)
312 {
313 tmp = errno;
314 chunk_unmap(&chunk->public);
315 errno = tmp;
316 return NULL;
317 }
318 chunk->len = sb.st_size;
319 /* map non-empty files only, as mmap() complains otherwise */
320 if (chunk->len)
321 {
322 /* in read-only mode, we allow writes, but don't sync to disk */
323 chunk->map = mmap(NULL, chunk->len, PROT_READ | PROT_WRITE,
324 wr ? MAP_SHARED : MAP_PRIVATE, chunk->fd, 0);
325 if (chunk->map == MAP_FAILED)
326 {
327 tmp = errno;
328 chunk_unmap(&chunk->public);
329 errno = tmp;
330 return NULL;
331 }
332 }
333 chunk->public = chunk_create(chunk->map, chunk->len);
334 return &chunk->public;
335 }
336
337 /**
338 * See header.
339 */
340 bool chunk_unmap(chunk_t *public)
341 {
342 mmaped_chunk_t *chunk;
343 bool ret = FALSE;
344 int tmp = 0;
345
346 chunk = (mmaped_chunk_t*)public;
347 if (chunk->map && chunk->map != MAP_FAILED)
348 {
349 ret = munmap(chunk->map, chunk->len) == 0;
350 tmp = errno;
351 }
352 close(chunk->fd);
353 free(chunk);
354 errno = tmp;
355
356 return ret;
357 }
358
359 /** hex conversion digits */
360 static char hexdig_upper[] = "0123456789ABCDEF";
361 static char hexdig_lower[] = "0123456789abcdef";
362
363 /**
364 * Described in header.
365 */
366 chunk_t chunk_to_hex(chunk_t chunk, char *buf, bool uppercase)
367 {
368 int i, len;
369 char *hexdig = hexdig_lower;
370
371 if (uppercase)
372 {
373 hexdig = hexdig_upper;
374 }
375
376 len = chunk.len * 2;
377 if (!buf)
378 {
379 buf = malloc(len + 1);
380 }
381 buf[len] = '\0';
382
383 for (i = 0; i < chunk.len; i++)
384 {
385 buf[i*2] = hexdig[(chunk.ptr[i] >> 4) & 0xF];
386 buf[i*2+1] = hexdig[(chunk.ptr[i] ) & 0xF];
387 }
388 return chunk_create(buf, len);
389 }
390
391 /**
392 * convert a signle hex character to its binary value
393 */
394 static char hex2bin(char hex)
395 {
396 switch (hex)
397 {
398 case '0' ... '9':
399 return hex - '0';
400 case 'A' ... 'F':
401 return hex - 'A' + 10;
402 case 'a' ... 'f':
403 return hex - 'a' + 10;
404 default:
405 return 0;
406 }
407 }
408
409 /**
410 * Described in header.
411 */
412 chunk_t chunk_from_hex(chunk_t hex, char *buf)
413 {
414 int i, len;
415 u_char *ptr;
416 bool odd = FALSE;
417
418 /* subtract the number of optional ':' separation characters */
419 len = hex.len;
420 ptr = hex.ptr;
421 for (i = 0; i < hex.len; i++)
422 {
423 if (*ptr++ == ':')
424 {
425 len--;
426 }
427 }
428
429 /* compute the number of binary bytes */
430 if (len % 2)
431 {
432 odd = TRUE;
433 len++;
434 }
435 len /= 2;
436
437 /* allocate buffer memory unless provided by caller */
438 if (!buf)
439 {
440 buf = malloc(len);
441 }
442
443 /* buffer is filled from the right */
444 memset(buf, 0, len);
445 hex.ptr += hex.len;
446
447 for (i = len - 1; i >= 0; i--)
448 {
449 /* skip separation characters */
450 if (*(--hex.ptr) == ':')
451 {
452 --hex.ptr;
453 }
454 buf[i] = hex2bin(*hex.ptr);
455 if (i > 0 || !odd)
456 {
457 buf[i] |= hex2bin(*(--hex.ptr)) << 4;
458 }
459 }
460 return chunk_create(buf, len);
461 }
462
463 /** base 64 conversion digits */
464 static char b64digits[] =
465 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
466
467 /**
468 * Described in header.
469 */
470 chunk_t chunk_to_base64(chunk_t chunk, char *buf)
471 {
472 int i, len;
473 char *pos;
474
475 len = chunk.len + ((3 - chunk.len % 3) % 3);
476 if (!buf)
477 {
478 buf = malloc(len * 4 / 3 + 1);
479 }
480 pos = buf;
481 for (i = 0; i < len; i+=3)
482 {
483 *pos++ = b64digits[chunk.ptr[i] >> 2];
484 if (i+1 >= chunk.len)
485 {
486 *pos++ = b64digits[(chunk.ptr[i] & 0x03) << 4];
487 *pos++ = '=';
488 *pos++ = '=';
489 break;
490 }
491 *pos++ = b64digits[((chunk.ptr[i] & 0x03) << 4) | (chunk.ptr[i+1] >> 4)];
492 if (i+2 >= chunk.len)
493 {
494 *pos++ = b64digits[(chunk.ptr[i+1] & 0x0F) << 2];
495 *pos++ = '=';
496 break;
497 }
498 *pos++ = b64digits[((chunk.ptr[i+1] & 0x0F) << 2) | (chunk.ptr[i+2] >> 6)];
499 *pos++ = b64digits[chunk.ptr[i+2] & 0x3F];
500 }
501 *pos = '\0';
502 return chunk_create(buf, len * 4 / 3);
503 }
504
505 /**
506 * convert a base 64 digit to its binary form (inversion of b64digits array)
507 */
508 static int b642bin(char b64)
509 {
510 switch (b64)
511 {
512 case 'A' ... 'Z':
513 return b64 - 'A';
514 case 'a' ... 'z':
515 return ('Z' - 'A' + 1) + b64 - 'a';
516 case '0' ... '9':
517 return ('Z' - 'A' + 1) + ('z' - 'a' + 1) + b64 - '0';
518 case '+':
519 case '-':
520 return 62;
521 case '/':
522 case '_':
523 return 63;
524 case '=':
525 return 0;
526 default:
527 return -1;
528 }
529 }
530
531 /**
532 * Described in header.
533 */
534 chunk_t chunk_from_base64(chunk_t base64, char *buf)
535 {
536 u_char *pos, byte[4];
537 int i, j, len, outlen;
538
539 len = base64.len / 4 * 3;
540 if (!buf)
541 {
542 buf = malloc(len);
543 }
544 pos = base64.ptr;
545 outlen = 0;
546 for (i = 0; i < len; i+=3)
547 {
548 outlen += 3;
549 for (j = 0; j < 4; j++)
550 {
551 if (*pos == '=')
552 {
553 outlen--;
554 }
555 byte[j] = b642bin(*pos++);
556 }
557 buf[i] = (byte[0] << 2) | (byte[1] >> 4);
558 buf[i+1] = (byte[1] << 4) | (byte[2] >> 2);
559 buf[i+2] = (byte[2] << 6) | (byte[3]);
560 }
561 return chunk_create(buf, outlen);
562 }
563
564 /** base 32 conversion digits */
565 static char b32digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
566
567 /**
568 * Described in header.
569 */
570 chunk_t chunk_to_base32(chunk_t chunk, char *buf)
571 {
572 int i, len;
573 char *pos;
574
575 len = chunk.len + ((5 - chunk.len % 5) % 5);
576 if (!buf)
577 {
578 buf = malloc(len * 8 / 5 + 1);
579 }
580 pos = buf;
581 for (i = 0; i < len; i+=5)
582 {
583 *pos++ = b32digits[chunk.ptr[i] >> 3];
584 if (i+1 >= chunk.len)
585 {
586 *pos++ = b32digits[(chunk.ptr[i] & 0x07) << 2];
587 memset(pos, '=', 6);
588 pos += 6;
589 break;
590 }
591 *pos++ = b32digits[((chunk.ptr[i] & 0x07) << 2) |
592 (chunk.ptr[i+1] >> 6)];
593 *pos++ = b32digits[(chunk.ptr[i+1] & 0x3E) >> 1];
594 if (i+2 >= chunk.len)
595 {
596 *pos++ = b32digits[(chunk.ptr[i+1] & 0x01) << 4];
597 memset(pos, '=', 4);
598 pos += 4;
599 break;
600 }
601 *pos++ = b32digits[((chunk.ptr[i+1] & 0x01) << 4) |
602 (chunk.ptr[i+2] >> 4)];
603 if (i+3 >= chunk.len)
604 {
605 *pos++ = b32digits[(chunk.ptr[i+2] & 0x0F) << 1];
606 memset(pos, '=', 3);
607 pos += 3;
608 break;
609 }
610 *pos++ = b32digits[((chunk.ptr[i+2] & 0x0F) << 1) |
611 (chunk.ptr[i+3] >> 7)];
612 *pos++ = b32digits[(chunk.ptr[i+3] & 0x7F) >> 2];
613 if (i+4 >= chunk.len)
614 {
615 *pos++ = b32digits[(chunk.ptr[i+3] & 0x03) << 3];
616 *pos++ = '=';
617 break;
618 }
619 *pos++ = b32digits[((chunk.ptr[i+3] & 0x03) << 3) |
620 (chunk.ptr[i+4] >> 5)];
621 *pos++ = b32digits[chunk.ptr[i+4] & 0x1F];
622 }
623 *pos = '\0';
624 return chunk_create(buf, len * 8 / 5);
625 }
626
627 /**
628 * Described in header.
629 */
630 int chunk_compare(chunk_t a, chunk_t b)
631 {
632 int compare_len = a.len - b.len;
633 int len = (compare_len < 0)? a.len : b.len;
634
635 if (compare_len != 0 || len == 0)
636 {
637 return compare_len;
638 }
639 return memcmp(a.ptr, b.ptr, len);
640 };
641
642
643 /**
644 * Described in header.
645 */
646 bool chunk_increment(chunk_t chunk)
647 {
648 int i;
649
650 for (i = chunk.len - 1; i >= 0; i--)
651 {
652 if (++chunk.ptr[i] != 0)
653 {
654 return FALSE;
655 }
656 }
657 return TRUE;
658 }
659
660 /**
661 * Remove non-printable characters from a chunk.
662 */
663 bool chunk_printable(chunk_t chunk, chunk_t *sane, char replace)
664 {
665 bool printable = TRUE;
666 int i;
667
668 if (sane)
669 {
670 *sane = chunk_clone(chunk);
671 }
672 for (i = 0; i < chunk.len; i++)
673 {
674 if (!isprint(chunk.ptr[i]))
675 {
676 if (sane)
677 {
678 sane->ptr[i] = replace;
679 }
680 printable = FALSE;
681 }
682 }
683 return printable;
684 }
685
686 /**
687 * Helper functions for chunk_mac()
688 */
689 static inline u_int64_t sipget(u_char *in)
690 {
691 u_int64_t v = 0;
692 int i;
693
694 for (i = 0; i < 64; i += 8, ++in)
695 {
696 v |= ((u_int64_t)*in) << i;
697 }
698 return v;
699 }
700
701 static inline u_int64_t siprotate(u_int64_t v, int shift)
702 {
703 return (v << shift) | (v >> (64 - shift));
704 }
705
706 static inline void sipround(u_int64_t *v0, u_int64_t *v1, u_int64_t *v2,
707 u_int64_t *v3)
708 {
709 *v0 += *v1;
710 *v1 = siprotate(*v1, 13);
711 *v1 ^= *v0;
712 *v0 = siprotate(*v0, 32);
713
714 *v2 += *v3;
715 *v3 = siprotate(*v3, 16);
716 *v3 ^= *v2;
717
718 *v2 += *v1;
719 *v1 = siprotate(*v1, 17);
720 *v1 ^= *v2;
721 *v2 = siprotate(*v2, 32);
722
723 *v0 += *v3;
724 *v3 = siprotate(*v3, 21);
725 *v3 ^= *v0;
726 }
727
728 static inline void sipcompress(u_int64_t *v0, u_int64_t *v1, u_int64_t *v2,
729 u_int64_t *v3, u_int64_t m)
730 {
731 *v3 ^= m;
732 sipround(v0, v1, v2, v3);
733 sipround(v0, v1, v2, v3);
734 *v0 ^= m;
735 }
736
737 static inline u_int64_t siplast(size_t len, u_char *pos)
738 {
739 u_int64_t b;
740 int rem = len & 7;
741
742 b = ((u_int64_t)len) << 56;
743 switch (rem)
744 {
745 case 7:
746 b |= ((u_int64_t)pos[6]) << 48;
747 case 6:
748 b |= ((u_int64_t)pos[5]) << 40;
749 case 5:
750 b |= ((u_int64_t)pos[4]) << 32;
751 case 4:
752 b |= ((u_int64_t)pos[3]) << 24;
753 case 3:
754 b |= ((u_int64_t)pos[2]) << 16;
755 case 2:
756 b |= ((u_int64_t)pos[1]) << 8;
757 case 1:
758 b |= ((u_int64_t)pos[0]);
759 break;
760 case 0:
761 break;
762 }
763 return b;
764 }
765
766 /**
767 * Caculate SipHash-2-4 with an optional first block given as argument.
768 */
769 static u_int64_t chunk_mac_inc(chunk_t chunk, u_char *key, u_int64_t m)
770 {
771 u_int64_t v0, v1, v2, v3, k0, k1;
772 size_t len = chunk.len;
773 u_char *pos = chunk.ptr, *end;
774
775 end = chunk.ptr + len - (len % 8);
776
777 k0 = sipget(key);
778 k1 = sipget(key + 8);
779
780 v0 = k0 ^ 0x736f6d6570736575ULL;
781 v1 = k1 ^ 0x646f72616e646f6dULL;
782 v2 = k0 ^ 0x6c7967656e657261ULL;
783 v3 = k1 ^ 0x7465646279746573ULL;
784
785 if (m)
786 {
787 sipcompress(&v0, &v1, &v2, &v3, m);
788 }
789
790 /* compression with c = 2 */
791 for (; pos != end; pos += 8)
792 {
793 m = sipget(pos);
794 sipcompress(&v0, &v1, &v2, &v3, m);
795 }
796 sipcompress(&v0, &v1, &v2, &v3, siplast(len, pos));
797
798 /* finalization with d = 4 */
799 v2 ^= 0xff;
800 sipround(&v0, &v1, &v2, &v3);
801 sipround(&v0, &v1, &v2, &v3);
802 sipround(&v0, &v1, &v2, &v3);
803 sipround(&v0, &v1, &v2, &v3);
804 return v0 ^ v1 ^ v2 ^ v3;
805 }
806
807 /**
808 * Described in header.
809 */
810 u_int64_t chunk_mac(chunk_t chunk, u_char *key)
811 {
812 return chunk_mac_inc(chunk, key, 0);
813 }
814
815 /**
816 * Secret key allocated randomly during first use.
817 */
818 static u_char key[16];
819
820 /**
821 * Static key used in case predictable hash values are required.
822 */
823 static u_char static_key[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
824 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
825
826 /**
827 * Only allocate the key once
828 */
829 static pthread_once_t key_allocated = PTHREAD_ONCE_INIT;
830
831 /**
832 * Allocate a key on first use, we do this manually to avoid dependencies on
833 * plugins.
834 */
835 static void allocate_key()
836 {
837 ssize_t len;
838 size_t done = 0;
839 int fd;
840
841 fd = open("/dev/urandom", O_RDONLY);
842 if (fd >= 0)
843 {
844 while (done < sizeof(key))
845 {
846 len = read(fd, key + done, sizeof(key) - done);
847 if (len < 0)
848 {
849 break;
850 }
851 done += len;
852 }
853 close(fd);
854 }
855 /* on error we use random() to generate the key (better than nothing) */
856 if (done < sizeof(key))
857 {
858 srandom(time(NULL) + getpid());
859 for (; done < sizeof(key); done++)
860 {
861 key[done] = (u_char)random();
862 }
863 }
864 }
865
866 /**
867 * Described in header.
868 */
869 u_int32_t chunk_hash_inc(chunk_t chunk, u_int32_t hash)
870 {
871 pthread_once(&key_allocated, allocate_key);
872 /* we could use a mac of the previous hash, but this is faster */
873 return chunk_mac_inc(chunk, key, ((u_int64_t)hash) << 32 | hash);
874 }
875
876 /**
877 * Described in header.
878 */
879 u_int32_t chunk_hash(chunk_t chunk)
880 {
881 pthread_once(&key_allocated, allocate_key);
882 return chunk_mac(chunk, key);
883 }
884
885 /**
886 * Described in header.
887 */
888 u_int32_t chunk_hash_static_inc(chunk_t chunk, u_int32_t hash)
889 { /* we could use a mac of the previous hash, but this is faster */
890 return chunk_mac_inc(chunk, static_key, ((u_int64_t)hash) << 32 | hash);
891 }
892
893 /**
894 * Described in header.
895 */
896 u_int32_t chunk_hash_static(chunk_t chunk)
897 {
898 return chunk_mac(chunk, static_key);
899 }
900
901 /**
902 * Described in header.
903 */
904 int chunk_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
905 const void *const *args)
906 {
907 chunk_t *chunk = *((chunk_t**)(args[0]));
908 bool first = TRUE;
909 chunk_t copy = *chunk;
910 int written = 0;
911
912 if (!spec->hash && !spec->plus)
913 {
914 u_int chunk_len = chunk->len;
915 const void *new_args[] = {&chunk->ptr, &chunk_len};
916 return mem_printf_hook(data, spec, new_args);
917 }
918
919 while (copy.len > 0)
920 {
921 if (first)
922 {
923 first = FALSE;
924 }
925 else if (!spec->plus)
926 {
927 written += print_in_hook(data, ":");
928 }
929 written += print_in_hook(data, "%02x", *copy.ptr++);
930 copy.len--;
931 }
932 return written;
933 }