summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/digest/bubblebabble/bubblebabble.c28
-rw-r--r--ext/digest/bubblebabble/depend3
-rw-r--r--ext/digest/bubblebabble/extconf.rb3
-rw-r--r--ext/digest/digest.c736
-rw-r--r--ext/digest/digest.h16
-rw-r--r--ext/digest/lib/digest.rb6
-rw-r--r--ext/digest/lib/digest/hmac.rb59
-rw-r--r--ext/digest/md5/md5init.c10
-rw-r--r--ext/digest/rmd160/rmd160init.c15
-rw-r--r--ext/digest/sha1/sha1init.c14
-rw-r--r--ext/digest/sha2/lib/digest/sha2.rb73
-rw-r--r--ext/digest/sha2/sha2init.c10
12 files changed, 569 insertions, 404 deletions
diff --git a/ext/digest/bubblebabble/bubblebabble.c b/ext/digest/bubblebabble/bubblebabble.c
index a7e4d9f7d6..3a03ceced0 100644
--- a/ext/digest/bubblebabble/bubblebabble.c
+++ b/ext/digest/bubblebabble/bubblebabble.c
@@ -12,8 +12,8 @@
************************************************/
#include "ruby.h"
+#include "digest.h"
-static VALUE mDigest, cDigest_Base;
static ID id_digest;
static VALUE
@@ -83,9 +83,6 @@ bubblebabble_str_new(VALUE str_digest)
* Digest.bubblebabble(string) -> bubblebabble_string
*
* Returns a BubbleBabble encoded version of a given _string_.
- *
- * If extra arguments are given, they are passed to
- * Digest::ALGORITHM.digest() along with the _string_.
*/
static VALUE
rb_digest_s_bubblebabble(VALUE klass, VALUE str)
@@ -95,12 +92,12 @@ rb_digest_s_bubblebabble(VALUE klass, VALUE str)
/*
* call-seq:
- * Digest::ALGORITHM.bubblebabble(string, ...) -> hash_string
+ * Digest::Class.bubblebabble(string, ...) -> hash_string
*
* Returns the BubbleBabble encoded hash value of a given _string_.
*/
static VALUE
-rb_digest_base_s_bubblebabble(int argc, VALUE *argv, VALUE klass)
+rb_digest_class_s_bubblebabble(int argc, VALUE *argv, VALUE klass)
{
return bubblebabble_str_new(rb_funcall2(klass, id_digest, argc, argv));
}
@@ -112,7 +109,7 @@ rb_digest_base_s_bubblebabble(int argc, VALUE *argv, VALUE klass)
* Returns the resulting hash value in a Bubblebabble encoded form.
*/
static VALUE
-rb_digest_base_bubblebabble(VALUE self)
+rb_digest_instance_bubblebabble(VALUE self)
{
return bubblebabble_str_new(rb_funcall(self, id_digest, 0));
}
@@ -124,17 +121,22 @@ rb_digest_base_bubblebabble(VALUE self)
void
Init_bubblebabble(void)
{
- mDigest = rb_define_module("Digest");
- cDigest_Base = rb_define_class_under(mDigest, "Base", rb_cObject);
+ VALUE mDigest, mDigest_Instance, cDigest_Class;
+
+ rb_require("digest");
+
+ mDigest = rb_path2class("Digest");
+ mDigest_Instance = rb_path2class("Digest::Instance");
+ cDigest_Class = rb_path2class("Digest::Class");
/* Digest::bubblebabble() */
rb_define_module_function(mDigest, "bubblebabble", rb_digest_s_bubblebabble, 1);
- /* Digest::Base::bubblebabble() */
- rb_define_singleton_method(cDigest_Base, "bubblebabble", rb_digest_base_s_bubblebabble, -1);
+ /* Digest::Class::bubblebabble() */
+ rb_define_singleton_method(cDigest_Class, "bubblebabble", rb_digest_class_s_bubblebabble, -1);
- /* Digest::Base#bubblebabble() */
- rb_define_method(cDigest_Base, "bubblebabble", rb_digest_base_bubblebabble, 0);
+ /* Digest::Instance#bubblebabble() */
+ rb_define_method(mDigest_Instance, "bubblebabble", rb_digest_instance_bubblebabble, 0);
id_digest = rb_intern("digest");
}
diff --git a/ext/digest/bubblebabble/depend b/ext/digest/bubblebabble/depend
new file mode 100644
index 0000000000..b20148ded4
--- /dev/null
+++ b/ext/digest/bubblebabble/depend
@@ -0,0 +1,3 @@
+bubblebabble.o: bubblebabble.c $(srcdir)/../digest.h $(hdrdir)/ruby.h \
+ $(topdir)/config.h $(hdrdir)/defines.h $(hdrdir)/intern.h \
+ $(srcdir)/../defs.h
diff --git a/ext/digest/bubblebabble/extconf.rb b/ext/digest/bubblebabble/extconf.rb
index 5b7f911e33..53cb83934a 100644
--- a/ext/digest/bubblebabble/extconf.rb
+++ b/ext/digest/bubblebabble/extconf.rb
@@ -1,3 +1,6 @@
require 'mkmf'
+$defs << "-DHAVE_CONFIG_H"
+$INCFLAGS << " -I$(srcdir)/.."
+
create_makefile('digest/bubblebabble')
diff --git a/ext/digest/digest.c b/ext/digest/digest.c
index 65a78c0d6c..4a5245f911 100644
--- a/ext/digest/digest.c
+++ b/ext/digest/digest.c
@@ -15,48 +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;
-/*
- * Document-class: Digest
- *
- * This module provides a framework for message digest libraries.
- */
+static ID id_reset, id_update, id_finish, id_digest, id_hexdigest, id_digest_length;
+static ID id_metadata;
+
+RUBY_EXTERN void Init_digest_base(void);
/*
- * Document-class: Digest::Base
+ * Document-module: Digest
*
- * This class provides a common interface to message digest
- * algorithms.
+ * This module provides a framework for message digest libraries.
*/
-static algo_t *
-get_digest_base_metadata(VALUE klass)
-{
- VALUE obj;
- algo_t *algo;
-
- if (rb_ivar_defined(klass, id_metadata) == Qfalse) {
- return NULL;
- }
-
- obj = rb_ivar_get(klass, id_metadata);
-
- Data_Get_Struct(obj, algo_t, algo);
-
- if (algo->api_version != 1) {
- /*
- * put conversion here if possible when API is updated
- */
- rb_raise(rb_eRuntimeError, "Incompatible digest API version");
- }
-
- return algo;
-}
-
static VALUE
-hexdigest_str_new(VALUE str_digest)
+hexencode_str_new(VALUE str_digest)
{
char *digest;
size_t digest_len;
@@ -88,259 +64,195 @@ 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
-rb_digest_base_alloc(VALUE klass)
+rb_digest_s_hexencode(VALUE klass, VALUE str)
{
- algo_t *algo;
- VALUE obj;
- void *pctx;
-
- if (klass == cDigest_Base) {
- rb_raise(rb_eNotImpError, "Digest::Base is an abstract class");
- }
-
- algo = get_digest_base_metadata(klass);
-
- if (algo == NULL) {
- return Data_Wrap_Struct(klass, 0, free, 0);
- }
-
- pctx = xmalloc(algo->ctx_size);
- algo->init_func(pctx);
+ return hexencode_str_new(str);
+}
- obj = Data_Wrap_Struct(klass, 0, free, pctx);
+/*
+ * Document-module: Digest::Instance
+ *
+ * This module provides instance methods for a digest implementation
+ * object to calculate message digest values.
+ */
- return obj;
+/*
+ * 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));
}
/*
* call-seq:
- * Digest::ALGORITHM.digest(string[, ...]) -> hash_string
+ * digest_obj.instance_eval { finish } -> digest_obj
+ *
+ * Finishes the digest and returns the resulting hash value.
*
- * Returns the hash value of a given string _data_. This is almost
- * equivalent to Digest::ALGORITHM.new(...).update(string).digest()
- * where extra arguments, if any, are passed through to the
- * constructor.
+ * 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_base_s_digest(int argc, VALUE *argv, VALUE klass)
+rb_digest_instance_finish(VALUE self)
{
- VALUE str;
- algo_t *algo;
- void *pctx;
- volatile VALUE obj;
-
- if (argc < 1) {
- rb_raise(rb_eArgError, "no data given");
- }
-
- str = *argv++;
- argc--;
-
- StringValue(str);
-
- algo = get_digest_base_metadata(klass);
-
- if (algo == NULL) {
- VALUE obj = rb_funcall2(klass, id_new, argc, argv);
- rb_funcall(obj, id_update, 1, str);
- return rb_funcall(obj, id_digest, 0);
- }
-
- obj = rb_digest_base_alloc(klass);
- Data_Get_Struct(obj, void, pctx);
-
- 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));
-
- return str;
+ rb_raise(rb_eRuntimeError, "%s does not implement finish()", rb_inspect(self));
}
/*
* call-seq:
- * Digest::ALGORITHM.hexdigest(string[, ...]) -> hash_string
+ * digest_obj.reset -> digest_obj
+ *
+ * Resets the digest to the initial state and returns self.
*
- * Returns the hex-encoded hash value of a given _string_. This
- * method just hex-encode the return value of
- * Digest::ALGORITHM.digest(string[, ...]) where extra arguments, if
- * any, are passed through along with the _string_.
+ * This method is overridden by each implementation subclass.
*/
static VALUE
-rb_digest_base_s_hexdigest(int argc, VALUE *argv, VALUE klass)
+rb_digest_instance_reset(VALUE self)
{
- return hexdigest_str_new(rb_funcall2(klass, id_digest, argc, argv));
+ rb_raise(rb_eRuntimeError, "%s does not implement reset()", rb_inspect(self));
}
-/* :nodoc: */
+/*
+ * 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_base_copy(VALUE copy, VALUE obj)
+rb_digest_instance_new(VALUE self)
{
- algo_t *algo;
- void *pctx1, *pctx2;
-
- if (copy == obj) return copy;
- rb_check_frozen(copy);
- algo = get_digest_base_metadata(rb_obj_class(copy));
-
- if (algo == NULL) {
- /* initialize_copy() is undefined or something */
- 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");
- }
- Data_Get_Struct(obj, void, pctx1);
- Data_Get_Struct(copy, void, pctx2);
- memcpy(pctx2, pctx1, algo->ctx_size);
-
- return copy;
+ VALUE clone = rb_obj_clone(self);
+ rb_funcall(clone, id_reset, 0);
+ return clone;
}
/*
* call-seq:
- * digest_obj.reset -> digest_obj
+ * digest_obj.digest -> string
+ * digest_obj.digest(string) -> string
*
- * Resets the digest to the initial state and returns self.
+ * If none is given, returns the resulting hash value of the digest,
+ * keeping the digest's state.
*
- * Every implementation subclass which constructor takes arguments
- * must redefine this method because Digest::Base#reset() internally
- * calls initialize() with no argument.
+ * 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_base_reset(VALUE self)
+rb_digest_instance_digest(int argc, VALUE *argv, VALUE self)
{
- algo_t *algo;
- void *pctx;
-
- algo = get_digest_base_metadata(rb_obj_class(self));
+ VALUE str, value;
- if (algo == NULL) {
- rb_funcall(self, id_initialize, 0);
+ 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);
- return self;
+ value = rb_funcall(clone, id_finish, 0);
+ rb_funcall(clone, id_reset, 0);
}
- Data_Get_Struct(self, void, pctx);
-
- memset(pctx, 0, algo->ctx_size);
- algo->init_func(pctx);
-
- return self;
+ return value;
}
/*
* call-seq:
- * digest_obj.update(string) -> digest_obj
- *
- * Updates the digest using a given _string_ and returns self.
+ * digest_obj.digest! -> string
*
- * Implementation subclasses must redefine this method, and should
- * make `<<' an alias to it.
+ * Returns the resulting hash value and resets the digest to the
+ * initial state.
*/
static VALUE
-rb_digest_base_update(VALUE self, VALUE str)
+rb_digest_instance_digest_bang(VALUE self)
{
- algo_t *algo;
- void *pctx;
-
- algo = get_digest_base_metadata(rb_obj_class(self));
-
- if (algo == NULL) {
- /* subclasses must define update() */
- rb_notimplement();
- }
+ VALUE value = rb_funcall(self, id_finish, 0);
+ rb_funcall(self, id_reset, 0);
- Data_Get_Struct(self, void, pctx);
-
- StringValue(str);
- algo->update_func(pctx, RSTRING_PTR(str), RSTRING_LEN(str));
-
- return self;
+ return value;
}
/*
* call-seq:
- * digest_obj << string -> digest_obj
+ * digest_obj.hexdigest -> string
+ * digest_obj.hexdigest(string) -> string
*
- * Calls update(string).
+ * If none is given, returns the resulting hash value of the digest in
+ * a hex-encoded form, keeping the digest's state.
*
- * Implementation subclasses need not but should alias this method to
- * update() to eliminate chain calls.
+ * 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_base_lshift(VALUE self, VALUE str)
+rb_digest_instance_hexdigest(int argc, VALUE *argv, VALUE self)
{
- algo_t *algo;
- void *pctx;
-
- algo = get_digest_base_metadata(rb_obj_class(self));
+ VALUE str, value;
- if (algo == NULL) {
- /* subclasses just need to define update(), not << */
+ 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);
- return self;
+ value = rb_funcall(clone, id_finish, 0);
+ rb_funcall(clone, id_reset, 0);
}
- Data_Get_Struct(self, void, pctx);
-
- StringValue(str);
- algo->update_func(pctx, RSTRING_PTR(str), RSTRING_LEN(str));
-
- return self;
+ return hexencode_str_new(value);
}
/*
* call-seq:
- * digest_obj.digest -> string
- *
- * Returns the resulting hash value.
+ * digest_obj.hexdigest! -> string
*
- * Implementation subclasses must redefine this method.
+ * Returns the resulting hash value and resets the digest to the
+ * initial state.
*/
static VALUE
-rb_digest_base_digest(VALUE self)
+rb_digest_instance_hexdigest_bang(VALUE self)
{
- algo_t *algo;
- void *pctx1, *pctx2;
- size_t ctx_size;
- VALUE str;
+ VALUE value = rb_funcall(self, id_finish, 0);
+ rb_funcall(self, id_reset, 0);
- 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);
-
- str = rb_str_new(0, algo->digest_len);
- algo->finish_func(pctx2, RSTRING_PTR(str));
- free(pctx2);
-
- return str;
+ return hexencode_str_new(value);
}
/*
* call-seq:
- * digest_obj.hexdigest -> string
* digest_obj.to_s -> string
*
- * Returns the resulting hash value in a hex-encoded form.
+ * Returns digest_obj.hexdigest().
*/
static VALUE
-rb_digest_base_hexdigest(VALUE self)
+rb_digest_instance_to_s(VALUE self)
{
- return hexdigest_str_new(rb_funcall(self, id_digest, 0));
+ return rb_funcall(self, id_hexdigest, 0);
}
/*
@@ -350,202 +262,378 @@ rb_digest_base_hexdigest(VALUE self)
* Creates a printable version of the digest object.
*/
static VALUE
-rb_digest_base_inspect(VALUE self)
+rb_digest_instance_inspect(VALUE self)
{
- algo_t *algo;
- VALUE klass, str;
- size_t digest_len = 32; /* no need to be just the right size */
+ VALUE str;
+ size_t digest_len = 32; /* about this size at least */
char *cname;
- klass = rb_obj_class(self);
- algo = get_digest_base_metadata(klass);
-
- if (algo != NULL)
- digest_len = algo->digest_len;
-
cname = rb_obj_classname(self);
- /* #<Digest::Alg: xxxxx...xxxx> */
+ /* #<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_base_hexdigest(self));
+ rb_str_buf_append(str, rb_digest_instance_hexdigest(0, 0, self));
rb_str_buf_cat2(str, ">");
return str;
}
/*
* call-seq:
- * digest_obj == string -> boolean
* digest_obj == another_digest_obj -> boolean
+ * digest_obj == string -> boolean
*
- * If a string is given, checks whether it is equal to the 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.
+ * 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_equal(VALUE self, VALUE other)
+rb_digest_instance_equal(VALUE self, VALUE other)
{
- algo_t *algo;
- VALUE klass;
VALUE str1, str2;
- klass = rb_obj_class(self);
-
- if (rb_obj_class(other) == klass) {
- str1 = rb_funcall(self, id_digest, 0);
- str2 = rb_funcall(other, id_digest, 0);
+ 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 {
- StringValue(other);
+ str1 = rb_digest_instance_to_s(self);
str2 = other;
-
- algo = get_digest_base_metadata(klass);
-
- if (RSTRING_LEN(str2) == algo->digest_len)
- str1 = rb_funcall(self, id_digest, 0);
- else
- str1 = rb_digest_base_hexdigest(self);
}
- if (RSTRING_LEN(str1) == RSTRING_LEN(str2)
- && rb_str_cmp(str1, str2) == 0)
- return Qtrue;
+ /* never blindly assume that subclass methods return strings */
+ StringValue(str1);
+ StringValue(str2);
+ if (RSTRING_LEN(str1) == RSTRING_LEN(str2) &&
+ rb_str_cmp(str1, str2) == 0) {
+ return Qtrue;
+ }
return Qfalse;
}
/*
* call-seq:
- * Digest::ALGORITHM.block_length(...) -> integer
+ * digest_obj.digest_length -> integer
*
- * Returns the digest length of the digest algorithm. Parameters
- * follow the same specification as the constructor.
+ * Returns the length of the hash value of the digest.
*
- * If an implementation subclass does not redefine this method,
- * returns Digest::ALGORITHM.new(...).digest_length().
+ * This method should be overridden by each implementation subclass.
+ * If not, digest_obj.digest().length() is returned.
*/
static VALUE
-rb_digest_base_s_digest_length(int argc, VALUE *argv,VALUE klass)
+rb_digest_instance_digest_length(VALUE self)
{
- algo_t *algo;
-
- algo = get_digest_base_metadata(klass);
+ /* subclasses really should redefine this method */
+ VALUE digest = rb_digest_instance_digest(0, 0, self);
- if (algo == NULL) {
- /* Subclasses really should redefine this method */
- VALUE obj = rb_funcall2(klass, id_new, argc, argv);
- return rb_funcall(obj, rb_intern("digest_length"), 0);
- }
+ /* never blindly assume that #digest() returns a string */
+ StringValue(digest);
+ return INT2NUM(RSTRING_LEN(digest));
+}
- return INT2NUM(algo->digest_len);
+/*
+ * 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 length of the hash value of the digest object.
+ * Returns the block length of the digest.
*
- * If an implementation subclass does not redefine this method,
- * returns digest_obj.digest().length().
+ * This method is overridden by each implementation subclass.
*/
static VALUE
-rb_digest_base_digest_length(VALUE self)
+rb_digest_instance_block_length(VALUE self)
{
- algo_t *algo;
+ rb_raise(rb_eRuntimeError, "%s does not implement block_length()", rb_inspect(self));
+}
- algo = get_digest_base_metadata(rb_obj_class(self));
+/*
+ * Document-class: Digest::Class
+ *
+ * This module stands as a base class for digest implementation
+ * classes.
+ */
- if (algo == NULL) {
- /* subclasses really should redefine this method */
- VALUE digest = rb_funcall(self, id_digest, 0);
- StringValue(digest);
- return INT2NUM(RSTRING_LEN(digest));
+/*
+ * 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 (argc < 1) {
+ rb_raise(rb_eArgError, "no data given");
}
- return INT2NUM(algo->digest_len);
+ str = *argv++;
+ argc--;
+
+ StringValue(str);
+
+ obj = rb_obj_alloc(klass);
+ rb_obj_call_init(obj, argc, argv);
+
+ return rb_funcall(obj, id_digest, 1, str);
}
/*
* call-seq:
- * Digest::ALGORITHM.block_length(...) -> integer
+ * Digest::Class.hexdigest(string[, ...]) -> hash_string
*
- * Returns the block length of the digest algorithm. Parameters
- * follow the same specification as the constructor.
+ * 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_class_s_hexdigest(int argc, VALUE *argv, VALUE klass)
+{
+ return hexencode_str_new(rb_funcall2(klass, id_digest, argc, argv));
+}
+
+/*
+ * Document-class: Digest::Base
*
- * If an implementation subclass does not redefine this method,
- * returns Digest::ALGORITHM.new(...).block_length().
+ * This abstract class provides a common interface to message digest
+ * implementation classes written in C.
*/
+
+static rb_digest_metadata_t *
+get_digest_base_metadata(VALUE klass)
+{
+ VALUE obj;
+ rb_digest_metadata_t *algo;
+
+ if (rb_ivar_defined(klass, id_metadata) == Qfalse) {
+ /* This class should not be subclassed in Ruby */
+ rb_notimplement();
+ }
+
+ 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");
+ }
+
+ return algo;
+}
+
static VALUE
-rb_digest_base_s_block_length(int argc, VALUE *argv,VALUE klass)
+rb_digest_base_alloc(VALUE klass)
{
- algo_t *algo;
+ rb_digest_metadata_t *algo;
+ VALUE obj;
+ void *pctx;
+
+ if (klass == rb_cDigest_Base) {
+ rb_raise(rb_eNotImpError, "Digest::Base is an abstract class");
+ }
algo = get_digest_base_metadata(klass);
- if (algo == NULL) {
- VALUE obj = rb_funcall2(klass, id_new, argc, argv);
- return rb_funcall(obj, rb_intern("block_length"), 0);
- }
+ pctx = xmalloc(algo->ctx_size);
+ algo->init_func(pctx);
- return INT2NUM(algo->block_len);
+ obj = Data_Wrap_Struct(klass, 0, free, pctx);
+
+ return obj;
}
-/*
- * call-seq:
- * digest_obj.block_length -> length
- *
- * Returns the block length of the digest.
- *
- * Implementation subclasses must redefine this method if used.
- */
+/* :nodoc: */
static VALUE
-rb_digest_base_block_length(VALUE self)
+rb_digest_base_copy(VALUE copy, VALUE obj)
+{
+ rb_digest_metadata_t *algo;
+ void *pctx1, *pctx2;
+
+ if (copy == obj) return copy;
+
+ rb_check_frozen(copy);
+
+ algo = get_digest_base_metadata(rb_obj_class(copy));
+
+ Data_Get_Struct(obj, void, pctx1);
+ Data_Get_Struct(copy, void, pctx2);
+ memcpy(pctx2, pctx1, algo->ctx_size);
+
+ return copy;
+}
+
+/* :nodoc: */
+static VALUE
+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 must define this method (only if used) */
- rb_notimplement();
- }
+ Data_Get_Struct(self, void, pctx);
- return INT2NUM(algo->block_len);
+ algo->init_func(pctx);
+
+ return self;
}
-void
-Init_digest(void)
+/* :nodoc: */
+static VALUE
+rb_digest_base_update(VALUE self, VALUE str)
{
- mDigest = rb_define_module("Digest");
+ rb_digest_metadata_t *algo;
+ void *pctx;
- cDigest_Base = rb_define_class_under(mDigest, "Base", rb_cObject);
+ algo = get_digest_base_metadata(rb_obj_class(self));
- 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);
+ Data_Get_Struct(self, void, pctx);
- rb_define_singleton_method(cDigest_Base, "digest_length", rb_digest_base_s_digest_length, -1);
- rb_define_singleton_method(cDigest_Base, "block_length", rb_digest_base_s_block_length, -1);
+ StringValue(str);
+ algo->update_func(pctx, RSTRING_PTR(str), RSTRING_LEN(str));
- 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, "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);
+ return self;
+}
- rb_define_method(cDigest_Base, "digest_length", rb_digest_base_digest_length, 0);
- rb_define_method(cDigest_Base, "block_length", rb_digest_base_block_length, 0);
+/* :nodoc: */
+static VALUE
+rb_digest_base_finish(VALUE self)
+{
+ rb_digest_metadata_t *algo;
+ void *pctx;
+ VALUE str;
+
+ algo = get_digest_base_metadata(rb_obj_class(self));
+
+ Data_Get_Struct(self, void, pctx);
+
+ str = rb_str_new(0, algo->digest_len);
+ algo->finish_func(pctx, RSTRING_PTR(str));
+
+ /* avoid potential coredump caused by use of a finished context */
+ algo->init_func(pctx);
+
+ return str;
+}
+
+/* :nodoc: */
+static VALUE
+rb_digest_base_digest_length(VALUE self)
+{
+ rb_digest_metadata_t *algo;
+
+ algo = get_digest_base_metadata(rb_obj_class(self));
+
+ return INT2NUM(algo->digest_len);
+}
+
+/* :nodoc: */
+static VALUE
+rb_digest_base_block_length(VALUE self)
+{
+ rb_digest_metadata_t *algo;
+
+ algo = get_digest_base_metadata(rb_obj_class(self));
+
+ return INT2NUM(algo->block_len);
+}
+
+void
+Init_digest(void)
+{
+ 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 f8c5dd3906..6e4906c859 100644
--- a/ext/digest/digest.h
+++ b/ext/digest/digest.h
@@ -15,16 +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/lib/digest.rb b/ext/digest/lib/digest.rb
index dc91e9444e..1d1e420a27 100644
--- a/ext/digest/lib/digest.rb
+++ b/ext/digest/lib/digest.rb
@@ -1,9 +1,9 @@
require 'digest.so'
module Digest
- 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"
def self.const_missing(name)
begin
diff --git a/ext/digest/lib/digest/hmac.rb b/ext/digest/lib/digest/hmac.rb
index bc2f3bcbc4..b542a23577 100644
--- a/ext/digest/lib/digest/hmac.rb
+++ b/ext/digest/lib/digest/hmac.rb
@@ -39,17 +39,14 @@
require 'digest'
module Digest
- class HMAC < Digest::Base
- def initialize(key, digest_class, *digest_params)
- @digest_class = digest_class.freeze
- @digest_params = digest_params.freeze
- @md = digest_class.new(*digest_params)
- @tmp_md = @md.clone
+ class HMAC < Digest::Class
+ def initialize(key, digester)
+ @md = digester.new
block_len = @md.block_length
if key.length > block_len
- key = @tmp_md.reset.update(key).digest
+ key = @md.digest(key)
end
ipad = Array.new(block_len).fill(0x36)
@@ -66,11 +63,11 @@ module Digest
end
def initialize_copy(other)
- @md = other.instance_eval { @md }
+ @md = @md.new
end
def update(text)
- @md.reset.update(@opad + @tmp_md.reset.update(@ipad + text).digest)
+ @md.reset.update(@opad + @md.digest(@ipad + text))
self
end
@@ -106,36 +103,36 @@ __END__
require 'test/unit'
module TM_HMAC
- def hmac_new(key)
- Digest::HMAC.new(key, *digest_spec())
- end
-
def test_s_hexdigest
- spec = digest_spec()
-
cases.each { |h|
- assert_equal(h[:hexdigest], Digest::HMAC.hexdigest(h[:data], h[:key], *spec))
+ digesters { |d|
+ assert_equal(h[:hexdigest], Digest::HMAC.hexdigest(h[:data], h[:key], d))
+ }
}
end
def test_hexdigest
cases.each { |h|
- hmac = hmac_new(h[:key])
- hmac.update(h[:data])
+ digesters { |d|
+ hmac = Digest::HMAC.new(h[:key], d)
- assert_equal(h[:hexdigest], hmac.hexdigest)
+ hmac.update(h[:data])
+
+ assert_equal(h[:hexdigest], hmac.hexdigest)
+ }
}
end
def test_reset
cases.each { |h|
- hmac = hmac_new(h[:key])
- hmac.update("test")
- hmac.reset
- hmac.update(h[:data])
+ digesters { |d|
+ hmac = Digest::HMAC.new(h[:key], d)
+ hmac.update("test")
+ hmac.reset
+ hmac.update(h[:data])
- p hmac
- assert_equal(h[:hexdigest], hmac.hexdigest)
+ assert_equal(h[:hexdigest], hmac.hexdigest)
+ }
}
end
end
@@ -143,8 +140,8 @@ end
class TC_HMAC_MD5 < Test::Unit::TestCase
include TM_HMAC
- def digest_spec
- [Digest::MD5]
+ def digesters
+ [Digest::MD5, Digest::MD5.new]
end
# Taken from RFC 2202: Test Cases for HMAC-MD5 and HMAC-SHA-1
@@ -186,8 +183,8 @@ end
class TC_HMAC_SHA1 < Test::Unit::TestCase
include TM_HMAC
- def digest_spec
- [Digest::SHA1]
+ def digesters
+ [Digest::SHA1, Digest::SHA1.new]
end
# Taken from RFC 2202: Test Cases for HMAC-MD5 and HMAC-SHA-1
@@ -229,8 +226,8 @@ end
class TC_HMAC_RMD160 < Test::Unit::TestCase
include TM_HMAC
- def digest_spec
- [Digest::RMD160]
+ def digesters
+ [Digest::RMD160, Digest::RMD160.new]
end
# Taken from RFC 2286: Test Cases for HMAC-RIPEMD160 and HMAC-RIPEMD128
diff --git a/ext/digest/md5/md5init.c b/ext/digest/md5/md5init.c
index 1230c17b57..17658f4fce 100644
--- a/ext/digest/md5/md5init.c
+++ b/ext/digest/md5/md5init.c
@@ -8,14 +8,14 @@
#include "md5.h"
#endif
-static algo_t md5 = {
- 1,
+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,
};
/*
diff --git a/ext/digest/rmd160/rmd160init.c b/ext/digest/rmd160/rmd160init.c
index a066763606..763867df86 100644
--- a/ext/digest/rmd160/rmd160init.c
+++ b/ext/digest/rmd160/rmd160init.c
@@ -8,14 +8,14 @@
#include "rmd160.h"
#endif
-static algo_t rmd160 = {
- 1,
+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,
};
/*
@@ -27,7 +27,6 @@ void
Init_rmd160()
{
VALUE mDigest, cDigest_Base, cDigest_RMD160;
- ID id_metadata;
rb_require("digest");
@@ -36,8 +35,6 @@ Init_rmd160()
cDigest_RMD160 = rb_define_class_under(mDigest, "RMD160", cDigest_Base);
- 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 68c7637ab8..b2146f05a9 100644
--- a/ext/digest/sha1/sha1init.c
+++ b/ext/digest/sha1/sha1init.c
@@ -8,14 +8,14 @@
#include "sha1.h"
#endif
-static algo_t sha1 = {
- 1,
+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,
};
/*
@@ -27,9 +27,9 @@ void
Init_sha1()
{
VALUE mDigest, cDigest_Base, cDigest_SHA1;
-
+
rb_require("digest");
-
+
mDigest = rb_path2class("Digest");
cDigest_Base = rb_path2class("Digest::Base");
diff --git a/ext/digest/sha2/lib/digest/sha2.rb b/ext/digest/sha2/lib/digest/sha2.rb
new file mode 100644
index 0000000000..683b9904a3
--- /dev/null
+++ b/ext/digest/sha2/lib/digest/sha2.rb
@@ -0,0 +1,73 @@
+#--
+# sha2.rb - defines Digest::SHA2 class which wraps up the SHA256,
+# SHA384, and SHA512 classes.
+#++
+# Copyright (c) 2006 Akinori MUSHA <knu@iDaemons.org>
+#
+# All rights reserved. You can redistribute and/or modify it under the same
+# terms as Ruby.
+#
+# $Id$
+
+require 'digest'
+
+module Digest
+ #
+ # A meta digest provider class for SHA256, SHA384 and SHA512.
+ #
+ class SHA2 < Digest::Class
+ # call-seq:
+ # Digest::SHA2.new(bitlen = 256) -> digest_obj
+ #
+ # Creates a new SHA2 hash object with a given bit length.
+ def initialize(bitlen = 256)
+ case bitlen
+ when 256
+ @sha2 = Digest::SHA256.new
+ when 384
+ @sha2 = Digest::SHA384.new
+ when 512
+ @sha2 = Digest::SHA512.new
+ else
+ raise ArgumentError, "unsupported bit length: %s" % bitlen.inspect
+ end
+ @bitlen = bitlen
+ end
+
+ # :nodoc:
+ def reset
+ @sha2.reset
+ self
+ end
+
+ # :nodoc:
+ def update(str)
+ @sha2.update(str)
+ self
+ end
+ alias << update
+
+ def finish
+ @sha2.digest!
+ end
+ private :finish
+
+ def block_length
+ @sha2.block_length
+ end
+
+ def digest_length
+ @sha2.digest_length
+ end
+
+ # :nodoc:
+ def initialize_copy(other)
+ @sha2 = @sha2.clone
+ end
+
+ # :nodoc:
+ def inspect
+ "#<%s:%d %s>" % [self.class.name, @bitlen, hexdigest]
+ end
+ end
+end
diff --git a/ext/digest/sha2/sha2init.c b/ext/digest/sha2/sha2init.c
index ee184819b8..c83a29316a 100644
--- a/ext/digest/sha2/sha2init.c
+++ b/ext/digest/sha2/sha2init.c
@@ -7,14 +7,14 @@
#define FOREACH_BITLEN(func) func(256) func(384) func(512)
#define DEFINE_ALGO_METADATA(bitlen) \
-static algo_t sha##bitlen = { \
- 1, \
+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)