зеркало из https://github.com/github/ruby.git
* ext/digest: Prefix C constants with RUBY_ and C type names with
rb_ to avoid name clash in writing extensions. * ext/digest: Introduce Digest::Class and Digest::Instance for ease of implementing subclasses and add-ons, inspried by gotoyuzo. * ext/digest: The Digest::Instance module now requires and assumes that any instance be resettable and clonable, and add some convenient instance methods such as "new()", for creating a new copy, parameter taking "digest()" and "hexdigest()", for instant calculation. These methods make digest instances work just like digest classes. * ext/digest/sha2/lib/digest/sha2.rb: 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. * ext/digest/lib/digest.rb: Adjust autoload entries for SHA2 classes. * ext/digest/lib/digest/hmac.rb: Follow the framework updates. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11197 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
03f19e27ed
Коммит
b2c7fe1bbf
26
ChangeLog
26
ChangeLog
|
@ -1,3 +1,29 @@
|
||||||
|
Fri Oct 20 20:28:37 2006 Akinori MUSHA <knu@iDaemons.org>
|
||||||
|
|
||||||
|
* ext/digest: Prefix C constants with RUBY_ and C type names with
|
||||||
|
rb_ to avoid name clash in writing extensions.
|
||||||
|
|
||||||
|
* ext/digest: Introduce Digest::Class and Digest::Instance for
|
||||||
|
ease of implementing subclasses and add-ons, inspried by
|
||||||
|
gotoyuzo.
|
||||||
|
|
||||||
|
* ext/digest: The Digest::Instance module now requires and assumes
|
||||||
|
that any instance be resettable and clonable, and add some
|
||||||
|
convenient instance methods such as "new()", for creating a new
|
||||||
|
copy, parameter taking "digest()" and "hexdigest()", for instant
|
||||||
|
calculation. These methods make digest instances work just like
|
||||||
|
digest classes.
|
||||||
|
|
||||||
|
* ext/digest/sha2/lib/digest/sha2.rb:
|
||||||
|
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.
|
||||||
|
|
||||||
|
* ext/digest/lib/digest.rb: Adjust autoload entries for SHA2
|
||||||
|
classes.
|
||||||
|
|
||||||
|
* ext/digest/lib/digest/hmac.rb: Follow the framework updates.
|
||||||
|
|
||||||
Fri Oct 20 10:47:43 2006 NAKAMURA Usaku <usa@ruby-lang.org>
|
Fri Oct 20 10:47:43 2006 NAKAMURA Usaku <usa@ruby-lang.org>
|
||||||
|
|
||||||
* lib/mkmf.rb: fixed the bug of handling COMMON_MACROS.
|
* lib/mkmf.rb: fixed the bug of handling COMMON_MACROS.
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
************************************************/
|
************************************************/
|
||||||
|
|
||||||
#include "ruby.h"
|
#include "ruby.h"
|
||||||
|
#include "digest.h"
|
||||||
|
|
||||||
static VALUE mDigest, cDigest_Base;
|
|
||||||
static ID id_digest;
|
static ID id_digest;
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
|
@ -83,9 +83,6 @@ bubblebabble_str_new(VALUE str_digest)
|
||||||
* Digest.bubblebabble(string) -> bubblebabble_string
|
* Digest.bubblebabble(string) -> bubblebabble_string
|
||||||
*
|
*
|
||||||
* Returns a BubbleBabble encoded version of a given _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
|
static VALUE
|
||||||
rb_digest_s_bubblebabble(VALUE klass, VALUE str)
|
rb_digest_s_bubblebabble(VALUE klass, VALUE str)
|
||||||
|
@ -95,12 +92,12 @@ rb_digest_s_bubblebabble(VALUE klass, VALUE str)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* Digest::ALGORITHM.bubblebabble(string, ...) -> hash_string
|
* Digest::Class.bubblebabble(string, ...) -> hash_string
|
||||||
*
|
*
|
||||||
* Returns the BubbleBabble encoded hash value of a given _string_.
|
* Returns the BubbleBabble encoded hash value of a given _string_.
|
||||||
*/
|
*/
|
||||||
static VALUE
|
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));
|
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.
|
* Returns the resulting hash value in a Bubblebabble encoded form.
|
||||||
*/
|
*/
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_digest_base_bubblebabble(VALUE self)
|
rb_digest_instance_bubblebabble(VALUE self)
|
||||||
{
|
{
|
||||||
return bubblebabble_str_new(rb_funcall(self, id_digest, 0));
|
return bubblebabble_str_new(rb_funcall(self, id_digest, 0));
|
||||||
}
|
}
|
||||||
|
@ -124,17 +121,22 @@ rb_digest_base_bubblebabble(VALUE self)
|
||||||
void
|
void
|
||||||
Init_bubblebabble(void)
|
Init_bubblebabble(void)
|
||||||
{
|
{
|
||||||
mDigest = rb_define_module("Digest");
|
VALUE mDigest, mDigest_Instance, cDigest_Class;
|
||||||
cDigest_Base = rb_define_class_under(mDigest, "Base", rb_cObject);
|
|
||||||
|
rb_require("digest");
|
||||||
|
|
||||||
|
mDigest = rb_path2class("Digest");
|
||||||
|
mDigest_Instance = rb_path2class("Digest::Instance");
|
||||||
|
cDigest_Class = rb_path2class("Digest::Class");
|
||||||
|
|
||||||
/* Digest::bubblebabble() */
|
/* Digest::bubblebabble() */
|
||||||
rb_define_module_function(mDigest, "bubblebabble", rb_digest_s_bubblebabble, 1);
|
rb_define_module_function(mDigest, "bubblebabble", rb_digest_s_bubblebabble, 1);
|
||||||
|
|
||||||
/* Digest::Base::bubblebabble() */
|
/* Digest::Class::bubblebabble() */
|
||||||
rb_define_singleton_method(cDigest_Base, "bubblebabble", rb_digest_base_s_bubblebabble, -1);
|
rb_define_singleton_method(cDigest_Class, "bubblebabble", rb_digest_class_s_bubblebabble, -1);
|
||||||
|
|
||||||
/* Digest::Base#bubblebabble() */
|
/* Digest::Instance#bubblebabble() */
|
||||||
rb_define_method(cDigest_Base, "bubblebabble", rb_digest_base_bubblebabble, 0);
|
rb_define_method(mDigest_Instance, "bubblebabble", rb_digest_instance_bubblebabble, 0);
|
||||||
|
|
||||||
id_digest = rb_intern("digest");
|
id_digest = rb_intern("digest");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
@ -1,3 +1,6 @@
|
||||||
require 'mkmf'
|
require 'mkmf'
|
||||||
|
|
||||||
|
$defs << "-DHAVE_CONFIG_H"
|
||||||
|
$INCFLAGS << " -I$(srcdir)/.."
|
||||||
|
|
||||||
create_makefile('digest/bubblebabble')
|
create_makefile('digest/bubblebabble')
|
||||||
|
|
|
@ -15,48 +15,24 @@
|
||||||
|
|
||||||
#include "digest.h"
|
#include "digest.h"
|
||||||
|
|
||||||
static VALUE mDigest, cDigest_Base;
|
static VALUE rb_mDigest;
|
||||||
static ID id_metadata, id_new, id_initialize, id_update, id_digest;
|
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);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Document-class: Digest
|
* Document-module: Digest
|
||||||
*
|
*
|
||||||
* This module provides a framework for message digest libraries.
|
* This module provides a framework for message digest libraries.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* Document-class: Digest::Base
|
|
||||||
*
|
|
||||||
* This class provides a common interface to message digest
|
|
||||||
* algorithms.
|
|
||||||
*/
|
|
||||||
|
|
||||||
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
|
static VALUE
|
||||||
hexdigest_str_new(VALUE str_digest)
|
hexencode_str_new(VALUE str_digest)
|
||||||
{
|
{
|
||||||
char *digest;
|
char *digest;
|
||||||
size_t digest_len;
|
size_t digest_len;
|
||||||
|
@ -88,45 +64,323 @@ hexdigest_str_new(VALUE str_digest)
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* Digest.hexencode(string) -> hexencoded_string
|
||||||
|
*
|
||||||
|
* Generates a hex-encoded version of a given _string_.
|
||||||
|
*/
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_digest_base_alloc(VALUE klass)
|
rb_digest_s_hexencode(VALUE klass, VALUE str)
|
||||||
{
|
{
|
||||||
algo_t *algo;
|
return hexencode_str_new(str);
|
||||||
VALUE obj;
|
}
|
||||||
void *pctx;
|
|
||||||
|
|
||||||
if (klass == cDigest_Base) {
|
/*
|
||||||
rb_raise(rb_eNotImpError, "Digest::Base is an abstract class");
|
* Document-module: Digest::Instance
|
||||||
}
|
*
|
||||||
|
* This module provides instance methods for a digest implementation
|
||||||
|
* object to calculate message digest values.
|
||||||
|
*/
|
||||||
|
|
||||||
algo = get_digest_base_metadata(klass);
|
/*
|
||||||
|
* call-seq:
|
||||||
if (algo == NULL) {
|
* digest_obj.update(string) -> digest_obj
|
||||||
return Data_Wrap_Struct(klass, 0, free, 0);
|
* digest_obj << string -> digest_obj
|
||||||
}
|
*
|
||||||
|
* Updates the digest using a given _string_ and returns self.
|
||||||
pctx = xmalloc(algo->ctx_size);
|
*
|
||||||
algo->init_func(pctx);
|
* The update() method and the left-shift operator are overridden by
|
||||||
|
* each implementation subclass. (One should be an alias for the
|
||||||
obj = Data_Wrap_Struct(klass, 0, free, pctx);
|
* other)
|
||||||
|
*/
|
||||||
return obj;
|
static VALUE
|
||||||
|
rb_digest_instance_update(VALUE self, VALUE str)
|
||||||
|
{
|
||||||
|
rb_raise(rb_eRuntimeError, "%s does not implement update()", rb_inspect(self));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* Digest::ALGORITHM.digest(string[, ...]) -> hash_string
|
* digest_obj.instance_eval { finish } -> digest_obj
|
||||||
*
|
*
|
||||||
* Returns the hash value of a given string _data_. This is almost
|
* Finishes the digest and returns the resulting hash value.
|
||||||
* equivalent to Digest::ALGORITHM.new(...).update(string).digest()
|
*
|
||||||
* where extra arguments, if any, are passed through to the
|
* This method is overridden by each implementation subclass and often
|
||||||
* constructor.
|
* 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
|
static VALUE
|
||||||
rb_digest_base_s_digest(int argc, VALUE *argv, VALUE klass)
|
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)
|
||||||
|
{
|
||||||
|
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_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;
|
VALUE str;
|
||||||
algo_t *algo;
|
|
||||||
void *pctx;
|
void *pctx;
|
||||||
volatile VALUE obj;
|
volatile VALUE obj;
|
||||||
|
|
||||||
|
@ -139,60 +393,97 @@ rb_digest_base_s_digest(int argc, VALUE *argv, VALUE klass)
|
||||||
|
|
||||||
StringValue(str);
|
StringValue(str);
|
||||||
|
|
||||||
algo = get_digest_base_metadata(klass);
|
obj = rb_obj_alloc(klass);
|
||||||
|
rb_obj_call_init(obj, argc, argv);
|
||||||
|
|
||||||
if (algo == NULL) {
|
return rb_funcall(obj, id_digest, 1, str);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* Digest::ALGORITHM.hexdigest(string[, ...]) -> hash_string
|
* Digest::Class.hexdigest(string[, ...]) -> hash_string
|
||||||
*
|
*
|
||||||
* Returns the hex-encoded hash value of a given _string_. This
|
* Returns the hex-encoded hash value of a given _string_. This is
|
||||||
* method just hex-encode the return value of
|
* almost equivalent to
|
||||||
* Digest::ALGORITHM.digest(string[, ...]) where extra arguments, if
|
* Digest.hexencode(Digest::Class.new(*parameters).digest(string)).
|
||||||
* any, are passed through along with the _string_.
|
|
||||||
*/
|
*/
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_digest_base_s_hexdigest(int argc, VALUE *argv, VALUE klass)
|
rb_digest_class_s_hexdigest(int argc, VALUE *argv, VALUE klass)
|
||||||
{
|
{
|
||||||
return hexdigest_str_new(rb_funcall2(klass, id_digest, argc, argv));
|
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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
pctx = xmalloc(algo->ctx_size);
|
||||||
|
algo->init_func(pctx);
|
||||||
|
|
||||||
|
obj = Data_Wrap_Struct(klass, 0, free, pctx);
|
||||||
|
|
||||||
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* :nodoc: */
|
/* :nodoc: */
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_digest_base_copy(VALUE copy, VALUE obj)
|
rb_digest_base_copy(VALUE copy, VALUE obj)
|
||||||
{
|
{
|
||||||
algo_t *algo;
|
rb_digest_metadata_t *algo;
|
||||||
void *pctx1, *pctx2;
|
void *pctx1, *pctx2;
|
||||||
|
|
||||||
if (copy == obj) return copy;
|
if (copy == obj) return copy;
|
||||||
|
|
||||||
rb_check_frozen(copy);
|
rb_check_frozen(copy);
|
||||||
|
|
||||||
algo = get_digest_base_metadata(rb_obj_class(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(obj, void, pctx1);
|
||||||
Data_Get_Struct(copy, void, pctx2);
|
Data_Get_Struct(copy, void, pctx2);
|
||||||
memcpy(pctx2, pctx1, algo->ctx_size);
|
memcpy(pctx2, pctx1, algo->ctx_size);
|
||||||
|
@ -200,60 +491,31 @@ rb_digest_base_copy(VALUE copy, VALUE obj)
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* :nodoc: */
|
||||||
* call-seq:
|
|
||||||
* digest_obj.reset -> digest_obj
|
|
||||||
*
|
|
||||||
* Resets the digest to the initial state and returns self.
|
|
||||||
*
|
|
||||||
* Every implementation subclass which constructor takes arguments
|
|
||||||
* must redefine this method because Digest::Base#reset() internally
|
|
||||||
* calls initialize() with no argument.
|
|
||||||
*/
|
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_digest_base_reset(VALUE self)
|
rb_digest_base_reset(VALUE self)
|
||||||
{
|
{
|
||||||
algo_t *algo;
|
rb_digest_metadata_t *algo;
|
||||||
void *pctx;
|
void *pctx;
|
||||||
|
|
||||||
algo = get_digest_base_metadata(rb_obj_class(self));
|
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);
|
Data_Get_Struct(self, void, pctx);
|
||||||
|
|
||||||
memset(pctx, 0, algo->ctx_size);
|
|
||||||
algo->init_func(pctx);
|
algo->init_func(pctx);
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* :nodoc: */
|
||||||
* call-seq:
|
|
||||||
* digest_obj.update(string) -> digest_obj
|
|
||||||
*
|
|
||||||
* Updates the digest using a given _string_ and returns self.
|
|
||||||
*
|
|
||||||
* Implementation subclasses must redefine this method, and should
|
|
||||||
* make `<<' an alias to it.
|
|
||||||
*/
|
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_digest_base_update(VALUE self, VALUE str)
|
rb_digest_base_update(VALUE self, VALUE str)
|
||||||
{
|
{
|
||||||
algo_t *algo;
|
rb_digest_metadata_t *algo;
|
||||||
void *pctx;
|
void *pctx;
|
||||||
|
|
||||||
algo = get_digest_base_metadata(rb_obj_class(self));
|
algo = get_digest_base_metadata(rb_obj_class(self));
|
||||||
|
|
||||||
if (algo == NULL) {
|
|
||||||
/* subclasses must define update() */
|
|
||||||
rb_notimplement();
|
|
||||||
}
|
|
||||||
|
|
||||||
Data_Get_Struct(self, void, pctx);
|
Data_Get_Struct(self, void, pctx);
|
||||||
|
|
||||||
StringValue(str);
|
StringValue(str);
|
||||||
|
@ -262,290 +524,116 @@ rb_digest_base_update(VALUE self, VALUE str)
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* :nodoc: */
|
||||||
* call-seq:
|
|
||||||
* digest_obj << string -> digest_obj
|
|
||||||
*
|
|
||||||
* Calls update(string).
|
|
||||||
*
|
|
||||||
* Implementation subclasses need not but should alias this method to
|
|
||||||
* update() to eliminate chain calls.
|
|
||||||
*/
|
|
||||||
static VALUE
|
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;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* call-seq:
|
|
||||||
* digest_obj.digest -> string
|
|
||||||
*
|
|
||||||
* Returns the resulting hash value.
|
|
||||||
*
|
|
||||||
* Implementation subclasses must redefine this method.
|
|
||||||
*/
|
|
||||||
static VALUE
|
|
||||||
rb_digest_base_digest(VALUE self)
|
|
||||||
{
|
|
||||||
algo_t *algo;
|
|
||||||
void *pctx1, *pctx2;
|
|
||||||
size_t ctx_size;
|
|
||||||
VALUE str;
|
VALUE str;
|
||||||
|
|
||||||
algo = get_digest_base_metadata(rb_obj_class(self));
|
algo = get_digest_base_metadata(rb_obj_class(self));
|
||||||
|
|
||||||
if (algo == NULL) {
|
Data_Get_Struct(self, void, pctx);
|
||||||
/* 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);
|
str = rb_str_new(0, algo->digest_len);
|
||||||
algo->finish_func(pctx2, RSTRING_PTR(str));
|
algo->finish_func(pctx, RSTRING_PTR(str));
|
||||||
free(pctx2);
|
|
||||||
|
/* avoid potential coredump caused by use of a finished context */
|
||||||
|
algo->init_func(pctx);
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* :nodoc: */
|
||||||
* call-seq:
|
|
||||||
* digest_obj.hexdigest -> string
|
|
||||||
* digest_obj.to_s -> string
|
|
||||||
*
|
|
||||||
* Returns the resulting hash value in a hex-encoded form.
|
|
||||||
*/
|
|
||||||
static VALUE
|
|
||||||
rb_digest_base_hexdigest(VALUE self)
|
|
||||||
{
|
|
||||||
return hexdigest_str_new(rb_funcall(self, id_digest, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* call-seq:
|
|
||||||
* digest_obj.inspect -> string
|
|
||||||
*
|
|
||||||
* Creates a printable version of the digest object.
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* call-seq:
|
|
||||||
* digest_obj == string -> boolean
|
|
||||||
* digest_obj == another_digest_obj -> 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.
|
|
||||||
*/
|
|
||||||
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_funcall(self, id_digest, 0);
|
|
||||||
str2 = rb_funcall(other, id_digest, 0);
|
|
||||||
} else {
|
|
||||||
StringValue(other);
|
|
||||||
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;
|
|
||||||
|
|
||||||
return Qfalse;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* call-seq:
|
|
||||||
* Digest::ALGORITHM.block_length(...) -> integer
|
|
||||||
*
|
|
||||||
* Returns the digest length of the digest algorithm. Parameters
|
|
||||||
* follow the same specification as the constructor.
|
|
||||||
*
|
|
||||||
* If an implementation subclass does not redefine this method,
|
|
||||||
* returns Digest::ALGORITHM.new(...).digest_length().
|
|
||||||
*/
|
|
||||||
static VALUE
|
|
||||||
rb_digest_base_s_digest_length(int argc, VALUE *argv,VALUE klass)
|
|
||||||
{
|
|
||||||
algo_t *algo;
|
|
||||||
|
|
||||||
algo = get_digest_base_metadata(klass);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return INT2NUM(algo->digest_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* call-seq:
|
|
||||||
* digest_obj.block_length -> integer
|
|
||||||
*
|
|
||||||
* Returns the length of the hash value of the digest object.
|
|
||||||
*
|
|
||||||
* If an implementation subclass does not redefine this method,
|
|
||||||
* returns digest_obj.digest().length().
|
|
||||||
*/
|
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_digest_base_digest_length(VALUE self)
|
rb_digest_base_digest_length(VALUE self)
|
||||||
{
|
{
|
||||||
algo_t *algo;
|
rb_digest_metadata_t *algo;
|
||||||
|
|
||||||
algo = get_digest_base_metadata(rb_obj_class(self));
|
algo = get_digest_base_metadata(rb_obj_class(self));
|
||||||
|
|
||||||
if (algo == NULL) {
|
|
||||||
/* subclasses really should redefine this method */
|
|
||||||
VALUE digest = rb_funcall(self, id_digest, 0);
|
|
||||||
StringValue(digest);
|
|
||||||
return INT2NUM(RSTRING_LEN(digest));
|
|
||||||
}
|
|
||||||
|
|
||||||
return INT2NUM(algo->digest_len);
|
return INT2NUM(algo->digest_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* :nodoc: */
|
||||||
* call-seq:
|
|
||||||
* Digest::ALGORITHM.block_length(...) -> integer
|
|
||||||
*
|
|
||||||
* Returns the block length of the digest algorithm. Parameters
|
|
||||||
* follow the same specification as the constructor.
|
|
||||||
*
|
|
||||||
* If an implementation subclass does not redefine this method,
|
|
||||||
* returns Digest::ALGORITHM.new(...).block_length().
|
|
||||||
*/
|
|
||||||
static VALUE
|
|
||||||
rb_digest_base_s_block_length(int argc, VALUE *argv,VALUE klass)
|
|
||||||
{
|
|
||||||
algo_t *algo;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return INT2NUM(algo->block_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* call-seq:
|
|
||||||
* digest_obj.block_length -> length
|
|
||||||
*
|
|
||||||
* Returns the block length of the digest.
|
|
||||||
*
|
|
||||||
* Implementation subclasses must redefine this method if used.
|
|
||||||
*/
|
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_digest_base_block_length(VALUE self)
|
rb_digest_base_block_length(VALUE self)
|
||||||
{
|
{
|
||||||
algo_t *algo;
|
rb_digest_metadata_t *algo;
|
||||||
|
|
||||||
algo = get_digest_base_metadata(rb_obj_class(self));
|
algo = get_digest_base_metadata(rb_obj_class(self));
|
||||||
|
|
||||||
if (algo == NULL) {
|
|
||||||
/* subclasses must define this method (only if used) */
|
|
||||||
rb_notimplement();
|
|
||||||
}
|
|
||||||
|
|
||||||
return INT2NUM(algo->block_len);
|
return INT2NUM(algo->block_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Init_digest(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);
|
/* module functions */
|
||||||
rb_define_singleton_method(cDigest_Base, "digest", rb_digest_base_s_digest, -1);
|
rb_define_module_function(rb_mDigest, "hexencode", rb_digest_s_hexencode, 1);
|
||||||
rb_define_singleton_method(cDigest_Base, "hexdigest", rb_digest_base_s_hexdigest, -1);
|
|
||||||
|
|
||||||
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);
|
* module Digest::Instance
|
||||||
|
*/
|
||||||
|
rb_mDigest_Instance = rb_define_module_under(rb_mDigest, "Instance");
|
||||||
|
|
||||||
rb_define_method(cDigest_Base, "initialize_copy", rb_digest_base_copy, 1);
|
/* instance methods that should be overridden */
|
||||||
rb_define_method(cDigest_Base, "reset", rb_digest_base_reset, 0);
|
rb_define_method(rb_mDigest_Instance, "update", rb_digest_instance_update, 1);
|
||||||
rb_define_method(cDigest_Base, "update", rb_digest_base_update, 1);
|
rb_define_method(rb_mDigest_Instance, "<<", rb_digest_instance_update, 1);
|
||||||
rb_define_method(cDigest_Base, "<<", rb_digest_base_lshift, 1);
|
rb_define_private_method(rb_mDigest_Instance, "finish", rb_digest_instance_finish, 0);
|
||||||
rb_define_method(cDigest_Base, "digest", rb_digest_base_digest, 0);
|
rb_define_method(rb_mDigest_Instance, "reset", rb_digest_instance_reset, 0);
|
||||||
rb_define_method(cDigest_Base, "hexdigest", rb_digest_base_hexdigest, 0);
|
rb_define_method(rb_mDigest_Instance, "digest_length", rb_digest_instance_digest_length, 0);
|
||||||
rb_define_method(cDigest_Base, "to_s", rb_digest_base_hexdigest, 0);
|
rb_define_method(rb_mDigest_Instance, "block_length", rb_digest_instance_block_length, 0);
|
||||||
rb_define_method(cDigest_Base, "inspect", rb_digest_base_inspect, 0);
|
|
||||||
rb_define_method(cDigest_Base, "==", rb_digest_base_equal, 1);
|
|
||||||
|
|
||||||
rb_define_method(cDigest_Base, "digest_length", rb_digest_base_digest_length, 0);
|
/* instance methods that may be overridden */
|
||||||
rb_define_method(cDigest_Base, "block_length", rb_digest_base_block_length, 0);
|
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_metadata = rb_intern("metadata");
|
||||||
id_new = rb_intern("new");
|
|
||||||
id_initialize = rb_intern("initialize");
|
/* class Digest::Base < Digest::Class */
|
||||||
id_update = rb_intern("update");
|
rb_cDigest_Base = rb_define_class_under(rb_mDigest, "Base", rb_cDigest_Class);
|
||||||
id_digest = rb_intern("digest");
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,16 +15,18 @@
|
||||||
|
|
||||||
#include "ruby.h"
|
#include "ruby.h"
|
||||||
|
|
||||||
typedef void (*hash_init_func_t)(void *);
|
#define RUBY_DIGEST_API_VERSION 2
|
||||||
typedef void (*hash_update_func_t)(void *, unsigned char *, size_t);
|
|
||||||
typedef void (*hash_finish_func_t)(void *, unsigned char *);
|
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 {
|
typedef struct {
|
||||||
int api_version;
|
int api_version;
|
||||||
size_t digest_len;
|
size_t digest_len;
|
||||||
size_t block_len;
|
size_t block_len;
|
||||||
size_t ctx_size;
|
size_t ctx_size;
|
||||||
hash_init_func_t init_func;
|
rb_digest_hash_init_func_t init_func;
|
||||||
hash_update_func_t update_func;
|
rb_digest_hash_update_func_t update_func;
|
||||||
hash_finish_func_t finish_func;
|
rb_digest_hash_finish_func_t finish_func;
|
||||||
} algo_t;
|
} rb_digest_metadata_t;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
require 'digest.so'
|
require 'digest.so'
|
||||||
|
|
||||||
module Digest
|
module Digest
|
||||||
autoload "SHA256", "digest/sha2"
|
autoload "SHA256", "digest/sha2.so"
|
||||||
autoload "SHA384", "digest/sha2"
|
autoload "SHA384", "digest/sha2.so"
|
||||||
autoload "SHA512", "digest/sha2"
|
autoload "SHA512", "digest/sha2.so"
|
||||||
|
|
||||||
def self.const_missing(name)
|
def self.const_missing(name)
|
||||||
begin
|
begin
|
||||||
|
|
|
@ -39,17 +39,14 @@
|
||||||
require 'digest'
|
require 'digest'
|
||||||
|
|
||||||
module Digest
|
module Digest
|
||||||
class HMAC < Digest::Base
|
class HMAC < Digest::Class
|
||||||
def initialize(key, digest_class, *digest_params)
|
def initialize(key, digester)
|
||||||
@digest_class = digest_class.freeze
|
@md = digester.new
|
||||||
@digest_params = digest_params.freeze
|
|
||||||
@md = digest_class.new(*digest_params)
|
|
||||||
@tmp_md = @md.clone
|
|
||||||
|
|
||||||
block_len = @md.block_length
|
block_len = @md.block_length
|
||||||
|
|
||||||
if key.length > block_len
|
if key.length > block_len
|
||||||
key = @tmp_md.reset.update(key).digest
|
key = @md.digest(key)
|
||||||
end
|
end
|
||||||
|
|
||||||
ipad = Array.new(block_len).fill(0x36)
|
ipad = Array.new(block_len).fill(0x36)
|
||||||
|
@ -66,11 +63,11 @@ module Digest
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize_copy(other)
|
def initialize_copy(other)
|
||||||
@md = other.instance_eval { @md }
|
@md = @md.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def update(text)
|
def update(text)
|
||||||
@md.reset.update(@opad + @tmp_md.reset.update(@ipad + text).digest)
|
@md.reset.update(@opad + @md.digest(@ipad + text))
|
||||||
|
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
@ -106,36 +103,36 @@ __END__
|
||||||
require 'test/unit'
|
require 'test/unit'
|
||||||
|
|
||||||
module TM_HMAC
|
module TM_HMAC
|
||||||
def hmac_new(key)
|
|
||||||
Digest::HMAC.new(key, *digest_spec())
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_s_hexdigest
|
def test_s_hexdigest
|
||||||
spec = digest_spec()
|
|
||||||
|
|
||||||
cases.each { |h|
|
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
|
end
|
||||||
|
|
||||||
def test_hexdigest
|
def test_hexdigest
|
||||||
cases.each { |h|
|
cases.each { |h|
|
||||||
hmac = hmac_new(h[:key])
|
digesters { |d|
|
||||||
hmac.update(h[:data])
|
hmac = Digest::HMAC.new(h[:key], d)
|
||||||
|
|
||||||
assert_equal(h[:hexdigest], hmac.hexdigest)
|
hmac.update(h[:data])
|
||||||
|
|
||||||
|
assert_equal(h[:hexdigest], hmac.hexdigest)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_reset
|
def test_reset
|
||||||
cases.each { |h|
|
cases.each { |h|
|
||||||
hmac = hmac_new(h[:key])
|
digesters { |d|
|
||||||
hmac.update("test")
|
hmac = Digest::HMAC.new(h[:key], d)
|
||||||
hmac.reset
|
hmac.update("test")
|
||||||
hmac.update(h[:data])
|
hmac.reset
|
||||||
|
hmac.update(h[:data])
|
||||||
|
|
||||||
p hmac
|
assert_equal(h[:hexdigest], hmac.hexdigest)
|
||||||
assert_equal(h[:hexdigest], hmac.hexdigest)
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -143,8 +140,8 @@ end
|
||||||
class TC_HMAC_MD5 < Test::Unit::TestCase
|
class TC_HMAC_MD5 < Test::Unit::TestCase
|
||||||
include TM_HMAC
|
include TM_HMAC
|
||||||
|
|
||||||
def digest_spec
|
def digesters
|
||||||
[Digest::MD5]
|
[Digest::MD5, Digest::MD5.new]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Taken from RFC 2202: Test Cases for HMAC-MD5 and HMAC-SHA-1
|
# 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
|
class TC_HMAC_SHA1 < Test::Unit::TestCase
|
||||||
include TM_HMAC
|
include TM_HMAC
|
||||||
|
|
||||||
def digest_spec
|
def digesters
|
||||||
[Digest::SHA1]
|
[Digest::SHA1, Digest::SHA1.new]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Taken from RFC 2202: Test Cases for HMAC-MD5 and HMAC-SHA-1
|
# 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
|
class TC_HMAC_RMD160 < Test::Unit::TestCase
|
||||||
include TM_HMAC
|
include TM_HMAC
|
||||||
|
|
||||||
def digest_spec
|
def digesters
|
||||||
[Digest::RMD160]
|
[Digest::RMD160, Digest::RMD160.new]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Taken from RFC 2286: Test Cases for HMAC-RIPEMD160 and HMAC-RIPEMD128
|
# Taken from RFC 2286: Test Cases for HMAC-RIPEMD160 and HMAC-RIPEMD128
|
||||||
|
|
|
@ -8,14 +8,14 @@
|
||||||
#include "md5.h"
|
#include "md5.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static algo_t md5 = {
|
static rb_digest_metadata_t md5 = {
|
||||||
1,
|
RUBY_DIGEST_API_VERSION,
|
||||||
MD5_DIGEST_LENGTH,
|
MD5_DIGEST_LENGTH,
|
||||||
MD5_BLOCK_LENGTH,
|
MD5_BLOCK_LENGTH,
|
||||||
sizeof(MD5_CTX),
|
sizeof(MD5_CTX),
|
||||||
(hash_init_func_t)MD5_Init,
|
(rb_digest_hash_init_func_t)MD5_Init,
|
||||||
(hash_update_func_t)MD5_Update,
|
(rb_digest_hash_update_func_t)MD5_Update,
|
||||||
(hash_finish_func_t)MD5_Finish,
|
(rb_digest_hash_finish_func_t)MD5_Finish,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -8,14 +8,14 @@
|
||||||
#include "rmd160.h"
|
#include "rmd160.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static algo_t rmd160 = {
|
static rb_digest_metadata_t rmd160 = {
|
||||||
1,
|
RUBY_DIGEST_API_VERSION,
|
||||||
RMD160_DIGEST_LENGTH,
|
RMD160_DIGEST_LENGTH,
|
||||||
RMD160_BLOCK_LENGTH,
|
RMD160_BLOCK_LENGTH,
|
||||||
sizeof(RMD160_CTX),
|
sizeof(RMD160_CTX),
|
||||||
(hash_init_func_t)RMD160_Init,
|
(rb_digest_hash_init_func_t)RMD160_Init,
|
||||||
(hash_update_func_t)RMD160_Update,
|
(rb_digest_hash_update_func_t)RMD160_Update,
|
||||||
(hash_finish_func_t)RMD160_Finish,
|
(rb_digest_hash_finish_func_t)RMD160_Finish,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -27,7 +27,6 @@ void
|
||||||
Init_rmd160()
|
Init_rmd160()
|
||||||
{
|
{
|
||||||
VALUE mDigest, cDigest_Base, cDigest_RMD160;
|
VALUE mDigest, cDigest_Base, cDigest_RMD160;
|
||||||
ID id_metadata;
|
|
||||||
|
|
||||||
rb_require("digest");
|
rb_require("digest");
|
||||||
|
|
||||||
|
@ -36,8 +35,6 @@ Init_rmd160()
|
||||||
|
|
||||||
cDigest_RMD160 = rb_define_class_under(mDigest, "RMD160", cDigest_Base);
|
cDigest_RMD160 = rb_define_class_under(mDigest, "RMD160", cDigest_Base);
|
||||||
|
|
||||||
id_metadata = rb_intern("metadata");
|
rb_ivar_set(cDigest_RMD160, rb_intern("metadata"),
|
||||||
|
|
||||||
rb_ivar_set(cDigest_RMD160, id_metadata,
|
|
||||||
Data_Wrap_Struct(rb_cObject, 0, 0, &rmd160));
|
Data_Wrap_Struct(rb_cObject, 0, 0, &rmd160));
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,14 +8,14 @@
|
||||||
#include "sha1.h"
|
#include "sha1.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static algo_t sha1 = {
|
static rb_digest_metadata_t sha1 = {
|
||||||
1,
|
RUBY_DIGEST_API_VERSION,
|
||||||
SHA1_DIGEST_LENGTH,
|
SHA1_DIGEST_LENGTH,
|
||||||
SHA1_BLOCK_LENGTH,
|
SHA1_BLOCK_LENGTH,
|
||||||
sizeof(SHA1_CTX),
|
sizeof(SHA1_CTX),
|
||||||
(hash_init_func_t)SHA1_Init,
|
(rb_digest_hash_init_func_t)SHA1_Init,
|
||||||
(hash_update_func_t)SHA1_Update,
|
(rb_digest_hash_update_func_t)SHA1_Update,
|
||||||
(hash_finish_func_t)SHA1_Finish,
|
(rb_digest_hash_finish_func_t)SHA1_Finish,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -27,9 +27,9 @@ void
|
||||||
Init_sha1()
|
Init_sha1()
|
||||||
{
|
{
|
||||||
VALUE mDigest, cDigest_Base, cDigest_SHA1;
|
VALUE mDigest, cDigest_Base, cDigest_SHA1;
|
||||||
|
|
||||||
rb_require("digest");
|
rb_require("digest");
|
||||||
|
|
||||||
mDigest = rb_path2class("Digest");
|
mDigest = rb_path2class("Digest");
|
||||||
cDigest_Base = rb_path2class("Digest::Base");
|
cDigest_Base = rb_path2class("Digest::Base");
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -7,14 +7,14 @@
|
||||||
#define FOREACH_BITLEN(func) func(256) func(384) func(512)
|
#define FOREACH_BITLEN(func) func(256) func(384) func(512)
|
||||||
|
|
||||||
#define DEFINE_ALGO_METADATA(bitlen) \
|
#define DEFINE_ALGO_METADATA(bitlen) \
|
||||||
static algo_t sha##bitlen = { \
|
static rb_digest_metadata_t sha##bitlen = { \
|
||||||
1, \
|
RUBY_DIGEST_API_VERSION, \
|
||||||
SHA##bitlen##_DIGEST_LENGTH, \
|
SHA##bitlen##_DIGEST_LENGTH, \
|
||||||
SHA##bitlen##_BLOCK_LENGTH, \
|
SHA##bitlen##_BLOCK_LENGTH, \
|
||||||
sizeof(SHA##bitlen##_CTX), \
|
sizeof(SHA##bitlen##_CTX), \
|
||||||
(hash_init_func_t)SHA##bitlen##_Init, \
|
(rb_digest_hash_init_func_t)SHA##bitlen##_Init, \
|
||||||
(hash_update_func_t)SHA##bitlen##_Update, \
|
(rb_digest_hash_update_func_t)SHA##bitlen##_Update, \
|
||||||
(hash_finish_func_t)SHA##bitlen##_Finish, \
|
(rb_digest_hash_finish_func_t)SHA##bitlen##_Finish, \
|
||||||
};
|
};
|
||||||
|
|
||||||
FOREACH_BITLEN(DEFINE_ALGO_METADATA)
|
FOREACH_BITLEN(DEFINE_ALGO_METADATA)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче