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