diff options
author | Christian Grothoff <christian@grothoff.org> | 2012-03-04 13:51:40 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2012-03-04 13:51:40 +0000 |
commit | 6a9425ddc6fa5de32bb97f05b46ab47c01106f80 (patch) | |
tree | 79211ae367b020cc79b103dab23b5e9d7c99688c /src/util | |
parent | 5c130e7d8357711b3646a39813670885c0891633 (diff) | |
download | gnunet-6a9425ddc6fa5de32bb97f05b46ab47c01106f80.tar.gz gnunet-6a9425ddc6fa5de32bb97f05b46ab47c01106f80.zip |
LRN: adding generic functions for conversion of binary data to ascii and back: GNUNET_CRYPTO_string_to_data and GNUNET_CRYPTO_data_to_string
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/crypto_hash.c | 119 |
1 files changed, 118 insertions, 1 deletions
diff --git a/src/util/crypto_hash.c b/src/util/crypto_hash.c index 63d965406..dce449ff0 100644 --- a/src/util/crypto_hash.c +++ b/src/util/crypto_hash.c | |||
@@ -241,7 +241,6 @@ GNUNET_CRYPTO_hash_file_cancel (struct GNUNET_CRYPTO_FileHashContext *fhc) | |||
241 | } | 241 | } |
242 | 242 | ||
243 | 243 | ||
244 | |||
245 | /* ***************** binary-ASCII encoding *************** */ | 244 | /* ***************** binary-ASCII encoding *************** */ |
246 | 245 | ||
247 | /** | 246 | /** |
@@ -262,6 +261,124 @@ getValue__ (unsigned char a) | |||
262 | 261 | ||
263 | 262 | ||
264 | /** | 263 | /** |
264 | * Convert binary data to ASCII encoding. The ASCII encoding is rather | ||
265 | * GNUnet specific. It was chosen such that it only uses characters | ||
266 | * in [0-9A-V], can be produced without complex arithmetics and uses a | ||
267 | * small number of characters. The GNUnet encoding uses 103 characters. | ||
268 | * Does not append 0-terminator, but returns a pointer to the place where | ||
269 | * it should be placed, if needed. | ||
270 | * | ||
271 | * @param data data to encode | ||
272 | * @param size size of data (in bytes) | ||
273 | * @param out buffer to fill | ||
274 | * @param out_size size of the buffer. Must be large enough to hold | ||
275 | * ((size*8) + (((size*8) % 5) > 0 ? 5 - ((size*8) % 5) : 0)) / 5 bytes | ||
276 | * @return pointer to the next byte in 'out' or NULL on error. | ||
277 | */ | ||
278 | char * | ||
279 | GNUNET_CRYPTO_data_to_string (unsigned char *data, size_t size, char *out, size_t out_size) | ||
280 | { | ||
281 | /** | ||
282 | * 32 characters for encoding (GNUNET_CRYPTO_hash => 32 characters) | ||
283 | */ | ||
284 | static char *encTable__ = "0123456789ABCDEFGHIJKLMNOPQRSTUV"; | ||
285 | unsigned int wpos; | ||
286 | unsigned int rpos; | ||
287 | unsigned int bits; | ||
288 | unsigned int vbit; | ||
289 | |||
290 | GNUNET_assert (data != NULL); | ||
291 | GNUNET_assert (out != NULL); | ||
292 | GNUNET_assert (out_size >= (((size*8) + ((size*8) % 5)) % 5)); | ||
293 | vbit = 0; | ||
294 | wpos = 0; | ||
295 | rpos = 0; | ||
296 | bits = 0; | ||
297 | while ((rpos < size) || (vbit > 0)) | ||
298 | { | ||
299 | if ((rpos < size) && (vbit < 5)) | ||
300 | { | ||
301 | bits = (bits << 8) | data[rpos++]; /* eat 8 more bits */ | ||
302 | vbit += 8; | ||
303 | } | ||
304 | if (vbit < 5) | ||
305 | { | ||
306 | bits <<= (5 - vbit); /* zero-padding */ | ||
307 | GNUNET_assert (vbit == ((size * 8) % 5)); | ||
308 | vbit = 5; | ||
309 | } | ||
310 | if (wpos >= out_size) | ||
311 | return NULL; | ||
312 | out[wpos++] = encTable__[(bits >> (vbit - 5)) & 31]; | ||
313 | vbit -= 5; | ||
314 | } | ||
315 | if (wpos != out_size) | ||
316 | return NULL; | ||
317 | GNUNET_assert (vbit == 0); | ||
318 | return &out[wpos]; | ||
319 | } | ||
320 | |||
321 | |||
322 | /** | ||
323 | * Convert ASCII encoding back to data | ||
324 | * out_size must match exactly the size of the data before it was encoded. | ||
325 | * | ||
326 | * @param enc the encoding | ||
327 | * @param enclen number of characters in 'enc' (without 0-terminator, which can be missing) | ||
328 | * @param out location where to store the decoded data | ||
329 | * @param out_size sizeof the output buffer | ||
330 | * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding | ||
331 | */ | ||
332 | int | ||
333 | GNUNET_CRYPTO_string_to_data (const char *enc, size_t enclen, | ||
334 | unsigned char *out, size_t out_size) | ||
335 | { | ||
336 | unsigned int rpos; | ||
337 | unsigned int wpos; | ||
338 | unsigned int bits; | ||
339 | unsigned int vbit; | ||
340 | int ret; | ||
341 | int shift; | ||
342 | int encoded_len = out_size * 8; | ||
343 | if (encoded_len % 5 > 0) | ||
344 | { | ||
345 | vbit = encoded_len % 5; /* padding! */ | ||
346 | shift = 5 - vbit; | ||
347 | } | ||
348 | else | ||
349 | { | ||
350 | vbit = 0; | ||
351 | shift = 0; | ||
352 | } | ||
353 | if ((encoded_len + shift) / 5 != enclen) | ||
354 | return GNUNET_SYSERR; | ||
355 | |||
356 | wpos = out_size; | ||
357 | rpos = enclen; | ||
358 | bits = (ret = getValue__ (enc[--rpos])) >> (5 - encoded_len % 5); | ||
359 | if (-1 == ret) | ||
360 | return GNUNET_SYSERR; | ||
361 | while (wpos > 0) | ||
362 | { | ||
363 | GNUNET_assert (rpos > 0); | ||
364 | bits = ((ret = getValue__ (enc[--rpos])) << vbit) | bits; | ||
365 | if (-1 == ret) | ||
366 | return GNUNET_SYSERR; | ||
367 | vbit += 5; | ||
368 | if (vbit >= 8) | ||
369 | { | ||
370 | out[--wpos] = (unsigned char) bits; | ||
371 | bits >>= 8; | ||
372 | vbit -= 8; | ||
373 | } | ||
374 | } | ||
375 | GNUNET_assert (rpos == 0); | ||
376 | GNUNET_assert (vbit == 0); | ||
377 | return GNUNET_OK; | ||
378 | } | ||
379 | |||
380 | |||
381 | /** | ||
265 | * Convert GNUNET_CRYPTO_hash to ASCII encoding. The ASCII encoding is rather | 382 | * Convert GNUNET_CRYPTO_hash to ASCII encoding. The ASCII encoding is rather |
266 | * GNUnet specific. It was chosen such that it only uses characters | 383 | * GNUnet specific. It was chosen such that it only uses characters |
267 | * in [0-9A-V], can be produced without complex arithmetics and uses a | 384 | * in [0-9A-V], can be produced without complex arithmetics and uses a |