source: roaraudio/libroar/hash.c @ 5889:d866fb1213d6

Last change on this file since 5889:d866fb1213d6 was 5837:96349d1c8634, checked in by phi, 11 years ago

Avoid %llX on win32 (Closes: #271)

File size: 12.8 KB
Line 
1//hash.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2013
5 *
6 *  This file is part of libroar a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  libroar is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
32 *  and are therefore GPL. Because of this it may be illigal to use
33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
36#include "libroar.h"
37
38#ifdef ROAR_HAVE_LIBGCRYPT
39#include <gcrypt.h>
40#endif
41
42struct roar_hash_state {
43 struct roar_hash_cmds * cmds;
44 void * state;
45};
46
47static const struct hashes {
48 const roar_hash_t    id;
49 const char         * name;
50 const ssize_t        dlen;
51} _libroar_hashes[] = {
52/*
53grep '^  +HT_' doc/new-cmds | sed 's/ *#(.*)$//; s/^  +HT_//; s/ *=.*$//' | while read n; do printf " {ROAR_HT_%-12s \"%-12s -1   },\n" $n, $n\",; done
54*/
55 {ROAR_HT_NONE,        "NONE",       -1   },
56 {ROAR_HT_MD5,         "MD5",         16  },
57 {ROAR_HT_SHA1,        "SHA1",        20  },
58 {ROAR_HT_RIPEMD160,   "RIPEMD160",   20  },
59 {ROAR_HT_MD2,         "MD2",        -1   },
60 {ROAR_HT_TIGER,       "TIGER",       24  },
61 {ROAR_HT_HAVAL,       "HAVAL",      -1   },
62 {ROAR_HT_SHA256,      "SHA256",      32  },
63 {ROAR_HT_SHA384,      "SHA384",      48  },
64 {ROAR_HT_SHA512,      "SHA512",      64  },
65 {ROAR_HT_SHA224,      "SHA224",      28  },
66 {ROAR_HT_MD4,         "MD4",         16  },
67 {ROAR_HT_CRC32,       "CRC32",       4   },
68 {ROAR_HT_RFC1510,     "RFC1510",     4   },
69 {ROAR_HT_RFC2440,     "RFC2440",     3   },
70 {ROAR_HT_WHIRLPOOL,   "WHIRLPOOL",   64  },
71 {ROAR_HT_UUID,        "UUID",        16  },
72 {ROAR_HT_GTN8,        "GTN8",        1   },
73 {ROAR_HT_GTN16,       "GTN16",       2   },
74 {ROAR_HT_GTN32,       "GTN32",       4   },
75 {ROAR_HT_GTN64,       "GTN64",       8   },
76 {ROAR_HT_CLIENTID,    "CLIENTID",   -1   },
77 {ROAR_HT_STREAMID,    "STREAMID",   -1   },
78 {ROAR_HT_SOURCEID,    "SOURCEID",   -1   },
79 {ROAR_HT_SAMPLEID,    "SAMPLEID",   -1   },
80 {ROAR_HT_MIXERID,     "MIXERID",    -1   },
81 {ROAR_HT_BRIDGEID,    "BRIDGEID",   -1   },
82 {ROAR_HT_LISTENID,    "LISTENID",   -1   },
83 {ROAR_HT_ACTIONID,    "ACTIONID",   -1   },
84 {ROAR_HT_MSGQUEUEID,  "MSGQUEUEID", -1   },
85 {ROAR_HT_MSGBUSID,    "MSGBUSID",   -1   },
86 {ROAR_HT_GTIN8,       "GTIN8",       4   },
87 {ROAR_HT_GTIN13,      "GTIN13",      8   },
88 {ROAR_HT_ISBN10,      "ISBN10",      8   },
89 {ROAR_HT_ISBN13,      "ISBN13",      8   },
90 {ROAR_HT_ADLER32,     "ADLER32",     4   },
91 {-1, NULL, -1}
92};
93
94int roar_hash_sha1_init(void * state);
95int roar_hash_sha1_uninit(void * state);
96int roar_hash_sha1_digest(void * state, void * digest, size_t * len);
97int roar_hash_sha1_proc_block(void * state, const void * block);
98int roar_hash_sha1_proc(void * state, const void * data, size_t len);
99
100static struct roar_hash_cmds _libroar_hash_cmds[] = {
101 {ROAR_HT_TIGER, sizeof(struct roar_hash_tiger), 512,
102  (int (*)(void *))roar_hash_tiger_init, (int (*)(void *))roar_hash_tiger_uninit,
103  (int (*)(void *, void *, size_t *))roar_hash_tiger_get_digest,
104  (int (*)(void *, const void *))roar_hash_tiger_proc_block,
105  (int (*)(void *, const void *, size_t))roar_hash_tiger_proc
106 },
107 {ROAR_HT_RFC2440, sizeof(uint32_t), -1,
108  roar_hash_crc24_init, NULL,
109  roar_hash_crc24_digest, NULL, roar_hash_crc24_proc
110 },
111 {ROAR_HT_ADLER32, sizeof(uint32_t), -1,
112  roar_hash_adler32_init, NULL,
113  roar_hash_adler32_digest, NULL, roar_hash_adler32_proc
114 },
115 {ROAR_HT_SHA1, sizeof(struct roar_hash_sha1), 64,
116  roar_hash_sha1_init, roar_hash_sha1_uninit,
117  roar_hash_sha1_digest, roar_hash_sha1_proc_block, roar_hash_sha1_proc},
118 {-1, -1, -1, NULL, NULL, NULL, NULL, NULL}
119};
120
121static struct roar_hash_cmds * roar_ht2cmds(const roar_hash_t ht) {
122 size_t i;
123
124 for(i = 0; _libroar_hash_cmds[i].algo != (roar_hash_t)-1; i++)
125  if ( _libroar_hash_cmds[i].algo == ht )
126   return &(_libroar_hash_cmds[i]);
127
128 roar_err_set(ROAR_ERROR_NOENT);
129 return NULL;
130}
131
132static inline int roar_ht2gcrypt_tested (const roar_hash_t ht) {
133#ifdef ROAR_HAVE_LIBGCRYPT
134 const char * name;
135
136 if ( ht > 512 )
137  return -1;
138
139 // test the algo:
140 name = gcry_md_algo_name(ht);
141
142 if ( name == NULL )
143  return -1;
144
145 if ( *name == 0 )
146  return -1;
147
148 return ht;
149#else
150 return -1;
151#endif
152}
153
154const char * roar_ht2str (const roar_hash_t  ht) {
155 int i;
156
157 for (i = 0; _libroar_hashes[i].id != (roar_hash_t)-1; i++)
158  if ( _libroar_hashes[i].id == ht )
159   return _libroar_hashes[i].name;
160
161 roar_err_set(ROAR_ERROR_NOENT);
162 return NULL;
163}
164
165roar_hash_t      roar_str2ht (const char * ht) {
166 int i;
167
168 for (i = 0; _libroar_hashes[i].id != (roar_hash_t)-1; i++)
169  if ( !strcasecmp(_libroar_hashes[i].name, ht) )
170   return _libroar_hashes[i].id;
171
172 roar_err_set(ROAR_ERROR_NOENT);
173 return -1;
174}
175
176ssize_t      roar_ht_digestlen (const roar_hash_t   ht) {
177 int i;
178
179 for (i = 0; _libroar_hashes[i].id != (uint_least32_t)-1; i++)
180  if ( _libroar_hashes[i].id == ht )
181   return _libroar_hashes[i].dlen;
182
183 roar_err_set(ROAR_ERROR_NOENT);
184 return -1;
185}
186
187static void _bin2hex(char * out, char * in, size_t inlen, int uppercase) {
188 const char * tab = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
189 unsigned char c;
190 int nib0, nib1;
191
192 for (; inlen; inlen--) {
193  c = *(in++);
194  nib0 = (c & 0x0F) >> 0;
195  nib1 = (c & 0xF0) >> 4;
196//  printf("inlen=%zu, c=%u, nibs={%i, %i}\n", inlen, (unsigned)c, nib1, nib0);
197  *(out++) = tab[nib1];
198  *(out++) = tab[nib0];
199 }
200 *out = 0;
201}
202
203ssize_t      roar_hash_digest2str(char * out, size_t outlen, void * digest, size_t digestlen, roar_hash_t ht) {
204 ssize_t slen = roar_ht_digestlen(ht);
205 union {
206  long long int llsi;
207 } tmp;
208 enum {
209  HEX,
210  TIGER,
211//  BASE64,
212  UUID,
213  INT,
214  GTIN
215 } type = HEX;
216
217 if ( out == NULL || digest == NULL ) {
218  roar_err_set(ROAR_ERROR_FAULT);
219  return -1;
220 }
221
222 if ( !(slen == -1 || (ssize_t)digestlen == slen) ) {
223  roar_err_set(ROAR_ERROR_INVAL);
224  return -1;
225 }
226
227 switch (ht) {
228  case ROAR_HT_TIGER: type = TIGER; break;
229  case ROAR_HT_UUID:  type = UUID;  break;
230  case ROAR_HT_CLIENTID:
231  case ROAR_HT_STREAMID:
232  case ROAR_HT_SOURCEID:
233  case ROAR_HT_SAMPLEID:
234  case ROAR_HT_MIXERID:
235  case ROAR_HT_BRIDGEID:
236  case ROAR_HT_LISTENID:
237  case ROAR_HT_ACTIONID:
238  case ROAR_HT_MSGQUEUEID:
239  case ROAR_HT_MSGBUSID:
240    type = INT;
241   break;
242  case ROAR_HT_GTIN8:
243  case ROAR_HT_GTIN13:
244  case ROAR_HT_ISBN10:
245    type = GTIN;
246   break;
247 }
248
249 switch (type) {
250  case HEX:
251    if ( outlen < (digestlen*2 + 1) ) {
252     roar_err_set(ROAR_ERROR_FAULT);
253     return -1;
254    }
255    _bin2hex(out, digest, digestlen, 0);
256   break;
257  case UUID:
258    if ( outlen < 37 || digestlen != 16 ) {
259     roar_err_set(ROAR_ERROR_FAULT);
260     return -1;
261    }
262    _bin2hex(out+ 0, digest+ 0, 4, 0);
263    out[ 8] = '-';
264    _bin2hex(out+ 9, digest+ 4, 2, 0);
265    out[13] = '-';
266    _bin2hex(out+14, digest+ 6, 2, 0);
267    out[18] = '-';
268    _bin2hex(out+19, digest+ 8, 2, 0);
269    out[23] = '-';
270    _bin2hex(out+24, digest+10, 6, 0);
271//    printf("%s\n", out+24);
272   break;
273  case TIGER:
274    if ( outlen < 51 || digestlen != 24 ) {
275     roar_err_set(ROAR_ERROR_FAULT);
276     return -1;
277    }
278    _bin2hex(out+ 0, digest+ 0, 8, 1);
279    out[16] = ' ';
280    _bin2hex(out+17, digest+ 8, 8, 1);
281    out[33] = ' ';
282    _bin2hex(out+34, digest+16, 8, 1);
283   break;
284  case INT:
285    switch (digestlen) {
286     case 1:
287       tmp.llsi = *(_LIBROAR_GOOD_CAST char*)digest;
288      break;
289     case 2:
290       tmp.llsi = ROAR_NET2HOST16(*(int16_t*)digest);
291      break;
292     case 4:
293       tmp.llsi = ROAR_NET2HOST32(*(int32_t*)digest);
294      break;
295     default:
296       roar_err_set(ROAR_ERROR_NOSYS);
297       return -1;
298      break;
299    }
300    snprintf(out, outlen-1, "%" LIBROAR__ll "i", (LIBROAR__longlong int)tmp.llsi);
301   break;
302  default:
303    roar_err_set(ROAR_ERROR_NOSYS);
304    return -1;
305 }
306
307 out[outlen-1] = 0;
308 return roar_mm_strlen(out);
309}
310
311int          roar_ht_is_supported(const roar_hash_t ht) {
312 roar_crypto_init();
313
314 if ( roar_ht2cmds(ht) != NULL )
315  return 1;
316
317#ifdef ROAR_HAVE_LIBGCRYPT
318 if ( roar_ht2gcrypt_tested(ht) == -1 )
319  return 0;
320
321 return 1;
322#else
323 return 0;
324#endif
325}
326
327struct roar_hash_state * roar_hash_new(roar_hash_t algo) {
328 struct roar_hash_cmds  * cmds = roar_ht2cmds(algo);
329 struct roar_hash_state * self;
330
331 if ( cmds == NULL )
332  return NULL;
333
334 self = roar_mm_malloc(sizeof(struct roar_hash_state));
335
336 if ( self == NULL )
337  return NULL;
338
339 memset(self, 0, sizeof(struct roar_hash_state));
340
341 self->cmds = cmds;
342
343 self->state = roar_mm_malloc(cmds->statelen);
344
345 if ( self->state == NULL ) {
346  roar_mm_free(self);
347  return NULL;
348 }
349
350 memset(self->state, 0, cmds->statelen);
351
352 if ( cmds->init != NULL ) {
353  if ( cmds->init(self->state) == -1 ) {
354   roar_mm_free(self->state);
355   roar_mm_free(self);
356   return NULL;
357  }
358 }
359
360 return self;
361}
362
363int roar_hash_free(struct roar_hash_state * state) {
364 int ret = 0;
365
366 if ( state == NULL ) {
367  roar_err_set(ROAR_ERROR_FAULT);
368  return -1;
369 }
370
371 if ( state->cmds->uninit != NULL )
372  ret = state->cmds->uninit(state->state);
373
374 // clear crypto data.
375 memset(state->state, 0, state->cmds->statelen);
376 roar_mm_free(state->state);
377
378 memset(state, 0, sizeof(struct roar_hash_state));
379 roar_mm_free(state);
380
381 return ret;
382}
383
384int roar_hash_digest(struct roar_hash_state * state, void * digest, size_t * len) {
385 if ( state == NULL ) {
386  roar_err_set(ROAR_ERROR_FAULT);
387  return -1;
388 }
389
390 if ( state->cmds->digest == NULL ) {
391  roar_err_set(ROAR_ERROR_NOSYS);
392  return -1;
393 }
394
395 return state->cmds->digest(state->state, digest, len);
396}
397
398int roar_hash_proc(struct roar_hash_state * state, const void * data, size_t len) {
399 if ( state == NULL ) {
400  roar_err_set(ROAR_ERROR_FAULT);
401  return -1;
402 }
403
404 if ( state->cmds->proc == NULL ) {
405  roar_err_set(ROAR_ERROR_NOSYS);
406  return -1;
407 }
408
409 return state->cmds->proc(state->state, data, len);
410}
411
412int roar_hash_buffer(void * digest, const void * data, size_t datalen, roar_hash_t algo) {
413 roar_crypto_init();
414
415 return roar_hash_salted_buffer(digest, data, datalen, algo, NULL, 0);
416}
417
418#ifdef ROAR_HAVE_LIBGCRYPT
419static inline int roar_hash_salted_buffer_gcrypt(void * digest, const void * data, size_t datalen, roar_hash_t algo, const void * salt, size_t saltlen) {
420 gcry_md_hd_t hdl;
421
422 roar_crypto_init();
423
424 algo = roar_ht2gcrypt_tested(algo);
425 if ( algo == (roar_hash_t)-1 )
426  return -1;
427
428
429 if ( salt == NULL ) {
430  // optimized for unsalted:
431  gcry_md_hash_buffer(algo, digest, data, datalen);
432  return 0;
433 } else {
434  if ( gcry_md_open(&hdl, algo, 0) != 0 )
435   return -1;
436
437  gcry_md_write(hdl, data, datalen);
438  gcry_md_write(hdl, salt, saltlen);
439
440  memcpy(digest, gcry_md_read(hdl, algo), gcry_md_get_algo_dlen(algo));
441
442  gcry_md_close(hdl);
443 }
444
445 return 0;
446}
447#endif
448
449int roar_hash_salted_buffer(void * digest, const void * data, size_t datalen, roar_hash_t algo, const void * salt, size_t saltlen) {
450 struct roar_hash_state * state;
451 size_t len;
452 int ret = 0;
453
454 ROAR_DBG("roar_hash_salted_buffer(digest=%p, data=%p, datalen=%llu, algo=%i, salt=%p, saltlen=%llu) = ?", digest, data, (unsigned long long int)datalen, algo, salt, (unsigned long long int)saltlen);
455
456 if ( digest == NULL || data == NULL ) {
457  roar_err_set(ROAR_ERROR_FAULT);
458  return -1;
459 }
460
461 len = roar_ht_digestlen(algo);
462 if ( len == (size_t)-1 ) /* this is a hack to avoid len to be of type ssize_t which breaks following code */
463  return -1;
464
465 if ( (state = roar_hash_new(algo)) != NULL ) {
466  ROAR_DBG("roar_hash_salted_buffer(*): ret=%i", ret);
467
468  if ( roar_hash_proc(state, data, datalen) == -1 )
469   ret = -1;
470
471  ROAR_DBG("roar_hash_salted_buffer(*): ret=%i", ret);
472
473  if ( saltlen != 0 )
474   if ( roar_hash_proc(state, salt, saltlen) == -1 )
475    ret = -1;
476
477  ROAR_DBG("roar_hash_salted_buffer(*): ret=%i", ret);
478
479  if ( roar_hash_digest(state, digest, &len) == -1 )
480   ret = -1;
481
482  ROAR_DBG("roar_hash_salted_buffer(*): ret=%i", ret);
483
484  if ( roar_hash_free(state) == -1 )
485   ret = -1;
486
487  ROAR_DBG("roar_hash_salted_buffer(*): ret=%i", ret);
488
489  return ret;
490 }
491
492 ROAR_DBG("roar_hash_salted_buffer(*): state=%p", state);
493
494#ifdef ROAR_HAVE_LIBGCRYPT
495 return roar_hash_salted_buffer_gcrypt(digest, data, datalen, algo, salt, saltlen);
496#else
497 roar_err_set(ROAR_ERROR_NOTSUP);
498 return -1;
499#endif
500}
501
502//ll
Note: See TracBrowser for help on using the repository browser.