1 /* -*- Mode: c; c-basic-offset: 2 -*-
2 *
3 * rdf_digest.c - RDF Digest Factory / Digest implementation
4 *
5 * Copyright (C) 2000-2008, David Beckett http://www.dajobe.org/
6 * Copyright (C) 2000-2005, Copyright (C) 2000-2006, Copyright (C) 2000-2006, University of Bristol, UK http://www.bristol.ac.uk/
7 *
8 * This package is Free Software and part of Redland http://librdf.org/
9 *
10 * It is licensed under the following three licenses as alternatives:
11 * 1. GNU Lesser General Public License (LGPL) V2.1 or any newer version
12 * 2. GNU General Public License (GPL) V2 or any newer version
13 * 3. Apache License, V2.0 or any newer version
14 *
15 * You may not use this file except in compliance with at least one of
16 * the above three licenses.
17 *
18 * See LICENSE.html or LICENSE.txt at the top of this package for the
19 * complete terms and further detail along with the license texts for
20 * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively.
21 *
22 *
23 */
24
25
26 #ifdef HAVE_CONFIG_H
27 #include <rdf_config.h>
28 #endif
29
30 #ifdef WIN32
31 #include <win32_rdf_config.h>
32 #endif
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdarg.h>
37
38 #ifdef HAVE_STDLIB_H
39 #include <stdlib.h>
40 #endif
41
42 #include <redland.h>
43
44 #ifndef STANDALONE
45 /* prototypes for helper functions */
46 static void librdf_delete_digest_factories(librdf_world* world);
47
48
49 /* helper functions */
50 static void
librdf_delete_digest_factories(librdf_world * world)51 librdf_delete_digest_factories(librdf_world *world)
52 {
53 librdf_digest_factory *factory, *next;
54
55 for(factory=world->digests; factory; factory=next) {
56 next=factory->next;
57 LIBRDF_FREE(librdf_digest_factory, factory->name);
58 LIBRDF_FREE(librdf_digest_factory, factory);
59 }
60 world->digests=NULL;
61 }
62
63
64 /**
65 * librdf_digest_register_factory:
66 * @world: redland world object
67 * @name: the name of the hash
68 * @factory: function to be called to register the factory parameters
69 *
70 * Register a hash factory.
71 *
72 **/
73 void
librdf_digest_register_factory(librdf_world * world,const char * name,void (* factory)(librdf_digest_factory *))74 librdf_digest_register_factory(librdf_world *world, const char *name,
75 void (*factory) (librdf_digest_factory*))
76 {
77 librdf_digest_factory *digest;
78
79 librdf_world_open(world);
80
81 #if defined(LIBRDF_DEBUG) && LIBRDF_DEBUG > 1
82 LIBRDF_DEBUG2("Received registration for digest %s\n", name);
83 #endif
84
85 for(digest = world->digests; digest; digest = digest->next ) {
86 if(!strcmp(digest->name, name)) {
87 librdf_log(world, 0, LIBRDF_LOG_ERROR, LIBRDF_FROM_DIGEST, NULL,
88 "digest %s already registered", digest->name);
89 return;
90 }
91 }
92
93 digest = LIBRDF_CALLOC(librdf_digest_factory*, 1, sizeof(*digest));
94 if(!digest)
95 goto oom;
96
97 digest->name = LIBRDF_MALLOC(char*, strlen(name) + 1);
98 if(!digest->name)
99 goto oom_tidy;
100 strcpy(digest->name, name);
101
102 digest->next = world->digests;
103 world->digests = digest;
104
105 /* Call the digest registration function on the new object */
106 (*factory)(digest);
107
108 #if defined(LIBRDF_DEBUG) && LIBRDF_DEBUG > 1
109 LIBRDF_DEBUG4("%s has context size %d and digest size %d\n", name, digest->context_length, digest->digest_length);
110 #endif
111
112 return;
113
114 oom_tidy:
115 LIBRDF_FREE(librdf_digest, digest);
116 oom:
117 LIBRDF_FATAL1(world, LIBRDF_FROM_DIGEST, "Out of memory");
118 }
119
120
121 /**
122 * librdf_get_digest_factory:
123 * @world: redland world object
124 * @name: the name of the factory
125 *
126 * Get a digest factory.
127 *
128 * Return value: the factory or NULL if not found
129 **/
130 librdf_digest_factory*
librdf_get_digest_factory(librdf_world * world,const char * name)131 librdf_get_digest_factory(librdf_world *world, const char *name)
132 {
133 librdf_digest_factory *factory;
134
135 librdf_world_open(world);
136
137 /* return 1st digest if no particular one wanted - why? */
138 if(!name) {
139 factory=world->digests;
140 if(!factory) {
141 LIBRDF_DEBUG1("No digests available\n");
142 return NULL;
143 }
144 } else {
145 for(factory=world->digests; factory; factory=factory->next) {
146 if(!strcmp(factory->name, name))
147 break;
148 }
149 /* else FACTORY with name digest_name not found -> return NULL */
150 }
151
152 return factory;
153 }
154
155
156 /**
157 * librdf_new_digest:
158 * @world: redland world object
159 * @name: the digest name to use to create this digest
160 *
161 * Constructor - create a new #librdf_digest object.
162 *
163 * After construction, data should be added to the digest using
164 * #librdf_digest_update or #librdf_digest_update_string with
165 * #librdf_digest_final to signify finishing. Then the digest
166 * value can be returned directly with #librdf_digest_get_digest
167 * of #librdf_digest_get_digest_length bytes or as a hex encoded
168 * string with #librdf_digest_to_string. The digest can be
169 * re-initialised for new data with #librdf_digest_init.
170 *
171 * Return value: new #librdf_digest object or NULL
172 **/
173 librdf_digest*
librdf_new_digest(librdf_world * world,const char * name)174 librdf_new_digest(librdf_world *world, const char *name)
175 {
176 librdf_digest_factory* factory;
177
178 librdf_world_open(world);
179
180 factory=librdf_get_digest_factory(world, name);
181 if(!factory)
182 return NULL;
183
184 return librdf_new_digest_from_factory(world, factory);
185 }
186
187
188 /**
189 * librdf_new_digest_from_factory:
190 * @world: redland world object
191 * @factory: the digest factory to use to create this digest
192 *
193 * Constructor - create a new #librdf_digest object.
194 *
195 * After construction, data should be added to the digest using
196 * #librdf_digest_update or #librdf_digest_update_string with
197 * #librdf_digest_final to signify finishing. Then the digest
198 * value can be returned directly with #librdf_digest_get_digest
199 * of #librdf_digest_get_digest_length bytes or as a hex encoded
200 * string with #librdf_digest_to_string. The digest can be
201 * re-initialised for new data with #librdf_digest_init.
202 *
203 * Return value: new #librdf_digest object or NULL
204 **/
205 librdf_digest*
librdf_new_digest_from_factory(librdf_world * world,librdf_digest_factory * factory)206 librdf_new_digest_from_factory(librdf_world *world,
207 librdf_digest_factory *factory)
208 {
209 librdf_digest* d;
210
211 librdf_world_open(world);
212
213 d = LIBRDF_CALLOC(librdf_digest*, 1, sizeof(*d));
214 if(!d)
215 return NULL;
216
217 d->world=world;
218
219 d->context = LIBRDF_CALLOC(void*, 1, factory->context_length);
220 if(!d->context) {
221 librdf_free_digest(d);
222 return NULL;
223 }
224
225 d->digest = LIBRDF_CALLOC(unsigned char*, 1, factory->digest_length);
226 if(!d->digest) {
227 librdf_free_digest(d);
228 return NULL;
229 }
230
231 d->factory=factory;
232
233 d->factory->init(d->context);
234
235 return d;
236 }
237
238
239 /**
240 * librdf_free_digest:
241 * @digest: the digest
242 *
243 * Destructor - destroy a #librdf_digest object.
244 *
245 **/
246 void
librdf_free_digest(librdf_digest * digest)247 librdf_free_digest(librdf_digest *digest)
248 {
249 if(!digest)
250 return;
251
252 if(digest->context)
253 LIBRDF_FREE(digest_context, digest->context);
254 if(digest->digest)
255 LIBRDF_FREE(digest_digest, digest->digest);
256 LIBRDF_FREE(librdf_digest, digest);
257 }
258
259
260
261 /* methods */
262
263 /**
264 * librdf_digest_init:
265 * @digest: the digest
266 *
267 * (Re)initialise the librdf_digest object.
268 *
269 * This is automatically called on construction but can be used to
270 * re-initialise the digest to the initial state for digesting new
271 * data.
272 **/
273 void
librdf_digest_init(librdf_digest * digest)274 librdf_digest_init(librdf_digest* digest)
275 {
276 digest->factory->init(digest->context);
277 }
278
279
280 /**
281 * librdf_digest_update:
282 * @digest: the digest
283 * @buf: the data buffer
284 * @length: the length of the data
285 *
286 * Add more data to the librdf_digest object.
287 *
288 **/
289 void
librdf_digest_update(librdf_digest * digest,const unsigned char * buf,size_t length)290 librdf_digest_update(librdf_digest* digest,
291 const unsigned char *buf, size_t length)
292 {
293 digest->factory->update(digest->context, buf, length);
294 }
295
296
297 /**
298 * librdf_digest_update_string:
299 * @digest: the digest
300 * @string: string to add
301 *
302 * Add a string to the librdf_digest object.
303 *
304 **/
305 void
librdf_digest_update_string(librdf_digest * digest,const unsigned char * string)306 librdf_digest_update_string(librdf_digest* digest,
307 const unsigned char *string)
308 {
309 digest->factory->update(digest->context, string,
310 strlen((const char*)string));
311 }
312
313
314 /**
315 * librdf_digest_final:
316 * @digest: the digest
317 *
318 * Finish the digesting of data.
319 *
320 * The digest can now be returned via librdf_digest_get_digest().
321 **/
322 void
librdf_digest_final(librdf_digest * digest)323 librdf_digest_final(librdf_digest* digest)
324 {
325 void* digest_data;
326
327 digest->factory->final(digest->context);
328
329 digest_data=(*(digest->factory->get_digest))(digest->context);
330 memcpy(digest->digest, digest_data, digest->factory->digest_length);
331 }
332
333
334 /**
335 * librdf_digest_get_digest:
336 * @digest: the digest
337 *
338 * Get the calculated digested value.
339 *
340 * Return value: pointer to the memory containing the digest. It will
341 * be #librdf_digest_get_digest_length bytes in length.
342 *
343 **/
344 void*
librdf_digest_get_digest(librdf_digest * digest)345 librdf_digest_get_digest(librdf_digest* digest)
346 {
347 return digest->digest;
348 }
349
350
351 /**
352 * librdf_digest_get_digest_length:
353 * @digest: the digest
354 *
355 * Get length of the calculated digested.
356 *
357 * Return value: size of the digest in bytes
358 *
359 **/
360 size_t
librdf_digest_get_digest_length(librdf_digest * digest)361 librdf_digest_get_digest_length(librdf_digest* digest)
362 {
363 return digest->factory->digest_length;
364 }
365
366
367 /**
368 * librdf_digest_to_string:
369 * @digest: the digest
370 *
371 * Get a string representation of the digest object.
372 *
373 * Return value: a newly allocated string that represents the digest.
374 * This must be released by the caller using librdf_free_memory().
375 **/
376 char*
librdf_digest_to_string(librdf_digest * digest)377 librdf_digest_to_string(librdf_digest* digest)
378 {
379 unsigned char* data = digest->digest;
380 size_t mdlen = digest->factory->digest_length;
381 char* b;
382 size_t i;
383
384 b = (char *)librdf_alloc_memory(1 + (mdlen<<1));
385 if(!b) {
386 LIBRDF_FATAL1(digest->world, LIBRDF_FROM_DIGEST, "Out of memory");
387 return NULL;
388 }
389
390 for(i = 0; i < mdlen; i++)
391 sprintf(b+(i<<1), "%02x", (unsigned int)data[i]);
392
393 b[i<<1] = '\0';
394
395 return b;
396 }
397
398
399 /**
400 * librdf_digest_print:
401 * @digest: the digest
402 * @fh: file handle
403 *
404 * Print the digest to a FILE handle.
405 *
406 **/
407 void
librdf_digest_print(librdf_digest * digest,FILE * fh)408 librdf_digest_print(librdf_digest* digest, FILE* fh)
409 {
410 char *s=librdf_digest_to_string(digest);
411
412 if(!s)
413 return;
414 fputs(s, fh);
415 LIBRDF_FREE(char*, s);
416 }
417
418
419 /**
420 * librdf_init_digest:
421 * @world: redland world object
422 *
423 * INTERNAL - Initialise the digest module.
424 *
425 **/
426 void
librdf_init_digest(librdf_world * world)427 librdf_init_digest(librdf_world *world)
428 {
429 #ifdef HAVE_OPENSSL_DIGESTS
430 librdf_digest_openssl_constructor(world);
431 #endif
432 #ifdef HAVE_LOCAL_MD5_DIGEST
433 librdf_digest_md5_constructor(world);
434 #endif
435 #ifdef HAVE_LOCAL_RIPEMD160_DIGEST
436 librdf_digest_rmd160_constructor(world);
437 #endif
438 #ifdef HAVE_LOCAL_SHA1_DIGEST
439 librdf_digest_sha1_constructor(world);
440 #endif
441
442 /* set default */
443 world->digest_factory=librdf_get_digest_factory(world,
444 world->digest_factory_name);
445
446 }
447
448
449 /**
450 * librdf_finish_digest:
451 * @world: redland world object
452 *
453 * INTERNAL - Terminate the digest module.
454 *
455 **/
456 void
librdf_finish_digest(librdf_world * world)457 librdf_finish_digest(librdf_world *world)
458 {
459 librdf_delete_digest_factories(world);
460 }
461 #endif
462
463
464 #ifdef STANDALONE
465
466 /* one more prototype */
467 int main(int argc, char *argv[]);
468
469 struct t
470 {
471 const char *type;
472 const char *result;
473 };
474
475 int
main(int argc,char * argv[])476 main(int argc, char *argv[])
477 {
478 librdf_digest* d;
479 const char *test_data="http://purl.org/net/dajobe/";
480 struct t test_data_answers[]={
481 {"MD5", "80b52def747e8748199c1a0cf66cb35c"},
482 {"SHA1", "67d6a7b73504ce5c6b47fd6db9b7c4939bfe5174"},
483 {"RIPEMD160", "83ce259f0c23642a95fc92fade583e6d8e15784d"},
484 {NULL, NULL},
485 };
486 int failures=0;
487
488 int i;
489 struct t *answer=NULL;
490 const char *program=librdf_basename((const char*)argv[0]);
491 librdf_world *world;
492
493 world=librdf_new_world();
494
495 for(i=0; ((answer= &test_data_answers[i]) && answer->type != NULL) ; i++) {
496 char *s;
497
498 fprintf(stdout, "%s: Trying to create new %s digest\n", program,
499 answer->type);
500 d=librdf_new_digest(world, answer->type);
501 if(!d) {
502 fprintf(stderr, "%s: Failed to create new digest type %s\n", program,
503 answer->type);
504 continue;
505 }
506 fprintf(stdout, "%s: Initialising digest type %s\n", program, answer->type);
507 librdf_digest_init(d);
508
509 fprintf(stdout, "%s: Writing data into digest\n", program);
510 librdf_digest_update(d, (unsigned char*)test_data, strlen(test_data));
511
512 fprintf(stdout, "%s: Finishing digesting\n", program);
513 librdf_digest_final(d);
514
515 fprintf(stdout, "%s: %s digest of data is: ", program, answer->type);
516 librdf_digest_print(d, stdout);
517 fputc('\n', stdout);
518
519 s=librdf_digest_to_string(d);
520 if(strcmp(s, answer->result)) {
521 fprintf(stderr, "%s: %s digest is wrong - expected: %s\n", program, answer->type, answer->result);
522 failures++;
523 } else
524 fprintf(stderr, "%s: %s digest is correct\n", program, answer->type);
525 LIBRDF_FREE(char*, s);
526
527 fprintf(stdout, "%s: Freeing digest\n", program);
528 librdf_free_digest(d);
529 }
530
531
532 librdf_free_world(world);
533
534 /* keep gcc -Wall happy */
535 return failures;
536 }
537
538 #endif
539