ext/digest/digest.c

Go to the documentation of this file.
00001 /************************************************
00002 
00003   digest.c -
00004 
00005   $Author: knu $
00006   created at: Fri May 25 08:57:27 JST 2001
00007 
00008   Copyright (C) 1995-2001 Yukihiro Matsumoto
00009   Copyright (C) 2001-2006 Akinori MUSHA
00010 
00011   $RoughId: digest.c,v 1.16 2001/07/13 15:38:27 knu Exp $
00012   $Id: digest.c 26339 2010-01-17 19:12:10Z knu $
00013 
00014 ************************************************/
00015 
00016 #include "digest.h"
00017 
00018 static VALUE rb_mDigest;
00019 static VALUE rb_mDigest_Instance;
00020 static VALUE rb_cDigest_Class;
00021 static VALUE rb_cDigest_Base;
00022 
00023 static ID id_reset, id_update, id_finish, id_digest, id_hexdigest, id_digest_length;
00024 static ID id_metadata;
00025 
00026 RUBY_EXTERN void Init_digest_base(void);
00027 
00028 /*
00029  * Document-module: Digest
00030  *
00031  * This module provides a framework for message digest libraries.
00032  */
00033 
00034 static VALUE
00035 hexencode_str_new(VALUE str_digest)
00036 {
00037     char *digest;
00038     size_t digest_len;
00039     size_t i;
00040     VALUE str;
00041     char *p;
00042     static const char hex[] = {
00043         '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
00044         'a', 'b', 'c', 'd', 'e', 'f'
00045     };
00046 
00047     StringValue(str_digest);
00048     digest = RSTRING_PTR(str_digest);
00049     digest_len = RSTRING_LEN(str_digest);
00050 
00051     if (LONG_MAX / 2 < digest_len) {
00052         rb_raise(rb_eRuntimeError, "digest string too long");
00053     }
00054 
00055     str = rb_str_new(0, digest_len * 2);
00056 
00057     for (i = 0, p = RSTRING_PTR(str); i < digest_len; i++) {
00058         unsigned char byte = digest[i];
00059 
00060         p[i + i]     = hex[byte >> 4];
00061         p[i + i + 1] = hex[byte & 0x0f];
00062     }
00063 
00064     return str;
00065 }
00066 
00067 /*
00068  * call-seq:
00069  *     Digest.hexencode(string) -> hexencoded_string
00070  *
00071  * Generates a hex-encoded version of a given _string_.
00072  */
00073 static VALUE
00074 rb_digest_s_hexencode(VALUE klass, VALUE str)
00075 {
00076     return hexencode_str_new(str);
00077 }
00078 
00079 NORETURN(static void rb_digest_instance_method_unimpl(VALUE self, const char *method));
00080 
00081 /*
00082  * Document-module: Digest::Instance
00083  *
00084  * This module provides instance methods for a digest implementation
00085  * object to calculate message digest values.
00086  */
00087 
00088 static void
00089 rb_digest_instance_method_unimpl(VALUE self, const char *method)
00090 {
00091     rb_raise(rb_eRuntimeError, "%s does not implement %s()",
00092              rb_obj_classname(self), method);
00093 }
00094 
00095 /*
00096  * call-seq:
00097  *     digest_obj.update(string) -> digest_obj
00098  *     digest_obj << string -> digest_obj
00099  *
00100  * Updates the digest using a given _string_ and returns self.
00101  *
00102  * The update() method and the left-shift operator are overridden by
00103  * each implementation subclass. (One should be an alias for the
00104  * other)
00105  */
00106 static VALUE
00107 rb_digest_instance_update(VALUE self, VALUE str)
00108 {
00109     rb_digest_instance_method_unimpl(self, "update");
00110 }
00111 
00112 /*
00113  * call-seq:
00114  *     digest_obj.instance_eval { finish } -> digest_obj
00115  *
00116  * Finishes the digest and returns the resulting hash value.
00117  *
00118  * This method is overridden by each implementation subclass and often
00119  * made private, because some of those subclasses may leave internal
00120  * data uninitialized.  Do not call this method from outside.  Use
00121  * #digest!() instead, which ensures that internal data be reset for
00122  * security reasons.
00123  */
00124 static VALUE
00125 rb_digest_instance_finish(VALUE self)
00126 {
00127     rb_digest_instance_method_unimpl(self, "finish");
00128 }
00129 
00130 /*
00131  * call-seq:
00132  *     digest_obj.reset -> digest_obj
00133  *
00134  * Resets the digest to the initial state and returns self.
00135  *
00136  * This method is overridden by each implementation subclass.
00137  */
00138 static VALUE
00139 rb_digest_instance_reset(VALUE self)
00140 {
00141     rb_digest_instance_method_unimpl(self, "reset");
00142 }
00143 
00144 /*
00145  * call-seq:
00146  *     digest_obj.new -> another_digest_obj
00147  *
00148  * Returns a new, initialized copy of the digest object.  Equivalent
00149  * to digest_obj.clone().reset().
00150  */
00151 static VALUE
00152 rb_digest_instance_new(VALUE self)
00153 {
00154     VALUE clone = rb_obj_clone(self);
00155     rb_funcall(clone, id_reset, 0);
00156     return clone;
00157 }
00158 
00159 /*
00160  * call-seq:
00161  *     digest_obj.digest -> string
00162  *     digest_obj.digest(string) -> string
00163  *
00164  * If none is given, returns the resulting hash value of the digest,
00165  * keeping the digest's state.
00166  *
00167  * If a _string_ is given, returns the hash value for the given
00168  * _string_, resetting the digest to the initial state before and
00169  * after the process.
00170  */
00171 static VALUE
00172 rb_digest_instance_digest(int argc, VALUE *argv, VALUE self)
00173 {
00174     VALUE str, value;
00175 
00176     if (rb_scan_args(argc, argv, "01", &str) > 0) {
00177         rb_funcall(self, id_reset, 0);
00178         rb_funcall(self, id_update, 1, str);
00179         value = rb_funcall(self, id_finish, 0);
00180         rb_funcall(self, id_reset, 0);
00181     } else {
00182         value = rb_funcall(rb_obj_clone(self), id_finish, 0);
00183     }
00184 
00185     return value;
00186 }
00187 
00188 /*
00189  * call-seq:
00190  *     digest_obj.digest! -> string
00191  *
00192  * Returns the resulting hash value and resets the digest to the
00193  * initial state.
00194  */
00195 static VALUE
00196 rb_digest_instance_digest_bang(VALUE self)
00197 {
00198     VALUE value = rb_funcall(self, id_finish, 0);
00199     rb_funcall(self, id_reset, 0);
00200 
00201     return value;
00202 }
00203 
00204 /*
00205  * call-seq:
00206  *     digest_obj.hexdigest -> string
00207  *     digest_obj.hexdigest(string) -> string
00208  *
00209  * If none is given, returns the resulting hash value of the digest in
00210  * a hex-encoded form, keeping the digest's state.
00211  *
00212  * If a _string_ is given, returns the hash value for the given
00213  * _string_ in a hex-encoded form, resetting the digest to the initial
00214  * state before and after the process.
00215  */
00216 static VALUE
00217 rb_digest_instance_hexdigest(int argc, VALUE *argv, VALUE self)
00218 {
00219     VALUE str, value;
00220 
00221     if (rb_scan_args(argc, argv, "01", &str) > 0) {
00222         rb_funcall(self, id_reset, 0);
00223         rb_funcall(self, id_update, 1, str);
00224         value = rb_funcall(self, id_finish, 0);
00225         rb_funcall(self, id_reset, 0);
00226     } else {
00227         value = rb_funcall(rb_obj_clone(self), id_finish, 0);
00228     }
00229 
00230     return hexencode_str_new(value);
00231 }
00232 
00233 /*
00234  * call-seq:
00235  *     digest_obj.hexdigest! -> string
00236  *
00237  * Returns the resulting hash value in a hex-encoded form and resets
00238  * the digest to the initial state.
00239  */
00240 static VALUE
00241 rb_digest_instance_hexdigest_bang(VALUE self)
00242 {
00243     VALUE value = rb_funcall(self, id_finish, 0);
00244     rb_funcall(self, id_reset, 0);
00245 
00246     return hexencode_str_new(value);
00247 }
00248 
00249 /*
00250  * call-seq:
00251  *     digest_obj.to_s -> string
00252  *
00253  * Returns digest_obj.hexdigest().
00254  */
00255 static VALUE
00256 rb_digest_instance_to_s(VALUE self)
00257 {
00258     return rb_funcall(self, id_hexdigest, 0);
00259 }
00260 
00261 /*
00262  * call-seq:
00263  *     digest_obj.inspect -> string
00264  *
00265  * Creates a printable version of the digest object.
00266  */
00267 static VALUE
00268 rb_digest_instance_inspect(VALUE self)
00269 {
00270     VALUE str;
00271     size_t digest_len = 32;     /* about this size at least */
00272     const char *cname;
00273 
00274     cname = rb_obj_classname(self);
00275 
00276     /* #<Digest::ClassName: xxxxx...xxxx> */
00277     str = rb_str_buf_new(2 + strlen(cname) + 2 + digest_len * 2 + 1);
00278     rb_str_buf_cat2(str, "#<");
00279     rb_str_buf_cat2(str, cname);
00280     rb_str_buf_cat2(str, ": ");
00281     rb_str_buf_append(str, rb_digest_instance_hexdigest(0, 0, self));
00282     rb_str_buf_cat2(str, ">");
00283     return str;
00284 }
00285 
00286 /*
00287  * call-seq:
00288  *     digest_obj == another_digest_obj -> boolean
00289  *     digest_obj == string -> boolean
00290  *
00291  * If a string is given, checks whether it is equal to the hex-encoded
00292  * hash value of the digest object.  If another digest instance is
00293  * given, checks whether they have the same hash value.  Otherwise
00294  * returns false.
00295  */
00296 static VALUE
00297 rb_digest_instance_equal(VALUE self, VALUE other)
00298 {
00299     VALUE str1, str2;
00300 
00301     if (rb_obj_is_kind_of(other, rb_mDigest_Instance) == Qtrue) {
00302         str1 = rb_digest_instance_digest(0, 0, self);
00303         str2 = rb_digest_instance_digest(0, 0, other);
00304     } else {
00305         str1 = rb_digest_instance_to_s(self);
00306         str2 = other;
00307     }
00308 
00309     /* never blindly assume that subclass methods return strings */
00310     StringValue(str1);
00311     StringValue(str2);
00312 
00313     if (RSTRING_LEN(str1) == RSTRING_LEN(str2) &&
00314         rb_str_cmp(str1, str2) == 0) {
00315         return Qtrue;
00316     }
00317     return Qfalse;
00318 }
00319 
00320 /*
00321  * call-seq:
00322  *     digest_obj.digest_length -> integer
00323  *
00324  * Returns the length of the hash value of the digest.
00325  *
00326  * This method should be overridden by each implementation subclass.
00327  * If not, digest_obj.digest().length() is returned.
00328  */
00329 static VALUE
00330 rb_digest_instance_digest_length(VALUE self)
00331 {
00332     /* subclasses really should redefine this method */
00333     VALUE digest = rb_digest_instance_digest(0, 0, self);
00334 
00335     /* never blindly assume that #digest() returns a string */
00336     StringValue(digest);
00337     return INT2NUM(RSTRING_LEN(digest));
00338 }
00339 
00340 /*
00341  * call-seq:
00342  *     digest_obj.length -> integer
00343  *     digest_obj.size -> integer
00344  *
00345  * Returns digest_obj.digest_length().
00346  */
00347 static VALUE
00348 rb_digest_instance_length(VALUE self)
00349 {
00350     return rb_funcall(self, id_digest_length, 0);
00351 }
00352 
00353 /*
00354  * call-seq:
00355  *     digest_obj.block_length -> integer
00356  *
00357  * Returns the block length of the digest.
00358  *
00359  * This method is overridden by each implementation subclass.
00360  */
00361 static VALUE
00362 rb_digest_instance_block_length(VALUE self)
00363 {
00364     rb_digest_instance_method_unimpl(self, "block_length");
00365 }
00366 
00367 /*
00368  * Document-class: Digest::Class
00369  *
00370  * This module stands as a base class for digest implementation
00371  * classes.
00372  */
00373 
00374 /*
00375  * call-seq:
00376  *     Digest::Class.digest(string, *parameters) -> hash_string
00377  *
00378  * Returns the hash value of a given _string_.  This is equivalent to
00379  * Digest::Class.new(*parameters).digest(string), where extra
00380  * _parameters_, if any, are passed through to the constructor and the
00381  * _string_ is passed to #digest().
00382  */
00383 static VALUE
00384 rb_digest_class_s_digest(int argc, VALUE *argv, VALUE klass)
00385 {
00386     VALUE str;
00387     volatile VALUE obj;
00388 
00389     if (argc < 1) {
00390         rb_raise(rb_eArgError, "no data given");
00391     }
00392 
00393     str = *argv++;
00394     argc--;
00395 
00396     StringValue(str);
00397 
00398     obj = rb_obj_alloc(klass);
00399     rb_obj_call_init(obj, argc, argv);
00400 
00401     return rb_funcall(obj, id_digest, 1, str);
00402 }
00403 
00404 /*
00405  * call-seq:
00406  *     Digest::Class.hexdigest(string[, ...]) -> hash_string
00407  *
00408  * Returns the hex-encoded hash value of a given _string_.  This is
00409  * almost equivalent to
00410  * Digest.hexencode(Digest::Class.new(*parameters).digest(string)).
00411  */
00412 static VALUE
00413 rb_digest_class_s_hexdigest(int argc, VALUE *argv, VALUE klass)
00414 {
00415     return hexencode_str_new(rb_funcall2(klass, id_digest, argc, argv));
00416 }
00417 
00418 /*
00419  * Document-class: Digest::Base
00420  *
00421  * This abstract class provides a common interface to message digest
00422  * implementation classes written in C.
00423  */
00424 
00425 static rb_digest_metadata_t *
00426 get_digest_base_metadata(VALUE klass)
00427 {
00428     VALUE p;
00429     VALUE obj;
00430     rb_digest_metadata_t *algo;
00431 
00432     for (p = klass; p; p = RCLASS_SUPER(p)) {
00433         if (rb_ivar_defined(p, id_metadata)) {
00434             obj = rb_ivar_get(p, id_metadata);
00435             break;
00436         }
00437     }
00438 
00439     if (!p)
00440         rb_raise(rb_eRuntimeError, "Digest::Base cannot be directly inherited in Ruby");
00441 
00442     Data_Get_Struct(obj, rb_digest_metadata_t, algo);
00443 
00444     switch (algo->api_version) {
00445       case 2:
00446         break;
00447 
00448       /*
00449        * put conversion here if possible when API is updated
00450        */
00451 
00452       default:
00453         rb_raise(rb_eRuntimeError, "Incompatible digest API version");
00454     }
00455 
00456     return algo;
00457 }
00458 
00459 static VALUE
00460 rb_digest_base_alloc(VALUE klass)
00461 {
00462     rb_digest_metadata_t *algo;
00463     VALUE obj;
00464     void *pctx;
00465 
00466     if (klass == rb_cDigest_Base) {
00467         rb_raise(rb_eNotImpError, "Digest::Base is an abstract class");
00468     }
00469 
00470     algo = get_digest_base_metadata(klass);
00471 
00472     pctx = xmalloc(algo->ctx_size);
00473     algo->init_func(pctx);
00474 
00475     obj = Data_Wrap_Struct(klass, 0, xfree, pctx);
00476 
00477     return obj;
00478 }
00479 
00480 /* :nodoc: */
00481 static VALUE
00482 rb_digest_base_copy(VALUE copy, VALUE obj)
00483 {
00484     rb_digest_metadata_t *algo;
00485     void *pctx1, *pctx2;
00486 
00487     if (copy == obj) return copy;
00488 
00489     rb_check_frozen(copy);
00490 
00491     algo = get_digest_base_metadata(rb_obj_class(copy));
00492 
00493     Data_Get_Struct(obj, void, pctx1);
00494     Data_Get_Struct(copy, void, pctx2);
00495     memcpy(pctx2, pctx1, algo->ctx_size);
00496 
00497     return copy;
00498 }
00499 
00500 /* :nodoc: */
00501 static VALUE
00502 rb_digest_base_reset(VALUE self)
00503 {
00504     rb_digest_metadata_t *algo;
00505     void *pctx;
00506 
00507     algo = get_digest_base_metadata(rb_obj_class(self));
00508 
00509     Data_Get_Struct(self, void, pctx);
00510 
00511     algo->init_func(pctx);
00512 
00513     return self;
00514 }
00515 
00516 /* :nodoc: */
00517 static VALUE
00518 rb_digest_base_update(VALUE self, VALUE str)
00519 {
00520     rb_digest_metadata_t *algo;
00521     void *pctx;
00522 
00523     algo = get_digest_base_metadata(rb_obj_class(self));
00524 
00525     Data_Get_Struct(self, void, pctx);
00526 
00527     StringValue(str);
00528     algo->update_func(pctx, (unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str));
00529 
00530     return self;
00531 }
00532 
00533 /* :nodoc: */
00534 static VALUE
00535 rb_digest_base_finish(VALUE self)
00536 {
00537     rb_digest_metadata_t *algo;
00538     void *pctx;
00539     VALUE str;
00540 
00541     algo = get_digest_base_metadata(rb_obj_class(self));
00542 
00543     Data_Get_Struct(self, void, pctx);
00544 
00545     str = rb_str_new(0, algo->digest_len);
00546     algo->finish_func(pctx, (unsigned char *)RSTRING_PTR(str));
00547 
00548     /* avoid potential coredump caused by use of a finished context */
00549     algo->init_func(pctx);
00550 
00551     return str;
00552 }
00553 
00554 /* :nodoc: */
00555 static VALUE
00556 rb_digest_base_digest_length(VALUE self)
00557 {
00558     rb_digest_metadata_t *algo;
00559 
00560     algo = get_digest_base_metadata(rb_obj_class(self));
00561 
00562     return INT2NUM(algo->digest_len);
00563 }
00564 
00565 /* :nodoc: */
00566 static VALUE
00567 rb_digest_base_block_length(VALUE self)
00568 {
00569     rb_digest_metadata_t *algo;
00570 
00571     algo = get_digest_base_metadata(rb_obj_class(self));
00572 
00573     return INT2NUM(algo->block_len);
00574 }
00575 
00576 void
00577 Init_digest(void)
00578 {
00579     id_reset           = rb_intern("reset");
00580     id_update          = rb_intern("update");
00581     id_finish          = rb_intern("finish");
00582     id_digest          = rb_intern("digest");
00583     id_hexdigest       = rb_intern("hexdigest");
00584     id_digest_length   = rb_intern("digest_length");
00585 
00586     /*
00587      * module Digest
00588      */
00589     rb_mDigest = rb_define_module("Digest");
00590 
00591     /* module functions */
00592     rb_define_module_function(rb_mDigest, "hexencode", rb_digest_s_hexencode, 1);
00593 
00594     /*
00595      * module Digest::Instance
00596      */
00597     rb_mDigest_Instance = rb_define_module_under(rb_mDigest, "Instance");
00598 
00599     /* instance methods that should be overridden */
00600     rb_define_method(rb_mDigest_Instance, "update", rb_digest_instance_update, 1);
00601     rb_define_method(rb_mDigest_Instance, "<<", rb_digest_instance_update, 1);
00602     rb_define_private_method(rb_mDigest_Instance, "finish", rb_digest_instance_finish, 0);
00603     rb_define_method(rb_mDigest_Instance, "reset", rb_digest_instance_reset, 0);
00604     rb_define_method(rb_mDigest_Instance, "digest_length", rb_digest_instance_digest_length, 0);
00605     rb_define_method(rb_mDigest_Instance, "block_length", rb_digest_instance_block_length, 0);
00606 
00607     /* instance methods that may be overridden */
00608     rb_define_method(rb_mDigest_Instance, "==", rb_digest_instance_equal, 1);
00609     rb_define_method(rb_mDigest_Instance, "inspect", rb_digest_instance_inspect, 0);
00610 
00611     /* instance methods that need not usually be overridden */
00612     rb_define_method(rb_mDigest_Instance, "new", rb_digest_instance_new, 0);
00613     rb_define_method(rb_mDigest_Instance, "digest", rb_digest_instance_digest, -1);
00614     rb_define_method(rb_mDigest_Instance, "digest!", rb_digest_instance_digest_bang, 0);
00615     rb_define_method(rb_mDigest_Instance, "hexdigest", rb_digest_instance_hexdigest, -1);
00616     rb_define_method(rb_mDigest_Instance, "hexdigest!", rb_digest_instance_hexdigest_bang, 0);
00617     rb_define_method(rb_mDigest_Instance, "to_s", rb_digest_instance_to_s, 0);
00618     rb_define_method(rb_mDigest_Instance, "length", rb_digest_instance_length, 0);
00619     rb_define_method(rb_mDigest_Instance, "size", rb_digest_instance_length, 0);
00620 
00621     /*
00622      * class Digest::Class
00623      */
00624     rb_cDigest_Class = rb_define_class_under(rb_mDigest, "Class", rb_cObject);
00625     rb_include_module(rb_cDigest_Class, rb_mDigest_Instance);
00626 
00627     /* class methods */
00628     rb_define_singleton_method(rb_cDigest_Class, "digest", rb_digest_class_s_digest, -1);
00629     rb_define_singleton_method(rb_cDigest_Class, "hexdigest", rb_digest_class_s_hexdigest, -1);
00630 
00631     id_metadata = rb_intern("metadata");
00632 
00633     /* class Digest::Base < Digest::Class */
00634     rb_cDigest_Base = rb_define_class_under(rb_mDigest, "Base", rb_cDigest_Class);
00635 
00636     rb_define_alloc_func(rb_cDigest_Base, rb_digest_base_alloc);
00637 
00638     rb_define_method(rb_cDigest_Base, "initialize_copy",  rb_digest_base_copy, 1);
00639     rb_define_method(rb_cDigest_Base, "reset", rb_digest_base_reset, 0);
00640     rb_define_method(rb_cDigest_Base, "update", rb_digest_base_update, 1);
00641     rb_define_method(rb_cDigest_Base, "<<", rb_digest_base_update, 1);
00642     rb_define_private_method(rb_cDigest_Base, "finish", rb_digest_base_finish, 0);
00643     rb_define_method(rb_cDigest_Base, "digest_length", rb_digest_base_digest_length, 0);
00644     rb_define_method(rb_cDigest_Base, "block_length", rb_digest_base_block_length, 0);
00645 }
00646 

Generated on Wed Aug 10 09:16:56 2011 for Ruby by  doxygen 1.4.7