|
Ruby 1.9.2p290(2011-07-09revision32553)
|
00001 /************************************************ 00002 00003 digest.c - 00004 00005 $Author: knu $ 00006 created at: Fri May 25 08:57:27 JST 2001 00007 00008 Copyright (C) 1995-2001 Yukihiro Matsumoto 00009 Copyright (C) 2001-2006 Akinori MUSHA 00010 00011 $RoughId: digest.c,v 1.16 2001/07/13 15:38:27 knu Exp $ 00012 $Id: digest.c 26339 2010-01-17 19:12:10Z knu $ 00013 00014 ************************************************/ 00015 00016 #include "digest.h" 00017 00018 static VALUE rb_mDigest; 00019 static VALUE rb_mDigest_Instance; 00020 static VALUE rb_cDigest_Class; 00021 static VALUE rb_cDigest_Base; 00022 00023 static ID id_reset, id_update, id_finish, id_digest, id_hexdigest, id_digest_length; 00024 static ID id_metadata; 00025 00026 RUBY_EXTERN void Init_digest_base(void); 00027 00028 /* 00029 * Document-module: Digest 00030 * 00031 * This module provides a framework for message digest libraries. 00032 */ 00033 00034 static VALUE 00035 hexencode_str_new(VALUE str_digest) 00036 { 00037 char *digest; 00038 size_t digest_len; 00039 size_t i; 00040 VALUE str; 00041 char *p; 00042 static const char hex[] = { 00043 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 00044 'a', 'b', 'c', 'd', 'e', 'f' 00045 }; 00046 00047 StringValue(str_digest); 00048 digest = RSTRING_PTR(str_digest); 00049 digest_len = RSTRING_LEN(str_digest); 00050 00051 if (LONG_MAX / 2 < digest_len) { 00052 rb_raise(rb_eRuntimeError, "digest string too long"); 00053 } 00054 00055 str = rb_str_new(0, digest_len * 2); 00056 00057 for (i = 0, p = RSTRING_PTR(str); i < digest_len; i++) { 00058 unsigned char byte = digest[i]; 00059 00060 p[i + i] = hex[byte >> 4]; 00061 p[i + i + 1] = hex[byte & 0x0f]; 00062 } 00063 00064 return str; 00065 } 00066 00067 /* 00068 * call-seq: 00069 * Digest.hexencode(string) -> hexencoded_string 00070 * 00071 * Generates a hex-encoded version of a given _string_. 00072 */ 00073 static VALUE 00074 rb_digest_s_hexencode(VALUE klass, VALUE str) 00075 { 00076 return hexencode_str_new(str); 00077 } 00078 00079 NORETURN(static void rb_digest_instance_method_unimpl(VALUE self, const char *method)); 00080 00081 /* 00082 * Document-module: Digest::Instance 00083 * 00084 * This module provides instance methods for a digest implementation 00085 * object to calculate message digest values. 00086 */ 00087 00088 static void 00089 rb_digest_instance_method_unimpl(VALUE self, const char *method) 00090 { 00091 rb_raise(rb_eRuntimeError, "%s does not implement %s()", 00092 rb_obj_classname(self), method); 00093 } 00094 00095 /* 00096 * call-seq: 00097 * digest_obj.update(string) -> digest_obj 00098 * digest_obj << string -> digest_obj 00099 * 00100 * Updates the digest using a given _string_ and returns self. 00101 * 00102 * The update() method and the left-shift operator are overridden by 00103 * each implementation subclass. (One should be an alias for the 00104 * other) 00105 */ 00106 static VALUE 00107 rb_digest_instance_update(VALUE self, VALUE str) 00108 { 00109 rb_digest_instance_method_unimpl(self, "update"); 00110 } 00111 00112 /* 00113 * call-seq: 00114 * digest_obj.instance_eval { finish } -> digest_obj 00115 * 00116 * Finishes the digest and returns the resulting hash value. 00117 * 00118 * This method is overridden by each implementation subclass and often 00119 * made private, because some of those subclasses may leave internal 00120 * data uninitialized. Do not call this method from outside. Use 00121 * #digest!() instead, which ensures that internal data be reset for 00122 * security reasons. 00123 */ 00124 static VALUE 00125 rb_digest_instance_finish(VALUE self) 00126 { 00127 rb_digest_instance_method_unimpl(self, "finish"); 00128 } 00129 00130 /* 00131 * call-seq: 00132 * digest_obj.reset -> digest_obj 00133 * 00134 * Resets the digest to the initial state and returns self. 00135 * 00136 * This method is overridden by each implementation subclass. 00137 */ 00138 static VALUE 00139 rb_digest_instance_reset(VALUE self) 00140 { 00141 rb_digest_instance_method_unimpl(self, "reset"); 00142 } 00143 00144 /* 00145 * call-seq: 00146 * digest_obj.new -> another_digest_obj 00147 * 00148 * Returns a new, initialized copy of the digest object. Equivalent 00149 * to digest_obj.clone().reset(). 00150 */ 00151 static VALUE 00152 rb_digest_instance_new(VALUE self) 00153 { 00154 VALUE clone = rb_obj_clone(self); 00155 rb_funcall(clone, id_reset, 0); 00156 return clone; 00157 } 00158 00159 /* 00160 * call-seq: 00161 * digest_obj.digest -> string 00162 * digest_obj.digest(string) -> string 00163 * 00164 * If none is given, returns the resulting hash value of the digest, 00165 * keeping the digest's state. 00166 * 00167 * If a _string_ is given, returns the hash value for the given 00168 * _string_, resetting the digest to the initial state before and 00169 * after the process. 00170 */ 00171 static VALUE 00172 rb_digest_instance_digest(int argc, VALUE *argv, VALUE self) 00173 { 00174 VALUE str, value; 00175 00176 if (rb_scan_args(argc, argv, "01", &str) > 0) { 00177 rb_funcall(self, id_reset, 0); 00178 rb_funcall(self, id_update, 1, str); 00179 value = rb_funcall(self, id_finish, 0); 00180 rb_funcall(self, id_reset, 0); 00181 } else { 00182 value = rb_funcall(rb_obj_clone(self), id_finish, 0); 00183 } 00184 00185 return value; 00186 } 00187 00188 /* 00189 * call-seq: 00190 * digest_obj.digest! -> string 00191 * 00192 * Returns the resulting hash value and resets the digest to the 00193 * initial state. 00194 */ 00195 static VALUE 00196 rb_digest_instance_digest_bang(VALUE self) 00197 { 00198 VALUE value = rb_funcall(self, id_finish, 0); 00199 rb_funcall(self, id_reset, 0); 00200 00201 return value; 00202 } 00203 00204 /* 00205 * call-seq: 00206 * digest_obj.hexdigest -> string 00207 * digest_obj.hexdigest(string) -> string 00208 * 00209 * If none is given, returns the resulting hash value of the digest in 00210 * a hex-encoded form, keeping the digest's state. 00211 * 00212 * If a _string_ is given, returns the hash value for the given 00213 * _string_ in a hex-encoded form, resetting the digest to the initial 00214 * state before and after the process. 00215 */ 00216 static VALUE 00217 rb_digest_instance_hexdigest(int argc, VALUE *argv, VALUE self) 00218 { 00219 VALUE str, value; 00220 00221 if (rb_scan_args(argc, argv, "01", &str) > 0) { 00222 rb_funcall(self, id_reset, 0); 00223 rb_funcall(self, id_update, 1, str); 00224 value = rb_funcall(self, id_finish, 0); 00225 rb_funcall(self, id_reset, 0); 00226 } else { 00227 value = rb_funcall(rb_obj_clone(self), id_finish, 0); 00228 } 00229 00230 return hexencode_str_new(value); 00231 } 00232 00233 /* 00234 * call-seq: 00235 * digest_obj.hexdigest! -> string 00236 * 00237 * Returns the resulting hash value in a hex-encoded form and resets 00238 * the digest to the initial state. 00239 */ 00240 static VALUE 00241 rb_digest_instance_hexdigest_bang(VALUE self) 00242 { 00243 VALUE value = rb_funcall(self, id_finish, 0); 00244 rb_funcall(self, id_reset, 0); 00245 00246 return hexencode_str_new(value); 00247 } 00248 00249 /* 00250 * call-seq: 00251 * digest_obj.to_s -> string 00252 * 00253 * Returns digest_obj.hexdigest(). 00254 */ 00255 static VALUE 00256 rb_digest_instance_to_s(VALUE self) 00257 { 00258 return rb_funcall(self, id_hexdigest, 0); 00259 } 00260 00261 /* 00262 * call-seq: 00263 * digest_obj.inspect -> string 00264 * 00265 * Creates a printable version of the digest object. 00266 */ 00267 static VALUE 00268 rb_digest_instance_inspect(VALUE self) 00269 { 00270 VALUE str; 00271 size_t digest_len = 32; /* about this size at least */ 00272 const char *cname; 00273 00274 cname = rb_obj_classname(self); 00275 00276 /* #<Digest::ClassName: xxxxx...xxxx> */ 00277 str = rb_str_buf_new(2 + strlen(cname) + 2 + digest_len * 2 + 1); 00278 rb_str_buf_cat2(str, "#<"); 00279 rb_str_buf_cat2(str, cname); 00280 rb_str_buf_cat2(str, ": "); 00281 rb_str_buf_append(str, rb_digest_instance_hexdigest(0, 0, self)); 00282 rb_str_buf_cat2(str, ">"); 00283 return str; 00284 } 00285 00286 /* 00287 * call-seq: 00288 * digest_obj == another_digest_obj -> boolean 00289 * digest_obj == string -> boolean 00290 * 00291 * If a string is given, checks whether it is equal to the hex-encoded 00292 * hash value of the digest object. If another digest instance is 00293 * given, checks whether they have the same hash value. Otherwise 00294 * returns false. 00295 */ 00296 static VALUE 00297 rb_digest_instance_equal(VALUE self, VALUE other) 00298 { 00299 VALUE str1, str2; 00300 00301 if (rb_obj_is_kind_of(other, rb_mDigest_Instance) == Qtrue) { 00302 str1 = rb_digest_instance_digest(0, 0, self); 00303 str2 = rb_digest_instance_digest(0, 0, other); 00304 } else { 00305 str1 = rb_digest_instance_to_s(self); 00306 str2 = other; 00307 } 00308 00309 /* never blindly assume that subclass methods return strings */ 00310 StringValue(str1); 00311 StringValue(str2); 00312 00313 if (RSTRING_LEN(str1) == RSTRING_LEN(str2) && 00314 rb_str_cmp(str1, str2) == 0) { 00315 return Qtrue; 00316 } 00317 return Qfalse; 00318 } 00319 00320 /* 00321 * call-seq: 00322 * digest_obj.digest_length -> integer 00323 * 00324 * Returns the length of the hash value of the digest. 00325 * 00326 * This method should be overridden by each implementation subclass. 00327 * If not, digest_obj.digest().length() is returned. 00328 */ 00329 static VALUE 00330 rb_digest_instance_digest_length(VALUE self) 00331 { 00332 /* subclasses really should redefine this method */ 00333 VALUE digest = rb_digest_instance_digest(0, 0, self); 00334 00335 /* never blindly assume that #digest() returns a string */ 00336 StringValue(digest); 00337 return INT2NUM(RSTRING_LEN(digest)); 00338 } 00339 00340 /* 00341 * call-seq: 00342 * digest_obj.length -> integer 00343 * digest_obj.size -> integer 00344 * 00345 * Returns digest_obj.digest_length(). 00346 */ 00347 static VALUE 00348 rb_digest_instance_length(VALUE self) 00349 { 00350 return rb_funcall(self, id_digest_length, 0); 00351 } 00352 00353 /* 00354 * call-seq: 00355 * digest_obj.block_length -> integer 00356 * 00357 * Returns the block length of the digest. 00358 * 00359 * This method is overridden by each implementation subclass. 00360 */ 00361 static VALUE 00362 rb_digest_instance_block_length(VALUE self) 00363 { 00364 rb_digest_instance_method_unimpl(self, "block_length"); 00365 } 00366 00367 /* 00368 * Document-class: Digest::Class 00369 * 00370 * This module stands as a base class for digest implementation 00371 * classes. 00372 */ 00373 00374 /* 00375 * call-seq: 00376 * Digest::Class.digest(string, *parameters) -> hash_string 00377 * 00378 * Returns the hash value of a given _string_. This is equivalent to 00379 * Digest::Class.new(*parameters).digest(string), where extra 00380 * _parameters_, if any, are passed through to the constructor and the 00381 * _string_ is passed to #digest(). 00382 */ 00383 static VALUE 00384 rb_digest_class_s_digest(int argc, VALUE *argv, VALUE klass) 00385 { 00386 VALUE str; 00387 volatile VALUE obj; 00388 00389 if (argc < 1) { 00390 rb_raise(rb_eArgError, "no data given"); 00391 } 00392 00393 str = *argv++; 00394 argc--; 00395 00396 StringValue(str); 00397 00398 obj = rb_obj_alloc(klass); 00399 rb_obj_call_init(obj, argc, argv); 00400 00401 return rb_funcall(obj, id_digest, 1, str); 00402 } 00403 00404 /* 00405 * call-seq: 00406 * Digest::Class.hexdigest(string[, ...]) -> hash_string 00407 * 00408 * Returns the hex-encoded hash value of a given _string_. This is 00409 * almost equivalent to 00410 * Digest.hexencode(Digest::Class.new(*parameters).digest(string)). 00411 */ 00412 static VALUE 00413 rb_digest_class_s_hexdigest(int argc, VALUE *argv, VALUE klass) 00414 { 00415 return hexencode_str_new(rb_funcall2(klass, id_digest, argc, argv)); 00416 } 00417 00418 /* 00419 * Document-class: Digest::Base 00420 * 00421 * This abstract class provides a common interface to message digest 00422 * implementation classes written in C. 00423 */ 00424 00425 static rb_digest_metadata_t * 00426 get_digest_base_metadata(VALUE klass) 00427 { 00428 VALUE p; 00429 VALUE obj; 00430 rb_digest_metadata_t *algo; 00431 00432 for (p = klass; p; p = RCLASS_SUPER(p)) { 00433 if (rb_ivar_defined(p, id_metadata)) { 00434 obj = rb_ivar_get(p, id_metadata); 00435 break; 00436 } 00437 } 00438 00439 if (!p) 00440 rb_raise(rb_eRuntimeError, "Digest::Base cannot be directly inherited in Ruby"); 00441 00442 Data_Get_Struct(obj, rb_digest_metadata_t, algo); 00443 00444 switch (algo->api_version) { 00445 case 2: 00446 break; 00447 00448 /* 00449 * put conversion here if possible when API is updated 00450 */ 00451 00452 default: 00453 rb_raise(rb_eRuntimeError, "Incompatible digest API version"); 00454 } 00455 00456 return algo; 00457 } 00458 00459 static VALUE 00460 rb_digest_base_alloc(VALUE klass) 00461 { 00462 rb_digest_metadata_t *algo; 00463 VALUE obj; 00464 void *pctx; 00465 00466 if (klass == rb_cDigest_Base) { 00467 rb_raise(rb_eNotImpError, "Digest::Base is an abstract class"); 00468 } 00469 00470 algo = get_digest_base_metadata(klass); 00471 00472 pctx = xmalloc(algo->ctx_size); 00473 algo->init_func(pctx); 00474 00475 obj = Data_Wrap_Struct(klass, 0, xfree, pctx); 00476 00477 return obj; 00478 } 00479 00480 /* :nodoc: */ 00481 static VALUE 00482 rb_digest_base_copy(VALUE copy, VALUE obj) 00483 { 00484 rb_digest_metadata_t *algo; 00485 void *pctx1, *pctx2; 00486 00487 if (copy == obj) return copy; 00488 00489 rb_check_frozen(copy); 00490 00491 algo = get_digest_base_metadata(rb_obj_class(copy)); 00492 00493 Data_Get_Struct(obj, void, pctx1); 00494 Data_Get_Struct(copy, void, pctx2); 00495 memcpy(pctx2, pctx1, algo->ctx_size); 00496 00497 return copy; 00498 } 00499 00500 /* :nodoc: */ 00501 static VALUE 00502 rb_digest_base_reset(VALUE self) 00503 { 00504 rb_digest_metadata_t *algo; 00505 void *pctx; 00506 00507 algo = get_digest_base_metadata(rb_obj_class(self)); 00508 00509 Data_Get_Struct(self, void, pctx); 00510 00511 algo->init_func(pctx); 00512 00513 return self; 00514 } 00515 00516 /* :nodoc: */ 00517 static VALUE 00518 rb_digest_base_update(VALUE self, VALUE str) 00519 { 00520 rb_digest_metadata_t *algo; 00521 void *pctx; 00522 00523 algo = get_digest_base_metadata(rb_obj_class(self)); 00524 00525 Data_Get_Struct(self, void, pctx); 00526 00527 StringValue(str); 00528 algo->update_func(pctx, (unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str)); 00529 00530 return self; 00531 } 00532 00533 /* :nodoc: */ 00534 static VALUE 00535 rb_digest_base_finish(VALUE self) 00536 { 00537 rb_digest_metadata_t *algo; 00538 void *pctx; 00539 VALUE str; 00540 00541 algo = get_digest_base_metadata(rb_obj_class(self)); 00542 00543 Data_Get_Struct(self, void, pctx); 00544 00545 str = rb_str_new(0, algo->digest_len); 00546 algo->finish_func(pctx, (unsigned char *)RSTRING_PTR(str)); 00547 00548 /* avoid potential coredump caused by use of a finished context */ 00549 algo->init_func(pctx); 00550 00551 return str; 00552 } 00553 00554 /* :nodoc: */ 00555 static VALUE 00556 rb_digest_base_digest_length(VALUE self) 00557 { 00558 rb_digest_metadata_t *algo; 00559 00560 algo = get_digest_base_metadata(rb_obj_class(self)); 00561 00562 return INT2NUM(algo->digest_len); 00563 } 00564 00565 /* :nodoc: */ 00566 static VALUE 00567 rb_digest_base_block_length(VALUE self) 00568 { 00569 rb_digest_metadata_t *algo; 00570 00571 algo = get_digest_base_metadata(rb_obj_class(self)); 00572 00573 return INT2NUM(algo->block_len); 00574 } 00575 00576 void 00577 Init_digest(void) 00578 { 00579 id_reset = rb_intern("reset"); 00580 id_update = rb_intern("update"); 00581 id_finish = rb_intern("finish"); 00582 id_digest = rb_intern("digest"); 00583 id_hexdigest = rb_intern("hexdigest"); 00584 id_digest_length = rb_intern("digest_length"); 00585 00586 /* 00587 * module Digest 00588 */ 00589 rb_mDigest = rb_define_module("Digest"); 00590 00591 /* module functions */ 00592 rb_define_module_function(rb_mDigest, "hexencode", rb_digest_s_hexencode, 1); 00593 00594 /* 00595 * module Digest::Instance 00596 */ 00597 rb_mDigest_Instance = rb_define_module_under(rb_mDigest, "Instance"); 00598 00599 /* instance methods that should be overridden */ 00600 rb_define_method(rb_mDigest_Instance, "update", rb_digest_instance_update, 1); 00601 rb_define_method(rb_mDigest_Instance, "<<", rb_digest_instance_update, 1); 00602 rb_define_private_method(rb_mDigest_Instance, "finish", rb_digest_instance_finish, 0); 00603 rb_define_method(rb_mDigest_Instance, "reset", rb_digest_instance_reset, 0); 00604 rb_define_method(rb_mDigest_Instance, "digest_length", rb_digest_instance_digest_length, 0); 00605 rb_define_method(rb_mDigest_Instance, "block_length", rb_digest_instance_block_length, 0); 00606 00607 /* instance methods that may be overridden */ 00608 rb_define_method(rb_mDigest_Instance, "==", rb_digest_instance_equal, 1); 00609 rb_define_method(rb_mDigest_Instance, "inspect", rb_digest_instance_inspect, 0); 00610 00611 /* instance methods that need not usually be overridden */ 00612 rb_define_method(rb_mDigest_Instance, "new", rb_digest_instance_new, 0); 00613 rb_define_method(rb_mDigest_Instance, "digest", rb_digest_instance_digest, -1); 00614 rb_define_method(rb_mDigest_Instance, "digest!", rb_digest_instance_digest_bang, 0); 00615 rb_define_method(rb_mDigest_Instance, "hexdigest", rb_digest_instance_hexdigest, -1); 00616 rb_define_method(rb_mDigest_Instance, "hexdigest!", rb_digest_instance_hexdigest_bang, 0); 00617 rb_define_method(rb_mDigest_Instance, "to_s", rb_digest_instance_to_s, 0); 00618 rb_define_method(rb_mDigest_Instance, "length", rb_digest_instance_length, 0); 00619 rb_define_method(rb_mDigest_Instance, "size", rb_digest_instance_length, 0); 00620 00621 /* 00622 * class Digest::Class 00623 */ 00624 rb_cDigest_Class = rb_define_class_under(rb_mDigest, "Class", rb_cObject); 00625 rb_include_module(rb_cDigest_Class, rb_mDigest_Instance); 00626 00627 /* class methods */ 00628 rb_define_singleton_method(rb_cDigest_Class, "digest", rb_digest_class_s_digest, -1); 00629 rb_define_singleton_method(rb_cDigest_Class, "hexdigest", rb_digest_class_s_hexdigest, -1); 00630 00631 id_metadata = rb_intern("metadata"); 00632 00633 /* class Digest::Base < Digest::Class */ 00634 rb_cDigest_Base = rb_define_class_under(rb_mDigest, "Base", rb_cDigest_Class); 00635 00636 rb_define_alloc_func(rb_cDigest_Base, rb_digest_base_alloc); 00637 00638 rb_define_method(rb_cDigest_Base, "initialize_copy", rb_digest_base_copy, 1); 00639 rb_define_method(rb_cDigest_Base, "reset", rb_digest_base_reset, 0); 00640 rb_define_method(rb_cDigest_Base, "update", rb_digest_base_update, 1); 00641 rb_define_method(rb_cDigest_Base, "<<", rb_digest_base_update, 1); 00642 rb_define_private_method(rb_cDigest_Base, "finish", rb_digest_base_finish, 0); 00643 rb_define_method(rb_cDigest_Base, "digest_length", rb_digest_base_digest_length, 0); 00644 rb_define_method(rb_cDigest_Base, "block_length", rb_digest_base_block_length, 0); 00645 } 00646
1.7.3