Update plibc header
[oweals/gnunet.git] / src / util / crypto_hash.c
1 /*
2      This file is part of GNUnet.
3      (C) 2001-2013 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19
20 */
21
22 /**
23  * @file util/crypto_hash.c
24  * @brief SHA-512 GNUNET_CRYPTO_hash related functions
25  * @author Christian Grothoff
26  */
27
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30 #include <gcrypt.h>
31
32 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
33
34 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
35
36 /**
37  * Hash block of given size.
38  *
39  * @param block the data to GNUNET_CRYPTO_hash, length is given as a second argument
40  * @param size the length of the data to GNUNET_CRYPTO_hash
41  * @param ret pointer to where to write the hashcode
42  */
43 void
44 GNUNET_CRYPTO_hash (const void *block, size_t size, struct GNUNET_HashCode * ret)
45 {
46   gcry_md_hash_buffer (GCRY_MD_SHA512, ret, block, size);
47 }
48
49
50 /**
51  * Context used when hashing a file.
52  */
53 struct GNUNET_CRYPTO_FileHashContext
54 {
55
56   /**
57    * Function to call upon completion.
58    */
59   GNUNET_CRYPTO_HashCompletedCallback callback;
60
61   /**
62    * Closure for callback.
63    */
64   void *callback_cls;
65
66   /**
67    * IO buffer.
68    */
69   unsigned char *buffer;
70
71   /**
72    * Name of the file we are hashing.
73    */
74   char *filename;
75
76   /**
77    * File descriptor.
78    */
79   struct GNUNET_DISK_FileHandle *fh;
80
81   /**
82    * Cummulated hash.
83    */
84   gcry_md_hd_t md;
85
86   /**
87    * Size of the file.
88    */
89   uint64_t fsize;
90
91   /**
92    * Current offset.
93    */
94   uint64_t offset;
95
96   /**
97    * Current task for hashing.
98    */
99   GNUNET_SCHEDULER_TaskIdentifier task;
100
101   /**
102    * Priority we use.
103    */
104   enum GNUNET_SCHEDULER_Priority priority;
105
106   /**
107    * Blocksize.
108    */
109   size_t bsize;
110
111 };
112
113
114 /**
115  * Report result of hash computation to callback
116  * and free associated resources.
117  */
118 static void
119 file_hash_finish (struct GNUNET_CRYPTO_FileHashContext *fhc,
120                   const struct GNUNET_HashCode * res)
121 {
122   fhc->callback (fhc->callback_cls, res);
123   GNUNET_free (fhc->filename);
124   if (!GNUNET_DISK_handle_invalid (fhc->fh))
125     GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fhc->fh));
126   gcry_md_close (fhc->md);
127   GNUNET_free (fhc);            /* also frees fhc->buffer */
128 }
129
130
131 /**
132  * File hashing task.
133  *
134  * @param cls closure
135  * @param tc context
136  */
137 static void
138 file_hash_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
139 {
140   struct GNUNET_CRYPTO_FileHashContext *fhc = cls;
141   struct GNUNET_HashCode *res;
142   size_t delta;
143
144   fhc->task = GNUNET_SCHEDULER_NO_TASK;
145   GNUNET_assert (fhc->offset <= fhc->fsize);
146   delta = fhc->bsize;
147   if (fhc->fsize - fhc->offset < delta)
148     delta = fhc->fsize - fhc->offset;
149   if (delta != GNUNET_DISK_file_read (fhc->fh, fhc->buffer, delta))
150   {
151     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "read", fhc->filename);
152     file_hash_finish (fhc, NULL);
153     return;
154   }
155   gcry_md_write (fhc->md, fhc->buffer, delta);
156   fhc->offset += delta;
157   if (fhc->offset == fhc->fsize)
158   {
159     res = (struct GNUNET_HashCode *) gcry_md_read (fhc->md, GCRY_MD_SHA512);
160     file_hash_finish (fhc, res);
161     return;
162   }
163   fhc->task = GNUNET_SCHEDULER_add_with_priority (fhc->priority,
164                                                   &file_hash_task, fhc);
165 }
166
167
168 /**
169  * Compute the hash of an entire file.
170  *
171  * @param priority scheduling priority to use
172  * @param filename name of file to hash
173  * @param blocksize number of bytes to process in one task
174  * @param callback function to call upon completion
175  * @param callback_cls closure for callback
176  * @return NULL on (immediate) errror
177  */
178 struct GNUNET_CRYPTO_FileHashContext *
179 GNUNET_CRYPTO_hash_file (enum GNUNET_SCHEDULER_Priority priority,
180                          const char *filename, size_t blocksize,
181                          GNUNET_CRYPTO_HashCompletedCallback callback,
182                          void *callback_cls)
183 {
184   struct GNUNET_CRYPTO_FileHashContext *fhc;
185
186   GNUNET_assert (blocksize > 0);
187   fhc =
188       GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_FileHashContext) + blocksize);
189   fhc->callback = callback;
190   fhc->callback_cls = callback_cls;
191   fhc->buffer = (unsigned char *) &fhc[1];
192   fhc->filename = GNUNET_strdup (filename);
193   if (GPG_ERR_NO_ERROR != gcry_md_open (&fhc->md, GCRY_MD_SHA512, 0))
194   {
195     GNUNET_break (0);
196     GNUNET_free (fhc);
197     return NULL;
198   }
199   fhc->bsize = blocksize;
200   if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fhc->fsize, GNUNET_NO, GNUNET_YES))
201   {
202     GNUNET_free (fhc->filename);
203     GNUNET_free (fhc);
204     return NULL;
205   }
206   fhc->fh =
207       GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
208                              GNUNET_DISK_PERM_NONE);
209   if (!fhc->fh)
210   {
211     GNUNET_free (fhc->filename);
212     GNUNET_free (fhc);
213     return NULL;
214   }
215   fhc->priority = priority;
216   fhc->task =
217       GNUNET_SCHEDULER_add_with_priority (priority, &file_hash_task, fhc);
218   return fhc;
219 }
220
221
222 /**
223  * Cancel a file hashing operation.
224  *
225  * @param fhc operation to cancel (callback must not yet have been invoked)
226  */
227 void
228 GNUNET_CRYPTO_hash_file_cancel (struct GNUNET_CRYPTO_FileHashContext *fhc)
229 {
230   GNUNET_SCHEDULER_cancel (fhc->task);
231   GNUNET_free (fhc->filename);
232   GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fhc->fh));
233   GNUNET_free (fhc);
234 }
235
236
237 /* ***************** binary-ASCII encoding *************** */
238
239
240 /**
241  * Convert GNUNET_CRYPTO_hash to ASCII encoding.  The ASCII encoding is rather
242  * GNUnet specific.  It was chosen such that it only uses characters
243  * in [0-9A-V], can be produced without complex arithmetics and uses a
244  * small number of characters.  The GNUnet encoding uses 103
245  * characters plus a null terminator.
246  *
247  * @param block the hash code
248  * @param result where to store the encoding (struct GNUNET_CRYPTO_HashAsciiEncoded can be
249  *  safely cast to char*, a '\\0' termination is set).
250  */
251 void
252 GNUNET_CRYPTO_hash_to_enc (const struct GNUNET_HashCode *block,
253                            struct GNUNET_CRYPTO_HashAsciiEncoded *result)
254 {
255   char *np;
256
257   np = GNUNET_STRINGS_data_to_string ((const unsigned char *) block,
258                                       sizeof (struct GNUNET_HashCode),
259                                       (char*) result,
260                                       sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1);
261   GNUNET_assert (NULL != np);
262   *np = '\0';
263 }
264
265
266 /**
267  * Convert ASCII encoding back to hash code.
268  *
269  * @param enc the encoding
270  * @param enclen number of characters in @a enc (without 0-terminator, which can be missing)
271  * @param result where to store the hash code
272  * @return #GNUNET_OK on success, #GNUNET_SYSERR if result has the wrong encoding
273  */
274 int
275 GNUNET_CRYPTO_hash_from_string2 (const char *enc,
276                                  size_t enclen,
277                                 struct GNUNET_HashCode *result)
278 {
279   char upper_enc[enclen];
280   char* up_ptr = upper_enc;
281
282   GNUNET_STRINGS_utf8_toupper(enc, &up_ptr);
283
284   return GNUNET_STRINGS_string_to_data (upper_enc, enclen,
285                                         (unsigned char*) result,
286                                         sizeof (struct GNUNET_HashCode));
287 }
288
289
290 /**
291  * @ingroup hash
292  *
293  * Compute the distance between 2 hashcodes.  The computation must be
294  * fast, not involve bits[0] or bits[4] (they're used elsewhere), and be
295  * somewhat consistent. And of course, the result should be a positive
296  * number.
297  *
298  * @param a some hash code
299  * @param b some hash code
300  * @return a positive number which is a measure for
301  *  hashcode proximity.
302  */
303 unsigned int
304 GNUNET_CRYPTO_hash_distance_u32 (const struct GNUNET_HashCode *a,
305                                  const struct GNUNET_HashCode *b)
306 {
307   unsigned int x1 = (a->bits[1] - b->bits[1]) >> 16;
308   unsigned int x2 = (b->bits[1] - a->bits[1]) >> 16;
309
310   return (x1 * x2);
311 }
312
313
314 /**
315  * Create a random hash code.
316  *
317  * @param mode desired quality level
318  * @param result hash code that is randomized
319  */
320 void
321 GNUNET_CRYPTO_hash_create_random (enum GNUNET_CRYPTO_Quality mode,
322                                   struct GNUNET_HashCode *result)
323 {
324   int i;
325
326   for (i = (sizeof (struct GNUNET_HashCode) / sizeof (uint32_t)) - 1; i >= 0; i--)
327     result->bits[i] = GNUNET_CRYPTO_random_u32 (mode, UINT32_MAX);
328 }
329
330
331 /**
332  * compute result(delta) = b - a
333  *
334  * @param a some hash code
335  * @param b some hash code
336  * @param result set to b - a
337  */
338 void
339 GNUNET_CRYPTO_hash_difference (const struct GNUNET_HashCode *a,
340                                const struct GNUNET_HashCode *b,
341                                struct GNUNET_HashCode *result)
342 {
343   int i;
344
345   for (i = (sizeof (struct GNUNET_HashCode) / sizeof (unsigned int)) - 1; i >= 0; i--)
346     result->bits[i] = b->bits[i] - a->bits[i];
347 }
348
349
350 /**
351  * compute result(b) = a + delta
352  *
353  * @param a some hash code
354  * @param delta some hash code
355  * @param result set to a + delta
356  */
357 void
358 GNUNET_CRYPTO_hash_sum (const struct GNUNET_HashCode * a,
359                         const struct GNUNET_HashCode * delta, struct GNUNET_HashCode * result)
360 {
361   int i;
362
363   for (i = (sizeof (struct GNUNET_HashCode) / sizeof (unsigned int)) - 1; i >= 0; i--)
364     result->bits[i] = delta->bits[i] + a->bits[i];
365 }
366
367
368 /**
369  * compute result = a ^ b
370  *
371  * @param a some hash code
372  * @param b some hash code
373  * @param result set to a ^ b
374  */
375 void
376 GNUNET_CRYPTO_hash_xor (const struct GNUNET_HashCode * a, const struct GNUNET_HashCode * b,
377                         struct GNUNET_HashCode * result)
378 {
379   int i;
380
381   for (i = (sizeof (struct GNUNET_HashCode) / sizeof (unsigned int)) - 1; i >= 0; i--)
382     result->bits[i] = a->bits[i] ^ b->bits[i];
383 }
384
385
386 /**
387  * Convert a hashcode into a key.
388  *
389  * @param hc hash code that serves to generate the key
390  * @param skey set to a valid session key
391  * @param iv set to a valid initialization vector
392  */
393 void
394 GNUNET_CRYPTO_hash_to_aes_key (const struct GNUNET_HashCode *hc,
395                                struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
396                                struct GNUNET_CRYPTO_SymmetricInitializationVector *iv)
397 {
398   GNUNET_assert (GNUNET_YES ==
399                  GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
400                                     "Hash key derivation", strlen ("Hash key derivation"),
401                                     hc, sizeof (struct GNUNET_HashCode),
402                                     NULL, 0));
403   GNUNET_assert (GNUNET_YES ==
404                  GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
405                                     "Initialization vector derivation", strlen ("Initialization vector derivation"),
406                                     hc, sizeof (struct GNUNET_HashCode),
407                                     NULL, 0));
408 }
409
410
411 /**
412  * Obtain a bit from a hashcode.
413  * @param code the GNUNET_CRYPTO_hash to index bit-wise
414  * @param bit index into the hashcode, [0...511]
415  * @return Bit \a bit from hashcode \a code, -1 for invalid index
416  */
417 int
418 GNUNET_CRYPTO_hash_get_bit (const struct GNUNET_HashCode * code, unsigned int bit)
419 {
420   GNUNET_assert (bit < 8 * sizeof (struct GNUNET_HashCode));
421   return (((unsigned char *) code)[bit >> 3] & (1 << (bit & 7))) > 0;
422 }
423
424
425 /**
426  * Determine how many low order bits match in two
427  * `struct GNUNET_HashCode`s.  i.e. - 010011 and 011111 share
428  * the first two lowest order bits, and therefore the
429  * return value is two (NOT XOR distance, nor how many
430  * bits match absolutely!).
431  *
432  * @param first the first hashcode
433  * @param second the hashcode to compare first to
434  *
435  * @return the number of bits that match
436  */
437 unsigned int
438 GNUNET_CRYPTO_hash_matching_bits (const struct GNUNET_HashCode * first,
439                                   const struct GNUNET_HashCode * second)
440 {
441   unsigned int i;
442
443   for (i = 0; i < sizeof (struct GNUNET_HashCode) * 8; i++)
444     if (GNUNET_CRYPTO_hash_get_bit (first, i) !=
445         GNUNET_CRYPTO_hash_get_bit (second, i))
446       return i;
447   return sizeof (struct GNUNET_HashCode) * 8;
448 }
449
450
451 /**
452  * Compare function for HashCodes, producing a total ordering
453  * of all hashcodes.
454  *
455  * @param h1 some hash code
456  * @param h2 some hash code
457  * @return 1 if h1 > h2, -1 if h1 < h2 and 0 if h1 == h2.
458  */
459 int
460 GNUNET_CRYPTO_hash_cmp (const struct GNUNET_HashCode *h1,
461                         const struct GNUNET_HashCode *h2)
462 {
463   unsigned int *i1;
464   unsigned int *i2;
465   int i;
466
467   i1 = (unsigned int *) h1;
468   i2 = (unsigned int *) h2;
469   for (i = (sizeof (struct GNUNET_HashCode) / sizeof (unsigned int)) - 1; i >= 0; i--)
470   {
471     if (i1[i] > i2[i])
472       return 1;
473     if (i1[i] < i2[i])
474       return -1;
475   }
476   return 0;
477 }
478
479
480 /**
481  * Find out which of the two `struct GNUNET_HashCode`s is closer to target
482  * in the XOR metric (Kademlia).
483  *
484  * @param h1 some hash code
485  * @param h2 some hash code
486  * @param target some hash code
487  * @return -1 if h1 is closer, 1 if h2 is closer and 0 if h1==h2.
488  */
489 int
490 GNUNET_CRYPTO_hash_xorcmp (const struct GNUNET_HashCode *h1,
491                            const struct GNUNET_HashCode *h2,
492                            const struct GNUNET_HashCode *target)
493 {
494   int i;
495   unsigned int d1;
496   unsigned int d2;
497
498   for (i = sizeof (struct GNUNET_HashCode) / sizeof (unsigned int) - 1; i >= 0; i--)
499   {
500     d1 = ((unsigned int *) h1)[i] ^ ((unsigned int *) target)[i];
501     d2 = ((unsigned int *) h2)[i] ^ ((unsigned int *) target)[i];
502     if (d1 > d2)
503       return 1;
504     else if (d1 < d2)
505       return -1;
506   }
507   return 0;
508 }
509
510
511 /**
512  * @brief Derive an authentication key
513  * @param key authentication key
514  * @param rkey root key
515  * @param salt salt
516  * @param salt_len size of the @a salt
517  * @param ... pair of void * & size_t for context chunks, terminated by NULL
518  */
519 void
520 GNUNET_CRYPTO_hmac_derive_key (struct GNUNET_CRYPTO_AuthKey *key,
521                                const struct GNUNET_CRYPTO_SymmetricSessionKey *rkey,
522                                const void *salt, size_t salt_len, ...)
523 {
524   va_list argp;
525
526   va_start (argp, salt_len);
527   GNUNET_CRYPTO_hmac_derive_key_v (key, rkey, salt, salt_len, argp);
528   va_end (argp);
529 }
530
531
532 /**
533  * @brief Derive an authentication key
534  * @param key authentication key
535  * @param rkey root key
536  * @param salt salt
537  * @param salt_len size of the @a salt
538  * @param argp pair of void * & size_t for context chunks, terminated by NULL
539  */
540 void
541 GNUNET_CRYPTO_hmac_derive_key_v (struct GNUNET_CRYPTO_AuthKey *key,
542                                  const struct GNUNET_CRYPTO_SymmetricSessionKey *rkey,
543                                  const void *salt, size_t salt_len,
544                                  va_list argp)
545 {
546   GNUNET_CRYPTO_kdf_v (key->key, sizeof (key->key),
547                        salt, salt_len,
548                        rkey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
549                        argp);
550 }
551
552
553 /**
554  * Calculate HMAC of a message (RFC 2104)
555  *
556  * @param key secret key
557  * @param plaintext input plaintext
558  * @param plaintext_len length of @a plaintext
559  * @param hmac where to store the hmac
560  */
561 void
562 GNUNET_CRYPTO_hmac (const struct GNUNET_CRYPTO_AuthKey *key,
563                     const void *plaintext, size_t plaintext_len,
564                     struct GNUNET_HashCode * hmac)
565 {
566   gcry_md_hd_t md;
567   const unsigned char *mc;
568
569   GNUNET_assert (GPG_ERR_NO_ERROR ==
570                  gcry_md_open (&md, GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC));
571   gcry_md_setkey (md, key->key, sizeof (key->key));
572   gcry_md_write (md, plaintext, plaintext_len);
573   mc = gcry_md_read (md, GCRY_MD_SHA512);
574   if (mc != NULL)
575     memcpy (hmac->bits, mc, sizeof (hmac->bits));
576   gcry_md_close (md);
577 }
578
579
580 /* end of crypto_hash.c */