source: roaraudio/libroar/hash.c @ 5407:edd703e264d0

Last change on this file since 5407:edd703e264d0 was 5381:430b1d26e12d, checked in by phi, 12 years ago

updated copyright years

File size: 12.2 KB
Line 
1//hash.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2012
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
94static struct roar_hash_cmds _libroar_hash_cmds[] = {
95 {ROAR_HT_TIGER, sizeof(struct roar_hash_tiger), 512,
96  (int (*)(void *))roar_hash_tiger_init, (int (*)(void *))roar_hash_tiger_uninit,
97  (int (*)(void *, void *, size_t *))roar_hash_tiger_get_digest,
98  (int (*)(void *, const void *))roar_hash_tiger_proc_block,
99  (int (*)(void *, const void *, size_t))roar_hash_tiger_proc
100 },
101 {ROAR_HT_RFC2440, sizeof(uint32_t), -1,
102  roar_hash_crc24_init, NULL,
103  roar_hash_crc24_digest, NULL, roar_hash_crc24_proc
104 },
105 {ROAR_HT_ADLER32, sizeof(uint32_t), -1,
106  roar_hash_adler32_init, NULL,
107  roar_hash_adler32_digest, NULL, roar_hash_adler32_proc
108 },
109 {-1, -1, -1, NULL, NULL, NULL, NULL, NULL}
110};
111
112static struct roar_hash_cmds * roar_ht2cmds(const roar_hash_t ht) {
113 size_t i;
114
115 for(i = 0; _libroar_hash_cmds[i].algo != (roar_hash_t)-1; i++)
116  if ( _libroar_hash_cmds[i].algo == ht )
117   return &(_libroar_hash_cmds[i]);
118
119 roar_err_set(ROAR_ERROR_NOENT);
120 return NULL;
121}
122
123static inline int roar_ht2gcrypt_tested (const roar_hash_t ht) {
124#ifdef ROAR_HAVE_LIBGCRYPT
125 const char * name;
126
127 if ( ht > 512 )
128  return -1;
129
130 // test the algo:
131 name = gcry_md_algo_name(ht);
132
133 if ( name == NULL )
134  return -1;
135
136 if ( *name == 0 )
137  return -1;
138
139 return ht;
140#else
141 return -1;
142#endif
143}
144
145const char * roar_ht2str (const roar_hash_t  ht) {
146 int i;
147
148 for (i = 0; _libroar_hashes[i].id != (roar_hash_t)-1; i++)
149  if ( _libroar_hashes[i].id == ht )
150   return _libroar_hashes[i].name;
151
152 roar_err_set(ROAR_ERROR_NOENT);
153 return NULL;
154}
155
156roar_hash_t      roar_str2ht (const char * ht) {
157 int i;
158
159 for (i = 0; _libroar_hashes[i].id != (roar_hash_t)-1; i++)
160  if ( !strcasecmp(_libroar_hashes[i].name, ht) )
161   return _libroar_hashes[i].id;
162
163 roar_err_set(ROAR_ERROR_NOENT);
164 return -1;
165}
166
167ssize_t      roar_ht_digestlen (const roar_hash_t   ht) {
168 int i;
169
170 for (i = 0; _libroar_hashes[i].id != (uint_least32_t)-1; i++)
171  if ( _libroar_hashes[i].id == ht )
172   return _libroar_hashes[i].dlen;
173
174 roar_err_set(ROAR_ERROR_NOENT);
175 return -1;
176}
177
178static void _bin2hex(char * out, char * in, size_t inlen, int uppercase) {
179 const char * tab = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
180 unsigned char c;
181 int nib0, nib1;
182
183 for (; inlen; inlen--) {
184  c = *(in++);
185  nib0 = (c & 0x0F) >> 0;
186  nib1 = (c & 0xF0) >> 4;
187//  printf("inlen=%zu, c=%u, nibs={%i, %i}\n", inlen, (unsigned)c, nib1, nib0);
188  *(out++) = tab[nib1];
189  *(out++) = tab[nib0];
190 }
191 *out = 0;
192}
193
194ssize_t      roar_hash_digest2str(char * out, size_t outlen, void * digest, size_t digestlen, roar_hash_t ht) {
195 ssize_t slen = roar_ht_digestlen(ht);
196 union {
197  long long int llsi;
198 } tmp;
199 enum {
200  HEX,
201  TIGER,
202//  BASE64,
203  UUID,
204  INT,
205  GTIN
206 } type = HEX;
207
208 if ( out == NULL || digest == NULL ) {
209  roar_err_set(ROAR_ERROR_FAULT);
210  return -1;
211 }
212
213 if ( !(slen == -1 || (ssize_t)digestlen == slen) ) {
214  roar_err_set(ROAR_ERROR_INVAL);
215  return -1;
216 }
217
218 switch (ht) {
219  case ROAR_HT_TIGER: type = TIGER; break;
220  case ROAR_HT_UUID:  type = UUID;  break;
221  case ROAR_HT_CLIENTID:
222  case ROAR_HT_STREAMID:
223  case ROAR_HT_SOURCEID:
224  case ROAR_HT_SAMPLEID:
225  case ROAR_HT_MIXERID:
226  case ROAR_HT_BRIDGEID:
227  case ROAR_HT_LISTENID:
228  case ROAR_HT_ACTIONID:
229  case ROAR_HT_MSGQUEUEID:
230  case ROAR_HT_MSGBUSID:
231    type = INT;
232   break;
233  case ROAR_HT_GTIN8:
234  case ROAR_HT_GTIN13:
235  case ROAR_HT_ISBN10:
236    type = GTIN;
237   break;
238 }
239
240 switch (type) {
241  case HEX:
242    if ( outlen < (digestlen*2 + 1) ) {
243     roar_err_set(ROAR_ERROR_FAULT);
244     return -1;
245    }
246    _bin2hex(out, digest, digestlen, 0);
247   break;
248  case UUID:
249    if ( outlen < 37 || digestlen != 16 ) {
250     roar_err_set(ROAR_ERROR_FAULT);
251     return -1;
252    }
253    _bin2hex(out+ 0, digest+ 0, 4, 0);
254    out[ 8] = '-';
255    _bin2hex(out+ 9, digest+ 4, 2, 0);
256    out[13] = '-';
257    _bin2hex(out+14, digest+ 6, 2, 0);
258    out[18] = '-';
259    _bin2hex(out+19, digest+ 8, 2, 0);
260    out[23] = '-';
261    _bin2hex(out+24, digest+10, 6, 0);
262//    printf("%s\n", out+24);
263   break;
264  case TIGER:
265    if ( outlen < 51 || digestlen != 24 ) {
266     roar_err_set(ROAR_ERROR_FAULT);
267     return -1;
268    }
269    _bin2hex(out+ 0, digest+ 0, 8, 1);
270    out[16] = ' ';
271    _bin2hex(out+17, digest+ 8, 8, 1);
272    out[33] = ' ';
273    _bin2hex(out+34, digest+16, 8, 1);
274   break;
275  case INT:
276    switch (digestlen) {
277     case 1:
278       tmp.llsi = *(_LIBROAR_GOOD_CAST char*)digest;
279      break;
280     case 2:
281       tmp.llsi = ROAR_NET2HOST16(*(int16_t*)digest);
282      break;
283     case 4:
284       tmp.llsi = ROAR_NET2HOST32(*(int32_t*)digest);
285      break;
286     default:
287       roar_err_set(ROAR_ERROR_NOSYS);
288       return -1;
289      break;
290    }
291    snprintf(out, outlen-1, "%lli", tmp.llsi);
292   break;
293  default:
294    roar_err_set(ROAR_ERROR_NOSYS);
295    return -1;
296 }
297
298 out[outlen-1] = 0;
299 return roar_mm_strlen(out);
300}
301
302int          roar_ht_is_supported(const roar_hash_t ht) {
303 roar_crypto_init();
304
305 if ( roar_ht2cmds(ht) != NULL )
306  return 1;
307
308#ifdef ROAR_HAVE_LIBGCRYPT
309 if ( roar_ht2gcrypt_tested(ht) == -1 )
310  return 0;
311
312 return 1;
313#else
314 return 0;
315#endif
316}
317
318struct roar_hash_state * roar_hash_new(roar_hash_t algo) {
319 struct roar_hash_cmds  * cmds = roar_ht2cmds(algo);
320 struct roar_hash_state * self;
321
322 if ( cmds == NULL )
323  return NULL;
324
325 self = roar_mm_malloc(sizeof(struct roar_hash_state));
326
327 if ( self == NULL )
328  return NULL;
329
330 memset(self, 0, sizeof(struct roar_hash_state));
331
332 self->cmds = cmds;
333
334 self->state = roar_mm_malloc(cmds->statelen);
335
336 if ( self->state == NULL ) {
337  roar_mm_free(self);
338  return NULL;
339 }
340
341 memset(self->state, 0, cmds->statelen);
342
343 if ( cmds->init != NULL ) {
344  if ( cmds->init(self->state) == -1 ) {
345   roar_mm_free(self->state);
346   roar_mm_free(self);
347   return NULL;
348  }
349 }
350
351 return self;
352}
353
354int roar_hash_free(struct roar_hash_state * state) {
355 int ret = 0;
356
357 if ( state == NULL ) {
358  roar_err_set(ROAR_ERROR_FAULT);
359  return -1;
360 }
361
362 if ( state->cmds->uninit != NULL )
363  ret = state->cmds->uninit(state->state);
364
365 roar_mm_free(state->state);
366 roar_mm_free(state);
367
368 return ret;
369}
370
371int roar_hash_digest(struct roar_hash_state * state, void * digest, size_t * len) {
372 if ( state == NULL ) {
373  roar_err_set(ROAR_ERROR_FAULT);
374  return -1;
375 }
376
377 if ( state->cmds->digest == NULL ) {
378  roar_err_set(ROAR_ERROR_NOSYS);
379  return -1;
380 }
381
382 return state->cmds->digest(state->state, digest, len);
383}
384
385int roar_hash_proc(struct roar_hash_state * state, const void * data, size_t len) {
386 if ( state == NULL ) {
387  roar_err_set(ROAR_ERROR_FAULT);
388  return -1;
389 }
390
391 if ( state->cmds->proc == NULL ) {
392  roar_err_set(ROAR_ERROR_NOSYS);
393  return -1;
394 }
395
396 return state->cmds->proc(state->state, data, len);
397}
398
399int roar_hash_buffer(void * digest, const void * data, size_t datalen, roar_hash_t algo) {
400 roar_crypto_init();
401
402 return roar_hash_salted_buffer(digest, data, datalen, algo, NULL, 0);
403}
404
405#ifdef ROAR_HAVE_LIBGCRYPT
406static 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) {
407 gcry_md_hd_t hdl;
408
409 roar_crypto_init();
410
411 algo = roar_ht2gcrypt_tested(algo);
412 if ( algo == (roar_hash_t)-1 )
413  return -1;
414
415
416 if ( salt == NULL ) {
417  // optimized for unsalted:
418  gcry_md_hash_buffer(algo, digest, data, datalen);
419  return 0;
420 } else {
421  if ( gcry_md_open(&hdl, algo, 0) != 0 )
422   return -1;
423
424  gcry_md_write(hdl, data, datalen);
425  gcry_md_write(hdl, salt, saltlen);
426
427  memcpy(digest, gcry_md_read(hdl, algo), gcry_md_get_algo_dlen(algo));
428
429  gcry_md_close(hdl);
430 }
431
432 return 0;
433}
434#endif
435
436int roar_hash_salted_buffer(void * digest, const void * data, size_t datalen, roar_hash_t algo, const void * salt, size_t saltlen) {
437 struct roar_hash_state * state;
438 size_t len;
439 int ret = 0;
440
441 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);
442
443 if ( digest == NULL || data == NULL ) {
444  roar_err_set(ROAR_ERROR_FAULT);
445  return -1;
446 }
447
448 len = roar_ht_digestlen(algo);
449 if ( len == (size_t)-1 ) /* this is a hack to avoid len to be of type ssize_t which breaks following code */
450  return -1;
451
452 if ( (state = roar_hash_new(algo)) != NULL ) {
453  ROAR_DBG("roar_hash_salted_buffer(*): ret=%i", ret);
454
455  if ( roar_hash_proc(state, data, datalen) == -1 )
456   ret = -1;
457
458  ROAR_DBG("roar_hash_salted_buffer(*): ret=%i", ret);
459
460  if ( saltlen != 0 )
461   if ( roar_hash_proc(state, salt, saltlen) == -1 )
462    ret = -1;
463
464  ROAR_DBG("roar_hash_salted_buffer(*): ret=%i", ret);
465
466  if ( roar_hash_digest(state, digest, &len) == -1 )
467   ret = -1;
468
469  ROAR_DBG("roar_hash_salted_buffer(*): ret=%i", ret);
470
471  if ( roar_hash_free(state) == -1 )
472   ret = -1;
473
474  ROAR_DBG("roar_hash_salted_buffer(*): ret=%i", ret);
475
476  return ret;
477 }
478
479 ROAR_DBG("roar_hash_salted_buffer(*): state=%p", state);
480
481#ifdef ROAR_HAVE_LIBGCRYPT
482 return roar_hash_salted_buffer_gcrypt(digest, data, datalen, algo, salt, saltlen);
483#else
484 roar_err_set(ROAR_ERROR_NOTSUP);
485 return -1;
486#endif
487}
488
489//ll
Note: See TracBrowser for help on using the repository browser.