digest 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 167eabf30e08121767b43efb87416093469e9b13742ec848645eb1e0108fbd01
4
+ data.tar.gz: 2689f6fc2502e420fc0b07ea1318f280089c9983c3081003a275e29b12cf9bfc
5
+ SHA512:
6
+ metadata.gz: 1bb1bb02c2d95a2e11b305ca813a8af85f7edb47b0eb4b2300b383af38be233ebf48ea4ba63467c8991a37ff03f676f3c01c5317221d8019dfd5d5b2a0db5442
7
+ data.tar.gz: 4fe7e3d971977df6eec664073973a26b29bb413c3975a254953c74fc8845ddefb003a8eeed1aa5a8ee9fe5b38b21ec774f33dabfba0db2e9542555cfd5373965
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
@@ -0,0 +1,8 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.6
5
+ - 2.4.3
6
+ - 2.5.0
7
+ - ruby-head
8
+ before_install: gem install bundler
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in digest.gemspec
6
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+ 1. Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
16
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22
+ SUCH DAMAGE.
@@ -0,0 +1,97 @@
1
+ # Digest
2
+
3
+ [![Build Status](https://travis-ci.org/ruby/digest.svg?branch=master)](https://travis-ci.org/ruby/digest)
4
+
5
+ This module provides a framework for message digest libraries.
6
+
7
+ You may want to look at OpenSSL::Digest as it supports more algorithms.
8
+
9
+ A cryptographic hash function is a procedure that takes data and returns a fixed bit string: the hash value, also known as _digest_. Hash functions are also called one-way functions, it is easy to compute a digest from a message, but it is infeasible to generate a message from a digest.
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ ```ruby
16
+ gem 'digest'
17
+ ```
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install digest
26
+
27
+ ## Usage
28
+
29
+ ```ruby
30
+ require 'digest'
31
+
32
+ # Compute a complete digest
33
+ Digest::SHA256.digest 'message' #=> "\xABS\n\x13\xE4Y..."
34
+
35
+ sha256 = Digest::SHA256.new
36
+ sha256.digest 'message' #=> "\xABS\n\x13\xE4Y..."
37
+
38
+ # Other encoding formats
39
+ Digest::SHA256.hexdigest 'message' #=> "ab530a13e459..."
40
+ Digest::SHA256.base64digest 'message' #=> "q1MKE+RZFJgr..."
41
+
42
+ # Compute digest by chunks
43
+ md5 = Digest::MD5.new
44
+ md5.update 'message1'
45
+ md5 << 'message2' # << is an alias for update
46
+
47
+ md5.hexdigest #=> "94af09c09bb9..."
48
+
49
+ # Compute digest for a file
50
+ sha256 = Digest::SHA256.file 'testfile'
51
+ sha256.hexdigest
52
+ ```
53
+
54
+ Additionally digests can be encoded in "bubble babble" format as a sequence of consonants and vowels which is more recognizable and comparable than a hexadecimal digest.
55
+
56
+ ```ruby
57
+ require 'digest/bubblebabble'
58
+
59
+ Digest::SHA256.bubblebabble 'message' #=> "xopoh-fedac-fenyh-..."
60
+ ```
61
+
62
+ See the bubble babble specification at http://web.mit.edu/kenta/www/one/bubblebabble/spec/jrtrjwzi/draft-huima-01.txt.
63
+
64
+ ## Digest algorithms
65
+
66
+ Different digest algorithms (or hash functions) are available:
67
+
68
+ ```
69
+ MD5::
70
+ See RFC 1321 The MD5 Message-Digest Algorithm
71
+ RIPEMD-160::
72
+ As Digest::RMD160.
73
+ See http://homes.esat.kuleuven.be/~bosselae/ripemd160.html.
74
+ SHA1::
75
+ See FIPS 180 Secure Hash Standard.
76
+ SHA2 family::
77
+ See FIPS 180 Secure Hash Standard which defines the following algorithms:
78
+ SHA512
79
+ SHA384
80
+ SHA256
81
+ ```
82
+
83
+ The latest versions of the FIPS publications can be found here: http://csrc.nist.gov/publications/PubsFIPS.html.
84
+
85
+ ## Development
86
+
87
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
88
+
89
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
90
+
91
+ ## Contributing
92
+
93
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/digest.
94
+
95
+ ## License
96
+
97
+ The gem is available as open source under the terms of the [2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause).
@@ -0,0 +1,15 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test" << "test/lib"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/test_*.rb"]
8
+ end
9
+
10
+ require 'rake/extensiontask'
11
+ %w(bubblebabble md5 rmd160 sha1 sha2).each do |ext|
12
+ Rake::ExtensionTask.new("digest/#{ext}")
13
+ end
14
+
15
+ task :default => :test
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "digest"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,45 @@
1
+ # coding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "digest"
6
+ spec.version = "1.0.0"
7
+ spec.authors = ["Akinori MUSHA"]
8
+ spec.email = ["knu@idaemons.org"]
9
+
10
+ spec.summary = %q{Provides a framework for message digest libraries.}
11
+ spec.description = %q{Provides a framework for message digest libraries.}
12
+ spec.homepage = "https://github.com/ruby/digest"
13
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
14
+
15
+ spec.files = [
16
+ ".gitignore", ".travis.yml", "Gemfile", "LICENSE.txt", "README.md", "Rakefile", "bin/console", "bin/setup",
17
+ "digest.gemspec", "ext/digest/bubblebabble/bubblebabble.c", "ext/digest/bubblebabble/extconf.rb", "ext/digest/defs.h",
18
+ "ext/digest/digest.c", "ext/digest/digest.h", "ext/digest/digest_conf.rb", "ext/digest/extconf.rb",
19
+ "ext/digest/md5/extconf.rb", "ext/digest/md5/md5.c", "ext/digest/md5/md5.h", "ext/digest/md5/md5cc.h",
20
+ "ext/digest/md5/md5init.c", "ext/digest/rmd160/extconf.rb", "ext/digest/rmd160/rmd160.c",
21
+ "ext/digest/rmd160/rmd160.h", "ext/digest/rmd160/rmd160init.c",
22
+ "ext/digest/sha1/extconf.rb", "ext/digest/sha1/sha1.c", "ext/digest/sha1/sha1.h", "ext/digest/sha1/sha1cc.h",
23
+ "ext/digest/sha1/sha1init.c", "ext/digest/sha2/extconf.rb", "ext/digest/sha2/lib/sha2.rb",
24
+ "ext/digest/sha2/sha2.c", "ext/digest/sha2/sha2.h", "ext/digest/sha2/sha2cc.h", "ext/digest/sha2/sha2init.c",
25
+ "ext/digest/test.sh", "ext/openssl/deprecation.rb", "lib/digest.rb"
26
+ ]
27
+ spec.required_ruby_version = ">= 2.3.0"
28
+
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
+ spec.extensions = %w[
33
+ ext/digest/extconf.rb
34
+ ext/digest/bubblebabble/extconf.rb
35
+ ext/digest/md5/extconf.rb
36
+ ext/digest/rmd160/extconf.rb
37
+ ext/digest/sha1/extconf.rb
38
+ ext/digest/sha2/extconf.rb
39
+ ]
40
+ spec.metadata["msys2_mingw_dependencies"] = "openssl"
41
+
42
+ spec.add_development_dependency "bundler"
43
+ spec.add_development_dependency "rake"
44
+ spec.add_development_dependency "rake-compiler"
45
+ end
@@ -0,0 +1,147 @@
1
+ /************************************************
2
+
3
+ bubblebabble.c - BubbleBabble encoding support
4
+
5
+ $Author$
6
+ created at: Fri Oct 13 18:31:42 JST 2006
7
+
8
+ Copyright (C) 2006 Akinori MUSHA
9
+
10
+ $Id$
11
+
12
+ ************************************************/
13
+
14
+ #include <ruby/ruby.h>
15
+ #include "../digest.h"
16
+
17
+ static ID id_digest;
18
+
19
+ static VALUE
20
+ bubblebabble_str_new(VALUE str_digest)
21
+ {
22
+ char *digest;
23
+ size_t digest_len;
24
+ VALUE str;
25
+ char *p;
26
+ size_t i, j, seed = 1;
27
+ static const char vowels[] = {
28
+ 'a', 'e', 'i', 'o', 'u', 'y'
29
+ };
30
+ static const char consonants[] = {
31
+ 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm', 'n',
32
+ 'p', 'r', 's', 't', 'v', 'z', 'x'
33
+ };
34
+
35
+ StringValue(str_digest);
36
+ digest = RSTRING_PTR(str_digest);
37
+ digest_len = RSTRING_LEN(str_digest);
38
+
39
+ if ((LONG_MAX - 2) / 3 < (digest_len | 1)) {
40
+ rb_raise(rb_eRuntimeError, "digest string too long");
41
+ }
42
+
43
+ str = rb_str_new(0, (digest_len | 1) * 3 + 2);
44
+ p = RSTRING_PTR(str);
45
+
46
+ i = j = 0;
47
+ p[j++] = 'x';
48
+
49
+ for (;;) {
50
+ unsigned char byte1, byte2;
51
+
52
+ if (i >= digest_len) {
53
+ p[j++] = vowels[seed % 6];
54
+ p[j++] = consonants[16];
55
+ p[j++] = vowels[seed / 6];
56
+ break;
57
+ }
58
+
59
+ byte1 = digest[i++];
60
+ p[j++] = vowels[(((byte1 >> 6) & 3) + seed) % 6];
61
+ p[j++] = consonants[(byte1 >> 2) & 15];
62
+ p[j++] = vowels[((byte1 & 3) + (seed / 6)) % 6];
63
+
64
+ if (i >= digest_len) {
65
+ break;
66
+ }
67
+
68
+ byte2 = digest[i++];
69
+ p[j++] = consonants[(byte2 >> 4) & 15];
70
+ p[j++] = '-';
71
+ p[j++] = consonants[byte2 & 15];
72
+
73
+ seed = (seed * 5 + byte1 * 7 + byte2) % 36;
74
+ }
75
+
76
+ p[j] = 'x';
77
+
78
+ return str;
79
+ }
80
+
81
+ /* Document-method: Digest::bubblebabble
82
+ *
83
+ * call-seq:
84
+ * Digest.bubblebabble(string) -> bubblebabble_string
85
+ *
86
+ * Returns a BubbleBabble encoded version of a given _string_.
87
+ */
88
+ static VALUE
89
+ rb_digest_s_bubblebabble(VALUE klass, VALUE str)
90
+ {
91
+ return bubblebabble_str_new(str);
92
+ }
93
+
94
+ /* Document-method: Digest::Class::bubblebabble
95
+ *
96
+ * call-seq:
97
+ * Digest::Class.bubblebabble(string, ...) -> hash_string
98
+ *
99
+ * Returns the BubbleBabble encoded hash value of a given _string_.
100
+ */
101
+ static VALUE
102
+ rb_digest_class_s_bubblebabble(int argc, VALUE *argv, VALUE klass)
103
+ {
104
+ return bubblebabble_str_new(rb_funcallv(klass, id_digest, argc, argv));
105
+ }
106
+
107
+ /* Document-method: Digest::Instance#bubblebabble
108
+ *
109
+ * call-seq:
110
+ * digest_obj.bubblebabble -> hash_string
111
+ *
112
+ * Returns the resulting hash value in a Bubblebabble encoded form.
113
+ */
114
+ static VALUE
115
+ rb_digest_instance_bubblebabble(VALUE self)
116
+ {
117
+ return bubblebabble_str_new(rb_funcall(self, id_digest, 0));
118
+ }
119
+
120
+ /*
121
+ * This module adds some methods to Digest classes to perform
122
+ * BubbleBabble encoding.
123
+ */
124
+ void
125
+ Init_bubblebabble(void)
126
+ {
127
+ #undef rb_intern
128
+ VALUE rb_mDigest, rb_mDigest_Instance, rb_cDigest_Class;
129
+
130
+ rb_require("digest");
131
+
132
+ rb_mDigest = rb_path2class("Digest");
133
+ rb_mDigest_Instance = rb_path2class("Digest::Instance");
134
+ rb_cDigest_Class = rb_path2class("Digest::Class");
135
+
136
+ #if 0
137
+ rb_mDigest = rb_define_module("Digest");
138
+ rb_mDigest_Instance = rb_define_module_under(rb_mDigest, "Instance");
139
+ rb_cDigest_Class = rb_define_class_under(rb_mDigest, "Class", rb_cObject);
140
+ #endif
141
+
142
+ rb_define_module_function(rb_mDigest, "bubblebabble", rb_digest_s_bubblebabble, 1);
143
+ rb_define_singleton_method(rb_cDigest_Class, "bubblebabble", rb_digest_class_s_bubblebabble, -1);
144
+ rb_define_method(rb_mDigest_Instance, "bubblebabble", rb_digest_instance_bubblebabble, 0);
145
+
146
+ id_digest = rb_intern("digest");
147
+ }
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: false
2
+ require 'mkmf'
3
+
4
+ $defs << "-DHAVE_CONFIG_H"
5
+
6
+ create_makefile('digest/bubblebabble')
@@ -0,0 +1,19 @@
1
+ /* -*- C -*-
2
+ * $Id$
3
+ */
4
+
5
+ #ifndef DEFS_H
6
+ #define DEFS_H
7
+
8
+ #include "ruby.h"
9
+ #include <sys/types.h>
10
+
11
+ #if defined(HAVE_SYS_CDEFS_H)
12
+ # include <sys/cdefs.h>
13
+ #endif
14
+ #if !defined(__BEGIN_DECLS)
15
+ # define __BEGIN_DECLS
16
+ # define __END_DECLS
17
+ #endif
18
+
19
+ #endif /* DEFS_H */
@@ -0,0 +1,821 @@
1
+ /************************************************
2
+
3
+ digest.c -
4
+
5
+ $Author$
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$
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 more algorithms.
34
+ *
35
+ * A cryptographic hash function is a procedure that takes data and returns a
36
+ * fixed bit string: the hash value, also known as _digest_. Hash functions
37
+ * are also called one-way functions, it is easy to compute a digest from
38
+ * a message, but it is infeasible to generate a message from a digest.
39
+ *
40
+ * == Examples
41
+ *
42
+ * require 'digest'
43
+ *
44
+ * # Compute a complete digest
45
+ * Digest::SHA256.digest 'message' #=> "\xABS\n\x13\xE4Y..."
46
+ *
47
+ * sha256 = Digest::SHA256.new
48
+ * sha256.digest 'message' #=> "\xABS\n\x13\xE4Y..."
49
+ *
50
+ * # Other encoding formats
51
+ * Digest::SHA256.hexdigest 'message' #=> "ab530a13e459..."
52
+ * Digest::SHA256.base64digest 'message' #=> "q1MKE+RZFJgr..."
53
+ *
54
+ * # Compute digest by chunks
55
+ * md5 = Digest::MD5.new
56
+ * md5.update 'message1'
57
+ * md5 << 'message2' # << is an alias for update
58
+ *
59
+ * md5.hexdigest #=> "94af09c09bb9..."
60
+ *
61
+ * # Compute digest for a file
62
+ * sha256 = Digest::SHA256.file 'testfile'
63
+ * sha256.hexdigest
64
+ *
65
+ * Additionally digests can be encoded in "bubble babble" format as a sequence
66
+ * of consonants and vowels which is more recognizable and comparable than a
67
+ * hexadecimal digest.
68
+ *
69
+ * require 'digest/bubblebabble'
70
+ *
71
+ * Digest::SHA256.bubblebabble 'message' #=> "xopoh-fedac-fenyh-..."
72
+ *
73
+ * See the bubble babble specification at
74
+ * http://web.mit.edu/kenta/www/one/bubblebabble/spec/jrtrjwzi/draft-huima-01.txt.
75
+ *
76
+ * == Digest algorithms
77
+ *
78
+ * Different digest algorithms (or hash functions) are available:
79
+ *
80
+ * MD5::
81
+ * See RFC 1321 The MD5 Message-Digest Algorithm
82
+ * RIPEMD-160::
83
+ * As Digest::RMD160.
84
+ * See http://homes.esat.kuleuven.be/~bosselae/ripemd160.html.
85
+ * SHA1::
86
+ * See FIPS 180 Secure Hash Standard.
87
+ * SHA2 family::
88
+ * See FIPS 180 Secure Hash Standard which defines the following algorithms:
89
+ * * SHA512
90
+ * * SHA384
91
+ * * SHA256
92
+ *
93
+ * The latest versions of the FIPS publications can be found here:
94
+ * http://csrc.nist.gov/publications/PubsFIPS.html.
95
+ */
96
+
97
+ static VALUE
98
+ hexencode_str_new(VALUE str_digest)
99
+ {
100
+ char *digest;
101
+ size_t digest_len;
102
+ size_t i;
103
+ VALUE str;
104
+ char *p;
105
+ static const char hex[] = {
106
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
107
+ 'a', 'b', 'c', 'd', 'e', 'f'
108
+ };
109
+
110
+ StringValue(str_digest);
111
+ digest = RSTRING_PTR(str_digest);
112
+ digest_len = RSTRING_LEN(str_digest);
113
+
114
+ if (LONG_MAX / 2 < digest_len) {
115
+ rb_raise(rb_eRuntimeError, "digest string too long");
116
+ }
117
+
118
+ str = rb_usascii_str_new(0, digest_len * 2);
119
+
120
+ for (i = 0, p = RSTRING_PTR(str); i < digest_len; i++) {
121
+ unsigned char byte = digest[i];
122
+
123
+ p[i + i] = hex[byte >> 4];
124
+ p[i + i + 1] = hex[byte & 0x0f];
125
+ }
126
+
127
+ RB_GC_GUARD(str_digest);
128
+
129
+ return str;
130
+ }
131
+
132
+ /*
133
+ * call-seq:
134
+ * Digest.hexencode(string) -> hexencoded_string
135
+ *
136
+ * Generates a hex-encoded version of a given _string_.
137
+ */
138
+ static VALUE
139
+ rb_digest_s_hexencode(VALUE klass, VALUE str)
140
+ {
141
+ return hexencode_str_new(str);
142
+ }
143
+
144
+ NORETURN(static void rb_digest_instance_method_unimpl(VALUE self, const char *method));
145
+
146
+ /*
147
+ * Document-module: Digest::Instance
148
+ *
149
+ * This module provides instance methods for a digest implementation
150
+ * object to calculate message digest values.
151
+ */
152
+
153
+ static void
154
+ rb_digest_instance_method_unimpl(VALUE self, const char *method)
155
+ {
156
+ rb_raise(rb_eRuntimeError, "%s does not implement %s()",
157
+ rb_obj_classname(self), method);
158
+ }
159
+
160
+ /*
161
+ * call-seq:
162
+ * digest_obj.update(string) -> digest_obj
163
+ * digest_obj << string -> digest_obj
164
+ *
165
+ * Updates the digest using a given _string_ and returns self.
166
+ *
167
+ * The update() method and the left-shift operator are overridden by
168
+ * each implementation subclass. (One should be an alias for the
169
+ * other)
170
+ */
171
+ static VALUE
172
+ rb_digest_instance_update(VALUE self, VALUE str)
173
+ {
174
+ rb_digest_instance_method_unimpl(self, "update");
175
+
176
+ UNREACHABLE;
177
+ }
178
+
179
+ /*
180
+ * call-seq:
181
+ * digest_obj.instance_eval { finish } -> digest_obj
182
+ *
183
+ * Finishes the digest and returns the resulting hash value.
184
+ *
185
+ * This method is overridden by each implementation subclass and often
186
+ * made private, because some of those subclasses may leave internal
187
+ * data uninitialized. Do not call this method from outside. Use
188
+ * #digest!() instead, which ensures that internal data be reset for
189
+ * security reasons.
190
+ */
191
+ static VALUE
192
+ rb_digest_instance_finish(VALUE self)
193
+ {
194
+ rb_digest_instance_method_unimpl(self, "finish");
195
+
196
+ UNREACHABLE;
197
+ }
198
+
199
+ /*
200
+ * call-seq:
201
+ * digest_obj.reset -> digest_obj
202
+ *
203
+ * Resets the digest to the initial state and returns self.
204
+ *
205
+ * This method is overridden by each implementation subclass.
206
+ */
207
+ static VALUE
208
+ rb_digest_instance_reset(VALUE self)
209
+ {
210
+ rb_digest_instance_method_unimpl(self, "reset");
211
+
212
+ UNREACHABLE;
213
+ }
214
+
215
+ /*
216
+ * call-seq:
217
+ * digest_obj.new -> another_digest_obj
218
+ *
219
+ * Returns a new, initialized copy of the digest object. Equivalent
220
+ * to digest_obj.clone().reset().
221
+ */
222
+ static VALUE
223
+ rb_digest_instance_new(VALUE self)
224
+ {
225
+ VALUE clone = rb_obj_clone(self);
226
+ rb_funcall(clone, id_reset, 0);
227
+ return clone;
228
+ }
229
+
230
+ /*
231
+ * call-seq:
232
+ * digest_obj.digest -> string
233
+ * digest_obj.digest(string) -> string
234
+ *
235
+ * If none is given, returns the resulting hash value of the digest,
236
+ * keeping the digest's state.
237
+ *
238
+ * If a _string_ is given, returns the hash value for the given
239
+ * _string_, resetting the digest to the initial state before and
240
+ * after the process.
241
+ */
242
+ static VALUE
243
+ rb_digest_instance_digest(int argc, VALUE *argv, VALUE self)
244
+ {
245
+ VALUE str, value;
246
+
247
+ if (rb_scan_args(argc, argv, "01", &str) > 0) {
248
+ rb_funcall(self, id_reset, 0);
249
+ rb_funcall(self, id_update, 1, str);
250
+ value = rb_funcall(self, id_finish, 0);
251
+ rb_funcall(self, id_reset, 0);
252
+ } else {
253
+ value = rb_funcall(rb_obj_clone(self), id_finish, 0);
254
+ }
255
+
256
+ return value;
257
+ }
258
+
259
+ /*
260
+ * call-seq:
261
+ * digest_obj.digest! -> string
262
+ *
263
+ * Returns the resulting hash value and resets the digest to the
264
+ * initial state.
265
+ */
266
+ static VALUE
267
+ rb_digest_instance_digest_bang(VALUE self)
268
+ {
269
+ VALUE value = rb_funcall(self, id_finish, 0);
270
+ rb_funcall(self, id_reset, 0);
271
+
272
+ return value;
273
+ }
274
+
275
+ /*
276
+ * call-seq:
277
+ * digest_obj.hexdigest -> string
278
+ * digest_obj.hexdigest(string) -> string
279
+ *
280
+ * If none is given, returns the resulting hash value of the digest in
281
+ * a hex-encoded form, keeping the digest's state.
282
+ *
283
+ * If a _string_ is given, returns the hash value for the given
284
+ * _string_ in a hex-encoded form, resetting the digest to the initial
285
+ * state before and after the process.
286
+ */
287
+ static VALUE
288
+ rb_digest_instance_hexdigest(int argc, VALUE *argv, VALUE self)
289
+ {
290
+ VALUE str, value;
291
+
292
+ if (rb_scan_args(argc, argv, "01", &str) > 0) {
293
+ rb_funcall(self, id_reset, 0);
294
+ rb_funcall(self, id_update, 1, str);
295
+ value = rb_funcall(self, id_finish, 0);
296
+ rb_funcall(self, id_reset, 0);
297
+ } else {
298
+ value = rb_funcall(rb_obj_clone(self), id_finish, 0);
299
+ }
300
+
301
+ return hexencode_str_new(value);
302
+ }
303
+
304
+ /*
305
+ * call-seq:
306
+ * digest_obj.hexdigest! -> string
307
+ *
308
+ * Returns the resulting hash value in a hex-encoded form and resets
309
+ * the digest to the initial state.
310
+ */
311
+ static VALUE
312
+ rb_digest_instance_hexdigest_bang(VALUE self)
313
+ {
314
+ VALUE value = rb_funcall(self, id_finish, 0);
315
+ rb_funcall(self, id_reset, 0);
316
+
317
+ return hexencode_str_new(value);
318
+ }
319
+
320
+ /*
321
+ * call-seq:
322
+ * digest_obj.to_s -> string
323
+ *
324
+ * Returns digest_obj.hexdigest().
325
+ */
326
+ static VALUE
327
+ rb_digest_instance_to_s(VALUE self)
328
+ {
329
+ return rb_funcall(self, id_hexdigest, 0);
330
+ }
331
+
332
+ /*
333
+ * call-seq:
334
+ * digest_obj.inspect -> string
335
+ *
336
+ * Creates a printable version of the digest object.
337
+ */
338
+ static VALUE
339
+ rb_digest_instance_inspect(VALUE self)
340
+ {
341
+ VALUE str;
342
+ size_t digest_len = 32; /* about this size at least */
343
+ const char *cname;
344
+
345
+ cname = rb_obj_classname(self);
346
+
347
+ /* #<Digest::ClassName: xxxxx...xxxx> */
348
+ str = rb_str_buf_new(2 + strlen(cname) + 2 + digest_len * 2 + 1);
349
+ rb_str_buf_cat2(str, "#<");
350
+ rb_str_buf_cat2(str, cname);
351
+ rb_str_buf_cat2(str, ": ");
352
+ rb_str_buf_append(str, rb_digest_instance_hexdigest(0, 0, self));
353
+ rb_str_buf_cat2(str, ">");
354
+ return str;
355
+ }
356
+
357
+ /*
358
+ * call-seq:
359
+ * digest_obj == another_digest_obj -> boolean
360
+ * digest_obj == string -> boolean
361
+ *
362
+ * If a string is given, checks whether it is equal to the hex-encoded
363
+ * hash value of the digest object. If another digest instance is
364
+ * given, checks whether they have the same hash value. Otherwise
365
+ * returns false.
366
+ */
367
+ static VALUE
368
+ rb_digest_instance_equal(VALUE self, VALUE other)
369
+ {
370
+ VALUE str1, str2;
371
+
372
+ if (rb_obj_is_kind_of(other, rb_mDigest_Instance) == Qtrue) {
373
+ str1 = rb_digest_instance_digest(0, 0, self);
374
+ str2 = rb_digest_instance_digest(0, 0, other);
375
+ } else {
376
+ str1 = rb_digest_instance_to_s(self);
377
+ str2 = rb_check_string_type(other);
378
+ if (NIL_P(str2)) return Qfalse;
379
+ }
380
+
381
+ /* never blindly assume that subclass methods return strings */
382
+ StringValue(str1);
383
+ StringValue(str2);
384
+
385
+ if (RSTRING_LEN(str1) == RSTRING_LEN(str2) &&
386
+ rb_str_cmp(str1, str2) == 0) {
387
+ return Qtrue;
388
+ }
389
+ return Qfalse;
390
+ }
391
+
392
+ /*
393
+ * call-seq:
394
+ * digest_obj.digest_length -> integer
395
+ *
396
+ * Returns the length of the hash value of the digest.
397
+ *
398
+ * This method should be overridden by each implementation subclass.
399
+ * If not, digest_obj.digest().length() is returned.
400
+ */
401
+ static VALUE
402
+ rb_digest_instance_digest_length(VALUE self)
403
+ {
404
+ /* subclasses really should redefine this method */
405
+ VALUE digest = rb_digest_instance_digest(0, 0, self);
406
+
407
+ /* never blindly assume that #digest() returns a string */
408
+ StringValue(digest);
409
+ return LONG2NUM(RSTRING_LEN(digest));
410
+ }
411
+
412
+ /*
413
+ * call-seq:
414
+ * digest_obj.length -> integer
415
+ * digest_obj.size -> integer
416
+ *
417
+ * Returns digest_obj.digest_length().
418
+ */
419
+ static VALUE
420
+ rb_digest_instance_length(VALUE self)
421
+ {
422
+ return rb_funcall(self, id_digest_length, 0);
423
+ }
424
+
425
+ /*
426
+ * call-seq:
427
+ * digest_obj.block_length -> integer
428
+ *
429
+ * Returns the block length of the digest.
430
+ *
431
+ * This method is overridden by each implementation subclass.
432
+ */
433
+ static VALUE
434
+ rb_digest_instance_block_length(VALUE self)
435
+ {
436
+ rb_digest_instance_method_unimpl(self, "block_length");
437
+
438
+ UNREACHABLE;
439
+ }
440
+
441
+ /*
442
+ * Document-class: Digest::Class
443
+ *
444
+ * This module stands as a base class for digest implementation
445
+ * classes.
446
+ */
447
+
448
+ /*
449
+ * call-seq:
450
+ * Digest::Class.digest(string, *parameters) -> hash_string
451
+ *
452
+ * Returns the hash value of a given _string_. This is equivalent to
453
+ * Digest::Class.new(*parameters).digest(string), where extra
454
+ * _parameters_, if any, are passed through to the constructor and the
455
+ * _string_ is passed to #digest().
456
+ */
457
+ static VALUE
458
+ rb_digest_class_s_digest(int argc, VALUE *argv, VALUE klass)
459
+ {
460
+ VALUE str;
461
+ volatile VALUE obj;
462
+
463
+ if (argc < 1) {
464
+ rb_raise(rb_eArgError, "no data given");
465
+ }
466
+
467
+ str = *argv++;
468
+ argc--;
469
+
470
+ StringValue(str);
471
+
472
+ obj = rb_obj_alloc(klass);
473
+ rb_obj_call_init(obj, argc, argv);
474
+
475
+ return rb_funcall(obj, id_digest, 1, str);
476
+ }
477
+
478
+ /*
479
+ * call-seq:
480
+ * Digest::Class.hexdigest(string[, ...]) -> hash_string
481
+ *
482
+ * Returns the hex-encoded hash value of a given _string_. This is
483
+ * almost equivalent to
484
+ * Digest.hexencode(Digest::Class.new(*parameters).digest(string)).
485
+ */
486
+ static VALUE
487
+ rb_digest_class_s_hexdigest(int argc, VALUE *argv, VALUE klass)
488
+ {
489
+ return hexencode_str_new(rb_funcallv(klass, id_digest, argc, argv));
490
+ }
491
+
492
+ /* :nodoc: */
493
+ static VALUE
494
+ rb_digest_class_init(VALUE self)
495
+ {
496
+ return self;
497
+ }
498
+
499
+ /*
500
+ * Document-class: Digest::Base
501
+ *
502
+ * This abstract class provides a common interface to message digest
503
+ * implementation classes written in C.
504
+ *
505
+ * ==Write a Digest subclass in C
506
+ * Digest::Base provides a common interface to message digest
507
+ * classes written in C. These classes must provide a struct
508
+ * of type rb_digest_metadata_t:
509
+ * typedef int (*rb_digest_hash_init_func_t)(void *);
510
+ * typedef void (*rb_digest_hash_update_func_t)(void *, unsigned char *, size_t);
511
+ * typedef int (*rb_digest_hash_finish_func_t)(void *, unsigned char *);
512
+ *
513
+ * typedef struct {
514
+ * int api_version;
515
+ * size_t digest_len;
516
+ * size_t block_len;
517
+ * size_t ctx_size;
518
+ * rb_digest_hash_init_func_t init_func;
519
+ * rb_digest_hash_update_func_t update_func;
520
+ * rb_digest_hash_finish_func_t finish_func;
521
+ * } rb_digest_metadata_t;
522
+ *
523
+ * This structure must be set as an instance variable named +metadata+
524
+ * (without the +@+ in front of the name). By example:
525
+ * static const rb_digest_metadata_t sha1 = {
526
+ * RUBY_DIGEST_API_VERSION,
527
+ * SHA1_DIGEST_LENGTH,
528
+ * SHA1_BLOCK_LENGTH,
529
+ * sizeof(SHA1_CTX),
530
+ * (rb_digest_hash_init_func_t)SHA1_Init,
531
+ * (rb_digest_hash_update_func_t)SHA1_Update,
532
+ * (rb_digest_hash_finish_func_t)SHA1_Finish,
533
+ * };
534
+ *
535
+ *
536
+ * rb_ivar_set(cDigest_SHA1, rb_intern("metadata"),
537
+ * Data_Wrap_Struct(0, 0, 0, (void *)&sha1));
538
+ */
539
+
540
+ static rb_digest_metadata_t *
541
+ get_digest_base_metadata(VALUE klass)
542
+ {
543
+ VALUE p;
544
+ VALUE obj;
545
+ rb_digest_metadata_t *algo;
546
+
547
+ for (p = klass; !NIL_P(p); p = rb_class_superclass(p)) {
548
+ if (rb_ivar_defined(p, id_metadata)) {
549
+ obj = rb_ivar_get(p, id_metadata);
550
+ break;
551
+ }
552
+ }
553
+
554
+ if (NIL_P(p))
555
+ rb_raise(rb_eRuntimeError, "Digest::Base cannot be directly inherited in Ruby");
556
+
557
+ if (!RB_TYPE_P(obj, T_DATA) || RTYPEDDATA_P(obj)) {
558
+ wrong:
559
+ if (p == klass)
560
+ rb_raise(rb_eTypeError, "%"PRIsVALUE"::metadata is not initialized properly",
561
+ klass);
562
+ else
563
+ rb_raise(rb_eTypeError, "%"PRIsVALUE"(%"PRIsVALUE")::metadata is not initialized properly",
564
+ klass, p);
565
+ }
566
+
567
+ #undef RUBY_UNTYPED_DATA_WARNING
568
+ #define RUBY_UNTYPED_DATA_WARNING 0
569
+ Data_Get_Struct(obj, rb_digest_metadata_t, algo);
570
+
571
+ if (!algo) goto wrong;
572
+
573
+ switch (algo->api_version) {
574
+ case 3:
575
+ break;
576
+
577
+ /*
578
+ * put conversion here if possible when API is updated
579
+ */
580
+
581
+ default:
582
+ rb_raise(rb_eRuntimeError, "Incompatible digest API version");
583
+ }
584
+
585
+ return algo;
586
+ }
587
+
588
+ static rb_digest_metadata_t *
589
+ get_digest_obj_metadata(VALUE obj)
590
+ {
591
+ return get_digest_base_metadata(rb_obj_class(obj));
592
+ }
593
+
594
+ static const rb_data_type_t digest_type = {
595
+ "digest",
596
+ {0, RUBY_TYPED_DEFAULT_FREE, 0,},
597
+ 0, 0,
598
+ (RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED),
599
+ };
600
+
601
+ static inline void
602
+ algo_init(const rb_digest_metadata_t *algo, void *pctx)
603
+ {
604
+ if (algo->init_func(pctx) != 1) {
605
+ rb_raise(rb_eRuntimeError, "Digest initialization failed.");
606
+ }
607
+ }
608
+
609
+ static VALUE
610
+ rb_digest_base_alloc(VALUE klass)
611
+ {
612
+ rb_digest_metadata_t *algo;
613
+ VALUE obj;
614
+ void *pctx;
615
+
616
+ if (klass == rb_cDigest_Base) {
617
+ rb_raise(rb_eNotImpError, "Digest::Base is an abstract class");
618
+ }
619
+
620
+ algo = get_digest_base_metadata(klass);
621
+
622
+ obj = rb_data_typed_object_zalloc(klass, algo->ctx_size, &digest_type);
623
+ pctx = RTYPEDDATA_DATA(obj);
624
+ algo_init(algo, pctx);
625
+
626
+ return obj;
627
+ }
628
+
629
+ /* :nodoc: */
630
+ static VALUE
631
+ rb_digest_base_copy(VALUE copy, VALUE obj)
632
+ {
633
+ rb_digest_metadata_t *algo;
634
+ void *pctx1, *pctx2;
635
+
636
+ if (copy == obj) return copy;
637
+
638
+ rb_check_frozen(copy);
639
+
640
+ algo = get_digest_obj_metadata(copy);
641
+ if (algo != get_digest_obj_metadata(obj))
642
+ rb_raise(rb_eTypeError, "different algorithms");
643
+
644
+ TypedData_Get_Struct(obj, void, &digest_type, pctx1);
645
+ TypedData_Get_Struct(copy, void, &digest_type, pctx2);
646
+ memcpy(pctx2, pctx1, algo->ctx_size);
647
+
648
+ return copy;
649
+ }
650
+
651
+ /*
652
+ * call-seq: digest_base.reset -> digest_base
653
+ *
654
+ * Reset the digest to its initial state and return +self+.
655
+ */
656
+ static VALUE
657
+ rb_digest_base_reset(VALUE self)
658
+ {
659
+ rb_digest_metadata_t *algo;
660
+ void *pctx;
661
+
662
+ algo = get_digest_obj_metadata(self);
663
+
664
+ TypedData_Get_Struct(self, void, &digest_type, pctx);
665
+
666
+ algo_init(algo, pctx);
667
+
668
+ return self;
669
+ }
670
+
671
+ /*
672
+ * call-seq:
673
+ * digest_base.update(string) -> digest_base
674
+ * digest_base << string -> digest_base
675
+ *
676
+ * Update the digest using given _string_ and return +self+.
677
+ */
678
+ static VALUE
679
+ rb_digest_base_update(VALUE self, VALUE str)
680
+ {
681
+ rb_digest_metadata_t *algo;
682
+ void *pctx;
683
+
684
+ algo = get_digest_obj_metadata(self);
685
+
686
+ TypedData_Get_Struct(self, void, &digest_type, pctx);
687
+
688
+ StringValue(str);
689
+ algo->update_func(pctx, (unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str));
690
+ RB_GC_GUARD(str);
691
+
692
+ return self;
693
+ }
694
+
695
+ /* :nodoc: */
696
+ static VALUE
697
+ rb_digest_base_finish(VALUE self)
698
+ {
699
+ rb_digest_metadata_t *algo;
700
+ void *pctx;
701
+ VALUE str;
702
+
703
+ algo = get_digest_obj_metadata(self);
704
+
705
+ TypedData_Get_Struct(self, void, &digest_type, pctx);
706
+
707
+ str = rb_str_new(0, algo->digest_len);
708
+ algo->finish_func(pctx, (unsigned char *)RSTRING_PTR(str));
709
+
710
+ /* avoid potential coredump caused by use of a finished context */
711
+ algo_init(algo, pctx);
712
+
713
+ return str;
714
+ }
715
+
716
+ /*
717
+ * call-seq: digest_base.digest_length -> Integer
718
+ *
719
+ * Return the length of the hash value in bytes.
720
+ */
721
+ static VALUE
722
+ rb_digest_base_digest_length(VALUE self)
723
+ {
724
+ rb_digest_metadata_t *algo;
725
+
726
+ algo = get_digest_obj_metadata(self);
727
+
728
+ return SIZET2NUM(algo->digest_len);
729
+ }
730
+
731
+ /*
732
+ * call-seq: digest_base.block_length -> Integer
733
+ *
734
+ * Return the block length of the digest in bytes.
735
+ */
736
+ static VALUE
737
+ rb_digest_base_block_length(VALUE self)
738
+ {
739
+ rb_digest_metadata_t *algo;
740
+
741
+ algo = get_digest_obj_metadata(self);
742
+
743
+ return SIZET2NUM(algo->block_len);
744
+ }
745
+
746
+ void
747
+ Init_digest(void)
748
+ {
749
+ #undef rb_intern
750
+ id_reset = rb_intern("reset");
751
+ id_update = rb_intern("update");
752
+ id_finish = rb_intern("finish");
753
+ id_digest = rb_intern("digest");
754
+ id_hexdigest = rb_intern("hexdigest");
755
+ id_digest_length = rb_intern("digest_length");
756
+ id_metadata = rb_id_metadata();
757
+ InitVM(digest);
758
+ }
759
+
760
+ void
761
+ InitVM_digest(void)
762
+ {
763
+ /*
764
+ * module Digest
765
+ */
766
+ rb_mDigest = rb_define_module("Digest");
767
+
768
+ /* module functions */
769
+ rb_define_module_function(rb_mDigest, "hexencode", rb_digest_s_hexencode, 1);
770
+
771
+ /*
772
+ * module Digest::Instance
773
+ */
774
+ rb_mDigest_Instance = rb_define_module_under(rb_mDigest, "Instance");
775
+
776
+ /* instance methods that should be overridden */
777
+ rb_define_method(rb_mDigest_Instance, "update", rb_digest_instance_update, 1);
778
+ rb_define_method(rb_mDigest_Instance, "<<", rb_digest_instance_update, 1);
779
+ rb_define_private_method(rb_mDigest_Instance, "finish", rb_digest_instance_finish, 0);
780
+ rb_define_method(rb_mDigest_Instance, "reset", rb_digest_instance_reset, 0);
781
+ rb_define_method(rb_mDigest_Instance, "digest_length", rb_digest_instance_digest_length, 0);
782
+ rb_define_method(rb_mDigest_Instance, "block_length", rb_digest_instance_block_length, 0);
783
+
784
+ /* instance methods that may be overridden */
785
+ rb_define_method(rb_mDigest_Instance, "==", rb_digest_instance_equal, 1);
786
+ rb_define_method(rb_mDigest_Instance, "inspect", rb_digest_instance_inspect, 0);
787
+
788
+ /* instance methods that need not usually be overridden */
789
+ rb_define_method(rb_mDigest_Instance, "new", rb_digest_instance_new, 0);
790
+ rb_define_method(rb_mDigest_Instance, "digest", rb_digest_instance_digest, -1);
791
+ rb_define_method(rb_mDigest_Instance, "digest!", rb_digest_instance_digest_bang, 0);
792
+ rb_define_method(rb_mDigest_Instance, "hexdigest", rb_digest_instance_hexdigest, -1);
793
+ rb_define_method(rb_mDigest_Instance, "hexdigest!", rb_digest_instance_hexdigest_bang, 0);
794
+ rb_define_method(rb_mDigest_Instance, "to_s", rb_digest_instance_to_s, 0);
795
+ rb_define_method(rb_mDigest_Instance, "length", rb_digest_instance_length, 0);
796
+ rb_define_method(rb_mDigest_Instance, "size", rb_digest_instance_length, 0);
797
+
798
+ /*
799
+ * class Digest::Class
800
+ */
801
+ rb_cDigest_Class = rb_define_class_under(rb_mDigest, "Class", rb_cObject);
802
+ rb_define_method(rb_cDigest_Class, "initialize", rb_digest_class_init, 0);
803
+ rb_include_module(rb_cDigest_Class, rb_mDigest_Instance);
804
+
805
+ /* class methods */
806
+ rb_define_singleton_method(rb_cDigest_Class, "digest", rb_digest_class_s_digest, -1);
807
+ rb_define_singleton_method(rb_cDigest_Class, "hexdigest", rb_digest_class_s_hexdigest, -1);
808
+
809
+ /* class Digest::Base < Digest::Class */
810
+ rb_cDigest_Base = rb_define_class_under(rb_mDigest, "Base", rb_cDigest_Class);
811
+
812
+ rb_define_alloc_func(rb_cDigest_Base, rb_digest_base_alloc);
813
+
814
+ rb_define_method(rb_cDigest_Base, "initialize_copy", rb_digest_base_copy, 1);
815
+ rb_define_method(rb_cDigest_Base, "reset", rb_digest_base_reset, 0);
816
+ rb_define_method(rb_cDigest_Base, "update", rb_digest_base_update, 1);
817
+ rb_define_method(rb_cDigest_Base, "<<", rb_digest_base_update, 1);
818
+ rb_define_private_method(rb_cDigest_Base, "finish", rb_digest_base_finish, 0);
819
+ rb_define_method(rb_cDigest_Base, "digest_length", rb_digest_base_digest_length, 0);
820
+ rb_define_method(rb_cDigest_Base, "block_length", rb_digest_base_block_length, 0);
821
+ }