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
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>.
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
19 #include <sys/types.h>
34 chunk_t chunk_empty
= { NULL
, 0 };
37 * Described in header.
39 chunk_t
chunk_create_clone(u_char
*ptr
, chunk_t chunk
)
41 chunk_t clone
= chunk_empty
;
43 if (chunk
.ptr
&& chunk
.len
> 0)
46 clone
.len
= chunk
.len
;
47 memcpy(clone
.ptr
, chunk
.ptr
, chunk
.len
);
54 * Described in header.
56 size_t chunk_length(const char* mode
, ...)
61 va_start(chunks
, mode
);
70 chunk_t ch
= va_arg(chunks
, chunk_t
);
84 * Described in header.
86 chunk_t
chunk_create_cat(u_char
*ptr
, const char* mode
, ...)
89 chunk_t construct
= chunk_create(ptr
, 0);
91 va_start(chunks
, mode
);
94 bool free_chunk
= FALSE
, clear_chunk
= FALSE
;
106 ch
= va_arg(chunks
, chunk_t
);
107 memcpy(ptr
, ch
.ptr
, ch
.len
);
109 construct
.len
+= ch
.len
;
130 * Described in header.
132 void chunk_split(chunk_t chunk
, const char *mode
, ...)
138 va_start(chunks
, mode
);
145 len
= va_arg(chunks
, u_int
);
146 ch
= va_arg(chunks
, chunk_t
*);
147 /* a null chunk means skip len bytes */
150 chunk
= chunk_skip(chunk
, len
);
157 ch
->len
= min(chunk
.len
, len
);
166 chunk
= chunk_skip(chunk
, ch
->len
);
171 ch
->len
= min(chunk
.len
, len
);
174 ch
->ptr
= malloc(ch
->len
);
175 memcpy(ch
->ptr
, chunk
.ptr
, ch
->len
);
181 chunk
= chunk_skip(chunk
, ch
->len
);
186 ch
->len
= min(ch
->len
, chunk
.len
);
187 ch
->len
= min(ch
->len
, len
);
190 memcpy(ch
->ptr
, chunk
.ptr
, ch
->len
);
196 chunk
= chunk_skip(chunk
, ch
->len
);
208 * Described in header.
210 bool chunk_write(chunk_t chunk
, char *path
, char *label
, mode_t mask
, bool force
)
216 if (!force
&& access(path
, F_OK
) == 0)
218 DBG1(DBG_LIB
, " %s file '%s' already exists", label
, path
);
221 oldmask
= umask(mask
);
222 fd
= fopen(path
, "w");
225 if (fwrite(chunk
.ptr
, sizeof(u_char
), chunk
.len
, fd
) == chunk
.len
)
227 DBG1(DBG_LIB
, " written %s file '%s' (%d bytes)",
228 label
, path
, chunk
.len
);
233 DBG1(DBG_LIB
, " writing %s file '%s' failed: %s",
234 label
, path
, strerror(errno
));
240 DBG1(DBG_LIB
, " could not open %s file '%s': %s", label
, path
,
248 * Described in header.
250 chunk_t
chunk_from_fd(int fd
)
254 ssize_t len
, total
= 0;
258 len
= read(fd
, pos
, buf
+ sizeof(buf
) - pos
);
261 DBG1(DBG_LIB
, "reading from file descriptor failed: %s",
270 if (total
== sizeof(buf
))
272 DBG1(DBG_LIB
, "buffer too small to read from file descriptor");
276 return chunk_clone(chunk_create(buf
, total
));
280 * Implementation for mmap()ed chunks
283 /* public chunk interface */
285 /* FD of open file */
296 chunk_t
*chunk_map(char *path
, bool wr
)
298 mmaped_chunk_t
*chunk
;
303 .fd
= open(path
, wr ? O_RDWR
: O_RDONLY
),
311 if (fstat(chunk
->fd
, &sb
) == -1)
314 chunk_unmap(&chunk
->public);
318 chunk
->len
= sb
.st_size
;
319 /* map non-empty files only, as mmap() complains otherwise */
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
)
328 chunk_unmap(&chunk
->public);
333 chunk
->public = chunk_create(chunk
->map
, chunk
->len
);
334 return &chunk
->public;
340 bool chunk_unmap(chunk_t
*public)
342 mmaped_chunk_t
*chunk
;
346 chunk
= (mmaped_chunk_t
*)public;
347 if (chunk
->map
&& chunk
->map
!= MAP_FAILED
)
349 ret
= munmap(chunk
->map
, chunk
->len
) == 0;
359 /** hex conversion digits */
360 static char hexdig_upper
[] = "0123456789ABCDEF";
361 static char hexdig_lower
[] = "0123456789abcdef";
364 * Described in header.
366 chunk_t
chunk_to_hex(chunk_t chunk
, char *buf
, bool uppercase
)
369 char *hexdig
= hexdig_lower
;
373 hexdig
= hexdig_upper
;
379 buf
= malloc(len
+ 1);
383 for (i
= 0; i
< chunk
.len
; i
++)
385 buf
[i
*2] = hexdig
[(chunk
.ptr
[i
] >> 4) & 0xF];
386 buf
[i
*2+1] = hexdig
[(chunk
.ptr
[i
] ) & 0xF];
388 return chunk_create(buf
, len
);
392 * convert a signle hex character to its binary value
394 static char hex2bin(char hex
)
401 return hex
- 'A' + 10;
403 return hex
- 'a' + 10;
410 * Described in header.
412 chunk_t
chunk_from_hex(chunk_t hex
, char *buf
)
418 /* subtract the number of optional ':' separation characters */
421 for (i
= 0; i
< hex
.len
; i
++)
429 /* compute the number of binary bytes */
437 /* allocate buffer memory unless provided by caller */
443 /* buffer is filled from the right */
447 for (i
= len
- 1; i
>= 0; i
--)
449 /* skip separation characters */
450 if (*(--hex
.ptr
) == ':')
454 buf
[i
] = hex2bin(*hex
.ptr
);
457 buf
[i
] |= hex2bin(*(--hex
.ptr
)) << 4;
460 return chunk_create(buf
, len
);
463 /** base 64 conversion digits */
464 static char b64digits
[] =
465 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
468 * Described in header.
470 chunk_t
chunk_to_base64(chunk_t chunk
, char *buf
)
475 len
= chunk
.len
+ ((3 - chunk
.len
% 3) % 3);
478 buf
= malloc(len
* 4 / 3 + 1);
481 for (i
= 0; i
< len
; i
+=3)
483 *pos
++ = b64digits
[chunk
.ptr
[i
] >> 2];
484 if (i
+1 >= chunk
.len
)
486 *pos
++ = b64digits
[(chunk
.ptr
[i
] & 0x03) << 4];
491 *pos
++ = b64digits
[((chunk
.ptr
[i
] & 0x03) << 4) | (chunk
.ptr
[i
+1] >> 4)];
492 if (i
+2 >= chunk
.len
)
494 *pos
++ = b64digits
[(chunk
.ptr
[i
+1] & 0x0F) << 2];
498 *pos
++ = b64digits
[((chunk
.ptr
[i
+1] & 0x0F) << 2) | (chunk
.ptr
[i
+2] >> 6)];
499 *pos
++ = b64digits
[chunk
.ptr
[i
+2] & 0x3F];
502 return chunk_create(buf
, len
* 4 / 3);
506 * convert a base 64 digit to its binary form (inversion of b64digits array)
508 static int b642bin(char b64
)
515 return ('Z' - 'A' + 1) + b64
- 'a';
517 return ('Z' - 'A' + 1) + ('z' - 'a' + 1) + b64
- '0';
532 * Described in header.
534 chunk_t
chunk_from_base64(chunk_t base64
, char *buf
)
536 u_char
*pos
, byte
[4];
537 int i
, j
, len
, outlen
;
539 len
= base64
.len
/ 4 * 3;
546 for (i
= 0; i
< len
; i
+=3)
549 for (j
= 0; j
< 4; j
++)
555 byte
[j
] = b642bin(*pos
++);
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]);
561 return chunk_create(buf
, outlen
);
564 /** base 32 conversion digits */
565 static char b32digits
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
568 * Described in header.
570 chunk_t
chunk_to_base32(chunk_t chunk
, char *buf
)
575 len
= chunk
.len
+ ((5 - chunk
.len
% 5) % 5);
578 buf
= malloc(len
* 8 / 5 + 1);
581 for (i
= 0; i
< len
; i
+=5)
583 *pos
++ = b32digits
[chunk
.ptr
[i
] >> 3];
584 if (i
+1 >= chunk
.len
)
586 *pos
++ = b32digits
[(chunk
.ptr
[i
] & 0x07) << 2];
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
)
596 *pos
++ = b32digits
[(chunk
.ptr
[i
+1] & 0x01) << 4];
601 *pos
++ = b32digits
[((chunk
.ptr
[i
+1] & 0x01) << 4) |
602 (chunk
.ptr
[i
+2] >> 4)];
603 if (i
+3 >= chunk
.len
)
605 *pos
++ = b32digits
[(chunk
.ptr
[i
+2] & 0x0F) << 1];
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
)
615 *pos
++ = b32digits
[(chunk
.ptr
[i
+3] & 0x03) << 3];
619 *pos
++ = b32digits
[((chunk
.ptr
[i
+3] & 0x03) << 3) |
620 (chunk
.ptr
[i
+4] >> 5)];
621 *pos
++ = b32digits
[chunk
.ptr
[i
+4] & 0x1F];
624 return chunk_create(buf
, len
* 8 / 5);
628 * Described in header.
630 int chunk_compare(chunk_t a
, chunk_t b
)
632 int compare_len
= a
.len
- b
.len
;
633 int len
= (compare_len
< 0)? a
.len
: b
.len
;
635 if (compare_len
!= 0 || len
== 0)
639 return memcmp(a
.ptr
, b
.ptr
, len
);
644 * Described in header.
646 bool chunk_increment(chunk_t chunk
)
650 for (i
= chunk
.len
- 1; i
>= 0; i
--)
652 if (++chunk
.ptr
[i
] != 0)
661 * Remove non-printable characters from a chunk.
663 bool chunk_printable(chunk_t chunk
, chunk_t
*sane
, char replace
)
665 bool printable
= TRUE
;
670 *sane
= chunk_clone(chunk
);
672 for (i
= 0; i
< chunk
.len
; i
++)
674 if (!isprint(chunk
.ptr
[i
]))
678 sane
->ptr
[i
] = replace
;
687 * Helper functions for chunk_mac()
689 static inline u_int64_t
sipget(u_char
*in
)
694 for (i
= 0; i
< 64; i
+= 8, ++in
)
696 v
|= ((u_int64_t
)*in
) << i
;
701 static inline u_int64_t
siprotate(u_int64_t v
, int shift
)
703 return (v
<< shift
) | (v
>> (64 - shift
));
706 static inline void sipround(u_int64_t
*v0
, u_int64_t
*v1
, u_int64_t
*v2
,
710 *v1
= siprotate(*v1
, 13);
712 *v0
= siprotate(*v0
, 32);
715 *v3
= siprotate(*v3
, 16);
719 *v1
= siprotate(*v1
, 17);
721 *v2
= siprotate(*v2
, 32);
724 *v3
= siprotate(*v3
, 21);
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
)
732 sipround(v0
, v1
, v2
, v3
);
733 sipround(v0
, v1
, v2
, v3
);
737 static inline u_int64_t
siplast(size_t len
, u_char
*pos
)
742 b
= ((u_int64_t
)len
) << 56;
746 b
|= ((u_int64_t
)pos
[6]) << 48;
748 b
|= ((u_int64_t
)pos
[5]) << 40;
750 b
|= ((u_int64_t
)pos
[4]) << 32;
752 b
|= ((u_int64_t
)pos
[3]) << 24;
754 b
|= ((u_int64_t
)pos
[2]) << 16;
756 b
|= ((u_int64_t
)pos
[1]) << 8;
758 b
|= ((u_int64_t
)pos
[0]);
767 * Caculate SipHash-2-4 with an optional first block given as argument.
769 static u_int64_t
chunk_mac_inc(chunk_t chunk
, u_char
*key
, u_int64_t m
)
771 u_int64_t v0
, v1
, v2
, v3
, k0
, k1
;
772 size_t len
= chunk
.len
;
773 u_char
*pos
= chunk
.ptr
, *end
;
775 end
= chunk
.ptr
+ len
- (len
% 8);
778 k1
= sipget(key
+ 8);
780 v0
= k0
^ 0x736f6d6570736575ULL
;
781 v1
= k1
^ 0x646f72616e646f6dULL
;
782 v2
= k0
^ 0x6c7967656e657261ULL
;
783 v3
= k1
^ 0x7465646279746573ULL
;
787 sipcompress(&v0
, &v1
, &v2
, &v3
, m
);
790 /* compression with c = 2 */
791 for (; pos
!= end
; pos
+= 8)
794 sipcompress(&v0
, &v1
, &v2
, &v3
, m
);
796 sipcompress(&v0
, &v1
, &v2
, &v3
, siplast(len
, pos
));
798 /* finalization with d = 4 */
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
;
808 * Described in header.
810 u_int64_t
chunk_mac(chunk_t chunk
, u_char
*key
)
812 return chunk_mac_inc(chunk
, key
, 0);
816 * Secret key allocated randomly during first use.
818 static u_char key
[16];
821 * Static key used in case predictable hash values are required.
823 static u_char static_key
[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
824 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
827 * Only allocate the key once
829 static pthread_once_t key_allocated
= PTHREAD_ONCE_INIT
;
832 * Allocate a key on first use, we do this manually to avoid dependencies on
835 static void allocate_key()
841 fd
= open("/dev/urandom", O_RDONLY
);
844 while (done
< sizeof(key
))
846 len
= read(fd
, key
+ done
, sizeof(key
) - done
);
855 /* on error we use random() to generate the key (better than nothing) */
856 if (done
< sizeof(key
))
858 srandom(time(NULL
) + getpid());
859 for (; done
< sizeof(key
); done
++)
861 key
[done
] = (u_char
)random();
867 * Described in header.
869 u_int32_t
chunk_hash_inc(chunk_t chunk
, u_int32_t hash
)
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
);
877 * Described in header.
879 u_int32_t
chunk_hash(chunk_t chunk
)
881 pthread_once(&key_allocated
, allocate_key
);
882 return chunk_mac(chunk
, key
);
886 * Described in header.
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
);
894 * Described in header.
896 u_int32_t
chunk_hash_static(chunk_t chunk
)
898 return chunk_mac(chunk
, static_key
);
902 * Described in header.
904 int chunk_printf_hook(printf_hook_data_t
*data
, printf_hook_spec_t
*spec
,
905 const void *const *args
)
907 chunk_t
*chunk
= *((chunk_t
**)(args
[0]));
909 chunk_t copy
= *chunk
;
912 if (!spec
->hash
&& !spec
->plus
)
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
);
925 else if (!spec
->plus
)
927 written
+= print_in_hook(data
, ":");
929 written
+= print_in_hook(data
, "%02x", *copy
.ptr
++);