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.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.travis.yml +8 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +97 -0
- data/Rakefile +15 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/digest.gemspec +45 -0
- data/ext/digest/bubblebabble/bubblebabble.c +147 -0
- data/ext/digest/bubblebabble/extconf.rb +6 -0
- data/ext/digest/defs.h +19 -0
- data/ext/digest/digest.c +821 -0
- data/ext/digest/digest.h +64 -0
- data/ext/digest/digest_conf.rb +17 -0
- data/ext/digest/extconf.rb +11 -0
- data/ext/digest/md5/extconf.rb +19 -0
- data/ext/digest/md5/md5.c +424 -0
- data/ext/digest/md5/md5.h +80 -0
- data/ext/digest/md5/md5cc.h +19 -0
- data/ext/digest/md5/md5init.c +64 -0
- data/ext/digest/rmd160/extconf.rb +19 -0
- data/ext/digest/rmd160/rmd160.c +463 -0
- data/ext/digest/rmd160/rmd160.h +56 -0
- data/ext/digest/rmd160/rmd160init.c +60 -0
- data/ext/digest/sha1/extconf.rb +19 -0
- data/ext/digest/sha1/sha1.c +271 -0
- data/ext/digest/sha1/sha1.h +39 -0
- data/ext/digest/sha1/sha1cc.h +14 -0
- data/ext/digest/sha1/sha1init.c +66 -0
- data/ext/digest/sha2/extconf.rb +21 -0
- data/ext/digest/sha2/lib/sha2.rb +142 -0
- data/ext/digest/sha2/sha2.c +1081 -0
- data/ext/digest/sha2/sha2.h +225 -0
- data/ext/digest/sha2/sha2cc.h +31 -0
- data/ext/digest/sha2/sha2init.c +55 -0
- data/ext/digest/test.sh +30 -0
- data/ext/openssl/deprecation.rb +23 -0
- data/lib/digest.rb +109 -0
- metadata +132 -0
checksums.yaml
ADDED
@@ -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
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -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.
|
data/README.md
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
# Digest
|
2
|
+
|
3
|
+
[](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).
|
data/Rakefile
ADDED
@@ -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
|
data/bin/console
ADDED
@@ -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__)
|
data/bin/setup
ADDED
data/digest.gemspec
ADDED
@@ -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
|
+
}
|
data/ext/digest/defs.h
ADDED
@@ -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 */
|
data/ext/digest/digest.c
ADDED
@@ -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
|
+
}
|