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