Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# 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