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