summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog26
-rw-r--r--ext/digest/bubblebabble/.cvsignore1
-rw-r--r--ext/digest/digest.c726
-rw-r--r--ext/digest/digest.h18
-rw-r--r--ext/digest/digest.txt113
-rw-r--r--ext/digest/digest.txt.ja111
-rw-r--r--ext/digest/lib/digest.rb41
-rw-r--r--ext/digest/lib/digest/hmac.rb270
-rw-r--r--ext/digest/md5/md5init.c18
-rw-r--r--ext/digest/rmd160/rmd160init.c23
-rw-r--r--ext/digest/sha1/sha1init.c22
-rw-r--r--ext/digest/sha2/sha2init.c18
-rw-r--r--ext/digest/test.sh5
-rw-r--r--test/digest/test_digest.rb28
14 files changed, 858 insertions, 562 deletions
diff --git a/ChangeLog b/ChangeLog
index 0a39adbaed..13e5298d00 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+Wed Oct 25 17:23:28 2006 Akinori MUSHA <knu@iDaemons.org>
+
+ * 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.
+
Wed Oct 25 08:03:23 2006 Tadayoshi Funaba <tadf@dotrb.org>
* lib/date/format.rb: updated based on date2 3.9.6.
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);
+ /* #<Digest::ClassName: xxxxx...xxxx> */
+ 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));
- /* #<Digest::Alg: xxxxx...xxxx> */
- 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 <knu@iDaemons.org>
+#
+# 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()
{
@@ -38,9 +45,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
diff --git a/test/digest/test_digest.rb b/test/digest/test_digest.rb
index 62f0aa2cd7..fa12086300 100644
--- a/test/digest/test_digest.rb
+++ b/test/digest/test_digest.rb
@@ -12,7 +12,6 @@ require 'digest'
rescue LoadError
end
end
-include Digest
module TestDigest
Data1 = "abc"
@@ -44,7 +43,8 @@ module TestDigest
def test_eq
# This test is also for clone()
- md1 = self.class::ALGO.new("ABC")
+ md1 = self.class::ALGO.new
+ md1 << "ABC"
assert_equal(md1, md1.clone, self.class::ALGO)
@@ -66,55 +66,55 @@ module TestDigest
class TestMD5 < Test::Unit::TestCase
include TestDigest
- ALGO = MD5
+ ALGO = Digest::MD5
DATA = {
Data1 => "900150983cd24fb0d6963f7d28e17f72",
Data2 => "8215ef0796a20bcaaae116d3876c664a",
}
- end if defined?(MD5)
+ end if defined?(Digest::MD5)
class TestSHA1 < Test::Unit::TestCase
include TestDigest
- ALGO = SHA1
+ ALGO = Digest::SHA1
DATA = {
Data1 => "a9993e364706816aba3e25717850c26c9cd0d89d",
Data2 => "84983e441c3bd26ebaae4aa1f95129e5e54670f1",
}
- end if defined?(SHA1)
+ end if defined?(Digest::SHA1)
class TestSHA256 < Test::Unit::TestCase
include TestDigest
- ALGO = SHA256
+ ALGO = Digest::SHA256
DATA = {
Data1 => "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
Data2 => "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1",
}
- end if defined?(SHA256)
+ end if defined?(Digest::SHA256)
class TestSHA384 < Test::Unit::TestCase
include TestDigest
- ALGO = SHA384
+ ALGO = Digest::SHA384
DATA = {
Data1 => "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7",
Data2 => "3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b",
}
- end if defined?(SHA384)
+ end if defined?(Digest::SHA384)
class TestSHA512 < Test::Unit::TestCase
include TestDigest
- ALGO = SHA512
+ ALGO = Digest::SHA512
DATA = {
Data1 => "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f",
Data2 => "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445",
}
- end if defined?(SHA512)
+ end if defined?(Digest::SHA512)
class TestRMD160 < Test::Unit::TestCase
include TestDigest
- ALGO = RMD160
+ ALGO = Digest::RMD160
DATA = {
Data1 => "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc",
Data2 => "12a053384a9c0c88e405a06c27dcf49ada62eb2b",
}
- end if defined?(RMD160)
+ end if defined?(Digest::RMD160)
end