Annotation of embedaddon/strongswan/src/libstrongswan/utils/chunk.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2008-2019 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: * Described in header
757: */
758: chunk_t chunk_copy_pad(chunk_t dst, chunk_t src, u_char chr)
759: {
760: if (dst.ptr)
761: {
762: if (dst.len > src.len)
763: {
764: memcpy(dst.ptr + dst.len - src.len, src.ptr, src.len);
765: memset(dst.ptr, chr, dst.len - src.len);
766: }
767: else
768: {
769: memcpy(dst.ptr, src.ptr + src.len - dst.len, dst.len);
770: }
771: }
772: return dst;
773: }
774:
775: /**
776: * Remove non-printable characters from a chunk.
777: */
778: bool chunk_printable(chunk_t chunk, chunk_t *sane, char replace)
779: {
780: bool printable = TRUE;
781: int i;
782:
783: if (sane)
784: {
785: *sane = chunk_clone(chunk);
786: }
787: for (i = 0; i < chunk.len; i++)
788: {
789: if (!isprint(chunk.ptr[i]))
790: {
791: if (sane)
792: {
793: sane->ptr[i] = replace;
794: }
795: printable = FALSE;
796: }
797: }
798: return printable;
799: }
800:
801: /**
802: * Helper functions for chunk_mac()
803: */
804: static inline uint64_t sipget(u_char *in)
805: {
806: uint64_t v = 0;
807: int i;
808:
809: for (i = 0; i < 64; i += 8, ++in)
810: {
811: v |= ((uint64_t)*in) << i;
812: }
813: return v;
814: }
815:
816: static inline uint64_t siprotate(uint64_t v, int shift)
817: {
818: return (v << shift) | (v >> (64 - shift));
819: }
820:
821: static inline void sipround(uint64_t *v0, uint64_t *v1, uint64_t *v2,
822: uint64_t *v3)
823: {
824: *v0 += *v1;
825: *v1 = siprotate(*v1, 13);
826: *v1 ^= *v0;
827: *v0 = siprotate(*v0, 32);
828:
829: *v2 += *v3;
830: *v3 = siprotate(*v3, 16);
831: *v3 ^= *v2;
832:
833: *v2 += *v1;
834: *v1 = siprotate(*v1, 17);
835: *v1 ^= *v2;
836: *v2 = siprotate(*v2, 32);
837:
838: *v0 += *v3;
839: *v3 = siprotate(*v3, 21);
840: *v3 ^= *v0;
841: }
842:
843: static inline void sipcompress(uint64_t *v0, uint64_t *v1, uint64_t *v2,
844: uint64_t *v3, uint64_t m)
845: {
846: *v3 ^= m;
847: sipround(v0, v1, v2, v3);
848: sipround(v0, v1, v2, v3);
849: *v0 ^= m;
850: }
851:
852: static inline uint64_t siplast(size_t len, u_char *pos)
853: {
854: uint64_t b;
855: int rem = len & 7;
856:
857: b = ((uint64_t)len) << 56;
858: switch (rem)
859: {
860: case 7:
861: b |= ((uint64_t)pos[6]) << 48;
862: case 6:
863: b |= ((uint64_t)pos[5]) << 40;
864: case 5:
865: b |= ((uint64_t)pos[4]) << 32;
866: case 4:
867: b |= ((uint64_t)pos[3]) << 24;
868: case 3:
869: b |= ((uint64_t)pos[2]) << 16;
870: case 2:
871: b |= ((uint64_t)pos[1]) << 8;
872: case 1:
873: b |= ((uint64_t)pos[0]);
874: break;
875: case 0:
876: break;
877: }
878: return b;
879: }
880:
881: /**
882: * Calculate SipHash-2-4 with an optional first block given as argument.
883: */
884: static uint64_t chunk_mac_inc(chunk_t chunk, u_char *key, uint64_t m)
885: {
886: uint64_t v0, v1, v2, v3, k0, k1;
887: size_t len = chunk.len;
888: u_char *pos = chunk.ptr, *end;
889:
890: end = chunk.ptr + len - (len % 8);
891:
892: k0 = sipget(key);
893: k1 = sipget(key + 8);
894:
895: v0 = k0 ^ 0x736f6d6570736575ULL;
896: v1 = k1 ^ 0x646f72616e646f6dULL;
897: v2 = k0 ^ 0x6c7967656e657261ULL;
898: v3 = k1 ^ 0x7465646279746573ULL;
899:
900: if (m)
901: {
902: sipcompress(&v0, &v1, &v2, &v3, m);
903: }
904:
905: /* compression with c = 2 */
906: for (; pos != end; pos += 8)
907: {
908: m = sipget(pos);
909: sipcompress(&v0, &v1, &v2, &v3, m);
910: }
911: sipcompress(&v0, &v1, &v2, &v3, siplast(len, pos));
912:
913: /* finalization with d = 4 */
914: v2 ^= 0xff;
915: sipround(&v0, &v1, &v2, &v3);
916: sipround(&v0, &v1, &v2, &v3);
917: sipround(&v0, &v1, &v2, &v3);
918: sipround(&v0, &v1, &v2, &v3);
919: return v0 ^ v1 ^ v2 ^ v3;
920: }
921:
922: /**
923: * Described in header.
924: */
925: uint64_t chunk_mac(chunk_t chunk, u_char *key)
926: {
927: return chunk_mac_inc(chunk, key, 0);
928: }
929:
930: /**
931: * Secret key allocated randomly with chunk_hash_seed().
932: */
933: static u_char hash_key[16] = {};
934:
935: /**
936: * Static key used in case predictable hash values are required.
937: */
938: static u_char static_key[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
939: 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
940:
941: /**
942: * See header
943: */
944: void chunk_hash_seed()
945: {
946: static bool seeded = FALSE;
947: ssize_t len;
948: size_t done = 0;
949: int fd;
950:
951: if (seeded)
952: {
953: /* just once to have the same seed during the whole process lifetimes */
954: return;
955: }
956:
957: fd = open("/dev/urandom", O_RDONLY);
958: if (fd >= 0)
959: {
960: while (done < sizeof(hash_key))
961: {
962: len = read(fd, hash_key + done, sizeof(hash_key) - done);
963: if (len < 0)
964: {
965: break;
966: }
967: done += len;
968: }
969: close(fd);
970: }
971: /* on error we use random() to generate the key (better than nothing) */
972: if (done < sizeof(hash_key))
973: {
974: srandom(time(NULL) + getpid());
975: for (; done < sizeof(hash_key); done++)
976: {
977: hash_key[done] = (u_char)random();
978: }
979: }
980: seeded = TRUE;
981: }
982:
983: /**
984: * Described in header.
985: */
986: uint32_t chunk_hash_inc(chunk_t chunk, uint32_t hash)
987: {
988: /* we could use a mac of the previous hash, but this is faster */
989: return chunk_mac_inc(chunk, hash_key, ((uint64_t)hash) << 32 | hash);
990: }
991:
992: /**
993: * Described in header.
994: */
995: uint32_t chunk_hash(chunk_t chunk)
996: {
997: return chunk_mac(chunk, hash_key);
998: }
999:
1000: /**
1001: * Described in header.
1002: */
1003: uint32_t chunk_hash_static_inc(chunk_t chunk, uint32_t hash)
1004: { /* we could use a mac of the previous hash, but this is faster */
1005: return chunk_mac_inc(chunk, static_key, ((uint64_t)hash) << 32 | hash);
1006: }
1007:
1008: /**
1009: * Described in header.
1010: */
1011: uint32_t chunk_hash_static(chunk_t chunk)
1012: {
1013: return chunk_mac(chunk, static_key);
1014: }
1015:
1016: /**
1017: * Described in header.
1018: */
1019: uint16_t chunk_internet_checksum_inc(chunk_t data, uint16_t checksum)
1020: {
1021: uint32_t sum = ntohs((uint16_t)~checksum);
1022:
1023: while (data.len > 1)
1024: {
1025: sum += untoh16(data.ptr);
1026: data = chunk_skip(data, 2);
1027: }
1028: if (data.len)
1029: {
1030: sum += (uint16_t)*data.ptr << 8;
1031: }
1032: while (sum >> 16)
1033: {
1034: sum = (sum & 0xffff) + (sum >> 16);
1035: }
1036: return htons(~sum);
1037: }
1038:
1039: /**
1040: * Described in header.
1041: */
1042: uint16_t chunk_internet_checksum(chunk_t data)
1043: {
1044: return chunk_internet_checksum_inc(data, 0xffff);
1045: }
1046:
1047: /**
1048: * Described in header.
1049: */
1050: int chunk_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
1051: const void *const *args)
1052: {
1053: chunk_t *chunk = *((chunk_t**)(args[0]));
1054: bool first = TRUE;
1055: chunk_t copy = *chunk;
1056: int written = 0;
1057:
1058: if (!spec->hash && !spec->plus)
1059: {
1060: u_int chunk_len = chunk->len;
1061: const void *new_args[] = {&chunk->ptr, &chunk_len};
1062: return mem_printf_hook(data, spec, new_args);
1063: }
1064:
1065: while (copy.len > 0)
1066: {
1067: if (first)
1068: {
1069: first = FALSE;
1070: }
1071: else if (!spec->plus)
1072: {
1073: written += print_in_hook(data, ":");
1074: }
1075: written += print_in_hook(data, "%02x", *copy.ptr++);
1076: copy.len--;
1077: }
1078: return written;
1079: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>