source: roaraudio/libroar/hash.c @ 5529:d86f148f08b2

Last change on this file since 5529:d86f148f08b2 was 5529:d86f148f08b2, checked in by phi, 12 years ago

Implemented SHA1 support (Closes: #232)

File size: 12.7 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
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, "%lli", 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 roar_mm_free(state->state);
375 roar_mm_free(state);
376
377 return ret;
378}
379
380int roar_hash_digest(struct roar_hash_state * state, void * digest, size_t * len) {
381 if ( state == NULL ) {
382  roar_err_set(ROAR_ERROR_FAULT);
383  return -1;
384 }
385
386 if ( state->cmds->digest == NULL ) {
387  roar_err_set(ROAR_ERROR_NOSYS);
388  return -1;
389 }
390
391 return state->cmds->digest(state->state, digest, len);
392}
393
394int roar_hash_proc(struct roar_hash_state * state, const void * data, size_t len) {
395 if ( state == NULL ) {
396  roar_err_set(ROAR_ERROR_FAULT);
397  return -1;
398 }
399
400 if ( state->cmds->proc == NULL ) {
401  roar_err_set(ROAR_ERROR_NOSYS);
402  return -1;
403 }
404
405 return state->cmds->proc(state->state, data, len);
406}
407
408int roar_hash_buffer(void * digest, const void * data, size_t datalen, roar_hash_t algo) {
409 roar_crypto_init();
410
411 return roar_hash_salted_buffer(digest, data, datalen, algo, NULL, 0);
412}
413
414#ifdef ROAR_HAVE_LIBGCRYPT
415static 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) {
416 gcry_md_hd_t hdl;
417
418 roar_crypto_init();
419
420 algo = roar_ht2gcrypt_tested(algo);
421 if ( algo == (roar_hash_t)-1 )
422  return -1;
423
424
425 if ( salt == NULL ) {
426  // optimized for unsalted:
427  gcry_md_hash_buffer(algo, digest, data, datalen);
428  return 0;
429 } else {
430  if ( gcry_md_open(&hdl, algo, 0) != 0 )
431   return -1;
432
433  gcry_md_write(hdl, data, datalen);
434  gcry_md_write(hdl, salt, saltlen);
435
436  memcpy(digest, gcry_md_read(hdl, algo), gcry_md_get_algo_dlen(algo));
437
438  gcry_md_close(hdl);
439 }
440
441 return 0;
442}
443#endif
444
445int roar_hash_salted_buffer(void * digest, const void * data, size_t datalen, roar_hash_t algo, const void * salt, size_t saltlen) {
446 struct roar_hash_state * state;
447 size_t len;
448 int ret = 0;
449
450 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);
451
452 if ( digest == NULL || data == NULL ) {
453  roar_err_set(ROAR_ERROR_FAULT);
454  return -1;
455 }
456
457 len = roar_ht_digestlen(algo);
458 if ( len == (size_t)-1 ) /* this is a hack to avoid len to be of type ssize_t which breaks following code */
459  return -1;
460
461 if ( (state = roar_hash_new(algo)) != NULL ) {
462  ROAR_DBG("roar_hash_salted_buffer(*): ret=%i", ret);
463
464  if ( roar_hash_proc(state, data, datalen) == -1 )
465   ret = -1;
466
467  ROAR_DBG("roar_hash_salted_buffer(*): ret=%i", ret);
468
469  if ( saltlen != 0 )
470   if ( roar_hash_proc(state, salt, saltlen) == -1 )
471    ret = -1;
472
473  ROAR_DBG("roar_hash_salted_buffer(*): ret=%i", ret);
474
475  if ( roar_hash_digest(state, digest, &len) == -1 )
476   ret = -1;
477
478  ROAR_DBG("roar_hash_salted_buffer(*): ret=%i", ret);
479
480  if ( roar_hash_free(state) == -1 )
481   ret = -1;
482
483  ROAR_DBG("roar_hash_salted_buffer(*): ret=%i", ret);
484
485  return ret;
486 }
487
488 ROAR_DBG("roar_hash_salted_buffer(*): state=%p", state);
489
490#ifdef ROAR_HAVE_LIBGCRYPT
491 return roar_hash_salted_buffer_gcrypt(digest, data, datalen, algo, salt, saltlen);
492#else
493 roar_err_set(ROAR_ERROR_NOTSUP);
494 return -1;
495#endif
496}
497
498//ll
Note: See TracBrowser for help on using the repository browser.