ext/digest/digest.c

Go to the documentation of this file.
00001 /************************************************
00002 
00003   digest.c -
00004 
00005   $Author: nagachika $
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 46809 2014-07-13 14:24:26Z nagachika $
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  * You may want to look at OpenSSL::Digest as it supports more algorithms.
00034  *
00035  * A cryptographic hash function is a procedure that takes data and returns a
00036  * fixed bit string: the hash value, also known as _digest_. Hash functions
00037  * are also called one-way functions, it is easy to compute a digest from
00038  * a message, but it is infeasible to generate a message from a digest.
00039  *
00040  * == Examples
00041  *
00042  *   require 'digest'
00043  *
00044  *   # Compute a complete digest
00045  *   Digest::SHA256.digest 'message'       #=> "\xABS\n\x13\xE4Y..."
00046  *
00047  *   sha256 = Digest::SHA256.new
00048  *   sha256.digest 'message'               #=> "\xABS\n\x13\xE4Y..."
00049  *
00050  *   # Other encoding formats
00051  *   Digest::SHA256.hexdigest 'message'    #=> "ab530a13e459..."
00052  *   Digest::SHA256.base64digest 'message' #=> "q1MKE+RZFJgr..."
00053  *
00054  *   # Compute digest by chunks
00055  *   md5 = Digest::MD5.new
00056  *   md5.update 'message1'
00057  *   md5 << 'message2'                     # << is an alias for update
00058  *
00059  *   md5.hexdigest                         #=> "94af09c09bb9..."
00060  *
00061  *   # Compute digest for a file
00062  *   sha256 = Digest::SHA256.file 'testfile'
00063  *   sha256.hexdigest
00064  *
00065  * Additionally digests can be encoded in "bubble babble" format as a sequence
00066  * of consonants and vowels which is more recognizable and comparable than a
00067  * hexadecimal digest.
00068  *
00069  *   require 'digest/bubblebabble'
00070  *
00071  *   Digest::SHA256.bubblebabble 'message' #=> "xopoh-fedac-fenyh-..."
00072  *
00073  * See the bubble babble specification at
00074  * http://web.mit.edu/kenta/www/one/bubblebabble/spec/jrtrjwzi/draft-huima-01.txt.
00075  *
00076  * == Digest algorithms
00077  *
00078  * Different digest algorithms (or hash functions) are available:
00079  *
00080  * HMAC::
00081  *   See FIPS PUB 198 The Keyed-Hash Message Authentication Code (HMAC).
00082  * RIPEMD-160::
00083  *   As Digest::RMD160.
00084  *   See http://homes.esat.kuleuven.be/~bosselae/ripemd160.html.
00085  * SHA1::
00086  *   See FIPS 180 Secure Hash Standard.
00087  * SHA2 family::
00088  *   See FIPS 180 Secure Hash Standard which defines the following algorithms:
00089  *   * SHA512
00090  *   * SHA384
00091  *   * SHA256
00092  *
00093  * The latest versions of the FIPS publications can be found here:
00094  * http://csrc.nist.gov/publications/PubsFIPS.html.
00095  */
00096 
00097 static VALUE
00098 hexencode_str_new(VALUE str_digest)
00099 {
00100     char *digest;
00101     size_t digest_len;
00102     size_t i;
00103     VALUE str;
00104     char *p;
00105     static const char hex[] = {
00106         '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
00107         'a', 'b', 'c', 'd', 'e', 'f'
00108     };
00109 
00110     StringValue(str_digest);
00111     digest = RSTRING_PTR(str_digest);
00112     digest_len = RSTRING_LEN(str_digest);
00113 
00114     if (LONG_MAX / 2 < digest_len) {
00115         rb_raise(rb_eRuntimeError, "digest string too long");
00116     }
00117 
00118     str = rb_usascii_str_new(0, digest_len * 2);
00119 
00120     for (i = 0, p = RSTRING_PTR(str); i < digest_len; i++) {
00121         unsigned char byte = digest[i];
00122 
00123         p[i + i]     = hex[byte >> 4];
00124         p[i + i + 1] = hex[byte & 0x0f];
00125     }
00126 
00127     return str;
00128 }
00129 
00130 /*
00131  * call-seq:
00132  *     Digest.hexencode(string) -> hexencoded_string
00133  *
00134  * Generates a hex-encoded version of a given _string_.
00135  */
00136 static VALUE
00137 rb_digest_s_hexencode(VALUE klass, VALUE str)
00138 {
00139     return hexencode_str_new(str);
00140 }
00141 
00142 NORETURN(static void rb_digest_instance_method_unimpl(VALUE self, const char *method));
00143 
00144 /*
00145  * Document-module: Digest::Instance
00146  *
00147  * This module provides instance methods for a digest implementation
00148  * object to calculate message digest values.
00149  */
00150 
00151 static void
00152 rb_digest_instance_method_unimpl(VALUE self, const char *method)
00153 {
00154     rb_raise(rb_eRuntimeError, "%s does not implement %s()",
00155              rb_obj_classname(self), method);
00156 }
00157 
00158 /*
00159  * call-seq:
00160  *     digest_obj.update(string) -> digest_obj
00161  *     digest_obj << string -> digest_obj
00162  *
00163  * Updates the digest using a given _string_ and returns self.
00164  *
00165  * The update() method and the left-shift operator are overridden by
00166  * each implementation subclass. (One should be an alias for the
00167  * other)
00168  */
00169 static VALUE
00170 rb_digest_instance_update(VALUE self, VALUE str)
00171 {
00172     rb_digest_instance_method_unimpl(self, "update");
00173 
00174     UNREACHABLE;
00175 }
00176 
00177 /*
00178  * call-seq:
00179  *     digest_obj.instance_eval { finish } -> digest_obj
00180  *
00181  * Finishes the digest and returns the resulting hash value.
00182  *
00183  * This method is overridden by each implementation subclass and often
00184  * made private, because some of those subclasses may leave internal
00185  * data uninitialized.  Do not call this method from outside.  Use
00186  * #digest!() instead, which ensures that internal data be reset for
00187  * security reasons.
00188  */
00189 static VALUE
00190 rb_digest_instance_finish(VALUE self)
00191 {
00192     rb_digest_instance_method_unimpl(self, "finish");
00193 
00194     UNREACHABLE;
00195 }
00196 
00197 /*
00198  * call-seq:
00199  *     digest_obj.reset -> digest_obj
00200  *
00201  * Resets the digest to the initial state and returns self.
00202  *
00203  * This method is overridden by each implementation subclass.
00204  */
00205 static VALUE
00206 rb_digest_instance_reset(VALUE self)
00207 {
00208     rb_digest_instance_method_unimpl(self, "reset");
00209 
00210     UNREACHABLE;
00211 }
00212 
00213 /*
00214  * call-seq:
00215  *     digest_obj.new -> another_digest_obj
00216  *
00217  * Returns a new, initialized copy of the digest object.  Equivalent
00218  * to digest_obj.clone().reset().
00219  */
00220 static VALUE
00221 rb_digest_instance_new(VALUE self)
00222 {
00223     VALUE clone = rb_obj_clone(self);
00224     rb_funcall(clone, id_reset, 0);
00225     return clone;
00226 }
00227 
00228 /*
00229  * call-seq:
00230  *     digest_obj.digest -> string
00231  *     digest_obj.digest(string) -> string
00232  *
00233  * If none is given, returns the resulting hash value of the digest,
00234  * keeping the digest's state.
00235  *
00236  * If a _string_ is given, returns the hash value for the given
00237  * _string_, resetting the digest to the initial state before and
00238  * after the process.
00239  */
00240 static VALUE
00241 rb_digest_instance_digest(int argc, VALUE *argv, VALUE self)
00242 {
00243     VALUE str, value;
00244 
00245     if (rb_scan_args(argc, argv, "01", &str) > 0) {
00246         rb_funcall(self, id_reset, 0);
00247         rb_funcall(self, id_update, 1, str);
00248         value = rb_funcall(self, id_finish, 0);
00249         rb_funcall(self, id_reset, 0);
00250     } else {
00251         value = rb_funcall(rb_obj_clone(self), id_finish, 0);
00252     }
00253 
00254     return value;
00255 }
00256 
00257 /*
00258  * call-seq:
00259  *     digest_obj.digest! -> string
00260  *
00261  * Returns the resulting hash value and resets the digest to the
00262  * initial state.
00263  */
00264 static VALUE
00265 rb_digest_instance_digest_bang(VALUE self)
00266 {
00267     VALUE value = rb_funcall(self, id_finish, 0);
00268     rb_funcall(self, id_reset, 0);
00269 
00270     return value;
00271 }
00272 
00273 /*
00274  * call-seq:
00275  *     digest_obj.hexdigest -> string
00276  *     digest_obj.hexdigest(string) -> string
00277  *
00278  * If none is given, returns the resulting hash value of the digest in
00279  * a hex-encoded form, keeping the digest's state.
00280  *
00281  * If a _string_ is given, returns the hash value for the given
00282  * _string_ in a hex-encoded form, resetting the digest to the initial
00283  * state before and after the process.
00284  */
00285 static VALUE
00286 rb_digest_instance_hexdigest(int argc, VALUE *argv, VALUE self)
00287 {
00288     VALUE str, value;
00289 
00290     if (rb_scan_args(argc, argv, "01", &str) > 0) {
00291         rb_funcall(self, id_reset, 0);
00292         rb_funcall(self, id_update, 1, str);
00293         value = rb_funcall(self, id_finish, 0);
00294         rb_funcall(self, id_reset, 0);
00295     } else {
00296         value = rb_funcall(rb_obj_clone(self), id_finish, 0);
00297     }
00298 
00299     return hexencode_str_new(value);
00300 }
00301 
00302 /*
00303  * call-seq:
00304  *     digest_obj.hexdigest! -> string
00305  *
00306  * Returns the resulting hash value in a hex-encoded form and resets
00307  * the digest to the initial state.
00308  */
00309 static VALUE
00310 rb_digest_instance_hexdigest_bang(VALUE self)
00311 {
00312     VALUE value = rb_funcall(self, id_finish, 0);
00313     rb_funcall(self, id_reset, 0);
00314 
00315     return hexencode_str_new(value);
00316 }
00317 
00318 /*
00319  * call-seq:
00320  *     digest_obj.to_s -> string
00321  *
00322  * Returns digest_obj.hexdigest().
00323  */
00324 static VALUE
00325 rb_digest_instance_to_s(VALUE self)
00326 {
00327     return rb_funcall(self, id_hexdigest, 0);
00328 }
00329 
00330 /*
00331  * call-seq:
00332  *     digest_obj.inspect -> string
00333  *
00334  * Creates a printable version of the digest object.
00335  */
00336 static VALUE
00337 rb_digest_instance_inspect(VALUE self)
00338 {
00339     VALUE str;
00340     size_t digest_len = 32;     /* about this size at least */
00341     const char *cname;
00342 
00343     cname = rb_obj_classname(self);
00344 
00345     /* #<Digest::ClassName: xxxxx...xxxx> */
00346     str = rb_str_buf_new(2 + strlen(cname) + 2 + digest_len * 2 + 1);
00347     rb_str_buf_cat2(str, "#<");
00348     rb_str_buf_cat2(str, cname);
00349     rb_str_buf_cat2(str, ": ");
00350     rb_str_buf_append(str, rb_digest_instance_hexdigest(0, 0, self));
00351     rb_str_buf_cat2(str, ">");
00352     return str;
00353 }
00354 
00355 /*
00356  * call-seq:
00357  *     digest_obj == another_digest_obj -> boolean
00358  *     digest_obj == string -> boolean
00359  *
00360  * If a string is given, checks whether it is equal to the hex-encoded
00361  * hash value of the digest object.  If another digest instance is
00362  * given, checks whether they have the same hash value.  Otherwise
00363  * returns false.
00364  */
00365 static VALUE
00366 rb_digest_instance_equal(VALUE self, VALUE other)
00367 {
00368     VALUE str1, str2;
00369 
00370     if (rb_obj_is_kind_of(other, rb_mDigest_Instance) == Qtrue) {
00371         str1 = rb_digest_instance_digest(0, 0, self);
00372         str2 = rb_digest_instance_digest(0, 0, other);
00373     } else {
00374         str1 = rb_digest_instance_to_s(self);
00375         str2 = rb_check_string_type(other);
00376         if (NIL_P(str2)) return Qfalse;
00377     }
00378 
00379     /* never blindly assume that subclass methods return strings */
00380     StringValue(str1);
00381     StringValue(str2);
00382 
00383     if (RSTRING_LEN(str1) == RSTRING_LEN(str2) &&
00384         rb_str_cmp(str1, str2) == 0) {
00385         return Qtrue;
00386     }
00387     return Qfalse;
00388 }
00389 
00390 /*
00391  * call-seq:
00392  *     digest_obj.digest_length -> integer
00393  *
00394  * Returns the length of the hash value of the digest.
00395  *
00396  * This method should be overridden by each implementation subclass.
00397  * If not, digest_obj.digest().length() is returned.
00398  */
00399 static VALUE
00400 rb_digest_instance_digest_length(VALUE self)
00401 {
00402     /* subclasses really should redefine this method */
00403     VALUE digest = rb_digest_instance_digest(0, 0, self);
00404 
00405     /* never blindly assume that #digest() returns a string */
00406     StringValue(digest);
00407     return INT2NUM(RSTRING_LEN(digest));
00408 }
00409 
00410 /*
00411  * call-seq:
00412  *     digest_obj.length -> integer
00413  *     digest_obj.size -> integer
00414  *
00415  * Returns digest_obj.digest_length().
00416  */
00417 static VALUE
00418 rb_digest_instance_length(VALUE self)
00419 {
00420     return rb_funcall(self, id_digest_length, 0);
00421 }
00422 
00423 /*
00424  * call-seq:
00425  *     digest_obj.block_length -> integer
00426  *
00427  * Returns the block length of the digest.
00428  *
00429  * This method is overridden by each implementation subclass.
00430  */
00431 static VALUE
00432 rb_digest_instance_block_length(VALUE self)
00433 {
00434     rb_digest_instance_method_unimpl(self, "block_length");
00435 
00436     UNREACHABLE;
00437 }
00438 
00439 /*
00440  * Document-class: Digest::Class
00441  *
00442  * This module stands as a base class for digest implementation
00443  * classes.
00444  */
00445 
00446 /*
00447  * call-seq:
00448  *     Digest::Class.digest(string, *parameters) -> hash_string
00449  *
00450  * Returns the hash value of a given _string_.  This is equivalent to
00451  * Digest::Class.new(*parameters).digest(string), where extra
00452  * _parameters_, if any, are passed through to the constructor and the
00453  * _string_ is passed to #digest().
00454  */
00455 static VALUE
00456 rb_digest_class_s_digest(int argc, VALUE *argv, VALUE klass)
00457 {
00458     VALUE str;
00459     volatile VALUE obj;
00460 
00461     if (argc < 1) {
00462         rb_raise(rb_eArgError, "no data given");
00463     }
00464 
00465     str = *argv++;
00466     argc--;
00467 
00468     StringValue(str);
00469 
00470     obj = rb_obj_alloc(klass);
00471     rb_obj_call_init(obj, argc, argv);
00472 
00473     return rb_funcall(obj, id_digest, 1, str);
00474 }
00475 
00476 /*
00477  * call-seq:
00478  *     Digest::Class.hexdigest(string[, ...]) -> hash_string
00479  *
00480  * Returns the hex-encoded hash value of a given _string_.  This is
00481  * almost equivalent to
00482  * Digest.hexencode(Digest::Class.new(*parameters).digest(string)).
00483  */
00484 static VALUE
00485 rb_digest_class_s_hexdigest(int argc, VALUE *argv, VALUE klass)
00486 {
00487     return hexencode_str_new(rb_funcall2(klass, id_digest, argc, argv));
00488 }
00489 
00490 /* :nodoc: */
00491 static VALUE
00492 rb_digest_class_init(VALUE self)
00493 {
00494     return self;
00495 }
00496 
00497 /*
00498  * Document-class: Digest::Base
00499  *
00500  * This abstract class provides a common interface to message digest
00501  * implementation classes written in C.
00502  */
00503 
00504 static rb_digest_metadata_t *
00505 get_digest_base_metadata(VALUE klass)
00506 {
00507     VALUE p;
00508     VALUE obj;
00509     rb_digest_metadata_t *algo;
00510 
00511     for (p = klass; !NIL_P(p); p = rb_class_superclass(p)) {
00512         if (rb_ivar_defined(p, id_metadata)) {
00513             obj = rb_ivar_get(p, id_metadata);
00514             break;
00515         }
00516     }
00517 
00518     if (NIL_P(p))
00519         rb_raise(rb_eRuntimeError, "Digest::Base cannot be directly inherited in Ruby");
00520 
00521     Data_Get_Struct(obj, rb_digest_metadata_t, algo);
00522 
00523     switch (algo->api_version) {
00524       case 2:
00525         break;
00526 
00527       /*
00528        * put conversion here if possible when API is updated
00529        */
00530 
00531       default:
00532         rb_raise(rb_eRuntimeError, "Incompatible digest API version");
00533     }
00534 
00535     return algo;
00536 }
00537 
00538 static VALUE
00539 rb_digest_base_alloc(VALUE klass)
00540 {
00541     rb_digest_metadata_t *algo;
00542     VALUE obj;
00543     void *pctx;
00544 
00545     if (klass == rb_cDigest_Base) {
00546         rb_raise(rb_eNotImpError, "Digest::Base is an abstract class");
00547     }
00548 
00549     algo = get_digest_base_metadata(klass);
00550 
00551     pctx = xmalloc(algo->ctx_size);
00552     algo->init_func(pctx);
00553 
00554     obj = Data_Wrap_Struct(klass, 0, xfree, pctx);
00555 
00556     return obj;
00557 }
00558 
00559 /* :nodoc: */
00560 static VALUE
00561 rb_digest_base_copy(VALUE copy, VALUE obj)
00562 {
00563     rb_digest_metadata_t *algo;
00564     void *pctx1, *pctx2;
00565 
00566     if (copy == obj) return copy;
00567 
00568     rb_check_frozen(copy);
00569 
00570     algo = get_digest_base_metadata(rb_obj_class(copy));
00571 
00572     Data_Get_Struct(obj, void, pctx1);
00573     Data_Get_Struct(copy, void, pctx2);
00574     memcpy(pctx2, pctx1, algo->ctx_size);
00575 
00576     return copy;
00577 }
00578 
00579 /* :nodoc: */
00580 static VALUE
00581 rb_digest_base_reset(VALUE self)
00582 {
00583     rb_digest_metadata_t *algo;
00584     void *pctx;
00585 
00586     algo = get_digest_base_metadata(rb_obj_class(self));
00587 
00588     Data_Get_Struct(self, void, pctx);
00589 
00590     algo->init_func(pctx);
00591 
00592     return self;
00593 }
00594 
00595 /* :nodoc: */
00596 static VALUE
00597 rb_digest_base_update(VALUE self, VALUE str)
00598 {
00599     rb_digest_metadata_t *algo;
00600     void *pctx;
00601 
00602     algo = get_digest_base_metadata(rb_obj_class(self));
00603 
00604     Data_Get_Struct(self, void, pctx);
00605 
00606     StringValue(str);
00607     algo->update_func(pctx, (unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str));
00608 
00609     return self;
00610 }
00611 
00612 /* :nodoc: */
00613 static VALUE
00614 rb_digest_base_finish(VALUE self)
00615 {
00616     rb_digest_metadata_t *algo;
00617     void *pctx;
00618     VALUE str;
00619 
00620     algo = get_digest_base_metadata(rb_obj_class(self));
00621 
00622     Data_Get_Struct(self, void, pctx);
00623 
00624     str = rb_str_new(0, algo->digest_len);
00625     algo->finish_func(pctx, (unsigned char *)RSTRING_PTR(str));
00626 
00627     /* avoid potential coredump caused by use of a finished context */
00628     algo->init_func(pctx);
00629 
00630     return str;
00631 }
00632 
00633 /* :nodoc: */
00634 static VALUE
00635 rb_digest_base_digest_length(VALUE self)
00636 {
00637     rb_digest_metadata_t *algo;
00638 
00639     algo = get_digest_base_metadata(rb_obj_class(self));
00640 
00641     return INT2NUM(algo->digest_len);
00642 }
00643 
00644 /* :nodoc: */
00645 static VALUE
00646 rb_digest_base_block_length(VALUE self)
00647 {
00648     rb_digest_metadata_t *algo;
00649 
00650     algo = get_digest_base_metadata(rb_obj_class(self));
00651 
00652     return INT2NUM(algo->block_len);
00653 }
00654 
00655 void
00656 Init_digest(void)
00657 {
00658     id_reset           = rb_intern("reset");
00659     id_update          = rb_intern("update");
00660     id_finish          = rb_intern("finish");
00661     id_digest          = rb_intern("digest");
00662     id_hexdigest       = rb_intern("hexdigest");
00663     id_digest_length   = rb_intern("digest_length");
00664 
00665     /*
00666      * module Digest
00667      */
00668     rb_mDigest = rb_define_module("Digest");
00669 
00670     /* module functions */
00671     rb_define_module_function(rb_mDigest, "hexencode", rb_digest_s_hexencode, 1);
00672 
00673     /*
00674      * module Digest::Instance
00675      */
00676     rb_mDigest_Instance = rb_define_module_under(rb_mDigest, "Instance");
00677 
00678     /* instance methods that should be overridden */
00679     rb_define_method(rb_mDigest_Instance, "update", rb_digest_instance_update, 1);
00680     rb_define_method(rb_mDigest_Instance, "<<", rb_digest_instance_update, 1);
00681     rb_define_private_method(rb_mDigest_Instance, "finish", rb_digest_instance_finish, 0);
00682     rb_define_method(rb_mDigest_Instance, "reset", rb_digest_instance_reset, 0);
00683     rb_define_method(rb_mDigest_Instance, "digest_length", rb_digest_instance_digest_length, 0);
00684     rb_define_method(rb_mDigest_Instance, "block_length", rb_digest_instance_block_length, 0);
00685 
00686     /* instance methods that may be overridden */
00687     rb_define_method(rb_mDigest_Instance, "==", rb_digest_instance_equal, 1);
00688     rb_define_method(rb_mDigest_Instance, "inspect", rb_digest_instance_inspect, 0);
00689 
00690     /* instance methods that need not usually be overridden */
00691     rb_define_method(rb_mDigest_Instance, "new", rb_digest_instance_new, 0);
00692     rb_define_method(rb_mDigest_Instance, "digest", rb_digest_instance_digest, -1);
00693     rb_define_method(rb_mDigest_Instance, "digest!", rb_digest_instance_digest_bang, 0);
00694     rb_define_method(rb_mDigest_Instance, "hexdigest", rb_digest_instance_hexdigest, -1);
00695     rb_define_method(rb_mDigest_Instance, "hexdigest!", rb_digest_instance_hexdigest_bang, 0);
00696     rb_define_method(rb_mDigest_Instance, "to_s", rb_digest_instance_to_s, 0);
00697     rb_define_method(rb_mDigest_Instance, "length", rb_digest_instance_length, 0);
00698     rb_define_method(rb_mDigest_Instance, "size", rb_digest_instance_length, 0);
00699 
00700     /*
00701      * class Digest::Class
00702      */
00703     rb_cDigest_Class = rb_define_class_under(rb_mDigest, "Class", rb_cObject);
00704     rb_define_method(rb_cDigest_Class, "initialize",  rb_digest_class_init, 0);
00705     rb_include_module(rb_cDigest_Class, rb_mDigest_Instance);
00706 
00707     /* class methods */
00708     rb_define_singleton_method(rb_cDigest_Class, "digest", rb_digest_class_s_digest, -1);
00709     rb_define_singleton_method(rb_cDigest_Class, "hexdigest", rb_digest_class_s_hexdigest, -1);
00710 
00711     id_metadata = rb_intern("metadata");
00712 
00713     /* class Digest::Base < Digest::Class */
00714     rb_cDigest_Base = rb_define_class_under(rb_mDigest, "Base", rb_cDigest_Class);
00715 
00716     rb_define_alloc_func(rb_cDigest_Base, rb_digest_base_alloc);
00717 
00718     rb_define_method(rb_cDigest_Base, "initialize_copy",  rb_digest_base_copy, 1);
00719     rb_define_method(rb_cDigest_Base, "reset", rb_digest_base_reset, 0);
00720     rb_define_method(rb_cDigest_Base, "update", rb_digest_base_update, 1);
00721     rb_define_method(rb_cDigest_Base, "<<", rb_digest_base_update, 1);
00722     rb_define_private_method(rb_cDigest_Base, "finish", rb_digest_base_finish, 0);
00723     rb_define_method(rb_cDigest_Base, "digest_length", rb_digest_base_digest_length, 0);
00724     rb_define_method(rb_cDigest_Base, "block_length", rb_digest_base_block_length, 0);
00725 }
00726 

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7