Ruby  2.0.0p247(2013-06-27revision41674)
ext/digest/digest.c
Go to the documentation of this file.
00001 /************************************************
00002 
00003   digest.c -
00004 
00005   $Author: eregon $
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 36588 2012-08-01 13:30:51Z eregon $
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 = other;
00360     }
00361 
00362     /* never blindly assume that subclass methods return strings */
00363     StringValue(str1);
00364     StringValue(str2);
00365 
00366     if (RSTRING_LEN(str1) == RSTRING_LEN(str2) &&
00367         rb_str_cmp(str1, str2) == 0) {
00368         return Qtrue;
00369     }
00370     return Qfalse;
00371 }
00372 
00373 /*
00374  * call-seq:
00375  *     digest_obj.digest_length -> integer
00376  *
00377  * Returns the length of the hash value of the digest.
00378  *
00379  * This method should be overridden by each implementation subclass.
00380  * If not, digest_obj.digest().length() is returned.
00381  */
00382 static VALUE
00383 rb_digest_instance_digest_length(VALUE self)
00384 {
00385     /* subclasses really should redefine this method */
00386     VALUE digest = rb_digest_instance_digest(0, 0, self);
00387 
00388     /* never blindly assume that #digest() returns a string */
00389     StringValue(digest);
00390     return INT2NUM(RSTRING_LEN(digest));
00391 }
00392 
00393 /*
00394  * call-seq:
00395  *     digest_obj.length -> integer
00396  *     digest_obj.size -> integer
00397  *
00398  * Returns digest_obj.digest_length().
00399  */
00400 static VALUE
00401 rb_digest_instance_length(VALUE self)
00402 {
00403     return rb_funcall(self, id_digest_length, 0);
00404 }
00405 
00406 /*
00407  * call-seq:
00408  *     digest_obj.block_length -> integer
00409  *
00410  * Returns the block length of the digest.
00411  *
00412  * This method is overridden by each implementation subclass.
00413  */
00414 static VALUE
00415 rb_digest_instance_block_length(VALUE self)
00416 {
00417     rb_digest_instance_method_unimpl(self, "block_length");
00418 
00419     UNREACHABLE;
00420 }
00421 
00422 /*
00423  * Document-class: Digest::Class
00424  *
00425  * This module stands as a base class for digest implementation
00426  * classes.
00427  */
00428 
00429 /*
00430  * call-seq:
00431  *     Digest::Class.digest(string, *parameters) -> hash_string
00432  *
00433  * Returns the hash value of a given _string_.  This is equivalent to
00434  * Digest::Class.new(*parameters).digest(string), where extra
00435  * _parameters_, if any, are passed through to the constructor and the
00436  * _string_ is passed to #digest().
00437  */
00438 static VALUE
00439 rb_digest_class_s_digest(int argc, VALUE *argv, VALUE klass)
00440 {
00441     VALUE str;
00442     volatile VALUE obj;
00443 
00444     if (argc < 1) {
00445         rb_raise(rb_eArgError, "no data given");
00446     }
00447 
00448     str = *argv++;
00449     argc--;
00450 
00451     StringValue(str);
00452 
00453     obj = rb_obj_alloc(klass);
00454     rb_obj_call_init(obj, argc, argv);
00455 
00456     return rb_funcall(obj, id_digest, 1, str);
00457 }
00458 
00459 /*
00460  * call-seq:
00461  *     Digest::Class.hexdigest(string[, ...]) -> hash_string
00462  *
00463  * Returns the hex-encoded hash value of a given _string_.  This is
00464  * almost equivalent to
00465  * Digest.hexencode(Digest::Class.new(*parameters).digest(string)).
00466  */
00467 static VALUE
00468 rb_digest_class_s_hexdigest(int argc, VALUE *argv, VALUE klass)
00469 {
00470     return hexencode_str_new(rb_funcall2(klass, id_digest, argc, argv));
00471 }
00472 
00473 /* :nodoc: */
00474 static VALUE
00475 rb_digest_class_init(VALUE self)
00476 {
00477     return self;
00478 }
00479 
00480 /*
00481  * Document-class: Digest::Base
00482  *
00483  * This abstract class provides a common interface to message digest
00484  * implementation classes written in C.
00485  */
00486 
00487 static rb_digest_metadata_t *
00488 get_digest_base_metadata(VALUE klass)
00489 {
00490     VALUE p;
00491     VALUE obj;
00492     rb_digest_metadata_t *algo;
00493 
00494     for (p = klass; !NIL_P(p); p = rb_class_superclass(p)) {
00495         if (rb_ivar_defined(p, id_metadata)) {
00496             obj = rb_ivar_get(p, id_metadata);
00497             break;
00498         }
00499     }
00500 
00501     if (NIL_P(p))
00502         rb_raise(rb_eRuntimeError, "Digest::Base cannot be directly inherited in Ruby");
00503 
00504     Data_Get_Struct(obj, rb_digest_metadata_t, algo);
00505 
00506     switch (algo->api_version) {
00507       case 2:
00508         break;
00509 
00510       /*
00511        * put conversion here if possible when API is updated
00512        */
00513 
00514       default:
00515         rb_raise(rb_eRuntimeError, "Incompatible digest API version");
00516     }
00517 
00518     return algo;
00519 }
00520 
00521 static VALUE
00522 rb_digest_base_alloc(VALUE klass)
00523 {
00524     rb_digest_metadata_t *algo;
00525     VALUE obj;
00526     void *pctx;
00527 
00528     if (klass == rb_cDigest_Base) {
00529         rb_raise(rb_eNotImpError, "Digest::Base is an abstract class");
00530     }
00531 
00532     algo = get_digest_base_metadata(klass);
00533 
00534     pctx = xmalloc(algo->ctx_size);
00535     algo->init_func(pctx);
00536 
00537     obj = Data_Wrap_Struct(klass, 0, xfree, pctx);
00538 
00539     return obj;
00540 }
00541 
00542 /* :nodoc: */
00543 static VALUE
00544 rb_digest_base_copy(VALUE copy, VALUE obj)
00545 {
00546     rb_digest_metadata_t *algo;
00547     void *pctx1, *pctx2;
00548 
00549     if (copy == obj) return copy;
00550 
00551     rb_check_frozen(copy);
00552 
00553     algo = get_digest_base_metadata(rb_obj_class(copy));
00554 
00555     Data_Get_Struct(obj, void, pctx1);
00556     Data_Get_Struct(copy, void, pctx2);
00557     memcpy(pctx2, pctx1, algo->ctx_size);
00558 
00559     return copy;
00560 }
00561 
00562 /* :nodoc: */
00563 static VALUE
00564 rb_digest_base_reset(VALUE self)
00565 {
00566     rb_digest_metadata_t *algo;
00567     void *pctx;
00568 
00569     algo = get_digest_base_metadata(rb_obj_class(self));
00570 
00571     Data_Get_Struct(self, void, pctx);
00572 
00573     algo->init_func(pctx);
00574 
00575     return self;
00576 }
00577 
00578 /* :nodoc: */
00579 static VALUE
00580 rb_digest_base_update(VALUE self, VALUE str)
00581 {
00582     rb_digest_metadata_t *algo;
00583     void *pctx;
00584 
00585     algo = get_digest_base_metadata(rb_obj_class(self));
00586 
00587     Data_Get_Struct(self, void, pctx);
00588 
00589     StringValue(str);
00590     algo->update_func(pctx, (unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str));
00591 
00592     return self;
00593 }
00594 
00595 /* :nodoc: */
00596 static VALUE
00597 rb_digest_base_finish(VALUE self)
00598 {
00599     rb_digest_metadata_t *algo;
00600     void *pctx;
00601     VALUE str;
00602 
00603     algo = get_digest_base_metadata(rb_obj_class(self));
00604 
00605     Data_Get_Struct(self, void, pctx);
00606 
00607     str = rb_str_new(0, algo->digest_len);
00608     algo->finish_func(pctx, (unsigned char *)RSTRING_PTR(str));
00609 
00610     /* avoid potential coredump caused by use of a finished context */
00611     algo->init_func(pctx);
00612 
00613     return str;
00614 }
00615 
00616 /* :nodoc: */
00617 static VALUE
00618 rb_digest_base_digest_length(VALUE self)
00619 {
00620     rb_digest_metadata_t *algo;
00621 
00622     algo = get_digest_base_metadata(rb_obj_class(self));
00623 
00624     return INT2NUM(algo->digest_len);
00625 }
00626 
00627 /* :nodoc: */
00628 static VALUE
00629 rb_digest_base_block_length(VALUE self)
00630 {
00631     rb_digest_metadata_t *algo;
00632 
00633     algo = get_digest_base_metadata(rb_obj_class(self));
00634 
00635     return INT2NUM(algo->block_len);
00636 }
00637 
00638 void
00639 Init_digest(void)
00640 {
00641     id_reset           = rb_intern("reset");
00642     id_update          = rb_intern("update");
00643     id_finish          = rb_intern("finish");
00644     id_digest          = rb_intern("digest");
00645     id_hexdigest       = rb_intern("hexdigest");
00646     id_digest_length   = rb_intern("digest_length");
00647 
00648     /*
00649      * module Digest
00650      */
00651     rb_mDigest = rb_define_module("Digest");
00652 
00653     /* module functions */
00654     rb_define_module_function(rb_mDigest, "hexencode", rb_digest_s_hexencode, 1);
00655 
00656     /*
00657      * module Digest::Instance
00658      */
00659     rb_mDigest_Instance = rb_define_module_under(rb_mDigest, "Instance");
00660 
00661     /* instance methods that should be overridden */
00662     rb_define_method(rb_mDigest_Instance, "update", rb_digest_instance_update, 1);
00663     rb_define_method(rb_mDigest_Instance, "<<", rb_digest_instance_update, 1);
00664     rb_define_private_method(rb_mDigest_Instance, "finish", rb_digest_instance_finish, 0);
00665     rb_define_method(rb_mDigest_Instance, "reset", rb_digest_instance_reset, 0);
00666     rb_define_method(rb_mDigest_Instance, "digest_length", rb_digest_instance_digest_length, 0);
00667     rb_define_method(rb_mDigest_Instance, "block_length", rb_digest_instance_block_length, 0);
00668 
00669     /* instance methods that may be overridden */
00670     rb_define_method(rb_mDigest_Instance, "==", rb_digest_instance_equal, 1);
00671     rb_define_method(rb_mDigest_Instance, "inspect", rb_digest_instance_inspect, 0);
00672 
00673     /* instance methods that need not usually be overridden */
00674     rb_define_method(rb_mDigest_Instance, "new", rb_digest_instance_new, 0);
00675     rb_define_method(rb_mDigest_Instance, "digest", rb_digest_instance_digest, -1);
00676     rb_define_method(rb_mDigest_Instance, "digest!", rb_digest_instance_digest_bang, 0);
00677     rb_define_method(rb_mDigest_Instance, "hexdigest", rb_digest_instance_hexdigest, -1);
00678     rb_define_method(rb_mDigest_Instance, "hexdigest!", rb_digest_instance_hexdigest_bang, 0);
00679     rb_define_method(rb_mDigest_Instance, "to_s", rb_digest_instance_to_s, 0);
00680     rb_define_method(rb_mDigest_Instance, "length", rb_digest_instance_length, 0);
00681     rb_define_method(rb_mDigest_Instance, "size", rb_digest_instance_length, 0);
00682 
00683     /*
00684      * class Digest::Class
00685      */
00686     rb_cDigest_Class = rb_define_class_under(rb_mDigest, "Class", rb_cObject);
00687     rb_define_method(rb_cDigest_Class, "initialize",  rb_digest_class_init, 0);
00688     rb_include_module(rb_cDigest_Class, rb_mDigest_Instance);
00689 
00690     /* class methods */
00691     rb_define_singleton_method(rb_cDigest_Class, "digest", rb_digest_class_s_digest, -1);
00692     rb_define_singleton_method(rb_cDigest_Class, "hexdigest", rb_digest_class_s_hexdigest, -1);
00693 
00694     id_metadata = rb_intern("metadata");
00695 
00696     /* class Digest::Base < Digest::Class */
00697     rb_cDigest_Base = rb_define_class_under(rb_mDigest, "Base", rb_cDigest_Class);
00698 
00699     rb_define_alloc_func(rb_cDigest_Base, rb_digest_base_alloc);
00700 
00701     rb_define_method(rb_cDigest_Base, "initialize_copy",  rb_digest_base_copy, 1);
00702     rb_define_method(rb_cDigest_Base, "reset", rb_digest_base_reset, 0);
00703     rb_define_method(rb_cDigest_Base, "update", rb_digest_base_update, 1);
00704     rb_define_method(rb_cDigest_Base, "<<", rb_digest_base_update, 1);
00705     rb_define_private_method(rb_cDigest_Base, "finish", rb_digest_base_finish, 0);
00706     rb_define_method(rb_cDigest_Base, "digest_length", rb_digest_base_digest_length, 0);
00707     rb_define_method(rb_cDigest_Base, "block_length", rb_digest_base_block_length, 0);
00708 }
00709