chunk: Add functions to map file contents to a chunk
[strongswan.git] / src / libstrongswan / utils / chunk.h
1 /*
2 * Copyright (C) 2008-2013 Tobias Brunner
3 * Copyright (C) 2005-2008 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 /**
19 * @defgroup chunk chunk
20 * @{ @ingroup utils
21 */
22
23 #ifndef CHUNK_H_
24 #define CHUNK_H_
25
26 #include <string.h>
27 #include <stdarg.h>
28 #include <sys/types.h>
29 #ifdef HAVE_ALLOCA_H
30 #include <alloca.h>
31 #endif
32
33 typedef struct chunk_t chunk_t;
34
35 /**
36 * General purpose pointer/length abstraction.
37 */
38 struct chunk_t {
39 /** Pointer to start of data */
40 u_char *ptr;
41 /** Length of data in bytes */
42 size_t len;
43 };
44
45 #include "utils.h"
46
47 /**
48 * A { NULL, 0 }-chunk handy for initialization.
49 */
50 extern chunk_t chunk_empty;
51
52 /**
53 * Create a new chunk pointing to "ptr" with length "len"
54 */
55 static inline chunk_t chunk_create(u_char *ptr, size_t len)
56 {
57 chunk_t chunk = {ptr, len};
58 return chunk;
59 }
60
61 /**
62 * Create a clone of a chunk pointing to "ptr"
63 */
64 chunk_t chunk_create_clone(u_char *ptr, chunk_t chunk);
65
66 /**
67 * Calculate length of multiple chunks
68 */
69 size_t chunk_length(const char *mode, ...);
70
71 /**
72 * Concatenate chunks into a chunk pointing to "ptr".
73 *
74 * The mode string specifies the number of chunks, and how to handle each of
75 * them with a single character: 'c' for copy (allocate new chunk), 'm' for move
76 * (free given chunk) or 's' for sensitive-move (clear given chunk, then free).
77 */
78 chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...);
79
80 /**
81 * Split up a chunk into parts, "mode" is a string of "a" (alloc),
82 * "c" (copy) and "m" (move). Each letter say for the corresponding chunk if
83 * it should get allocated on heap, copied into existing chunk, or the chunk
84 * should point into "chunk". The length of each part is an argument before
85 * each target chunk. E.g.:
86 * chunk_split(chunk, "mcac", 3, &a, 7, &b, 5, &c, d.len, &d);
87 */
88 void chunk_split(chunk_t chunk, const char *mode, ...);
89
90 /**
91 * Write the binary contents of a chunk_t to a file
92 *
93 * @param chunk contents to write to file
94 * @param path path where file is written to
95 * @param label label specifying file type
96 * @param mask file mode creation mask
97 * @param force overwrite existing file by force
98 * @return TRUE if write operation was successful
99 */
100 bool chunk_write(chunk_t chunk, char *path, char *label, mode_t mask, bool force);
101
102 /**
103 * Store data read from FD into a chunk
104 *
105 * @param fd file descriptor to read from
106 * @return chunk or chunk_empty on failure
107 */
108 chunk_t chunk_from_fd(int fd);
109
110 /**
111 * mmap() a file to a chunk
112 *
113 * The returned chunk structure is allocated from heap, but it must be freed
114 * through chunk_unmap(). A user may alter the chunk ptr or len, but must pass
115 * the chunk pointer returned from chunk_map() to chunk_unmap() after use.
116 *
117 * On error, errno is set appropriately.
118 *
119 * @param path path of file to map
120 * @param wr TRUE to sync writes to disk
121 * @return mapped chunk, NULL on error
122 */
123 chunk_t *chunk_map(char *path, bool wr);
124
125 /**
126 * munmap() a chunk previously mapped with chunk_map()
127 *
128 * When unmapping a writeable map, the return value should be checked to
129 * ensure changes landed on disk.
130 *
131 * @param chunk pointer returned from chunk_map()
132 * @return TRUE of changes written back to file
133 */
134 bool chunk_unmap(chunk_t *chunk);
135
136 /**
137 * Convert a chunk of data to hex encoding.
138 *
139 * The resulting string is '\\0' terminated, but the chunk does not include
140 * the '\\0'. If buf is supplied, it must hold at least (chunk.len * 2 + 1).
141 *
142 * @param chunk data to convert to hex encoding
143 * @param buf buffer to write to, NULL to malloc
144 * @param uppercase TRUE to use uppercase letters
145 * @return chunk of encoded data
146 */
147 chunk_t chunk_to_hex(chunk_t chunk, char *buf, bool uppercase);
148
149 /**
150 * Convert a hex encoded in a binary chunk.
151 *
152 * If buf is supplied, it must hold at least (hex.len / 2) + (hex.len % 2)
153 * bytes. It is filled by the right to give correct values for short inputs.
154 *
155 * @param hex hex encoded input data
156 * @param buf buffer to write decoded data, NULL to malloc
157 * @return converted data
158 */
159 chunk_t chunk_from_hex(chunk_t hex, char *buf);
160
161 /**
162 * Convert a chunk of data to its base64 encoding.
163 *
164 * The resulting string is '\\0' terminated, but the chunk does not include
165 * the '\\0'. If buf is supplied, it must hold at least (chunk.len * 4 / 3 + 1).
166 *
167 * @param chunk data to convert
168 * @param buf buffer to write to, NULL to malloc
169 * @return chunk of encoded data
170 */
171 chunk_t chunk_to_base64(chunk_t chunk, char *buf);
172
173 /**
174 * Convert a base64 in a binary chunk.
175 *
176 * If buf is supplied, it must hold at least (base64.len / 4 * 3).
177 *
178 * @param base64 base64 encoded input data
179 * @param buf buffer to write decoded data, NULL to malloc
180 * @return converted data
181 */
182 chunk_t chunk_from_base64(chunk_t base64, char *buf);
183
184 /**
185 * Convert a chunk of data to its base32 encoding.
186 *
187 * The resulting string is '\\0' terminated, but the chunk does not include
188 * the '\\0'. If buf is supplied, it must hold (chunk.len * 8 / 5 + 1) bytes.
189 *
190 * @param chunk data to convert
191 * @param buf buffer to write to, NULL to malloc
192 * @return chunk of encoded data
193 */
194 chunk_t chunk_to_base32(chunk_t chunk, char *buf);
195
196 /**
197 * Free contents of a chunk
198 */
199 static inline void chunk_free(chunk_t *chunk)
200 {
201 free(chunk->ptr);
202 *chunk = chunk_empty;
203 }
204
205 /**
206 * Overwrite the contents of a chunk and free it
207 */
208 static inline void chunk_clear(chunk_t *chunk)
209 {
210 if (chunk->ptr)
211 {
212 memwipe(chunk->ptr, chunk->len);
213 chunk_free(chunk);
214 }
215 }
216
217 /**
218 * Initialize a chunk using a char array
219 */
220 #define chunk_from_chars(...) ((chunk_t){(u_char[]){__VA_ARGS__}, sizeof((u_char[]){__VA_ARGS__})})
221
222 /**
223 * Initialize a chunk to point to a thing
224 */
225 #define chunk_from_thing(thing) chunk_create((u_char*)&(thing), sizeof(thing))
226
227 /**
228 * Initialize a chunk from a string, not containing 0-terminator
229 */
230 #define chunk_from_str(str) ({char *x = (str); chunk_create((u_char*)x, strlen(x));})
231
232 /**
233 * Allocate a chunk on the heap
234 */
235 #define chunk_alloc(bytes) ({size_t x = (bytes); chunk_create(x ? malloc(x) : NULL, x);})
236
237 /**
238 * Allocate a chunk on the stack
239 */
240 #define chunk_alloca(bytes) ({size_t x = (bytes); chunk_create(x ? alloca(x) : NULL, x);})
241
242 /**
243 * Clone a chunk on heap
244 */
245 #define chunk_clone(chunk) ({chunk_t x = (chunk); chunk_create_clone(x.len ? malloc(x.len) : NULL, x);})
246
247 /**
248 * Clone a chunk on stack
249 */
250 #define chunk_clonea(chunk) ({chunk_t x = (chunk); chunk_create_clone(x.len ? alloca(x.len) : NULL, x);})
251
252 /**
253 * Concatenate chunks into a chunk on heap
254 */
255 #define chunk_cat(mode, ...) chunk_create_cat(malloc(chunk_length(mode, __VA_ARGS__)), mode, __VA_ARGS__)
256
257 /**
258 * Concatenate chunks into a chunk on stack
259 */
260 #define chunk_cata(mode, ...) chunk_create_cat(alloca(chunk_length(mode, __VA_ARGS__)), mode, __VA_ARGS__)
261
262 /**
263 * Skip n bytes in chunk (forward pointer, shorten length)
264 */
265 static inline chunk_t chunk_skip(chunk_t chunk, size_t bytes)
266 {
267 if (chunk.len > bytes)
268 {
269 chunk.ptr += bytes;
270 chunk.len -= bytes;
271 return chunk;
272 }
273 return chunk_empty;
274 }
275
276 /**
277 * Skip a leading zero-valued byte
278 */
279 static inline chunk_t chunk_skip_zero(chunk_t chunk)
280 {
281 if (chunk.len > 1 && *chunk.ptr == 0x00)
282 {
283 chunk.ptr++;
284 chunk.len--;
285 }
286 return chunk;
287 }
288
289
290 /**
291 * Compare two chunks, returns zero if a equals b
292 * or negative/positive if a is small/greater than b
293 */
294 int chunk_compare(chunk_t a, chunk_t b);
295
296 /**
297 * Compare two chunks for equality,
298 * NULL chunks are never equal.
299 */
300 static inline bool chunk_equals(chunk_t a, chunk_t b)
301 {
302 return a.ptr != NULL && b.ptr != NULL &&
303 a.len == b.len && memeq(a.ptr, b.ptr, a.len);
304 }
305
306 /**
307 * Compare two chunks (given as pointers) for equality (useful as callback),
308 * NULL chunks are never equal.
309 */
310 static inline bool chunk_equals_ptr(chunk_t *a, chunk_t *b)
311 {
312 return a != NULL && b != NULL && chunk_equals(*a, *b);
313 }
314
315 /**
316 * Increment a chunk, as it would reprensent a network order integer.
317 *
318 * @param chunk chunk to increment
319 * @return TRUE if an overflow occurred
320 */
321 bool chunk_increment(chunk_t chunk);
322
323 /**
324 * Check if a chunk has printable characters only.
325 *
326 * If sane is given, chunk is cloned into sane and all non printable characters
327 * get replaced by "replace".
328 *
329 * @param chunk chunk to check for printability
330 * @param sane pointer where sane version is allocated, or NULL
331 * @param replace character to use for replaceing unprintable characters
332 * @return TRUE if all characters in chunk are printable
333 */
334 bool chunk_printable(chunk_t chunk, chunk_t *sane, char replace);
335
336 /**
337 * Computes a 32 bit hash of the given chunk.
338 *
339 * @note The output of this function is randomized, that is, it will only
340 * produce the same output for the same input when calling it from the same
341 * process. For a more predictable hash function use chunk_hash_static()
342 * instead.
343 *
344 * @note This hash is only intended for hash tables not for cryptographic
345 * purposes.
346 *
347 * @param chunk data to hash
348 * @return hash value
349 */
350 u_int32_t chunk_hash(chunk_t chunk);
351
352 /**
353 * Incremental version of chunk_hash. Use this to hash two or more chunks.
354 *
355 * @param chunk data to hash
356 * @param hash previous hash value
357 * @return hash value
358 */
359 u_int32_t chunk_hash_inc(chunk_t chunk, u_int32_t hash);
360
361 /**
362 * Computes a 32 bit hash of the given chunk.
363 *
364 * Compared to chunk_hash() this will always calculate the same output for the
365 * same input. Therefore, it should not be used for hash tables (to prevent
366 * hash flooding).
367 *
368 * @note This hash is not intended for cryptographic purposes.
369 *
370 * @param chunk data to hash
371 * @return hash value
372 */
373 u_int32_t chunk_hash_static(chunk_t chunk);
374
375 /**
376 * Incremental version of chunk_hash_static(). Use this to hash two or more
377 * chunks in a predictable way.
378 *
379 * @param chunk data to hash
380 * @param hash previous hash value
381 * @return hash value
382 */
383 u_int32_t chunk_hash_static_inc(chunk_t chunk, u_int32_t hash);
384
385 /**
386 * Computes a quick MAC from the given chunk and key using SipHash.
387 *
388 * The key must have a length of 128-bit (16 bytes).
389 *
390 * @note While SipHash has strong features using it for cryptographic purposes
391 * is not recommended (in particular because of the rather short output size).
392 *
393 * @param chunk data to process
394 * @param key key to use
395 * @return MAC for given input and key
396 */
397 u_int64_t chunk_mac(chunk_t chunk, u_char *key);
398
399 /**
400 * printf hook function for chunk_t.
401 *
402 * Arguments are:
403 * chunk_t *chunk
404 * Use #-modifier to print a compact version
405 * Use +-modifier to print a compact version without separator
406 */
407 int chunk_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
408 const void *const *args);
409
410 #endif /** CHUNK_H_ @}*/