1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* 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
This commit is contained in:
knu 2006-10-25 08:54:05 +00:00
parent 0bdf887afc
commit 817afbd987
14 changed files with 883 additions and 587 deletions

View file

@ -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.

View file

@ -1,4 +1,3 @@
Makefile
mkmf.log
*.def
extconf.h

View file

@ -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;
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);
/*
* Digest::Base
* Document-module: Digest
*
* 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);
return algo;
}
static VALUE
hexdigest_str_new(VALUE str_digest)
hexencode_str_new(VALUE str_digest)
{
char *digest;
size_t digest_len;
@ -72,85 +64,405 @@ 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)
{
return hexencode_str_new(str);
}
/*
* Document-module: Digest::Instance
*
* This module provides instance methods for a digest implementation
* object to calculate message digest values.
*/
/*
* 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_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));
}
/*
* 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));
}
/*
* 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;
}
/*
* 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);
return value;
}
/*
* 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;
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 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)
{
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'
};
size_t digest_len = 32; /* about this size at least */
char *cname;
StringValue(str_digest);
digest = RSTRING_PTR(str_digest);
digest_len = RSTRING_LEN(str_digest);
if ((LONG_MAX - 2) / 3 < (digest_len | 1)) {
rb_raise(rb_eRuntimeError, "digest string too long");
}
str = rb_str_new(0, (digest_len | 1) * 3 + 2);
p = RSTRING_PTR(str);
i = j = 0;
p[j++] = 'x';
for (;;) {
unsigned char byte1, byte2;
if (i >= digest_len) {
p[j++] = vowels[seed % 6];
p[j++] = consonants[16];
p[j++] = vowels[seed / 6];
break;
}
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];
if (i >= digest_len) {
break;
}
byte2 = digest[i++];
p[j++] = consonants[(byte2 >> 4) & 15];
p[j++] = '-';
p[j++] = consonants[byte2 & 15];
seed = (seed * 5 + byte1 * 7 + byte2) % 36;
}
p[j] = 'x';
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_instance_equal(VALUE self, VALUE other)
{
VALUE str1, str2;
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;
}
/* 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_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);
/* never blindly assume that #digest() returns a string */
StringValue(digest);
return INT2NUM(RSTRING_LEN(digest));
}
/*
* 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_instance_block_length(VALUE self)
{
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 (argc < 1) {
rb_raise(rb_eArgError, "no data given");
}
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::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_class_s_hexdigest(int argc, VALUE *argv, VALUE klass)
{
return hexencode_str_new(rb_funcall2(klass, id_digest, argc, argv));
}
/*
* Document-class: Digest::Base
*
* 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_alloc(VALUE klass)
{
algo_t *algo;
rb_digest_metadata_t *algo;
VALUE obj;
void *pctx;
if (klass == cDigest_Base) {
if (klass == rb_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);
@ -159,62 +471,19 @@ rb_digest_base_alloc(VALUE klass)
return obj;
}
static VALUE
rb_digest_base_s_digest(VALUE klass, VALUE str)
{
algo_t *algo = get_digest_base_metadata(klass);
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);
}
obj = rb_digest_base_alloc(klass);
Data_Get_Struct(obj, void, pctx);
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));
return str;
}
static VALUE
rb_digest_base_s_hexdigest(VALUE klass, VALUE str)
{
return hexdigest_str_new(rb_funcall(klass, id_digest, 1, str));
}
static VALUE
rb_digest_base_s_bubblebabble(VALUE klass, VALUE str)
{
return bubblebabble_str_new(rb_funcall(klass, id_digest, 1, str));
}
/* :nodoc: */
static VALUE
rb_digest_base_copy(VALUE copy, VALUE obj)
{
algo_t *algo;
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));
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);
@ -222,41 +491,31 @@ rb_digest_base_copy(VALUE copy, VALUE obj)
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) {
rb_funcall(self, id_initialize, 0);
return self;
}
Data_Get_Struct(self, void, pctx);
memset(pctx, 0, algo->ctx_size);
algo->init_func(pctx);
return self;
}
/* :nodoc: */
static VALUE
rb_digest_base_update(VALUE self, VALUE str)
{
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 update() */
rb_notimplement();
}
Data_Get_Struct(self, void, pctx);
StringValue(str);
@ -265,183 +524,116 @@ rb_digest_base_update(VALUE self, VALUE str)
return self;
}
/* :nodoc: */
static VALUE
rb_digest_base_lshift(VALUE self, VALUE str)
rb_digest_base_finish(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));
return self;
}
static VALUE
rb_digest_base_init(int argc, VALUE *argv, VALUE self)
{
VALUE arg;
rb_scan_args(argc, argv, "01", &arg);
if (!NIL_P(arg)) rb_digest_base_update(self, arg);
return self;
}
static VALUE
rb_digest_base_digest(VALUE self)
{
algo_t *algo;
void *pctx1, *pctx2;
size_t ctx_size;
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);
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_hexdigest(VALUE self)
rb_digest_base_digest_length(VALUE self)
{
return hexdigest_str_new(rb_funcall(self, id_digest, 0));
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_bubblebabble(VALUE self)
rb_digest_base_block_length(VALUE self)
{
return bubblebabble_str_new(rb_funcall(self, id_digest, 0));
rb_digest_metadata_t *algo;
algo = get_digest_base_metadata(rb_obj_class(self));
return INT2NUM(algo->block_len);
}
static VALUE
rb_digest_base_inspect(VALUE self)
{
algo_t *algo;
VALUE klass, str;
size_t digest_len = 32; /* no need to be just the right size */
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> */
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;
}
static VALUE
rb_digest_base_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_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;
return Qfalse;
}
/*
* 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");
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");
cDigest_Base = rb_define_class_under(mDigest, "Base", rb_cObject);
/*
* module Digest
*/
rb_mDigest = rb_define_module("Digest");
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);
/* module functions */
rb_define_module_function(rb_mDigest, "hexencode", rb_digest_s_hexencode, 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);
/*
* 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);
}

View file

@ -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;

View file

@ -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:

View file

@ -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:

View file

@ -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

View file

@ -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

View file

@ -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));
}

View file

@ -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));
}

View file

@ -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));
}

View file

@ -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));

View file

@ -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

View file

@ -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