5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2008 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
20 #include "silccrypto.h"
27 /* The main SILC hash structure. */
28 struct SilcHashStruct {
34 /* List of dynamically registered hash functions. */
35 SilcDList silc_hash_list = NULL;
36 #endif /* SILC_SYMBIAN */
38 /* Default hash functions for silc_hash_register_default(). */
39 const SilcHashObject silc_default_hash[] =
41 { "sha256", "2.16.840.1.101.3.4.2.1",
42 32, 64, silc_sha256_init, silc_sha256_update, silc_sha256_final,
43 silc_sha256_transform, silc_sha256_context_len },
44 { "sha512", "2.16.840.1.101.3.4.2.3",
45 32, 64, silc_sha512_init, silc_sha512_update, silc_sha512_final,
46 silc_sha512_transform, silc_sha512_context_len },
47 { "sha1", "1.3.14.3.2.26",
48 20, 64, silc_sha1_init, silc_sha1_update, silc_sha1_final,
49 silc_sha1_transform, silc_sha1_context_len },
50 { "md5", "1.2.840.113549.2.5",
51 16, 64, silc_md5_init, silc_md5_update, silc_md5_final,
52 silc_md5_transform, silc_md5_context_len },
54 { NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
57 /* Registers a new hash function */
59 SilcBool silc_hash_register(const SilcHashObject *hash)
64 SILC_LOG_DEBUG(("Registering new hash function `%s'", hash->name));
66 /* Check for existing */
68 SilcHashObject *entry;
69 silc_dlist_start(silc_hash_list);
70 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
71 if (!strcmp(entry->name, hash->name))
76 new = silc_calloc(1, sizeof(*new));
79 new->name = strdup(hash->name);
84 new->oid = strdup(hash->oid);
89 new->hash_len = hash->hash_len;
90 new->block_len = hash->block_len;
91 new->init = hash->init;
92 new->update = hash->update;
93 new->final = hash->final;
94 new->transform = hash->transform;
95 new->context_len = hash->context_len;
98 if (silc_hash_list == NULL)
99 silc_hash_list = silc_dlist_init();
100 silc_dlist_add(silc_hash_list, new);
102 #endif /* SILC_SYMBIAN */
106 /* Unregister a hash function */
108 SilcBool silc_hash_unregister(SilcHashObject *hash)
111 SilcHashObject *entry;
113 SILC_LOG_DEBUG(("Unregistering hash function"));
118 silc_dlist_start(silc_hash_list);
119 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
120 if (hash == SILC_ALL_HASH_FUNCTIONS || entry == hash) {
121 silc_dlist_del(silc_hash_list, entry);
122 silc_free(entry->name);
123 silc_free(entry->oid);
126 if (silc_dlist_count(silc_hash_list) == 0) {
127 silc_dlist_uninit(silc_hash_list);
128 silc_hash_list = NULL;
135 #endif /* SILC_SYMBIAN */
139 /* Register default hash functions */
141 SilcBool silc_hash_register_default(void)
143 /* We use builtin hash functions */
147 /* Unregister all hash functions */
149 SilcBool silc_hash_unregister_all(void)
152 SilcHashObject *entry;
157 silc_dlist_start(silc_hash_list);
158 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
159 silc_hash_unregister(entry);
163 #endif /* SILC_SYMBIAN */
167 /* Allocates a new SilcHash object. New object is returned into new_hash
170 SilcBool silc_hash_alloc(const char *name, SilcHash *new_hash)
172 SilcHashObject *entry = NULL;
175 SILC_LOG_DEBUG(("Allocating new hash %s", name));
178 /* Check list of registered hash functions */
179 if (silc_hash_list) {
180 silc_dlist_start(silc_hash_list);
181 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
182 if (!strcmp(entry->name, name))
186 #endif /* SILC_SYMBIAN */
189 /* Check builtin hash function list */
190 for (i = 0; silc_default_hash[i].name; i++) {
191 if (!strcmp(silc_default_hash[i].name, name)) {
192 entry = (SilcHashObject *)&(silc_default_hash[i]);
199 *new_hash = silc_calloc(1, sizeof(**new_hash));
202 (*new_hash)->hash = entry;
203 (*new_hash)->context = silc_calloc(1, entry->context_len());
204 if (!(*new_hash)->context) {
205 silc_free(*new_hash);
214 /* Allocate hash by OID string */
216 SilcBool silc_hash_alloc_by_oid(const char *oid, SilcHash *new_hash)
218 SilcHashObject *entry = NULL;
221 SILC_LOG_DEBUG(("Allocating new hash %s", oid));
224 /* Check list of registered hash functions */
225 if (silc_hash_list) {
226 silc_dlist_start(silc_hash_list);
227 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
228 if (!strcmp(entry->oid, oid))
232 #endif /* SILC_SYMBIAN */
235 /* Check builtin hash function list */
236 for (i = 0; silc_default_hash[i].oid; i++) {
237 if (!strcmp(silc_default_hash[i].oid, oid)) {
238 entry = (SilcHashObject *)&(silc_default_hash[i]);
245 *new_hash = silc_calloc(1, sizeof(**new_hash));
248 (*new_hash)->hash = entry;
249 (*new_hash)->context = silc_calloc(1, entry->context_len());
250 if (!(*new_hash)->context) {
251 silc_free(*new_hash);
260 /* Free's the SilcHash object */
262 void silc_hash_free(SilcHash hash)
265 silc_free(hash->context);
270 /* Returns the length of the hash digest. */
272 SilcUInt32 silc_hash_len(SilcHash hash)
274 return hash->hash->hash_len;
277 /* Returns the block lenght of the hash. */
279 SilcUInt32 silc_hash_block_len(SilcHash hash)
281 return hash->hash->block_len;
284 /* Returns the name of the hash function */
286 const char *silc_hash_get_name(SilcHash hash)
288 return hash->hash->name;
291 /* Returns hash OID string */
293 const char *silc_hash_get_oid(SilcHash hash)
295 return hash->hash->oid;
298 /* Returns TRUE if hash algorithm `name' is supported. */
300 SilcBool silc_hash_is_supported(const char *name)
302 SilcHashObject *entry;
306 if (silc_hash_list) {
307 silc_dlist_start(silc_hash_list);
308 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
309 if (!strcmp(entry->name, name))
313 #endif /* SILC_SYMBIAN */
315 for (i = 0; silc_default_hash[i].name; i++)
316 if (!strcmp(silc_default_hash[i].name, name))
322 /* Returns comma separated list of supported hash functions. */
324 char *silc_hash_get_supported(void)
326 SilcHashObject *entry, *entry2;
331 if (silc_hash_list) {
332 silc_dlist_start(silc_hash_list);
333 while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
334 len += strlen(entry->name);
335 list = silc_realloc(list, len + 1);
337 memcpy(list + (len - strlen(entry->name)),
338 entry->name, strlen(entry->name));
339 memcpy(list + len, ",", 1);
343 #endif /* SILC_SYMBIAN */
345 for (i = 0; silc_default_hash[i].name; i++) {
346 entry = (SilcHashObject *)&(silc_default_hash[i]);
348 if (silc_hash_list) {
349 silc_dlist_start(silc_hash_list);
350 while ((entry2 = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
351 if (!strcmp(entry2->name, entry->name))
358 len += strlen(entry->name);
359 list = silc_realloc(list, len + 1);
361 memcpy(list + (len - strlen(entry->name)),
362 entry->name, strlen(entry->name));
363 memcpy(list + len, ",", 1);
372 /* Creates the hash value and returns it to the return_hash argument. */
374 void silc_hash_make(SilcHash hash, const unsigned char *data,
375 SilcUInt32 len, unsigned char *return_hash)
377 silc_hash_init(hash);
378 silc_hash_update(hash, data, len);
379 silc_hash_final(hash, return_hash);
382 void silc_hash_init(SilcHash hash)
384 hash->hash->init(hash->context);
387 void silc_hash_update(SilcHash hash, const unsigned char *data,
390 hash->hash->update(hash->context, (unsigned char *)data, data_len);
393 void silc_hash_final(SilcHash hash, unsigned char *return_hash)
395 hash->hash->final(hash->context, return_hash);
398 void silc_hash_transform(SilcHash hash, void *state,
399 const unsigned char *data)
401 hash->hash->transform(state, data);
404 /* Creates fingerprint of the data. If `hash' is NULL SHA1 is used as
405 default hash function. The returned fingerprint must be freed by the
408 char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data,
411 SilcHash new_hash = NULL;
416 if (!silc_hash_alloc("sha1", &new_hash))
421 silc_hash_make(hash, data, data_len, h);
422 ret = silc_fingerprint(h, hash->hash->hash_len);
424 if (new_hash != NULL)
425 silc_hash_free(new_hash);
429 static const char vo[]= "aeiouy";
430 static const char co[]= "bcdfghklmnprstvzx";
432 /* Creates a babbleprint (Bubble Babble Encoding, developed by Antti
433 Huima (draft-huima-babble-01.txt)), by first computing real fingerprint
434 using `hash' or if NULL, then using SHA1, and then encoding the
435 fingerprint to the babbleprint. */
437 char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
440 SilcHash new_hash = NULL;
442 unsigned char hval[32];
443 unsigned int a, b, c, d, e, check;
447 if (!silc_hash_alloc("sha1", &new_hash))
452 /* Take fingerprint */
453 silc_hash_make(hash, data, data_len, hval);
455 /* Encode babbleprint */
456 out_len = (((hash->hash->hash_len + 1) / 2) + 1) * 6;
457 babbleprint = silc_calloc(out_len, sizeof(*babbleprint));
459 silc_hash_free(new_hash);
462 babbleprint[0] = co[16];
465 for (i = 0, k = 1; i < hash->hash->hash_len - 1; i += 2, k += 6) {
466 a = (((hval[i] >> 6) & 3) + check) % 6;
467 b = (hval[i] >> 2) & 15;
468 c = ((hval[i] & 3) + (check / 6)) % 6;
469 d = (hval[i + 1] >> 4) & 15;
470 e = hval[i + 1] & 15;
472 check = ((check * 5) + (hval[i] * 7) + hval[i + 1]) % 36;
474 babbleprint[k + 0] = vo[a];
475 babbleprint[k + 1] = co[b];
476 babbleprint[k + 2] = vo[c];
477 babbleprint[k + 3] = co[d];
478 babbleprint[k + 4] = '-';
479 babbleprint[k + 5] = co[e];
482 if ((hash->hash->hash_len % 2) != 0) {
483 a = (((hval[i] >> 6) & 3) + check) % 6;
484 b = (hval[i] >> 2) & 15;
485 c = ((hval[i] & 3) + (check / 6)) % 6;
486 babbleprint[k + 0] = vo[a];
487 babbleprint[k + 1] = co[b];
488 babbleprint[k + 2] = vo[c];
493 babbleprint[k + 0] = vo[a];
494 babbleprint[k + 1] = co[b];
495 babbleprint[k + 2] = vo[c];
497 babbleprint[k + 3] = co[16];
499 if (new_hash != NULL)
500 silc_hash_free(new_hash);