Ruby
1.9.3p429(2013-05-15revision40747)
Main Page
Modules
Data Structures
Files
File List
Globals
ext
digest
digest.c
Go to the documentation of this file.
1
/************************************************
2
3
digest.c -
4
5
$Author: drbrain $
6
created at: Fri May 25 08:57:27 JST 2001
7
8
Copyright (C) 1995-2001 Yukihiro Matsumoto
9
Copyright (C) 2001-2006 Akinori MUSHA
10
11
$RoughId: digest.c,v 1.16 2001/07/13 15:38:27 knu Exp $
12
$Id: digest.c 32951 2011-08-12 17:26:00Z drbrain $
13
14
************************************************/
15
16
#include "
digest.h
"
17
18
static
VALUE
rb_mDigest
;
19
static
VALUE
rb_mDigest_Instance
;
20
static
VALUE
rb_cDigest_Class
;
21
static
VALUE
rb_cDigest_Base
;
22
23
static
ID
id_reset
,
id_update
,
id_finish
,
id_digest
,
id_hexdigest
,
id_digest_length
;
24
static
ID
id_metadata
;
25
26
RUBY_EXTERN
void
Init_digest_base
(
void
);
27
28
/*
29
* Document-module: Digest
30
*
31
* This module provides a framework for message digest libraries.
32
*
33
* You may want to look at OpenSSL::Digest as it supports support more
34
* algorithms.
35
*
36
* A cryptographic hash function is a procedure that takes data and return a
37
* fixed bit string : the hash value, also known as _digest_. Hash functions
38
* are also called one-way functions, it is easy to compute a digest from
39
* a message, but it is infeasible to generate a message from a digest.
40
*
41
* == Example
42
*
43
* require 'digest'
44
*
45
* # Compute a complete digest
46
* sha256 = Digest::SHA256.new
47
* digest = sha256.digest message
48
*
49
* # Compute digest by chunks
50
* sha256 = Digest::SHA256.new
51
* sha256.update message1
52
* sha256 << message2 # << is an alias for update
53
*
54
* digest = sha256.digest
55
*
56
* == Digest algorithms
57
*
58
* Different digest algorithms (or hash functions) are available :
59
*
60
* HMAC::
61
* See FIPS PUB 198 The Keyed-Hash Message Authentication Code (HMAC)
62
* RIPEMD-160::
63
* (as Digest::RMD160) see
64
* http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
65
* SHA1::
66
* See FIPS 180 Secure Hash Standard
67
* SHA2 family::
68
* See FIPS 180 Secure Hash Standard which defines the following algorithms:
69
* * SHA512
70
* * SHA384
71
* * SHA256
72
*
73
* The latest versions of the FIPS publications can be found here:
74
* http://csrc.nist.gov/publications/PubsFIPS.html
75
*
76
* Additionally Digest::BubbleBabble encodes a digest as a sequence of
77
* consonants and vowels which is more recognizable and comparable than a
78
* hexadecimal digest. See http://en.wikipedia.org/wiki/Bubblebabble
79
*/
80
81
static
VALUE
82
hexencode_str_new
(
VALUE
str_digest)
83
{
84
char
*digest;
85
size_t
digest_len;
86
size_t
i
;
87
VALUE
str;
88
char
*
p
;
89
static
const
char
hex[] = {
90
'0'
,
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'6'
,
'7'
,
'8'
,
'9'
,
91
'a'
,
'b'
,
'c'
,
'd'
,
'e'
,
'f'
92
};
93
94
StringValue
(str_digest);
95
digest =
RSTRING_PTR
(str_digest);
96
digest_len =
RSTRING_LEN
(str_digest);
97
98
if
(
LONG_MAX
/ 2 < digest_len) {
99
rb_raise
(
rb_eRuntimeError
,
"digest string too long"
);
100
}
101
102
str =
rb_str_new
(0, digest_len * 2);
103
104
for
(i = 0, p =
RSTRING_PTR
(str); i < digest_len; i++) {
105
unsigned
char
byte = digest[
i
];
106
107
p[i +
i
] = hex[byte >> 4];
108
p[i + i + 1] = hex[byte & 0x0f];
109
}
110
111
return
str;
112
}
113
114
/*
115
* call-seq:
116
* Digest.hexencode(string) -> hexencoded_string
117
*
118
* Generates a hex-encoded version of a given _string_.
119
*/
120
static
VALUE
121
rb_digest_s_hexencode
(
VALUE
klass,
VALUE
str)
122
{
123
return
hexencode_str_new
(str);
124
}
125
126
NORETURN
(
static
void
rb_digest_instance_method_unimpl
(
VALUE
self
,
const
char
*method));
127
128
/*
129
* Document-module: Digest::Instance
130
*
131
* This module provides instance methods for a digest implementation
132
* object to calculate message digest values.
133
*/
134
135
static
void
136
rb_digest_instance_method_unimpl
(
VALUE
self
,
const
char
*method)
137
{
138
rb_raise
(
rb_eRuntimeError
,
"%s does not implement %s()"
,
139
rb_obj_classname
(
self
), method);
140
}
141
142
/*
143
* call-seq:
144
* digest_obj.update(string) -> digest_obj
145
* digest_obj << string -> digest_obj
146
*
147
* Updates the digest using a given _string_ and returns self.
148
*
149
* The update() method and the left-shift operator are overridden by
150
* each implementation subclass. (One should be an alias for the
151
* other)
152
*/
153
static
VALUE
154
rb_digest_instance_update
(
VALUE
self
,
VALUE
str)
155
{
156
rb_digest_instance_method_unimpl
(
self
,
"update"
);
157
}
158
159
/*
160
* call-seq:
161
* digest_obj.instance_eval { finish } -> digest_obj
162
*
163
* Finishes the digest and returns the resulting hash value.
164
*
165
* This method is overridden by each implementation subclass and often
166
* made private, because some of those subclasses may leave internal
167
* data uninitialized. Do not call this method from outside. Use
168
* #digest!() instead, which ensures that internal data be reset for
169
* security reasons.
170
*/
171
static
VALUE
172
rb_digest_instance_finish
(
VALUE
self
)
173
{
174
rb_digest_instance_method_unimpl
(
self
,
"finish"
);
175
}
176
177
/*
178
* call-seq:
179
* digest_obj.reset -> digest_obj
180
*
181
* Resets the digest to the initial state and returns self.
182
*
183
* This method is overridden by each implementation subclass.
184
*/
185
static
VALUE
186
rb_digest_instance_reset
(
VALUE
self
)
187
{
188
rb_digest_instance_method_unimpl
(
self
,
"reset"
);
189
}
190
191
/*
192
* call-seq:
193
* digest_obj.new -> another_digest_obj
194
*
195
* Returns a new, initialized copy of the digest object. Equivalent
196
* to digest_obj.clone().reset().
197
*/
198
static
VALUE
199
rb_digest_instance_new
(
VALUE
self
)
200
{
201
VALUE
clone =
rb_obj_clone
(
self
);
202
rb_funcall
(clone,
id_reset
, 0);
203
return
clone;
204
}
205
206
/*
207
* call-seq:
208
* digest_obj.digest -> string
209
* digest_obj.digest(string) -> string
210
*
211
* If none is given, returns the resulting hash value of the digest,
212
* keeping the digest's state.
213
*
214
* If a _string_ is given, returns the hash value for the given
215
* _string_, resetting the digest to the initial state before and
216
* after the process.
217
*/
218
static
VALUE
219
rb_digest_instance_digest
(
int
argc
,
VALUE
*
argv
,
VALUE
self
)
220
{
221
VALUE
str, value;
222
223
if
(
rb_scan_args
(argc, argv,
"01"
, &str) > 0) {
224
rb_funcall
(
self
,
id_reset
, 0);
225
rb_funcall
(
self
,
id_update
, 1, str);
226
value =
rb_funcall
(
self
,
id_finish
, 0);
227
rb_funcall
(
self
,
id_reset
, 0);
228
}
else
{
229
value =
rb_funcall
(
rb_obj_clone
(
self
),
id_finish
, 0);
230
}
231
232
return
value;
233
}
234
235
/*
236
* call-seq:
237
* digest_obj.digest! -> string
238
*
239
* Returns the resulting hash value and resets the digest to the
240
* initial state.
241
*/
242
static
VALUE
243
rb_digest_instance_digest_bang
(
VALUE
self
)
244
{
245
VALUE
value =
rb_funcall
(
self
,
id_finish
, 0);
246
rb_funcall
(
self
,
id_reset
, 0);
247
248
return
value;
249
}
250
251
/*
252
* call-seq:
253
* digest_obj.hexdigest -> string
254
* digest_obj.hexdigest(string) -> string
255
*
256
* If none is given, returns the resulting hash value of the digest in
257
* a hex-encoded form, keeping the digest's state.
258
*
259
* If a _string_ is given, returns the hash value for the given
260
* _string_ in a hex-encoded form, resetting the digest to the initial
261
* state before and after the process.
262
*/
263
static
VALUE
264
rb_digest_instance_hexdigest
(
int
argc
,
VALUE
*
argv
,
VALUE
self
)
265
{
266
VALUE
str, value;
267
268
if
(
rb_scan_args
(argc, argv,
"01"
, &str) > 0) {
269
rb_funcall
(
self
,
id_reset
, 0);
270
rb_funcall
(
self
,
id_update
, 1, str);
271
value =
rb_funcall
(
self
,
id_finish
, 0);
272
rb_funcall
(
self
,
id_reset
, 0);
273
}
else
{
274
value =
rb_funcall
(
rb_obj_clone
(
self
),
id_finish
, 0);
275
}
276
277
return
hexencode_str_new
(value);
278
}
279
280
/*
281
* call-seq:
282
* digest_obj.hexdigest! -> string
283
*
284
* Returns the resulting hash value in a hex-encoded form and resets
285
* the digest to the initial state.
286
*/
287
static
VALUE
288
rb_digest_instance_hexdigest_bang
(
VALUE
self
)
289
{
290
VALUE
value =
rb_funcall
(
self
,
id_finish
, 0);
291
rb_funcall
(
self
,
id_reset
, 0);
292
293
return
hexencode_str_new
(value);
294
}
295
296
/*
297
* call-seq:
298
* digest_obj.to_s -> string
299
*
300
* Returns digest_obj.hexdigest().
301
*/
302
static
VALUE
303
rb_digest_instance_to_s
(
VALUE
self
)
304
{
305
return
rb_funcall
(
self
,
id_hexdigest
, 0);
306
}
307
308
/*
309
* call-seq:
310
* digest_obj.inspect -> string
311
*
312
* Creates a printable version of the digest object.
313
*/
314
static
VALUE
315
rb_digest_instance_inspect
(
VALUE
self
)
316
{
317
VALUE
str;
318
size_t
digest_len = 32;
/* about this size at least */
319
const
char
*cname;
320
321
cname =
rb_obj_classname
(
self
);
322
323
/* #<Digest::ClassName: xxxxx...xxxx> */
324
str =
rb_str_buf_new
(2 +
strlen
(cname) + 2 + digest_len * 2 + 1);
325
rb_str_buf_cat2
(str,
"#<"
);
326
rb_str_buf_cat2
(str, cname);
327
rb_str_buf_cat2
(str,
": "
);
328
rb_str_buf_append
(str,
rb_digest_instance_hexdigest
(0, 0,
self
));
329
rb_str_buf_cat2
(str,
">"
);
330
return
str;
331
}
332
333
/*
334
* call-seq:
335
* digest_obj == another_digest_obj -> boolean
336
* digest_obj == string -> boolean
337
*
338
* If a string is given, checks whether it is equal to the hex-encoded
339
* hash value of the digest object. If another digest instance is
340
* given, checks whether they have the same hash value. Otherwise
341
* returns false.
342
*/
343
static
VALUE
344
rb_digest_instance_equal
(
VALUE
self
,
VALUE
other)
345
{
346
VALUE
str1, str2;
347
348
if
(
rb_obj_is_kind_of
(other,
rb_mDigest_Instance
) ==
Qtrue
) {
349
str1 =
rb_digest_instance_digest
(0, 0,
self
);
350
str2 =
rb_digest_instance_digest
(0, 0, other);
351
}
else
{
352
str1 =
rb_digest_instance_to_s
(
self
);
353
str2 = other;
354
}
355
356
/* never blindly assume that subclass methods return strings */
357
StringValue
(str1);
358
StringValue
(str2);
359
360
if
(
RSTRING_LEN
(str1) ==
RSTRING_LEN
(str2) &&
361
rb_str_cmp
(str1, str2) == 0) {
362
return
Qtrue
;
363
}
364
return
Qfalse
;
365
}
366
367
/*
368
* call-seq:
369
* digest_obj.digest_length -> integer
370
*
371
* Returns the length of the hash value of the digest.
372
*
373
* This method should be overridden by each implementation subclass.
374
* If not, digest_obj.digest().length() is returned.
375
*/
376
static
VALUE
377
rb_digest_instance_digest_length
(
VALUE
self
)
378
{
379
/* subclasses really should redefine this method */
380
VALUE
digest =
rb_digest_instance_digest
(0, 0,
self
);
381
382
/* never blindly assume that #digest() returns a string */
383
StringValue
(digest);
384
return
INT2NUM
(
RSTRING_LEN
(digest));
385
}
386
387
/*
388
* call-seq:
389
* digest_obj.length -> integer
390
* digest_obj.size -> integer
391
*
392
* Returns digest_obj.digest_length().
393
*/
394
static
VALUE
395
rb_digest_instance_length
(
VALUE
self
)
396
{
397
return
rb_funcall
(
self
,
id_digest_length
, 0);
398
}
399
400
/*
401
* call-seq:
402
* digest_obj.block_length -> integer
403
*
404
* Returns the block length of the digest.
405
*
406
* This method is overridden by each implementation subclass.
407
*/
408
static
VALUE
409
rb_digest_instance_block_length
(
VALUE
self
)
410
{
411
rb_digest_instance_method_unimpl
(
self
,
"block_length"
);
412
}
413
414
/*
415
* Document-class: Digest::Class
416
*
417
* This module stands as a base class for digest implementation
418
* classes.
419
*/
420
421
/*
422
* call-seq:
423
* Digest::Class.digest(string, *parameters) -> hash_string
424
*
425
* Returns the hash value of a given _string_. This is equivalent to
426
* Digest::Class.new(*parameters).digest(string), where extra
427
* _parameters_, if any, are passed through to the constructor and the
428
* _string_ is passed to #digest().
429
*/
430
static
VALUE
431
rb_digest_class_s_digest
(
int
argc
,
VALUE
*
argv
,
VALUE
klass)
432
{
433
VALUE
str;
434
volatile
VALUE
obj;
435
436
if
(argc < 1) {
437
rb_raise
(
rb_eArgError
,
"no data given"
);
438
}
439
440
str = *argv++;
441
argc--;
442
443
StringValue
(str);
444
445
obj =
rb_obj_alloc
(klass);
446
rb_obj_call_init
(obj, argc, argv);
447
448
return
rb_funcall
(obj,
id_digest
, 1, str);
449
}
450
451
/*
452
* call-seq:
453
* Digest::Class.hexdigest(string[, ...]) -> hash_string
454
*
455
* Returns the hex-encoded hash value of a given _string_. This is
456
* almost equivalent to
457
* Digest.hexencode(Digest::Class.new(*parameters).digest(string)).
458
*/
459
static
VALUE
460
rb_digest_class_s_hexdigest
(
int
argc
,
VALUE
*
argv
,
VALUE
klass)
461
{
462
return
hexencode_str_new
(
rb_funcall2
(klass,
id_digest
, argc, argv));
463
}
464
465
/* :nodoc: */
466
static
VALUE
467
rb_digest_class_init
(
VALUE
self
)
468
{
469
return
self
;
470
}
471
472
/*
473
* Document-class: Digest::Base
474
*
475
* This abstract class provides a common interface to message digest
476
* implementation classes written in C.
477
*/
478
479
static
rb_digest_metadata_t
*
480
get_digest_base_metadata
(
VALUE
klass)
481
{
482
VALUE
p
;
483
VALUE
obj;
484
rb_digest_metadata_t
*algo;
485
486
for
(p = klass; !
NIL_P
(p); p =
rb_class_superclass
(p)) {
487
if
(
rb_ivar_defined
(p,
id_metadata
)) {
488
obj =
rb_ivar_get
(p,
id_metadata
);
489
break
;
490
}
491
}
492
493
if
(
NIL_P
(p))
494
rb_raise
(
rb_eRuntimeError
,
"Digest::Base cannot be directly inherited in Ruby"
);
495
496
Data_Get_Struct
(obj,
rb_digest_metadata_t
, algo);
497
498
switch
(algo->
api_version
) {
499
case
2:
500
break
;
501
502
/*
503
* put conversion here if possible when API is updated
504
*/
505
506
default
:
507
rb_raise
(
rb_eRuntimeError
,
"Incompatible digest API version"
);
508
}
509
510
return
algo;
511
}
512
513
static
VALUE
514
rb_digest_base_alloc
(
VALUE
klass)
515
{
516
rb_digest_metadata_t
*algo;
517
VALUE
obj;
518
void
*pctx;
519
520
if
(klass ==
rb_cDigest_Base
) {
521
rb_raise
(
rb_eNotImpError
,
"Digest::Base is an abstract class"
);
522
}
523
524
algo =
get_digest_base_metadata
(klass);
525
526
pctx =
xmalloc
(algo->
ctx_size
);
527
algo->
init_func
(pctx);
528
529
obj =
Data_Wrap_Struct
(klass, 0,
xfree
, pctx);
530
531
return
obj;
532
}
533
534
/* :nodoc: */
535
static
VALUE
536
rb_digest_base_copy
(
VALUE
copy,
VALUE
obj)
537
{
538
rb_digest_metadata_t
*algo;
539
void
*pctx1, *pctx2;
540
541
if
(copy == obj)
return
copy;
542
543
rb_check_frozen
(copy);
544
545
algo =
get_digest_base_metadata
(
rb_obj_class
(copy));
546
547
Data_Get_Struct
(obj,
void
, pctx1);
548
Data_Get_Struct
(copy,
void
, pctx2);
549
memcpy(pctx2, pctx1, algo->
ctx_size
);
550
551
return
copy;
552
}
553
554
/* :nodoc: */
555
static
VALUE
556
rb_digest_base_reset
(
VALUE
self
)
557
{
558
rb_digest_metadata_t
*algo;
559
void
*pctx;
560
561
algo =
get_digest_base_metadata
(
rb_obj_class
(
self
));
562
563
Data_Get_Struct
(
self
,
void
, pctx);
564
565
algo->
init_func
(pctx);
566
567
return
self
;
568
}
569
570
/* :nodoc: */
571
static
VALUE
572
rb_digest_base_update
(
VALUE
self
,
VALUE
str)
573
{
574
rb_digest_metadata_t
*algo;
575
void
*pctx;
576
577
algo =
get_digest_base_metadata
(
rb_obj_class
(
self
));
578
579
Data_Get_Struct
(
self
,
void
, pctx);
580
581
StringValue
(str);
582
algo->
update_func
(pctx, (
unsigned
char
*)
RSTRING_PTR
(str),
RSTRING_LEN
(str));
583
584
return
self
;
585
}
586
587
/* :nodoc: */
588
static
VALUE
589
rb_digest_base_finish
(
VALUE
self
)
590
{
591
rb_digest_metadata_t
*algo;
592
void
*pctx;
593
VALUE
str;
594
595
algo =
get_digest_base_metadata
(
rb_obj_class
(
self
));
596
597
Data_Get_Struct
(
self
,
void
, pctx);
598
599
str =
rb_str_new
(0, algo->
digest_len
);
600
algo->
finish_func
(pctx, (
unsigned
char
*)
RSTRING_PTR
(str));
601
602
/* avoid potential coredump caused by use of a finished context */
603
algo->
init_func
(pctx);
604
605
return
str;
606
}
607
608
/* :nodoc: */
609
static
VALUE
610
rb_digest_base_digest_length
(
VALUE
self
)
611
{
612
rb_digest_metadata_t
*algo;
613
614
algo =
get_digest_base_metadata
(
rb_obj_class
(
self
));
615
616
return
INT2NUM
(algo->
digest_len
);
617
}
618
619
/* :nodoc: */
620
static
VALUE
621
rb_digest_base_block_length
(
VALUE
self
)
622
{
623
rb_digest_metadata_t
*algo;
624
625
algo =
get_digest_base_metadata
(
rb_obj_class
(
self
));
626
627
return
INT2NUM
(algo->
block_len
);
628
}
629
630
void
631
Init_digest
(
void
)
632
{
633
id_reset
=
rb_intern
(
"reset"
);
634
id_update
=
rb_intern
(
"update"
);
635
id_finish
=
rb_intern
(
"finish"
);
636
id_digest
=
rb_intern
(
"digest"
);
637
id_hexdigest
=
rb_intern
(
"hexdigest"
);
638
id_digest_length
=
rb_intern
(
"digest_length"
);
639
640
/*
641
* module Digest
642
*/
643
rb_mDigest
=
rb_define_module
(
"Digest"
);
644
645
/* module functions */
646
rb_define_module_function
(
rb_mDigest
,
"hexencode"
,
rb_digest_s_hexencode
, 1);
647
648
/*
649
* module Digest::Instance
650
*/
651
rb_mDigest_Instance
=
rb_define_module_under
(
rb_mDigest
,
"Instance"
);
652
653
/* instance methods that should be overridden */
654
rb_define_method
(
rb_mDigest_Instance
,
"update"
,
rb_digest_instance_update
, 1);
655
rb_define_method
(
rb_mDigest_Instance
,
"<<"
,
rb_digest_instance_update
, 1);
656
rb_define_private_method
(
rb_mDigest_Instance
,
"finish"
,
rb_digest_instance_finish
, 0);
657
rb_define_method
(
rb_mDigest_Instance
,
"reset"
,
rb_digest_instance_reset
, 0);
658
rb_define_method
(
rb_mDigest_Instance
,
"digest_length"
,
rb_digest_instance_digest_length
, 0);
659
rb_define_method
(
rb_mDigest_Instance
,
"block_length"
,
rb_digest_instance_block_length
, 0);
660
661
/* instance methods that may be overridden */
662
rb_define_method
(
rb_mDigest_Instance
,
"=="
,
rb_digest_instance_equal
, 1);
663
rb_define_method
(
rb_mDigest_Instance
,
"inspect"
,
rb_digest_instance_inspect
, 0);
664
665
/* instance methods that need not usually be overridden */
666
rb_define_method
(
rb_mDigest_Instance
,
"new"
,
rb_digest_instance_new
, 0);
667
rb_define_method
(
rb_mDigest_Instance
,
"digest"
,
rb_digest_instance_digest
, -1);
668
rb_define_method
(
rb_mDigest_Instance
,
"digest!"
,
rb_digest_instance_digest_bang
, 0);
669
rb_define_method
(
rb_mDigest_Instance
,
"hexdigest"
,
rb_digest_instance_hexdigest
, -1);
670
rb_define_method
(
rb_mDigest_Instance
,
"hexdigest!"
,
rb_digest_instance_hexdigest_bang
, 0);
671
rb_define_method
(
rb_mDigest_Instance
,
"to_s"
,
rb_digest_instance_to_s
, 0);
672
rb_define_method
(
rb_mDigest_Instance
,
"length"
,
rb_digest_instance_length
, 0);
673
rb_define_method
(
rb_mDigest_Instance
,
"size"
,
rb_digest_instance_length
, 0);
674
675
/*
676
* class Digest::Class
677
*/
678
rb_cDigest_Class
=
rb_define_class_under
(
rb_mDigest
,
"Class"
,
rb_cObject
);
679
rb_define_method
(
rb_cDigest_Class
,
"initialize"
,
rb_digest_class_init
, 0);
680
rb_include_module
(
rb_cDigest_Class
,
rb_mDigest_Instance
);
681
682
/* class methods */
683
rb_define_singleton_method
(
rb_cDigest_Class
,
"digest"
,
rb_digest_class_s_digest
, -1);
684
rb_define_singleton_method
(
rb_cDigest_Class
,
"hexdigest"
,
rb_digest_class_s_hexdigest
, -1);
685
686
id_metadata
=
rb_intern
(
"metadata"
);
687
688
/* class Digest::Base < Digest::Class */
689
rb_cDigest_Base
=
rb_define_class_under
(
rb_mDigest
,
"Base"
,
rb_cDigest_Class
);
690
691
rb_define_alloc_func
(
rb_cDigest_Base
,
rb_digest_base_alloc
);
692
693
rb_define_method
(
rb_cDigest_Base
,
"initialize_copy"
,
rb_digest_base_copy
, 1);
694
rb_define_method
(
rb_cDigest_Base
,
"reset"
,
rb_digest_base_reset
, 0);
695
rb_define_method
(
rb_cDigest_Base
,
"update"
,
rb_digest_base_update
, 1);
696
rb_define_method
(
rb_cDigest_Base
,
"<<"
,
rb_digest_base_update
, 1);
697
rb_define_private_method
(
rb_cDigest_Base
,
"finish"
,
rb_digest_base_finish
, 0);
698
rb_define_method
(
rb_cDigest_Base
,
"digest_length"
,
rb_digest_base_digest_length
, 0);
699
rb_define_method
(
rb_cDigest_Base
,
"block_length"
,
rb_digest_base_block_length
, 0);
700
}
701
Generated on Thu May 23 2013 20:33:01 for Ruby by
1.8.3