digest 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+ }