From 817afbd987d35e4d65f599270f3b42777698556f Mon Sep 17 00:00:00 2001 From: knu Date: Wed, 25 Oct 2006 08:54:05 +0000 Subject: * ext/digest, test/digest/test_digest.rb: Merge from trunk: - Introduce versioning in Digest::Base API, and prefix C constants with RUBY_ and C type names with rb_ to avoid name clash in writing extensions. - Introduce Digest::Class and Digest::Instance for ease of implementing subclasses and add-ons. - Digest::Instance module requires and assumes that any instance be resettable and clonable. An instance method #new() is added so digest instances work just like digest classes. - The constructor does no longer take an initial string to feed; digest() and hexdigest() now do, instead. This allows digest classes to take their own hashing parameters. - Make some changes to digest() and hexdigest() class methods, which now take extra arguments, which are passed through to the constructor in an internal call. - Add #digest_length/size/length() and #block_length(), - Add the Digest::SHA2 class to wrap up SHA2 variants: SHA256, SHA384 and SHA512, hoping this module would make a decent example of a digest subclass written in Ruby. - Rip BubbleBabble support out of the base class and have a separate module named digest/bubblebabble. - Remove RD documents in favor of newly written and embedded RDoc documentation. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@11223 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/digest/bubblebabble/.cvsignore | 1 - ext/digest/digest.c | 726 +++++++++++++++++++++++-------------- ext/digest/digest.h | 18 +- ext/digest/digest.txt | 113 ------ ext/digest/digest.txt.ja | 111 ------ ext/digest/lib/digest.rb | 41 ++- ext/digest/lib/digest/hmac.rb | 270 ++++++++++++++ ext/digest/md5/md5init.c | 18 +- ext/digest/rmd160/rmd160init.c | 23 +- ext/digest/sha1/sha1init.c | 22 +- ext/digest/sha2/sha2init.c | 18 +- ext/digest/test.sh | 5 +- 12 files changed, 818 insertions(+), 548 deletions(-) delete mode 100644 ext/digest/digest.txt delete mode 100644 ext/digest/digest.txt.ja create mode 100644 ext/digest/lib/digest/hmac.rb (limited to 'ext') diff --git a/ext/digest/bubblebabble/.cvsignore b/ext/digest/bubblebabble/.cvsignore index 814345ece8..4088712231 100644 --- a/ext/digest/bubblebabble/.cvsignore +++ b/ext/digest/bubblebabble/.cvsignore @@ -1,4 +1,3 @@ Makefile mkmf.log *.def -extconf.h diff --git a/ext/digest/digest.c b/ext/digest/digest.c index b8144f3706..4a5245f911 100644 --- a/ext/digest/digest.c +++ b/ext/digest/digest.c @@ -15,32 +15,24 @@ #include "digest.h" -static VALUE mDigest, cDigest_Base; -static ID id_metadata, id_new, id_initialize, id_update, id_digest; +static VALUE rb_mDigest; +static VALUE rb_mDigest_Instance; +static VALUE rb_cDigest_Class; +static VALUE rb_cDigest_Base; -/* - * Digest::Base - */ - -static algo_t * -get_digest_base_metadata(VALUE klass) -{ - VALUE obj; - algo_t *algo; +static ID id_reset, id_update, id_finish, id_digest, id_hexdigest, id_digest_length; +static ID id_metadata; - if (rb_ivar_defined(klass, id_metadata) == Qfalse) { - return NULL; - } - - obj = rb_ivar_get(klass, id_metadata); +RUBY_EXTERN void Init_digest_base(void); - Data_Get_Struct(obj, algo_t, algo); - - return algo; -} +/* + * Document-module: Digest + * + * This module provides a framework for message digest libraries. + */ static VALUE -hexdigest_str_new(VALUE str_digest) +hexencode_str_new(VALUE str_digest) { char *digest; size_t digest_len; @@ -72,376 +64,576 @@ hexdigest_str_new(VALUE str_digest) return str; } +/* + * call-seq: + * Digest.hexencode(string) -> hexencoded_string + * + * Generates a hex-encoded version of a given _string_. + */ static VALUE -bubblebabble_str_new(VALUE str_digest) +rb_digest_s_hexencode(VALUE klass, VALUE str) { - char *digest; - size_t digest_len; - VALUE str; - char *p; - int i, j, seed = 1; - static const char vowels[] = { - 'a', 'e', 'i', 'o', 'u', 'y' - }; - static const char consonants[] = { - 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm', 'n', - 'p', 'r', 's', 't', 'v', 'z', 'x' - }; + return hexencode_str_new(str); +} - StringValue(str_digest); - digest = RSTRING_PTR(str_digest); - digest_len = RSTRING_LEN(str_digest); +/* + * Document-module: Digest::Instance + * + * This module provides instance methods for a digest implementation + * object to calculate message digest values. + */ - if ((LONG_MAX - 2) / 3 < (digest_len | 1)) { - rb_raise(rb_eRuntimeError, "digest string too long"); - } +/* + * call-seq: + * digest_obj.update(string) -> digest_obj + * digest_obj << string -> digest_obj + * + * Updates the digest using a given _string_ and returns self. + * + * The update() method and the left-shift operator are overridden by + * each implementation subclass. (One should be an alias for the + * other) + */ +static VALUE +rb_digest_instance_update(VALUE self, VALUE str) +{ + rb_raise(rb_eRuntimeError, "%s does not implement update()", rb_inspect(self)); +} - str = rb_str_new(0, (digest_len | 1) * 3 + 2); - p = RSTRING_PTR(str); +/* + * call-seq: + * digest_obj.instance_eval { finish } -> digest_obj + * + * Finishes the digest and returns the resulting hash value. + * + * This method is overridden by each implementation subclass and often + * made private, because some of those subclasses may leave internal + * data uninitialized. Do not call this method from outside. Use + * #digest!() instead, which ensures that internal data be reset for + * security reasons. + */ +static VALUE +rb_digest_instance_finish(VALUE self) +{ + rb_raise(rb_eRuntimeError, "%s does not implement finish()", rb_inspect(self)); +} - i = j = 0; - p[j++] = 'x'; +/* + * call-seq: + * digest_obj.reset -> digest_obj + * + * Resets the digest to the initial state and returns self. + * + * This method is overridden by each implementation subclass. + */ +static VALUE +rb_digest_instance_reset(VALUE self) +{ + rb_raise(rb_eRuntimeError, "%s does not implement reset()", rb_inspect(self)); +} - for (;;) { - unsigned char byte1, byte2; +/* + * call-seq: + * digest_obj.new -> another_digest_obj + * + * Returns a new, initialized copy of the digest object. Equivalent + * to digest_obj.clone().reset(). + */ +static VALUE +rb_digest_instance_new(VALUE self) +{ + VALUE clone = rb_obj_clone(self); + rb_funcall(clone, id_reset, 0); + return clone; +} + +/* + * call-seq: + * digest_obj.digest -> string + * digest_obj.digest(string) -> string + * + * If none is given, returns the resulting hash value of the digest, + * keeping the digest's state. + * + * If a _string_ is given, returns the hash value for the given + * _string_, resetting the digest to the initial state before and + * after the process. + */ +static VALUE +rb_digest_instance_digest(int argc, VALUE *argv, VALUE self) +{ + VALUE str, value; + + if (rb_scan_args(argc, argv, "01", &str) > 0) { + rb_funcall(self, id_reset, 0); + rb_funcall(self, id_update, 1, str); + value = rb_funcall(self, id_finish, 0); + rb_funcall(self, id_reset, 0); + } else { + VALUE clone = rb_obj_clone(self); + + value = rb_funcall(clone, id_finish, 0); + rb_funcall(clone, id_reset, 0); + } + + return value; +} - if (i >= digest_len) { - p[j++] = vowels[seed % 6]; - p[j++] = consonants[16]; - p[j++] = vowels[seed / 6]; - break; - } +/* + * call-seq: + * digest_obj.digest! -> string + * + * Returns the resulting hash value and resets the digest to the + * initial state. + */ +static VALUE +rb_digest_instance_digest_bang(VALUE self) +{ + VALUE value = rb_funcall(self, id_finish, 0); + rb_funcall(self, id_reset, 0); - byte1 = digest[i++]; - p[j++] = vowels[(((byte1 >> 6) & 3) + seed) % 6]; - p[j++] = consonants[(byte1 >> 2) & 15]; - p[j++] = vowels[((byte1 & 3) + (seed / 6)) % 6]; + return value; +} - if (i >= digest_len) { - break; - } +/* + * call-seq: + * digest_obj.hexdigest -> string + * digest_obj.hexdigest(string) -> string + * + * If none is given, returns the resulting hash value of the digest in + * a hex-encoded form, keeping the digest's state. + * + * If a _string_ is given, returns the hash value for the given + * _string_ in a hex-encoded form, resetting the digest to the initial + * state before and after the process. + */ +static VALUE +rb_digest_instance_hexdigest(int argc, VALUE *argv, VALUE self) +{ + VALUE str, value; - byte2 = digest[i++]; - p[j++] = consonants[(byte2 >> 4) & 15]; - p[j++] = '-'; - p[j++] = consonants[byte2 & 15]; + if (rb_scan_args(argc, argv, "01", &str) > 0) { + rb_funcall(self, id_reset, 0); + rb_funcall(self, id_update, 1, str); + value = rb_funcall(self, id_finish, 0); + rb_funcall(self, id_reset, 0); + } else { + VALUE clone = rb_obj_clone(self); - seed = (seed * 5 + byte1 * 7 + byte2) % 36; + value = rb_funcall(clone, id_finish, 0); + rb_funcall(clone, id_reset, 0); } - p[j] = 'x'; + return hexencode_str_new(value); +} + +/* + * call-seq: + * digest_obj.hexdigest! -> string + * + * Returns the resulting hash value and resets the digest to the + * initial state. + */ +static VALUE +rb_digest_instance_hexdigest_bang(VALUE self) +{ + VALUE value = rb_funcall(self, id_finish, 0); + rb_funcall(self, id_reset, 0); + + return hexencode_str_new(value); +} + +/* + * call-seq: + * digest_obj.to_s -> string + * + * Returns digest_obj.hexdigest(). + */ +static VALUE +rb_digest_instance_to_s(VALUE self) +{ + return rb_funcall(self, id_hexdigest, 0); +} + +/* + * call-seq: + * digest_obj.inspect -> string + * + * Creates a printable version of the digest object. + */ +static VALUE +rb_digest_instance_inspect(VALUE self) +{ + VALUE str; + size_t digest_len = 32; /* about this size at least */ + char *cname; + + cname = rb_obj_classname(self); + /* # */ + str = rb_str_buf_new(2 + strlen(cname) + 2 + digest_len * 2 + 1); + rb_str_buf_cat2(str, "#<"); + rb_str_buf_cat2(str, cname); + rb_str_buf_cat2(str, ": "); + rb_str_buf_append(str, rb_digest_instance_hexdigest(0, 0, self)); + rb_str_buf_cat2(str, ">"); return str; } +/* + * call-seq: + * digest_obj == another_digest_obj -> boolean + * digest_obj == string -> boolean + * + * If a string is given, checks whether it is equal to the hex-encoded + * hash value of the digest object. If another instance of the same + * digest class is given, checks whether they have the same hash + * value. Otherwise returns false. + */ static VALUE -rb_digest_base_alloc(VALUE klass) +rb_digest_instance_equal(VALUE self, VALUE other) { - algo_t *algo; - VALUE obj; - void *pctx; + VALUE str1, str2; - if (klass == cDigest_Base) { - rb_raise(rb_eNotImpError, "Digest::Base is an abstract class"); + if (rb_obj_class(self) == rb_obj_class(other)) { + str1 = rb_digest_instance_digest(0, 0, self); + str2 = rb_digest_instance_digest(0, 0, other); + } else { + str1 = rb_digest_instance_to_s(self); + str2 = other; } - algo = get_digest_base_metadata(klass); + /* never blindly assume that subclass methods return strings */ + StringValue(str1); + StringValue(str2); - if (algo == NULL) { - return Data_Wrap_Struct(klass, 0, free, 0); + if (RSTRING_LEN(str1) == RSTRING_LEN(str2) && + rb_str_cmp(str1, str2) == 0) { + return Qtrue; } + return Qfalse; +} - pctx = xmalloc(algo->ctx_size); - algo->init_func(pctx); +/* + * call-seq: + * digest_obj.digest_length -> integer + * + * Returns the length of the hash value of the digest. + * + * This method should be overridden by each implementation subclass. + * If not, digest_obj.digest().length() is returned. + */ +static VALUE +rb_digest_instance_digest_length(VALUE self) +{ + /* subclasses really should redefine this method */ + VALUE digest = rb_digest_instance_digest(0, 0, self); - obj = Data_Wrap_Struct(klass, 0, free, pctx); + /* never blindly assume that #digest() returns a string */ + StringValue(digest); + return INT2NUM(RSTRING_LEN(digest)); +} - return obj; +/* + * call-seq: + * digest_obj.length -> integer + * digest_obj.size -> integer + * + * Returns digest_obj.digest_length(). + */ +static VALUE +rb_digest_instance_length(VALUE self) +{ + return rb_funcall(self, id_digest_length, 0); } +/* + * call-seq: + * digest_obj.block_length -> integer + * + * Returns the block length of the digest. + * + * This method is overridden by each implementation subclass. + */ static VALUE -rb_digest_base_s_digest(VALUE klass, VALUE str) +rb_digest_instance_block_length(VALUE self) { - algo_t *algo = get_digest_base_metadata(klass); + rb_raise(rb_eRuntimeError, "%s does not implement block_length()", rb_inspect(self)); +} + +/* + * Document-class: Digest::Class + * + * This module stands as a base class for digest implementation + * classes. + */ + +/* + * call-seq: + * Digest::Class.digest(string, *parameters) -> hash_string + * + * Returns the hash value of a given _string_. This is equivalent to + * Digest::Class.new(*parameters).digest(string), where extra + * _parameters_, if any, are passed through to the constructor and the + * _string_ is passed to #digest(). + */ +static VALUE +rb_digest_class_s_digest(int argc, VALUE *argv, VALUE klass) +{ + VALUE str; void *pctx; volatile VALUE obj; - if (algo == NULL) { - VALUE obj = rb_funcall(klass, id_new, 0); - rb_funcall(obj, id_update, 1, str); - return rb_funcall(obj, id_digest, 0); + if (argc < 1) { + rb_raise(rb_eArgError, "no data given"); } - obj = rb_digest_base_alloc(klass); - Data_Get_Struct(obj, void, pctx); + str = *argv++; + argc--; StringValue(str); - algo->update_func(pctx, RSTRING_PTR(str), RSTRING_LEN(str)); - str = rb_str_new(0, algo->digest_len); - algo->finish_func(pctx, RSTRING_PTR(str)); + obj = rb_obj_alloc(klass); + rb_obj_call_init(obj, argc, argv); - return str; + return rb_funcall(obj, id_digest, 1, str); } +/* + * call-seq: + * Digest::Class.hexdigest(string[, ...]) -> hash_string + * + * Returns the hex-encoded hash value of a given _string_. This is + * almost equivalent to + * Digest.hexencode(Digest::Class.new(*parameters).digest(string)). + */ static VALUE -rb_digest_base_s_hexdigest(VALUE klass, VALUE str) +rb_digest_class_s_hexdigest(int argc, VALUE *argv, VALUE klass) { - return hexdigest_str_new(rb_funcall(klass, id_digest, 1, str)); + return hexencode_str_new(rb_funcall2(klass, id_digest, argc, argv)); } -static VALUE -rb_digest_base_s_bubblebabble(VALUE klass, VALUE str) -{ - return bubblebabble_str_new(rb_funcall(klass, id_digest, 1, str)); -} +/* + * Document-class: Digest::Base + * + * This abstract class provides a common interface to message digest + * implementation classes written in C. + */ -static VALUE -rb_digest_base_copy(VALUE copy, VALUE obj) +static rb_digest_metadata_t * +get_digest_base_metadata(VALUE klass) { - algo_t *algo; - void *pctx1, *pctx2; - - if (copy == obj) return copy; - rb_check_frozen(copy); - algo = get_digest_base_metadata(rb_obj_class(copy)); + VALUE obj; + rb_digest_metadata_t *algo; - if (algo == NULL) { - /* initialize_copy() is undefined or something */ + if (rb_ivar_defined(klass, id_metadata) == Qfalse) { + /* This class should not be subclassed in Ruby */ rb_notimplement(); } - /* get_digest_base_metadata() may return a NULL */ - if (algo != get_digest_base_metadata(rb_obj_class(obj))) { - rb_raise(rb_eTypeError, "wrong argument class"); + obj = rb_ivar_get(klass, id_metadata); + + Data_Get_Struct(obj, rb_digest_metadata_t, algo); + + switch (algo->api_version) { + case 2: + break; + + /* + * put conversion here if possible when API is updated + */ + + default: + rb_raise(rb_eRuntimeError, "Incompatible digest API version"); } - Data_Get_Struct(obj, void, pctx1); - Data_Get_Struct(copy, void, pctx2); - memcpy(pctx2, pctx1, algo->ctx_size); - return copy; + return algo; } static VALUE -rb_digest_base_reset(VALUE self) +rb_digest_base_alloc(VALUE klass) { - algo_t *algo; + rb_digest_metadata_t *algo; + VALUE obj; void *pctx; - algo = get_digest_base_metadata(rb_obj_class(self)); - - if (algo == NULL) { - rb_funcall(self, id_initialize, 0); - - return self; + if (klass == rb_cDigest_Base) { + rb_raise(rb_eNotImpError, "Digest::Base is an abstract class"); } - Data_Get_Struct(self, void, pctx); + algo = get_digest_base_metadata(klass); - memset(pctx, 0, algo->ctx_size); + pctx = xmalloc(algo->ctx_size); algo->init_func(pctx); - return self; + obj = Data_Wrap_Struct(klass, 0, free, pctx); + + return obj; } +/* :nodoc: */ static VALUE -rb_digest_base_update(VALUE self, VALUE str) +rb_digest_base_copy(VALUE copy, VALUE obj) { - algo_t *algo; - void *pctx; + rb_digest_metadata_t *algo; + void *pctx1, *pctx2; - algo = get_digest_base_metadata(rb_obj_class(self)); + if (copy == obj) return copy; - if (algo == NULL) { - /* subclasses must define update() */ - rb_notimplement(); - } + rb_check_frozen(copy); - Data_Get_Struct(self, void, pctx); + algo = get_digest_base_metadata(rb_obj_class(copy)); - StringValue(str); - algo->update_func(pctx, RSTRING_PTR(str), RSTRING_LEN(str)); + Data_Get_Struct(obj, void, pctx1); + Data_Get_Struct(copy, void, pctx2); + memcpy(pctx2, pctx1, algo->ctx_size); - return self; + return copy; } +/* :nodoc: */ static VALUE -rb_digest_base_lshift(VALUE self, VALUE str) +rb_digest_base_reset(VALUE self) { - algo_t *algo; + rb_digest_metadata_t *algo; void *pctx; algo = get_digest_base_metadata(rb_obj_class(self)); - if (algo == NULL) { - /* subclasses just need to define update(), not << */ - rb_funcall(self, id_update, 1, str); - - return self; - } - Data_Get_Struct(self, void, pctx); - StringValue(str); - algo->update_func(pctx, RSTRING_PTR(str), RSTRING_LEN(str)); + algo->init_func(pctx); return self; } +/* :nodoc: */ static VALUE -rb_digest_base_init(int argc, VALUE *argv, VALUE self) +rb_digest_base_update(VALUE self, VALUE str) { - VALUE arg; + rb_digest_metadata_t *algo; + void *pctx; - rb_scan_args(argc, argv, "01", &arg); + algo = get_digest_base_metadata(rb_obj_class(self)); - if (!NIL_P(arg)) rb_digest_base_update(self, arg); + Data_Get_Struct(self, void, pctx); + + StringValue(str); + algo->update_func(pctx, RSTRING_PTR(str), RSTRING_LEN(str)); return self; } +/* :nodoc: */ static VALUE -rb_digest_base_digest(VALUE self) +rb_digest_base_finish(VALUE self) { - algo_t *algo; - void *pctx1, *pctx2; - size_t ctx_size; + rb_digest_metadata_t *algo; + void *pctx; VALUE str; algo = get_digest_base_metadata(rb_obj_class(self)); - if (algo == NULL) { - /* subclasses must define update() */ - rb_notimplement(); - } - - Data_Get_Struct(self, void, pctx1); - - ctx_size = algo->ctx_size; - pctx2 = xmalloc(ctx_size); - memcpy(pctx2, pctx1, ctx_size); + Data_Get_Struct(self, void, pctx); str = rb_str_new(0, algo->digest_len); - algo->finish_func(pctx2, RSTRING_PTR(str)); - free(pctx2); - - return str; -} + algo->finish_func(pctx, RSTRING_PTR(str)); -static VALUE -rb_digest_base_hexdigest(VALUE self) -{ - return hexdigest_str_new(rb_funcall(self, id_digest, 0)); -} + /* avoid potential coredump caused by use of a finished context */ + algo->init_func(pctx); -static VALUE -rb_digest_base_bubblebabble(VALUE self) -{ - return bubblebabble_str_new(rb_funcall(self, id_digest, 0)); + return str; } +/* :nodoc: */ static VALUE -rb_digest_base_inspect(VALUE self) +rb_digest_base_digest_length(VALUE self) { - algo_t *algo; - VALUE klass, str; - size_t digest_len = 32; /* no need to be just the right size */ - char *cname; + rb_digest_metadata_t *algo; - klass = rb_obj_class(self); - algo = get_digest_base_metadata(klass); - - if (algo != NULL) - digest_len = algo->digest_len; - - cname = rb_obj_classname(self); + algo = get_digest_base_metadata(rb_obj_class(self)); - /* # */ - str = rb_str_buf_new(2 + strlen(cname) + 2 + digest_len * 2 + 1); - rb_str_buf_cat2(str, "#<"); - rb_str_buf_cat2(str, cname); - rb_str_buf_cat2(str, ": "); - rb_str_buf_append(str, rb_digest_base_hexdigest(self)); - rb_str_buf_cat2(str, ">"); - return str; + return INT2NUM(algo->digest_len); } +/* :nodoc: */ static VALUE -rb_digest_base_equal(VALUE self, VALUE other) +rb_digest_base_block_length(VALUE self) { - algo_t *algo; - VALUE klass; - VALUE str1, str2; + rb_digest_metadata_t *algo; - klass = rb_obj_class(self); - - if (rb_obj_class(other) == klass) { - str1 = rb_digest_base_digest(self); - str2 = rb_digest_base_digest(other); - } else { - StringValue(other); - str2 = other; - - algo = get_digest_base_metadata(klass); - - if (RSTRING_LEN(str2) == algo->digest_len) - str1 = rb_digest_base_digest(self); - else - str1 = rb_digest_base_hexdigest(self); - } - - if (RSTRING_LEN(str1) == RSTRING_LEN(str2) - && rb_str_cmp(str1, str2) == 0) - return Qtrue; + algo = get_digest_base_metadata(rb_obj_class(self)); - return Qfalse; + return INT2NUM(algo->block_len); } -/* - * This module provides an interface to the following hash algorithms: - * - * - the MD5 Message-Digest Algorithm by the RSA Data Security, - * Inc., described in RFC 1321 - * - * - the SHA-1 Secure Hash Algorithm by NIST (the US' National - * Institute of Standards and Technology), described in FIPS PUB - * 180-1. - * - * - the SHA-256/384/512 Secure Hash Algorithm by NIST (the US' - * National Institute of Standards and Technology), described in - * FIPS PUB 180-2. - * - * - the RIPEMD-160 cryptographic hash function, designed by Hans - * Dobbertin, Antoon Bosselaers, and Bart Preneel. - */ - void Init_digest(void) { - mDigest = rb_define_module("Digest"); - - cDigest_Base = rb_define_class_under(mDigest, "Base", rb_cObject); - - rb_define_alloc_func(cDigest_Base, rb_digest_base_alloc); - rb_define_singleton_method(cDigest_Base, "digest", rb_digest_base_s_digest, 1); - rb_define_singleton_method(cDigest_Base, "hexdigest", rb_digest_base_s_hexdigest, 1); - rb_define_singleton_method(cDigest_Base, "bubblebabble", rb_digest_base_s_bubblebabble, 1); - - rb_define_method(cDigest_Base, "initialize", rb_digest_base_init, -1); - rb_define_method(cDigest_Base, "initialize_copy", rb_digest_base_copy, 1); - rb_define_method(cDigest_Base, "reset", rb_digest_base_reset, 0); - rb_define_method(cDigest_Base, "update", rb_digest_base_update, 1); - rb_define_method(cDigest_Base, "<<", rb_digest_base_lshift, 1); - rb_define_method(cDigest_Base, "digest", rb_digest_base_digest, 0); - rb_define_method(cDigest_Base, "hexdigest", rb_digest_base_hexdigest, 0); - rb_define_method(cDigest_Base, "bubblebabble", rb_digest_base_bubblebabble, 0); - rb_define_method(cDigest_Base, "to_s", rb_digest_base_hexdigest, 0); - rb_define_method(cDigest_Base, "inspect", rb_digest_base_inspect, 0); - rb_define_method(cDigest_Base, "==", rb_digest_base_equal, 1); + id_reset = rb_intern("reset"); + id_update = rb_intern("update"); + id_finish = rb_intern("finish"); + id_digest = rb_intern("digest"); + id_hexdigest = rb_intern("hexdigest"); + id_digest_length = rb_intern("digest_length"); + + /* + * module Digest + */ + rb_mDigest = rb_define_module("Digest"); + + /* module functions */ + rb_define_module_function(rb_mDigest, "hexencode", rb_digest_s_hexencode, 1); + + /* + * module Digest::Instance + */ + rb_mDigest_Instance = rb_define_module_under(rb_mDigest, "Instance"); + + /* instance methods that should be overridden */ + rb_define_method(rb_mDigest_Instance, "update", rb_digest_instance_update, 1); + rb_define_method(rb_mDigest_Instance, "<<", rb_digest_instance_update, 1); + rb_define_private_method(rb_mDigest_Instance, "finish", rb_digest_instance_finish, 0); + rb_define_method(rb_mDigest_Instance, "reset", rb_digest_instance_reset, 0); + rb_define_method(rb_mDigest_Instance, "digest_length", rb_digest_instance_digest_length, 0); + rb_define_method(rb_mDigest_Instance, "block_length", rb_digest_instance_block_length, 0); + + /* instance methods that may be overridden */ + rb_define_method(rb_mDigest_Instance, "==", rb_digest_instance_equal, 1); + rb_define_method(rb_mDigest_Instance, "inspect", rb_digest_instance_inspect, 0); + + /* instance methods that need not usually be overridden */ + rb_define_method(rb_mDigest_Instance, "new", rb_digest_instance_new, 0); + rb_define_method(rb_mDigest_Instance, "digest", rb_digest_instance_digest, -1); + rb_define_method(rb_mDigest_Instance, "digest!", rb_digest_instance_digest_bang, 0); + rb_define_method(rb_mDigest_Instance, "hexdigest", rb_digest_instance_hexdigest, -1); + rb_define_method(rb_mDigest_Instance, "hexdigest!", rb_digest_instance_hexdigest_bang, 0); + rb_define_method(rb_mDigest_Instance, "to_s", rb_digest_instance_hexdigest, 0); + rb_define_method(rb_mDigest_Instance, "length", rb_digest_instance_length, 0); + rb_define_method(rb_mDigest_Instance, "size", rb_digest_instance_length, 0); + + /* + * class Digest::Class + */ + rb_cDigest_Class = rb_define_class_under(rb_mDigest, "Class", rb_cObject); + rb_include_module(rb_cDigest_Class, rb_mDigest_Instance); + + /* class methods */ + rb_define_singleton_method(rb_cDigest_Class, "digest", rb_digest_class_s_digest, -1); + rb_define_singleton_method(rb_cDigest_Class, "hexdigest", rb_digest_class_s_hexdigest, -1); id_metadata = rb_intern("metadata"); - id_new = rb_intern("new"); - id_initialize = rb_intern("initialize"); - id_update = rb_intern("update"); - id_digest = rb_intern("digest"); + + /* class Digest::Base < Digest::Class */ + rb_cDigest_Base = rb_define_class_under(rb_mDigest, "Base", rb_cDigest_Class); + + rb_define_alloc_func(rb_cDigest_Base, rb_digest_base_alloc); + + rb_define_method(rb_cDigest_Base, "initialize_copy", rb_digest_base_copy, 1); + rb_define_method(rb_cDigest_Base, "reset", rb_digest_base_reset, 0); + rb_define_method(rb_cDigest_Base, "update", rb_digest_base_update, 1); + rb_define_method(rb_cDigest_Base, "<<", rb_digest_base_update, 1); + rb_define_private_method(rb_cDigest_Base, "finish", rb_digest_base_finish, 0); + rb_define_method(rb_cDigest_Base, "digest_length", rb_digest_base_digest_length, 0); + rb_define_method(rb_cDigest_Base, "block_length", rb_digest_base_block_length, 0); } diff --git a/ext/digest/digest.h b/ext/digest/digest.h index ee3c680a36..6e4906c859 100644 --- a/ext/digest/digest.h +++ b/ext/digest/digest.h @@ -15,14 +15,18 @@ #include "ruby.h" -typedef void (*hash_init_func_t)(void *); -typedef void (*hash_update_func_t)(void *, unsigned char *, size_t); -typedef void (*hash_finish_func_t)(void *, unsigned char *); +#define RUBY_DIGEST_API_VERSION 2 + +typedef void (*rb_digest_hash_init_func_t)(void *); +typedef void (*rb_digest_hash_update_func_t)(void *, unsigned char *, size_t); +typedef void (*rb_digest_hash_finish_func_t)(void *, unsigned char *); typedef struct { + int api_version; size_t digest_len; + size_t block_len; size_t ctx_size; - hash_init_func_t init_func; - hash_update_func_t update_func; - hash_finish_func_t finish_func; -} algo_t; + rb_digest_hash_init_func_t init_func; + rb_digest_hash_update_func_t update_func; + rb_digest_hash_finish_func_t finish_func; +} rb_digest_metadata_t; diff --git a/ext/digest/digest.txt b/ext/digest/digest.txt deleted file mode 100644 index 5797dd18f9..0000000000 --- a/ext/digest/digest.txt +++ /dev/null @@ -1,113 +0,0 @@ -.\" digest.txt - -*- Indented-Text -*- created at: Fri May 25 08:13:50 JST 2001 -$RoughId: digest.txt,v 1.9 2001/07/13 19:46:51 knu Exp $ -$Id$ - -** MD5(Class) - -A class to implement the MD5 Message-Digest Algorithm by RSA Data -Security, Inc., described in RFC1321. - -Superclass: Digest::Base - -require 'digest/md5' - -** SHA1(Class) - -A class to implement the SHA-1 Secure Hash Algorithm by NIST (the US' -National Institute of Standards and Technology), described in FIPS PUB -180-1. - -Superclass: Digest::Base - -require 'digest/sha1' - -** SHA256(Class) -** SHA384(Class) -** SHA512(Class) - -Classes to implement the SHA-256/384/512 Secure Hash Algorithm(s) by -NIST (the US' National Institute of Standards and Technology), -described in FIPS PUB 180-2. - -Superclass: Digest::Base - -require 'digest/sha2' - -** RMD160(Class) - -A class to implement the RIPEMD-160 cryptographic hash function, -designed by Hans Dobbertin, Antoon Bosselaers, and Bart Preneel. - -Superclass: Digest::Base - -require 'digest/rmd160' - - -Those above classes provide a common interface as shown below. - - -Class Methods: - - new([str]) - - Creates a new digest object. If a string argument is given, - it is added to the object. (see update.) - - digest(str) - - Immediately calculates and return the hash of the given - strings as a string. Equivalent to new(str).digest. - - hexdigest(str) - - Immediately calculates and return the hash of the given - strings as a string of hexadecimal digits. Equivalent to - new(str).hexdigest. - -Methods: - - clone - - Creates a copy of the digest object. - - digest - - Returns the hash of the added strings as a string of 16 bytes - for MD5, 20 bytes for SHA1 and RMD160, 32 bytes for SHA256, 48 - bytes for SHA384, and 64 bytes for SHA512. - - hexdigest - to_s - - Returns the hash of the added strings as a string of 32 - hexadecimal digits for MD5, 40 hexadecimal digits for SHA1 and - RMD160, 64 hexadecimal digits for SHA256, 96 hexadecimal - digits for SHA384, and 128 hexadecimal digits for SHA512. - This method is equal to: - - def hexdigest - digest.unpack("H*")[0] - end - - update(str) - << str - - Appends the string str to the digest object. Repeated calls - are equivalent to a single call with the concatenation of all - the arguments, i.e. m.update(a); m.update(b) is equivalent to - m.update(a + b) and m << a << b is equivalent to m << a + b. - - == md - - Checks if the object is equal to the given digest object. - - == str - - Regards the value as either a digest value or a hexdigest - value (depending on the length) and checks if the object is - equal to the given string. - -------------------------------------------------------- -Local variables: -fill-column: 70 -end: diff --git a/ext/digest/digest.txt.ja b/ext/digest/digest.txt.ja deleted file mode 100644 index 8997d25b9d..0000000000 --- a/ext/digest/digest.txt.ja +++ /dev/null @@ -1,111 +0,0 @@ -.\" digest.txt.ja - -*- Indented-Text -*- created at: Fri May 25 08:22:19 JST 2001 -$RoughId: digest.txt.jp,v 1.8 2001/07/13 15:38:27 knu Exp $ -$Id$ - -** MD5(クラス) - -RFC1321に記述されているRSA Data Security, Inc. の MD5 Message-Digest -Algorithmを実装するクラス。 - -Superclass: Digest::Base - -require 'digest/md5' - -** SHA1(クラス) - -FIPS PUB 180-1に記述されているNIST (the US' National Institute of -Standards and Technology) の SHA-1 Secure Hash Algorithmを実装するクラス。 - -Superclass: Digest::Base - -require 'digest/sha1' - -** SHA256(クラス) -** SHA384(クラス) -** SHA512(クラス) - -FIPS PUB 180-2に記述されているNIST (the US' National Institute of -Standards and Technology) の SHA-256/384/512 Secure Hash Algorithmを -実装するクラス。 - -Superclass: Digest::Base - -require 'digest/sha2' - -** RMD160(クラス) - -Hans Dobbertin, Antoon Bosselaers, Bart Preneel によって設計された -RIPEMD-160 ハッシュ関数を実装するクラス。 - -Superclass: Digest::Base - -require 'digest/rmd160' - - -これらのクラスは以下のような共通のインターフェースを提供する。 - - -Class Methods: - - new([str]) - - 新しいダイジェストオブジェクトを生成する.文字列引数が与えられる - とそれを追加する(see update)。 - - digest(str) - - 与えられた文字列に対するハッシュ値を文字列で返す。 - new(str).digest と等価。 - - hexdigest(str) - - 与えられた文字列に対するハッシュ値を、ASCIIコードを使って - 16進数の列を示す文字列にエンコードして返す。 - new(str).hexdigest と等価。 - -Methods: - - clone - - ダイジェストオブジェクトの複製を作る。 - - digest - - 今までに追加した文字列に対するハッシュ値を文字列で返す。MD5では - 16バイト長、SHA1およびRMD160では20バイト長、SHA256では32バイト長、 - SHA384では48バイト長、SHA512では64バイト長となる。 - - hexdigest - to_s - - 今までに追加した文字列に対するハッシュ値を、ASCIIコードを使って - 16進数の列を示す文字列にエンコードして返す。MD5では32バイト長、 - SHA1およびRMD160では40バイト長、SHA256では64バイト長、SHA384では - 96バイト長、SHA512では128バイト長となる。Rubyで書くと以下と同じ。 - - def hexdigest - digest.unpack("H*")[0] - end - - update(str) - << str - - 文字列を追加する。複数回updateを呼ぶことは文字列を連結して - updateを呼ぶことと等しい。すなわち m.update(a); m.update(b) は - m.update(a + b) と、 m << a << b は m << a + b とそれぞれ等価 - である。 - - == md - - 与えられたダイジェストオブジェクトと比較する。 - - == str - - 与えられた文字列を digest 値、もしくは hexdigest 値と比較する。 - いずれの値と見るかは与えられた文字列の長さによって自動判別 - される。 - -------------------------------------------------------- -Local variables: -fill-column: 70 -end: diff --git a/ext/digest/lib/digest.rb b/ext/digest/lib/digest.rb index c277a0eea5..578c6f53d4 100644 --- a/ext/digest/lib/digest.rb +++ b/ext/digest/lib/digest.rb @@ -1,27 +1,46 @@ require 'digest.so' module Digest - autoload "MD5", "digest/md5" - autoload "RMD160", "digest/rmd160" - autoload "SHA1", "digest/sha1" - autoload "SHA256", "digest/sha2" - autoload "SHA384", "digest/sha2" - autoload "SHA512", "digest/sha2" + autoload "SHA256", "digest/sha2.so" + autoload "SHA384", "digest/sha2.so" + autoload "SHA512", "digest/sha2.so" - class Base - # creates a digest object and read given file, _name_. + def self.const_missing(name) + begin + require File.join('digest', name.to_s.downcase) + + return Digest.const_get(name) if Digest.const_defined?(name) + rescue LoadError => e + end + + raise NameError, "Digest class not found: Digest::#{name}" + end + + class ::Digest::Class + # creates a digest object and reads a given file, _name_. # # p Digest::SHA256.file("X11R6.8.2-src.tar.bz2").hexdigest # # => "f02e3c85572dc9ad7cb77c2a638e3be24cc1b5bea9fdbb0b0299c9668475c534" def self.file(name) - digest = self.new + new.file(name) + end + end + + module Instance + # updates the digest with the contents of a given file _name_ and + # returns self. + def file(name) File.open(name, "rb") {|f| buf = "" while f.read(16384, buf) - digest.update buf + update buf end } - digest + self end end end + +def Digest(name) + Digest.const_get(name) +end diff --git a/ext/digest/lib/digest/hmac.rb b/ext/digest/lib/digest/hmac.rb new file mode 100644 index 0000000000..a6415a156a --- /dev/null +++ b/ext/digest/lib/digest/hmac.rb @@ -0,0 +1,270 @@ +# = digest/hmac.rb +# +# An implementation of HMAC keyed-hashing algorithm +# +# == Overview +# +# This library adds a method named hmac() to Digest classes, which +# creates a Digest class for calculating HMAC digests. +# +# == Examples +# +# require 'digest/hmac' +# +# # one-liner example +# puts Digest::HMAC.hexdigest("data", "hash key", Digest::SHA1) +# +# # rather longer one +# hmac = Digest::HMAC.new("foo", Digest::RMD160) +# +# buf = "" +# while stream.read(16384, buf) +# hmac.update(buf) +# end +# +# puts hmac.bubblebabble +# +# == License +# +# Copyright (c) 2006 Akinori MUSHA +# +# Documentation by Akinori MUSHA +# +# All rights reserved. You can redistribute and/or modify it under +# the same terms as Ruby. +# +# $Id$ +# + +require 'digest' + +module Digest + class HMAC < Digest::Class + def initialize(key, digester) + @md = digester.new + + block_len = @md.block_length + + if key.length > block_len + key = @md.digest(key) + end + + ipad = Array.new(block_len).fill(0x36) + opad = Array.new(block_len).fill(0x5c) + + i = 0 + key.each_byte { |c| + ipad[i] ^= c + opad[i] ^= c + i += 1 + } + + @key = key.freeze + @ipad = ipad.inject('') { |s, c| s << c.chr }.freeze + @opad = opad.inject('') { |s, c| s << c.chr }.freeze + end + + def initialize_copy(other) + @md = other.instance_eval { @md.clone } + end + + def update(text) + @md.reset.update(@opad + @md.digest(@ipad + text)) + self + end + + def reset + @md.reset + self + end + + def finish + @md.digest! + end + private :finish + + def digest_length + @md.digest_length + end + + def block_length + @md.block_length + end + + def inspect + sprintf('#<%s: key=%s, digest=%s>', self.class.name, @key.inspect, @md.inspect.sub(/^\#<(.*)>$/) { $1 }); + end + end +end + +if $0 == __FILE__ + eval DATA.read, nil, $0, __LINE__+4 +end + +__END__ + +require 'test/unit' + +module TM_HMAC + def test_s_hexdigest + cases.each { |h| + digesters.each { |d| + assert_equal(h[:hexdigest], Digest::HMAC.hexdigest(h[:data], h[:key], d)) + } + } + end + + def test_hexdigest + cases.each { |h| + digesters.each { |d| + hmac = Digest::HMAC.new(h[:key], d) + + hmac.update(h[:data]) + + assert_equal(h[:hexdigest], hmac.hexdigest) + } + } + end + + def test_reset + cases.each { |h| + digesters.each { |d| + hmac = Digest::HMAC.new(h[:key], d) + hmac.update("test") + hmac.reset + hmac.update(h[:data]) + + assert_equal(h[:hexdigest], hmac.hexdigest) + } + } + end +end + +class TC_HMAC_MD5 < Test::Unit::TestCase + include TM_HMAC + + def digesters + [Digest::MD5, Digest::MD5.new] + end + + # Taken from RFC 2202: Test Cases for HMAC-MD5 and HMAC-SHA-1 + def cases + [ + { + :key => "\x0b" * 16, + :data => "Hi There", + :hexdigest => "9294727a3638bb1c13f48ef8158bfc9d", + }, { + :key => "Jefe", + :data => "what do ya want for nothing?", + :hexdigest => "750c783e6ab0b503eaa86e310a5db738", + }, { + :key => "\xaa" * 16, + :data => "\xdd" * 50, + :hexdigest => "56be34521d144c88dbb8c733f0e8b3f6", + }, { + :key => "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", + :data => "\xcd" * 50, + :hexdigest => "697eaf0aca3a3aea3a75164746ffaa79", + }, { + :key => "\x0c" * 16, + :data => "Test With Truncation", + :hexdigest => "56461ef2342edc00f9bab995690efd4c", + }, { + :key => "\xaa" * 80, + :data => "Test Using Larger Than Block-Size Key - Hash Key First", + :hexdigest => "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd", + }, { + :key => "\xaa" * 80, + :data => "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", + :hexdigest => "6f630fad67cda0ee1fb1f562db3aa53e", + } + ] + end +end + +class TC_HMAC_SHA1 < Test::Unit::TestCase + include TM_HMAC + + def digesters + [Digest::SHA1, Digest::SHA1.new] + end + + # Taken from RFC 2202: Test Cases for HMAC-MD5 and HMAC-SHA-1 + def cases + [ + { + :key => "\x0b" * 20, + :data => "Hi There", + :hexdigest => "b617318655057264e28bc0b6fb378c8ef146be00", + }, { + :key => "Jefe", + :data => "what do ya want for nothing?", + :hexdigest => "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79", + }, { + :key => "\xaa" * 20, + :data => "\xdd" * 50, + :hexdigest => "125d7342b9ac11cd91a39af48aa17b4f63f175d3", + }, { + :key => "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", + :data => "\xcd" * 50, + :hexdigest => "4c9007f4026250c6bc8414f9bf50c86c2d7235da", + }, { + :key => "\x0c" * 20, + :data => "Test With Truncation", + :hexdigest => "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04", + }, { + :key => "\xaa" * 80, + :data => "Test Using Larger Than Block-Size Key - Hash Key First", + :hexdigest => "aa4ae5e15272d00e95705637ce8a3b55ed402112", + }, { + :key => "\xaa" * 80, + :data => "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", + :hexdigest => "e8e99d0f45237d786d6bbaa7965c7808bbff1a91", + } + ] + end +end + +class TC_HMAC_RMD160 < Test::Unit::TestCase + include TM_HMAC + + def digesters + [Digest::RMD160, Digest::RMD160.new] + end + + # Taken from RFC 2286: Test Cases for HMAC-RIPEMD160 and HMAC-RIPEMD128 + def cases + [ + { + :key => "\x0b" * 20, + :data => "Hi There", + :hexdigest => "24cb4bd67d20fc1a5d2ed7732dcc39377f0a5668", + }, { + :key => "Jefe", + :data => "what do ya want for nothing?", + :hexdigest => "dda6c0213a485a9e24f4742064a7f033b43c4069", + }, { + :key => "\xaa" * 20, + :data => "\xdd" * 50, + :hexdigest => "b0b105360de759960ab4f35298e116e295d8e7c1", + }, { + :key => "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", + :data => "\xcd" * 50, + :hexdigest => "d5ca862f4d21d5e610e18b4cf1beb97a4365ecf4", + }, { + :key => "\x0c" * 20, + :data => "Test With Truncation", + :hexdigest => "7619693978f91d90539ae786500ff3d8e0518e39", + }, { + :key => "\xaa" * 80, + :data => "Test Using Larger Than Block-Size Key - Hash Key First", + :hexdigest => "6466ca07ac5eac29e1bd523e5ada7605b791fd8b", + }, { + :key => "\xaa" * 80, + :data => "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", + :hexdigest => "69ea60798d71616cce5fd0871e23754cd75d5a0a", + } + ] + end +end diff --git a/ext/digest/md5/md5init.c b/ext/digest/md5/md5init.c index 6fdf6e0a26..17658f4fce 100644 --- a/ext/digest/md5/md5init.c +++ b/ext/digest/md5/md5init.c @@ -8,14 +8,21 @@ #include "md5.h" #endif -static algo_t md5 = { +static rb_digest_metadata_t md5 = { + RUBY_DIGEST_API_VERSION, MD5_DIGEST_LENGTH, + MD5_BLOCK_LENGTH, sizeof(MD5_CTX), - (hash_init_func_t)MD5_Init, - (hash_update_func_t)MD5_Update, - (hash_finish_func_t)MD5_Finish, + (rb_digest_hash_init_func_t)MD5_Init, + (rb_digest_hash_update_func_t)MD5_Update, + (rb_digest_hash_finish_func_t)MD5_Finish, }; +/* + * A class for calculating message digests using the MD5 + * Message-Digest Algorithm by RSA Data Security, Inc., described in + * RFC1321. + */ void Init_md5() { @@ -28,9 +35,6 @@ Init_md5() cDigest_MD5 = rb_define_class_under(mDigest, "MD5", cDigest_Base); - rb_define_const(cDigest_MD5, "DIGEST_LENGTH", INT2NUM(MD5_DIGEST_LENGTH)); - rb_define_const(cDigest_MD5, "BLOCK_LENGTH", INT2NUM(MD5_BLOCK_LENGTH)); - rb_ivar_set(cDigest_MD5, rb_intern("metadata"), Data_Wrap_Struct(rb_cObject, 0, 0, &md5)); } diff --git a/ext/digest/rmd160/rmd160init.c b/ext/digest/rmd160/rmd160init.c index 585ba05c33..763867df86 100644 --- a/ext/digest/rmd160/rmd160init.c +++ b/ext/digest/rmd160/rmd160init.c @@ -8,19 +8,25 @@ #include "rmd160.h" #endif -static algo_t rmd160 = { +static rb_digest_metadata_t rmd160 = { + RUBY_DIGEST_API_VERSION, RMD160_DIGEST_LENGTH, + RMD160_BLOCK_LENGTH, sizeof(RMD160_CTX), - (hash_init_func_t)RMD160_Init, - (hash_update_func_t)RMD160_Update, - (hash_finish_func_t)RMD160_Finish, + (rb_digest_hash_init_func_t)RMD160_Init, + (rb_digest_hash_update_func_t)RMD160_Update, + (rb_digest_hash_finish_func_t)RMD160_Finish, }; +/* + * A class for calculating message digests using RIPEMD-160 + * cryptographic hash function, designed by Hans Dobbertin, Antoon + * Bosselaers, and Bart Preneel. + */ void Init_rmd160() { VALUE mDigest, cDigest_Base, cDigest_RMD160; - ID id_metadata; rb_require("digest"); @@ -29,11 +35,6 @@ Init_rmd160() cDigest_RMD160 = rb_define_class_under(mDigest, "RMD160", cDigest_Base); - rb_define_const(cDigest_RMD160, "DIGEST_LENGTH", INT2NUM(RMD160_DIGEST_LENGTH)); - rb_define_const(cDigest_RMD160, "BLOCK_LENGTH", INT2NUM(RMD160_BLOCK_LENGTH)); - - id_metadata = rb_intern("metadata"); - - rb_ivar_set(cDigest_RMD160, id_metadata, + rb_ivar_set(cDigest_RMD160, rb_intern("metadata"), Data_Wrap_Struct(rb_cObject, 0, 0, &rmd160)); } diff --git a/ext/digest/sha1/sha1init.c b/ext/digest/sha1/sha1init.c index e56f18bf63..b2146f05a9 100644 --- a/ext/digest/sha1/sha1init.c +++ b/ext/digest/sha1/sha1init.c @@ -8,29 +8,33 @@ #include "sha1.h" #endif -static algo_t sha1 = { +static rb_digest_metadata_t sha1 = { + RUBY_DIGEST_API_VERSION, SHA1_DIGEST_LENGTH, + SHA1_BLOCK_LENGTH, sizeof(SHA1_CTX), - (hash_init_func_t)SHA1_Init, - (hash_update_func_t)SHA1_Update, - (hash_finish_func_t)SHA1_Finish, + (rb_digest_hash_init_func_t)SHA1_Init, + (rb_digest_hash_update_func_t)SHA1_Update, + (rb_digest_hash_finish_func_t)SHA1_Finish, }; +/* + * A class for calculating message digests using the SHA-1 Secure Hash + * Algorithm by NIST (the US' National Institute of Standards and + * Technology), described in FIPS PUB 180-1. + */ void Init_sha1() { VALUE mDigest, cDigest_Base, cDigest_SHA1; - + rb_require("digest"); - + mDigest = rb_path2class("Digest"); cDigest_Base = rb_path2class("Digest::Base"); cDigest_SHA1 = rb_define_class_under(mDigest, "SHA1", cDigest_Base); - rb_define_const(cDigest_SHA1, "DIGEST_LENGTH", INT2NUM(SHA1_DIGEST_LENGTH)); - rb_define_const(cDigest_SHA1, "BLOCK_LENGTH", INT2NUM(SHA1_BLOCK_LENGTH)); - rb_ivar_set(cDigest_SHA1, rb_intern("metadata"), Data_Wrap_Struct(rb_cObject, 0, 0, &sha1)); } diff --git a/ext/digest/sha2/sha2init.c b/ext/digest/sha2/sha2init.c index c5a16ab4df..c83a29316a 100644 --- a/ext/digest/sha2/sha2init.c +++ b/ext/digest/sha2/sha2init.c @@ -7,16 +7,23 @@ #define FOREACH_BITLEN(func) func(256) func(384) func(512) #define DEFINE_ALGO_METADATA(bitlen) \ -static algo_t sha##bitlen = { \ +static rb_digest_metadata_t sha##bitlen = { \ + RUBY_DIGEST_API_VERSION, \ SHA##bitlen##_DIGEST_LENGTH, \ + SHA##bitlen##_BLOCK_LENGTH, \ sizeof(SHA##bitlen##_CTX), \ - (hash_init_func_t)SHA##bitlen##_Init, \ - (hash_update_func_t)SHA##bitlen##_Update, \ - (hash_finish_func_t)SHA##bitlen##_Finish, \ + (rb_digest_hash_init_func_t)SHA##bitlen##_Init, \ + (rb_digest_hash_update_func_t)SHA##bitlen##_Update, \ + (rb_digest_hash_finish_func_t)SHA##bitlen##_Finish, \ }; FOREACH_BITLEN(DEFINE_ALGO_METADATA) +/* + * Classes for calculating message digests using the SHA-256/384/512 + * Secure Hash Algorithm(s) by NIST (the US' National Institute of + * Standards and Technology), described in FIPS PUB 180-2. + */ void Init_sha2() { @@ -37,9 +44,6 @@ Init_sha2() #define DEFINE_ALGO_CLASS(bitlen) \ cDigest_SHA##bitlen = rb_define_class_under(mDigest, "SHA" #bitlen, cDigest_Base); \ -\ - rb_define_const(cDigest_SHA##bitlen, "DIGEST_LENGTH", INT2NUM(SHA##bitlen##_DIGEST_LENGTH)); \ - rb_define_const(cDigest_SHA##bitlen, "BLOCK_LENGTH", INT2NUM(SHA##bitlen##_BLOCK_LENGTH)); \ \ rb_ivar_set(cDigest_SHA##bitlen, id_metadata, \ Data_Wrap_Struct(rb_cObject, 0, 0, &sha##bitlen)); diff --git a/ext/digest/test.sh b/ext/digest/test.sh index 6fb07d2177..328c7575e6 100644 --- a/ext/digest/test.sh +++ b/ext/digest/test.sh @@ -11,8 +11,6 @@ ${RUBY} extconf.rb --with-cflags="${CFLAGS}" ${MAKE} clean ${MAKE} -mkdir -p lib/digest - for algo in md5 rmd160 sha1 sha2; do args=--with-cflags="${CFLAGS}" @@ -27,7 +25,6 @@ for algo in md5 rmd160 sha1 sha2; do ln -sf ../../$algo/$algo.so lib/digest/ done -${RUBY} -I. -I./lib test.rb +${RUBY} -I. -I./lib ../../test/digest/test_digest.rb rm lib/digest/*.so -rmdir lib/digest -- cgit v1.2.3