00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097 static VALUE
00098 hexencode_str_new(VALUE str_digest)
00099 {
00100 char *digest;
00101 size_t digest_len;
00102 size_t i;
00103 VALUE str;
00104 char *p;
00105 static const char hex[] = {
00106 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
00107 'a', 'b', 'c', 'd', 'e', 'f'
00108 };
00109
00110 StringValue(str_digest);
00111 digest = RSTRING_PTR(str_digest);
00112 digest_len = RSTRING_LEN(str_digest);
00113
00114 if (LONG_MAX / 2 < digest_len) {
00115 rb_raise(rb_eRuntimeError, "digest string too long");
00116 }
00117
00118 str = rb_usascii_str_new(0, digest_len * 2);
00119
00120 for (i = 0, p = RSTRING_PTR(str); i < digest_len; i++) {
00121 unsigned char byte = digest[i];
00122
00123 p[i + i] = hex[byte >> 4];
00124 p[i + i + 1] = hex[byte & 0x0f];
00125 }
00126
00127 return str;
00128 }
00129
00130
00131
00132
00133
00134
00135
00136 static VALUE
00137 rb_digest_s_hexencode(VALUE klass, VALUE str)
00138 {
00139 return hexencode_str_new(str);
00140 }
00141
00142 NORETURN(static void rb_digest_instance_method_unimpl(VALUE self, const char *method));
00143
00144
00145
00146
00147
00148
00149
00150
00151 static void
00152 rb_digest_instance_method_unimpl(VALUE self, const char *method)
00153 {
00154 rb_raise(rb_eRuntimeError, "%s does not implement %s()",
00155 rb_obj_classname(self), method);
00156 }
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169 static VALUE
00170 rb_digest_instance_update(VALUE self, VALUE str)
00171 {
00172 rb_digest_instance_method_unimpl(self, "update");
00173
00174 UNREACHABLE;
00175 }
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189 static VALUE
00190 rb_digest_instance_finish(VALUE self)
00191 {
00192 rb_digest_instance_method_unimpl(self, "finish");
00193
00194 UNREACHABLE;
00195 }
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205 static VALUE
00206 rb_digest_instance_reset(VALUE self)
00207 {
00208 rb_digest_instance_method_unimpl(self, "reset");
00209
00210 UNREACHABLE;
00211 }
00212
00213
00214
00215
00216
00217
00218
00219
00220 static VALUE
00221 rb_digest_instance_new(VALUE self)
00222 {
00223 VALUE clone = rb_obj_clone(self);
00224 rb_funcall(clone, id_reset, 0);
00225 return clone;
00226 }
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240 static VALUE
00241 rb_digest_instance_digest(int argc, VALUE *argv, VALUE self)
00242 {
00243 VALUE str, value;
00244
00245 if (rb_scan_args(argc, argv, "01", &str) > 0) {
00246 rb_funcall(self, id_reset, 0);
00247 rb_funcall(self, id_update, 1, str);
00248 value = rb_funcall(self, id_finish, 0);
00249 rb_funcall(self, id_reset, 0);
00250 } else {
00251 value = rb_funcall(rb_obj_clone(self), id_finish, 0);
00252 }
00253
00254 return value;
00255 }
00256
00257
00258
00259
00260
00261
00262
00263
00264 static VALUE
00265 rb_digest_instance_digest_bang(VALUE self)
00266 {
00267 VALUE value = rb_funcall(self, id_finish, 0);
00268 rb_funcall(self, id_reset, 0);
00269
00270 return value;
00271 }
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285 static VALUE
00286 rb_digest_instance_hexdigest(int argc, VALUE *argv, VALUE self)
00287 {
00288 VALUE str, value;
00289
00290 if (rb_scan_args(argc, argv, "01", &str) > 0) {
00291 rb_funcall(self, id_reset, 0);
00292 rb_funcall(self, id_update, 1, str);
00293 value = rb_funcall(self, id_finish, 0);
00294 rb_funcall(self, id_reset, 0);
00295 } else {
00296 value = rb_funcall(rb_obj_clone(self), id_finish, 0);
00297 }
00298
00299 return hexencode_str_new(value);
00300 }
00301
00302
00303
00304
00305
00306
00307
00308
00309 static VALUE
00310 rb_digest_instance_hexdigest_bang(VALUE self)
00311 {
00312 VALUE value = rb_funcall(self, id_finish, 0);
00313 rb_funcall(self, id_reset, 0);
00314
00315 return hexencode_str_new(value);
00316 }
00317
00318
00319
00320
00321
00322
00323
00324 static VALUE
00325 rb_digest_instance_to_s(VALUE self)
00326 {
00327 return rb_funcall(self, id_hexdigest, 0);
00328 }
00329
00330
00331
00332
00333
00334
00335
00336 static VALUE
00337 rb_digest_instance_inspect(VALUE self)
00338 {
00339 VALUE str;
00340 size_t digest_len = 32;
00341 const char *cname;
00342
00343 cname = rb_obj_classname(self);
00344
00345
00346 str = rb_str_buf_new(2 + strlen(cname) + 2 + digest_len * 2 + 1);
00347 rb_str_buf_cat2(str, "#<");
00348 rb_str_buf_cat2(str, cname);
00349 rb_str_buf_cat2(str, ": ");
00350 rb_str_buf_append(str, rb_digest_instance_hexdigest(0, 0, self));
00351 rb_str_buf_cat2(str, ">");
00352 return str;
00353 }
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365 static VALUE
00366 rb_digest_instance_equal(VALUE self, VALUE other)
00367 {
00368 VALUE str1, str2;
00369
00370 if (rb_obj_is_kind_of(other, rb_mDigest_Instance) == Qtrue) {
00371 str1 = rb_digest_instance_digest(0, 0, self);
00372 str2 = rb_digest_instance_digest(0, 0, other);
00373 } else {
00374 str1 = rb_digest_instance_to_s(self);
00375 str2 = rb_check_string_type(other);
00376 if (NIL_P(str2)) return Qfalse;
00377 }
00378
00379
00380 StringValue(str1);
00381 StringValue(str2);
00382
00383 if (RSTRING_LEN(str1) == RSTRING_LEN(str2) &&
00384 rb_str_cmp(str1, str2) == 0) {
00385 return Qtrue;
00386 }
00387 return Qfalse;
00388 }
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399 static VALUE
00400 rb_digest_instance_digest_length(VALUE self)
00401 {
00402
00403 VALUE digest = rb_digest_instance_digest(0, 0, self);
00404
00405
00406 StringValue(digest);
00407 return INT2NUM(RSTRING_LEN(digest));
00408 }
00409
00410
00411
00412
00413
00414
00415
00416
00417 static VALUE
00418 rb_digest_instance_length(VALUE self)
00419 {
00420 return rb_funcall(self, id_digest_length, 0);
00421 }
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431 static VALUE
00432 rb_digest_instance_block_length(VALUE self)
00433 {
00434 rb_digest_instance_method_unimpl(self, "block_length");
00435
00436 UNREACHABLE;
00437 }
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455 static VALUE
00456 rb_digest_class_s_digest(int argc, VALUE *argv, VALUE klass)
00457 {
00458 VALUE str;
00459 volatile VALUE obj;
00460
00461 if (argc < 1) {
00462 rb_raise(rb_eArgError, "no data given");
00463 }
00464
00465 str = *argv++;
00466 argc--;
00467
00468 StringValue(str);
00469
00470 obj = rb_obj_alloc(klass);
00471 rb_obj_call_init(obj, argc, argv);
00472
00473 return rb_funcall(obj, id_digest, 1, str);
00474 }
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484 static VALUE
00485 rb_digest_class_s_hexdigest(int argc, VALUE *argv, VALUE klass)
00486 {
00487 return hexencode_str_new(rb_funcall2(klass, id_digest, argc, argv));
00488 }
00489
00490
00491 static VALUE
00492 rb_digest_class_init(VALUE self)
00493 {
00494 return self;
00495 }
00496
00497
00498
00499
00500
00501
00502
00503
00504 static rb_digest_metadata_t *
00505 get_digest_base_metadata(VALUE klass)
00506 {
00507 VALUE p;
00508 VALUE obj;
00509 rb_digest_metadata_t *algo;
00510
00511 for (p = klass; !NIL_P(p); p = rb_class_superclass(p)) {
00512 if (rb_ivar_defined(p, id_metadata)) {
00513 obj = rb_ivar_get(p, id_metadata);
00514 break;
00515 }
00516 }
00517
00518 if (NIL_P(p))
00519 rb_raise(rb_eRuntimeError, "Digest::Base cannot be directly inherited in Ruby");
00520
00521 Data_Get_Struct(obj, rb_digest_metadata_t, algo);
00522
00523 switch (algo->api_version) {
00524 case 2:
00525 break;
00526
00527
00528
00529
00530
00531 default:
00532 rb_raise(rb_eRuntimeError, "Incompatible digest API version");
00533 }
00534
00535 return algo;
00536 }
00537
00538 static VALUE
00539 rb_digest_base_alloc(VALUE klass)
00540 {
00541 rb_digest_metadata_t *algo;
00542 VALUE obj;
00543 void *pctx;
00544
00545 if (klass == rb_cDigest_Base) {
00546 rb_raise(rb_eNotImpError, "Digest::Base is an abstract class");
00547 }
00548
00549 algo = get_digest_base_metadata(klass);
00550
00551 pctx = xmalloc(algo->ctx_size);
00552 algo->init_func(pctx);
00553
00554 obj = Data_Wrap_Struct(klass, 0, xfree, pctx);
00555
00556 return obj;
00557 }
00558
00559
00560 static VALUE
00561 rb_digest_base_copy(VALUE copy, VALUE obj)
00562 {
00563 rb_digest_metadata_t *algo;
00564 void *pctx1, *pctx2;
00565
00566 if (copy == obj) return copy;
00567
00568 rb_check_frozen(copy);
00569
00570 algo = get_digest_base_metadata(rb_obj_class(copy));
00571
00572 Data_Get_Struct(obj, void, pctx1);
00573 Data_Get_Struct(copy, void, pctx2);
00574 memcpy(pctx2, pctx1, algo->ctx_size);
00575
00576 return copy;
00577 }
00578
00579
00580 static VALUE
00581 rb_digest_base_reset(VALUE self)
00582 {
00583 rb_digest_metadata_t *algo;
00584 void *pctx;
00585
00586 algo = get_digest_base_metadata(rb_obj_class(self));
00587
00588 Data_Get_Struct(self, void, pctx);
00589
00590 algo->init_func(pctx);
00591
00592 return self;
00593 }
00594
00595
00596 static VALUE
00597 rb_digest_base_update(VALUE self, VALUE str)
00598 {
00599 rb_digest_metadata_t *algo;
00600 void *pctx;
00601
00602 algo = get_digest_base_metadata(rb_obj_class(self));
00603
00604 Data_Get_Struct(self, void, pctx);
00605
00606 StringValue(str);
00607 algo->update_func(pctx, (unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str));
00608
00609 return self;
00610 }
00611
00612
00613 static VALUE
00614 rb_digest_base_finish(VALUE self)
00615 {
00616 rb_digest_metadata_t *algo;
00617 void *pctx;
00618 VALUE str;
00619
00620 algo = get_digest_base_metadata(rb_obj_class(self));
00621
00622 Data_Get_Struct(self, void, pctx);
00623
00624 str = rb_str_new(0, algo->digest_len);
00625 algo->finish_func(pctx, (unsigned char *)RSTRING_PTR(str));
00626
00627
00628 algo->init_func(pctx);
00629
00630 return str;
00631 }
00632
00633
00634 static VALUE
00635 rb_digest_base_digest_length(VALUE self)
00636 {
00637 rb_digest_metadata_t *algo;
00638
00639 algo = get_digest_base_metadata(rb_obj_class(self));
00640
00641 return INT2NUM(algo->digest_len);
00642 }
00643
00644
00645 static VALUE
00646 rb_digest_base_block_length(VALUE self)
00647 {
00648 rb_digest_metadata_t *algo;
00649
00650 algo = get_digest_base_metadata(rb_obj_class(self));
00651
00652 return INT2NUM(algo->block_len);
00653 }
00654
00655 void
00656 Init_digest(void)
00657 {
00658 id_reset = rb_intern("reset");
00659 id_update = rb_intern("update");
00660 id_finish = rb_intern("finish");
00661 id_digest = rb_intern("digest");
00662 id_hexdigest = rb_intern("hexdigest");
00663 id_digest_length = rb_intern("digest_length");
00664
00665
00666
00667
00668 rb_mDigest = rb_define_module("Digest");
00669
00670
00671 rb_define_module_function(rb_mDigest, "hexencode", rb_digest_s_hexencode, 1);
00672
00673
00674
00675
00676 rb_mDigest_Instance = rb_define_module_under(rb_mDigest, "Instance");
00677
00678
00679 rb_define_method(rb_mDigest_Instance, "update", rb_digest_instance_update, 1);
00680 rb_define_method(rb_mDigest_Instance, "<<", rb_digest_instance_update, 1);
00681 rb_define_private_method(rb_mDigest_Instance, "finish", rb_digest_instance_finish, 0);
00682 rb_define_method(rb_mDigest_Instance, "reset", rb_digest_instance_reset, 0);
00683 rb_define_method(rb_mDigest_Instance, "digest_length", rb_digest_instance_digest_length, 0);
00684 rb_define_method(rb_mDigest_Instance, "block_length", rb_digest_instance_block_length, 0);
00685
00686
00687 rb_define_method(rb_mDigest_Instance, "==", rb_digest_instance_equal, 1);
00688 rb_define_method(rb_mDigest_Instance, "inspect", rb_digest_instance_inspect, 0);
00689
00690
00691 rb_define_method(rb_mDigest_Instance, "new", rb_digest_instance_new, 0);
00692 rb_define_method(rb_mDigest_Instance, "digest", rb_digest_instance_digest, -1);
00693 rb_define_method(rb_mDigest_Instance, "digest!", rb_digest_instance_digest_bang, 0);
00694 rb_define_method(rb_mDigest_Instance, "hexdigest", rb_digest_instance_hexdigest, -1);
00695 rb_define_method(rb_mDigest_Instance, "hexdigest!", rb_digest_instance_hexdigest_bang, 0);
00696 rb_define_method(rb_mDigest_Instance, "to_s", rb_digest_instance_to_s, 0);
00697 rb_define_method(rb_mDigest_Instance, "length", rb_digest_instance_length, 0);
00698 rb_define_method(rb_mDigest_Instance, "size", rb_digest_instance_length, 0);
00699
00700
00701
00702
00703 rb_cDigest_Class = rb_define_class_under(rb_mDigest, "Class", rb_cObject);
00704 rb_define_method(rb_cDigest_Class, "initialize", rb_digest_class_init, 0);
00705 rb_include_module(rb_cDigest_Class, rb_mDigest_Instance);
00706
00707
00708 rb_define_singleton_method(rb_cDigest_Class, "digest", rb_digest_class_s_digest, -1);
00709 rb_define_singleton_method(rb_cDigest_Class, "hexdigest", rb_digest_class_s_hexdigest, -1);
00710
00711 id_metadata = rb_intern("metadata");
00712
00713
00714 rb_cDigest_Base = rb_define_class_under(rb_mDigest, "Base", rb_cDigest_Class);
00715
00716 rb_define_alloc_func(rb_cDigest_Base, rb_digest_base_alloc);
00717
00718 rb_define_method(rb_cDigest_Base, "initialize_copy", rb_digest_base_copy, 1);
00719 rb_define_method(rb_cDigest_Base, "reset", rb_digest_base_reset, 0);
00720 rb_define_method(rb_cDigest_Base, "update", rb_digest_base_update, 1);
00721 rb_define_method(rb_cDigest_Base, "<<", rb_digest_base_update, 1);
00722 rb_define_private_method(rb_cDigest_Base, "finish", rb_digest_base_finish, 0);
00723 rb_define_method(rb_cDigest_Base, "digest_length", rb_digest_base_digest_length, 0);
00724 rb_define_method(rb_cDigest_Base, "block_length", rb_digest_base_block_length, 0);
00725 }
00726