Replace chunk_hash() with output from chunk_mac()
[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/stat.h>
20 #include <unistd.h>
21 #include <errno.h>
22 #include <ctype.h>
23
24 #include "chunk.h"
25 #include "debug.h"
26
27 /**
28 * Empty chunk.
29 */
30 chunk_t chunk_empty = { NULL, 0 };
31
32 /**
33 * Described in header.
34 */
35 chunk_t chunk_create_clone(u_char *ptr, chunk_t chunk)
36 {
37 chunk_t clone = chunk_empty;
38
39 if (chunk.ptr && chunk.len > 0)
40 {
41 clone.ptr = ptr;
42 clone.len = chunk.len;
43 memcpy(clone.ptr, chunk.ptr, chunk.len);
44 }
45
46 return clone;
47 }
48
49 /**
50 * Described in header.
51 */
52 size_t chunk_length(const char* mode, ...)
53 {
54 va_list chunks;
55 size_t length = 0;
56
57 va_start(chunks, mode);
58 while (TRUE)
59 {
60 switch (*mode++)
61 {
62 case 'm':
63 case 'c':
64 case 's':
65 {
66 chunk_t ch = va_arg(chunks, chunk_t);
67 length += ch.len;
68 continue;
69 }
70 default:
71 break;
72 }
73 break;
74 }
75 va_end(chunks);
76 return length;
77 }
78
79 /**
80 * Described in header.
81 */
82 chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...)
83 {
84 va_list chunks;
85 chunk_t construct = chunk_create(ptr, 0);
86
87 va_start(chunks, mode);
88 while (TRUE)
89 {
90 bool free_chunk = FALSE, clear_chunk = FALSE;
91 chunk_t ch;
92
93 switch (*mode++)
94 {
95 case 's':
96 clear_chunk = TRUE;
97 /* FALL */
98 case 'm':
99 free_chunk = TRUE;
100 /* FALL */
101 case 'c':
102 ch = va_arg(chunks, chunk_t);
103 memcpy(ptr, ch.ptr, ch.len);
104 ptr += ch.len;
105 construct.len += ch.len;
106 if (clear_chunk)
107 {
108 chunk_clear(&ch);
109 }
110 else if (free_chunk)
111 {
112 free(ch.ptr);
113 }
114 continue;
115 default:
116 break;
117 }
118 break;
119 }
120 va_end(chunks);
121
122 return construct;
123 }
124
125 /**
126 * Described in header.
127 */
128 void chunk_split(chunk_t chunk, const char *mode, ...)
129 {
130 va_list chunks;
131 u_int len;
132 chunk_t *ch;
133
134 va_start(chunks, mode);
135 while (TRUE)
136 {
137 if (*mode == '\0')
138 {
139 break;
140 }
141 len = va_arg(chunks, u_int);
142 ch = va_arg(chunks, chunk_t*);
143 /* a null chunk means skip len bytes */
144 if (ch == NULL)
145 {
146 chunk = chunk_skip(chunk, len);
147 continue;
148 }
149 switch (*mode++)
150 {
151 case 'm':
152 {
153 ch->len = min(chunk.len, len);
154 if (ch->len)
155 {
156 ch->ptr = chunk.ptr;
157 }
158 else
159 {
160 ch->ptr = NULL;
161 }
162 chunk = chunk_skip(chunk, ch->len);
163 continue;
164 }
165 case 'a':
166 {
167 ch->len = min(chunk.len, len);
168 if (ch->len)
169 {
170 ch->ptr = malloc(ch->len);
171 memcpy(ch->ptr, chunk.ptr, ch->len);
172 }
173 else
174 {
175 ch->ptr = NULL;
176 }
177 chunk = chunk_skip(chunk, ch->len);
178 continue;
179 }
180 case 'c':
181 {
182 ch->len = min(ch->len, chunk.len);
183 ch->len = min(ch->len, len);
184 if (ch->len)
185 {
186 memcpy(ch->ptr, chunk.ptr, ch->len);
187 }
188 else
189 {
190 ch->ptr = NULL;
191 }
192 chunk = chunk_skip(chunk, ch->len);
193 continue;
194 }
195 default:
196 break;
197 }
198 break;
199 }
200 va_end(chunks);
201 }
202
203 /**
204 * Described in header.
205 */
206 bool chunk_write(chunk_t chunk, char *path, char *label, mode_t mask, bool force)
207 {
208 mode_t oldmask;
209 FILE *fd;
210 bool good = FALSE;
211
212 if (!force && access(path, F_OK) == 0)
213 {
214 DBG1(DBG_LIB, " %s file '%s' already exists", label, path);
215 return FALSE;
216 }
217 oldmask = umask(mask);
218 fd = fopen(path, "w");
219 if (fd)
220 {
221 if (fwrite(chunk.ptr, sizeof(u_char), chunk.len, fd) == chunk.len)
222 {
223 DBG1(DBG_LIB, " written %s file '%s' (%d bytes)",
224 label, path, chunk.len);
225 good = TRUE;
226 }
227 else
228 {
229 DBG1(DBG_LIB, " writing %s file '%s' failed: %s",
230 label, path, strerror(errno));
231 }
232 fclose(fd);
233 }
234 else
235 {
236 DBG1(DBG_LIB, " could not open %s file '%s': %s", label, path,
237 strerror(errno));
238 }
239 umask(oldmask);
240 return good;
241 }
242
243
244 /** hex conversion digits */
245 static char hexdig_upper[] = "0123456789ABCDEF";
246 static char hexdig_lower[] = "0123456789abcdef";
247
248 /**
249 * Described in header.
250 */
251 chunk_t chunk_to_hex(chunk_t chunk, char *buf, bool uppercase)
252 {
253 int i, len;
254 char *hexdig = hexdig_lower;
255
256 if (uppercase)
257 {
258 hexdig = hexdig_upper;
259 }
260
261 len = chunk.len * 2;
262 if (!buf)
263 {
264 buf = malloc(len + 1);
265 }
266 buf[len] = '\0';
267
268 for (i = 0; i < chunk.len; i++)
269 {
270 buf[i*2] = hexdig[(chunk.ptr[i] >> 4) & 0xF];
271 buf[i*2+1] = hexdig[(chunk.ptr[i] ) & 0xF];
272 }
273 return chunk_create(buf, len);
274 }
275
276 /**
277 * convert a signle hex character to its binary value
278 */
279 static char hex2bin(char hex)
280 {
281 switch (hex)
282 {
283 case '0' ... '9':
284 return hex - '0';
285 case 'A' ... 'F':
286 return hex - 'A' + 10;
287 case 'a' ... 'f':
288 return hex - 'a' + 10;
289 default:
290 return 0;
291 }
292 }
293
294 /**
295 * Described in header.
296 */
297 chunk_t chunk_from_hex(chunk_t hex, char *buf)
298 {
299 int i, len;
300 u_char *ptr;
301 bool odd = FALSE;
302
303 /* subtract the number of optional ':' separation characters */
304 len = hex.len;
305 ptr = hex.ptr;
306 for (i = 0; i < hex.len; i++)
307 {
308 if (*ptr++ == ':')
309 {
310 len--;
311 }
312 }
313
314 /* compute the number of binary bytes */
315 if (len % 2)
316 {
317 odd = TRUE;
318 len++;
319 }
320 len /= 2;
321
322 /* allocate buffer memory unless provided by caller */
323 if (!buf)
324 {
325 buf = malloc(len);
326 }
327
328 /* buffer is filled from the right */
329 memset(buf, 0, len);
330 hex.ptr += hex.len;
331
332 for (i = len - 1; i >= 0; i--)
333 {
334 /* skip separation characters */
335 if (*(--hex.ptr) == ':')
336 {
337 --hex.ptr;
338 }
339 buf[i] = hex2bin(*hex.ptr);
340 if (i > 0 || !odd)
341 {
342 buf[i] |= hex2bin(*(--hex.ptr)) << 4;
343 }
344 }
345 return chunk_create(buf, len);
346 }
347
348 /** base 64 conversion digits */
349 static char b64digits[] =
350 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
351
352 /**
353 * Described in header.
354 */
355 chunk_t chunk_to_base64(chunk_t chunk, char *buf)
356 {
357 int i, len;
358 char *pos;
359
360 len = chunk.len + ((3 - chunk.len % 3) % 3);
361 if (!buf)
362 {
363 buf = malloc(len * 4 / 3 + 1);
364 }
365 pos = buf;
366 for (i = 0; i < len; i+=3)
367 {
368 *pos++ = b64digits[chunk.ptr[i] >> 2];
369 if (i+1 >= chunk.len)
370 {
371 *pos++ = b64digits[(chunk.ptr[i] & 0x03) << 4];
372 *pos++ = '=';
373 *pos++ = '=';
374 break;
375 }
376 *pos++ = b64digits[((chunk.ptr[i] & 0x03) << 4) | (chunk.ptr[i+1] >> 4)];
377 if (i+2 >= chunk.len)
378 {
379 *pos++ = b64digits[(chunk.ptr[i+1] & 0x0F) << 2];
380 *pos++ = '=';
381 break;
382 }
383 *pos++ = b64digits[((chunk.ptr[i+1] & 0x0F) << 2) | (chunk.ptr[i+2] >> 6)];
384 *pos++ = b64digits[chunk.ptr[i+2] & 0x3F];
385 }
386 *pos = '\0';
387 return chunk_create(buf, len * 4 / 3);
388 }
389
390 /**
391 * convert a base 64 digit to its binary form (inversion of b64digits array)
392 */
393 static int b642bin(char b64)
394 {
395 switch (b64)
396 {
397 case 'A' ... 'Z':
398 return b64 - 'A';
399 case 'a' ... 'z':
400 return ('Z' - 'A' + 1) + b64 - 'a';
401 case '0' ... '9':
402 return ('Z' - 'A' + 1) + ('z' - 'a' + 1) + b64 - '0';
403 case '+':
404 case '-':
405 return 62;
406 case '/':
407 case '_':
408 return 63;
409 case '=':
410 return 0;
411 default:
412 return -1;
413 }
414 }
415
416 /**
417 * Described in header.
418 */
419 chunk_t chunk_from_base64(chunk_t base64, char *buf)
420 {
421 u_char *pos, byte[4];
422 int i, j, len, outlen;
423
424 len = base64.len / 4 * 3;
425 if (!buf)
426 {
427 buf = malloc(len);
428 }
429 pos = base64.ptr;
430 outlen = 0;
431 for (i = 0; i < len; i+=3)
432 {
433 outlen += 3;
434 for (j = 0; j < 4; j++)
435 {
436 if (*pos == '=')
437 {
438 outlen--;
439 }
440 byte[j] = b642bin(*pos++);
441 }
442 buf[i] = (byte[0] << 2) | (byte[1] >> 4);
443 buf[i+1] = (byte[1] << 4) | (byte[2] >> 2);
444 buf[i+2] = (byte[2] << 6) | (byte[3]);
445 }
446 return chunk_create(buf, outlen);
447 }
448
449 /** base 32 conversion digits */
450 static char b32digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
451
452 /**
453 * Described in header.
454 */
455 chunk_t chunk_to_base32(chunk_t chunk, char *buf)
456 {
457 int i, len;
458 char *pos;
459
460 len = chunk.len + ((5 - chunk.len % 5) % 5);
461 if (!buf)
462 {
463 buf = malloc(len * 8 / 5 + 1);
464 }
465 pos = buf;
466 for (i = 0; i < len; i+=5)
467 {
468 *pos++ = b32digits[chunk.ptr[i] >> 3];
469 if (i+1 >= chunk.len)
470 {
471 *pos++ = b32digits[(chunk.ptr[i] & 0x07) << 2];
472 memset(pos, '=', 6);
473 pos += 6;
474 break;
475 }
476 *pos++ = b32digits[((chunk.ptr[i] & 0x07) << 2) |
477 (chunk.ptr[i+1] >> 6)];
478 *pos++ = b32digits[(chunk.ptr[i+1] & 0x3E) >> 1];
479 if (i+2 >= chunk.len)
480 {
481 *pos++ = b32digits[(chunk.ptr[i+1] & 0x01) << 4];
482 memset(pos, '=', 4);
483 pos += 4;
484 break;
485 }
486 *pos++ = b32digits[((chunk.ptr[i+1] & 0x01) << 4) |
487 (chunk.ptr[i+2] >> 4)];
488 if (i+3 >= chunk.len)
489 {
490 *pos++ = b32digits[(chunk.ptr[i+2] & 0x0F) << 1];
491 memset(pos, '=', 3);
492 pos += 3;
493 break;
494 }
495 *pos++ = b32digits[((chunk.ptr[i+2] & 0x0F) << 1) |
496 (chunk.ptr[i+3] >> 7)];
497 *pos++ = b32digits[(chunk.ptr[i+3] & 0x7F) >> 2];
498 if (i+4 >= chunk.len)
499 {
500 *pos++ = b32digits[(chunk.ptr[i+3] & 0x03) << 3];
501 *pos++ = '=';
502 break;
503 }
504 *pos++ = b32digits[((chunk.ptr[i+3] & 0x03) << 3) |
505 (chunk.ptr[i+4] >> 5)];
506 *pos++ = b32digits[chunk.ptr[i+4] & 0x1F];
507 }
508 *pos = '\0';
509 return chunk_create(buf, len * 8 / 5);
510 }
511
512 /**
513 * Described in header.
514 */
515 int chunk_compare(chunk_t a, chunk_t b)
516 {
517 int compare_len = a.len - b.len;
518 int len = (compare_len < 0)? a.len : b.len;
519
520 if (compare_len != 0 || len == 0)
521 {
522 return compare_len;
523 }
524 return memcmp(a.ptr, b.ptr, len);
525 };
526
527
528 /**
529 * Described in header.
530 */
531 bool chunk_increment(chunk_t chunk)
532 {
533 int i;
534
535 for (i = chunk.len - 1; i >= 0; i--)
536 {
537 if (++chunk.ptr[i] != 0)
538 {
539 return FALSE;
540 }
541 }
542 return TRUE;
543 }
544
545 /**
546 * Remove non-printable characters from a chunk.
547 */
548 bool chunk_printable(chunk_t chunk, chunk_t *sane, char replace)
549 {
550 bool printable = TRUE;
551 int i;
552
553 if (sane)
554 {
555 *sane = chunk_clone(chunk);
556 }
557 for (i = 0; i < chunk.len; i++)
558 {
559 if (!isprint(chunk.ptr[i]))
560 {
561 if (sane)
562 {
563 sane->ptr[i] = replace;
564 }
565 printable = FALSE;
566 }
567 }
568 return printable;
569 }
570
571 /**
572 * Helper functions for chunk_mac()
573 */
574 static inline u_int64_t sipget(u_char *in)
575 {
576 u_int64_t v = 0;
577 int i;
578
579 for (i = 0; i < 64; i += 8, ++in)
580 {
581 v |= ((u_int64_t)*in) << i;
582 }
583 return v;
584 }
585
586 static inline u_int64_t siprotate(u_int64_t v, int shift)
587 {
588 return (v << shift) | (v >> (64 - shift));
589 }
590
591 static inline void sipround(u_int64_t *v0, u_int64_t *v1, u_int64_t *v2,
592 u_int64_t *v3)
593 {
594 *v0 += *v1;
595 *v1 = siprotate(*v1, 13);
596 *v1 ^= *v0;
597 *v0 = siprotate(*v0, 32);
598
599 *v2 += *v3;
600 *v3 = siprotate(*v3, 16);
601 *v3 ^= *v2;
602
603 *v2 += *v1;
604 *v1 = siprotate(*v1, 17);
605 *v1 ^= *v2;
606 *v2 = siprotate(*v2, 32);
607
608 *v0 += *v3;
609 *v3 = siprotate(*v3, 21);
610 *v3 ^= *v0;
611 }
612
613 static inline void sipcompress(u_int64_t *v0, u_int64_t *v1, u_int64_t *v2,
614 u_int64_t *v3, u_int64_t m)
615 {
616 *v3 ^= m;
617 sipround(v0, v1, v2, v3);
618 sipround(v0, v1, v2, v3);
619 *v0 ^= m;
620 }
621
622 static inline u_int64_t siplast(size_t len, u_char *pos)
623 {
624 u_int64_t b;
625 int rem = len & 7;
626
627 b = ((u_int64_t)len) << 56;
628 switch (rem)
629 {
630 case 7:
631 b |= ((u_int64_t)pos[6]) << 48;
632 case 6:
633 b |= ((u_int64_t)pos[5]) << 40;
634 case 5:
635 b |= ((u_int64_t)pos[4]) << 32;
636 case 4:
637 b |= ((u_int64_t)pos[3]) << 24;
638 case 3:
639 b |= ((u_int64_t)pos[2]) << 16;
640 case 2:
641 b |= ((u_int64_t)pos[1]) << 8;
642 case 1:
643 b |= ((u_int64_t)pos[0]);
644 break;
645 case 0:
646 break;
647 }
648 return b;
649 }
650
651 /**
652 * Caculate SipHash-2-4 with an optional first block given as argument.
653 */
654 static u_int64_t chunk_mac_inc(chunk_t chunk, u_char *key, u_int64_t m)
655 {
656 u_int64_t v0, v1, v2, v3, k0, k1;
657 size_t len = chunk.len;
658 u_char *pos = chunk.ptr, *end;
659
660 end = chunk.ptr + len - (len % 8);
661
662 k0 = sipget(key);
663 k1 = sipget(key + 8);
664
665 v0 = k0 ^ 0x736f6d6570736575ULL;
666 v1 = k1 ^ 0x646f72616e646f6dULL;
667 v2 = k0 ^ 0x6c7967656e657261ULL;
668 v3 = k1 ^ 0x7465646279746573ULL;
669
670 if (m)
671 {
672 sipcompress(&v0, &v1, &v2, &v3, m);
673 }
674
675 /* compression with c = 2 */
676 for (; pos != end; pos += 8)
677 {
678 m = sipget(pos);
679 sipcompress(&v0, &v1, &v2, &v3, m);
680 }
681 sipcompress(&v0, &v1, &v2, &v3, siplast(len, pos));
682
683 /* finalization with d = 4 */
684 v2 ^= 0xff;
685 sipround(&v0, &v1, &v2, &v3);
686 sipround(&v0, &v1, &v2, &v3);
687 sipround(&v0, &v1, &v2, &v3);
688 sipround(&v0, &v1, &v2, &v3);
689 return v0 ^ v1 ^ v2 ^ v3;
690 }
691
692 /**
693 * Described in header.
694 */
695 u_int64_t chunk_mac(chunk_t chunk, u_char *key)
696 {
697 return chunk_mac_inc(chunk, key, 0);
698 }
699
700 /**
701 * Key used for chunk_hash.
702 */
703 static u_char key[16];
704
705 /**
706 * Described in header.
707 */
708 u_int32_t chunk_hash_inc(chunk_t chunk, u_int32_t hash)
709 {
710 /* we could use a mac of the previous hash, but this is faster */
711 return chunk_mac_inc(chunk, key, ((u_int64_t)hash) << 32 | hash);
712 }
713
714 /**
715 * Described in header.
716 */
717 u_int32_t chunk_hash(chunk_t chunk)
718 {
719 return chunk_mac(chunk, key);
720 }
721
722 /**
723 * Described in header.
724 */
725 int chunk_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
726 const void *const *args)
727 {
728 chunk_t *chunk = *((chunk_t**)(args[0]));
729 bool first = TRUE;
730 chunk_t copy = *chunk;
731 int written = 0;
732
733 if (!spec->hash)
734 {
735 u_int chunk_len = chunk->len;
736 const void *new_args[] = {&chunk->ptr, &chunk_len};
737 return mem_printf_hook(data, spec, new_args);
738 }
739
740 while (copy.len > 0)
741 {
742 if (first)
743 {
744 first = FALSE;
745 }
746 else
747 {
748 written += print_in_hook(data, ":");
749 }
750 written += print_in_hook(data, "%02x", *copy.ptr++);
751 copy.len--;
752 }
753 return written;
754 }