ruby-mcrypt 0.1.1
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.
- data/.gitignore +5 -0
- data/Manifest +14 -0
- data/README.rdoc +84 -0
- data/Rakefile +63 -0
- data/VERSION +1 -0
- data/ext/.gitignore +8 -0
- data/ext/extconf.rb +46 -0
- data/ext/mcrypt_wrapper.c +588 -0
- data/lib/.gitignore +3 -0
- data/lib/mcrypt.rb +472 -0
- data/ruby-mcrypt.gemspec +147 -0
- data/test/generate/.gitignore +3 -0
- data/test/generate/Makefile +11 -0
- data/test/generate/generate_testcases.c +389 -0
- data/test/helper.rb +13 -0
- data/test/test_basics.rb +216 -0
- data/test/test_brute.rb +3386 -0
- data/test/test_reciprocity.rb +50 -0
- metadata +174 -0
data/Manifest
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
Manifest
|
2
|
+
README.rdoc
|
3
|
+
Rakefile
|
4
|
+
ext/extconf.rb
|
5
|
+
ext/mcrypt_wrapper.c
|
6
|
+
lib/mcrypt.rb
|
7
|
+
ruby-mcrypt.gemspec
|
8
|
+
test/generate/Makefile
|
9
|
+
test/generate/generate_testcases.c
|
10
|
+
test/helper.rb
|
11
|
+
test/test_all.rb
|
12
|
+
test/test_basics.rb
|
13
|
+
test/test_brute.rb
|
14
|
+
test/test_reciprocity.rb
|
data/README.rdoc
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
= Mcrypt - libmcrypt bindings for Ruby
|
2
|
+
|
3
|
+
Mcrypt provides Ruby-language bindings for libmcrypt(3), a
|
4
|
+
symmetric cryptography library. {Libmcrypt}[http://mcrypt.sourceforge.net/]
|
5
|
+
supports lots of different ciphers and encryption modes.
|
6
|
+
|
7
|
+
== You will need
|
8
|
+
|
9
|
+
* A working Ruby installation (>= 1.8.6 or 1.9)
|
10
|
+
* A working libmcrypt installation (2.5.x or 2.6.x, tested with 2.5.8)
|
11
|
+
* A sane build environment
|
12
|
+
|
13
|
+
== Installation
|
14
|
+
|
15
|
+
Install the gem:
|
16
|
+
gem install ruby-mcrypt --test -- --with-mcrypt-dir=/path/to/mcrypt/prefix
|
17
|
+
|
18
|
+
If you want to run the longer test suite, do this instead:
|
19
|
+
MCRYPT_TEST_BRUTE=1 \
|
20
|
+
gem install ruby-mcrypt --test -- --with-mcrypt-dir=/path/to/mcrypt/prefix
|
21
|
+
|
22
|
+
Put this in your code:
|
23
|
+
require 'rubygems'
|
24
|
+
require 'mcrypt'
|
25
|
+
|
26
|
+
Or in Rails' environment.rb:
|
27
|
+
gem "ruby-mcrypt", :lib => "mcrypt"
|
28
|
+
|
29
|
+
== Usage
|
30
|
+
|
31
|
+
crypto = Mcrypt.new(:twofish, :cbc, MY_KEY, MY_IV, :pkcs)
|
32
|
+
|
33
|
+
# encryption and decryption in one step
|
34
|
+
ciphertext = crypto.encrypt(plaintext)
|
35
|
+
plaintext = crypto.decrypt(ciphertext)
|
36
|
+
|
37
|
+
# encrypt in smaller steps
|
38
|
+
while chunk = $stdin.read(4096)
|
39
|
+
$stdout << crypto.encrypt_more(chunk)
|
40
|
+
end
|
41
|
+
$stdout << crypto.encrypt_finish
|
42
|
+
|
43
|
+
# or decrypt:
|
44
|
+
while chunk = $stdin.read(4096)
|
45
|
+
$stdout << crypto.decrypt_more(chunk)
|
46
|
+
end
|
47
|
+
$stdout << crypto.decrypt_finish
|
48
|
+
|
49
|
+
== Known Issues
|
50
|
+
|
51
|
+
* Test coverage is lacking.
|
52
|
+
|
53
|
+
If you find any bugs, please let the author know.
|
54
|
+
|
55
|
+
== Wish List
|
56
|
+
|
57
|
+
* IO-like behavior, e.g. crypto.open($stdin) { |stream| ... }
|
58
|
+
|
59
|
+
== Author
|
60
|
+
|
61
|
+
* Philip Garrett <philgarr at gmail.com>
|
62
|
+
|
63
|
+
== Copyright and License
|
64
|
+
|
65
|
+
Copyright (c) 2009-2010 Philip Garrett.
|
66
|
+
|
67
|
+
Permission is hereby granted, free of charge, to any person obtaining a
|
68
|
+
copy of this software and associated documentation files (the
|
69
|
+
"Software"), to deal in the Software without restriction, including
|
70
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
71
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
72
|
+
permit persons to whom the Software is furnished to do so, subject to
|
73
|
+
the following conditions:
|
74
|
+
|
75
|
+
The above copyright notice and this permission notice shall be included
|
76
|
+
in all copies or substantial portions of the Software.
|
77
|
+
|
78
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
79
|
+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
80
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
81
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
82
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
83
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
84
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rbconfig'
|
3
|
+
require 'rake'
|
4
|
+
require 'rake/testtask'
|
5
|
+
|
6
|
+
# http://stackoverflow.com/questions/213368/how-can-i-reliably-discover-the-full-path-of-the-ruby-executable
|
7
|
+
RUBY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']).sub(/.*\s.*/m, '"\&"')
|
8
|
+
|
9
|
+
task :default => :test
|
10
|
+
|
11
|
+
begin
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gemspec|
|
14
|
+
gemspec.name = "ruby-mcrypt"
|
15
|
+
gemspec.summary = "Ruby bindings for libmcrypt"
|
16
|
+
gemspec.description = File.read(File.join(File.dirname(__FILE__),"README.rdoc"))
|
17
|
+
gemspec.email = "philgarr@gmail.com"
|
18
|
+
gemspec.homepage = "http://github.com/kingpong/ruby-mcrypt"
|
19
|
+
gemspec.authors = ["Philip Garrett"]
|
20
|
+
gemspec.required_ruby_version = '>= 1.8.6'
|
21
|
+
gemspec.requirements << 'libmcrypt (2.5.x or 2.6.x, tested with 2.5.8)'
|
22
|
+
end
|
23
|
+
Jeweler::GemcutterTasks.new
|
24
|
+
rescue LoadError
|
25
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
26
|
+
end
|
27
|
+
|
28
|
+
EXTENSION = "ext/mcrypt.#{Config::CONFIG["DLEXT"]}"
|
29
|
+
|
30
|
+
desc "Compile extension"
|
31
|
+
task :compile => EXTENSION
|
32
|
+
file EXTENSION => FileList["ext/Makefile","ext/*.c"] do
|
33
|
+
Dir.chdir("ext") do
|
34
|
+
system("make") || raise("could not build ruby-mcrypt")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
file "ext/Makefile" => ["ext/extconf.rb"] do
|
39
|
+
Dir.chdir("ext") do
|
40
|
+
system("RUBY","extconf.rb",*ARGV) || raise("could not configure ruby-mcrypt for your system")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
desc "Delete build files and products"
|
45
|
+
task :clean do
|
46
|
+
%W( #{EXTENSION} ext/Makefile ext/*.o ).each do |pattern|
|
47
|
+
Dir[pattern].each {|filespec| File.unlink(filespec) }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
Rake::TestTask.new do |t|
|
52
|
+
t.libs << ["test", "ext"]
|
53
|
+
t.test_files = FileList['test/test*.rb']
|
54
|
+
t.verbose = true
|
55
|
+
end
|
56
|
+
task :test => FileList[EXTENSION, "lib/mcrypt.rb"]
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
|
63
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.1
|
data/ext/.gitignore
ADDED
data/ext/extconf.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'mkmf'
|
3
|
+
extension_name = 'mcrypt'
|
4
|
+
dir_config(extension_name)
|
5
|
+
|
6
|
+
if RUBY_VERSION =~ /\A1.9/
|
7
|
+
$CPPFLAGS += " -DRUBY_19"
|
8
|
+
elsif RUBY_VERSION =~ /\A1.8/
|
9
|
+
$CPPFLAGS += " -DRUBY_18"
|
10
|
+
end
|
11
|
+
|
12
|
+
unless have_header("mcrypt.h") && have_library("mcrypt","mcrypt_module_open")
|
13
|
+
$stderr.puts <<-EOF
|
14
|
+
|
15
|
+
########################################################################
|
16
|
+
|
17
|
+
Unable to find your mcrypt library.
|
18
|
+
|
19
|
+
Make sure you have libmcrypt installed (and libmcrypt-devel if you're
|
20
|
+
on a Linux distribution that does things that way).
|
21
|
+
|
22
|
+
If your libmcrypt is in a nonstandard location and has header files in
|
23
|
+
PREFIX/include and libraries in PREFIX/lib, try installing the gem like
|
24
|
+
this (note the extra "--"):
|
25
|
+
|
26
|
+
gem install kingpong-ruby-mcrypt --source=http://gems.github.com \\
|
27
|
+
-- --with-mcrypt-dir=/path/to/mcrypt/prefix
|
28
|
+
|
29
|
+
You can also specify the include and library directories separately:
|
30
|
+
|
31
|
+
gem install kingpong-ruby-mcrypt --source=http://gems.github.com \\
|
32
|
+
-- --with-mcrypt-include=/path/to/mcrypt/include \\
|
33
|
+
--with-mcrypt-lib=/path/to/mcrypt/lib
|
34
|
+
|
35
|
+
Specifically, if you're using MacPorts, this should work for you:
|
36
|
+
|
37
|
+
sudo port install libmcrypt +universal
|
38
|
+
sudo gem install kingpong-ruby-mcrypt --source=http://gems.github.com \\
|
39
|
+
-- --with-mcrypt-dir=/opt/local
|
40
|
+
|
41
|
+
########################################################################
|
42
|
+
|
43
|
+
EOF
|
44
|
+
exit 1
|
45
|
+
end
|
46
|
+
create_makefile(extension_name)
|
@@ -0,0 +1,588 @@
|
|
1
|
+
/*
|
2
|
+
* mcrypt_wrapper.c
|
3
|
+
*
|
4
|
+
* Copyright (c) 2009 Philip Garrett.
|
5
|
+
*
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a
|
7
|
+
* copy of this software and associated documentation files (the
|
8
|
+
* "Software"), to deal in the Software without restriction, including
|
9
|
+
* without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
* distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
* permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
* the following conditions:
|
13
|
+
*
|
14
|
+
* The above copyright notice and this permission notice shall be included
|
15
|
+
* in all copies or substantial portions of the Software.
|
16
|
+
*
|
17
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
18
|
+
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
20
|
+
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
21
|
+
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
22
|
+
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
23
|
+
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
24
|
+
*/
|
25
|
+
|
26
|
+
#include "ruby.h"
|
27
|
+
#include <string.h>
|
28
|
+
#include <mcrypt.h>
|
29
|
+
|
30
|
+
#ifdef RUBY_18
|
31
|
+
# ifndef RSTRING_PTR
|
32
|
+
# define RSTRING_PTR(x) (RSTRING(x)->ptr)
|
33
|
+
# endif
|
34
|
+
# ifndef RSTRING_LEN
|
35
|
+
# define RSTRING_LEN(x) (RSTRING(x)->len)
|
36
|
+
# endif
|
37
|
+
#endif
|
38
|
+
|
39
|
+
#define RSTR_N(V) (NIL_P(V) ? NULL : RSTRING_PTR(V))
|
40
|
+
#define TO_RB_BOOL(V) ((V) ? Qtrue : Qfalse)
|
41
|
+
|
42
|
+
/* utilities */
|
43
|
+
static ID sym_to_s;
|
44
|
+
static VALUE to_s(VALUE o);
|
45
|
+
|
46
|
+
static ID sym_canonicalize_algorithm;
|
47
|
+
static VALUE canonicalize_algorithm(VALUE o);
|
48
|
+
|
49
|
+
static char *dup_rbstring(VALUE o, int include_null);
|
50
|
+
|
51
|
+
static VALUE enumerate_key_sizes(int *sizes, int num_of_sizes, int max_size);
|
52
|
+
|
53
|
+
/* globals */
|
54
|
+
static VALUE cMcrypt;
|
55
|
+
static VALUE cInvalidAlgorithmOrModeError;
|
56
|
+
static VALUE cMcryptRuntimeError;
|
57
|
+
|
58
|
+
|
59
|
+
static void mc_free(void *p)
|
60
|
+
{
|
61
|
+
MCRYPT *box = (MCRYPT *)p;
|
62
|
+
if (*box != NULL) {
|
63
|
+
mcrypt_generic_deinit(*box); /* shutdown */
|
64
|
+
mcrypt_module_close(*box); /* free */
|
65
|
+
}
|
66
|
+
free(box);
|
67
|
+
}
|
68
|
+
|
69
|
+
static VALUE mc_alloc(VALUE klass)
|
70
|
+
{
|
71
|
+
MCRYPT *box;
|
72
|
+
box = malloc(sizeof(MCRYPT));
|
73
|
+
*box = 0; /* will populate in mc_initialize */
|
74
|
+
return Data_Wrap_Struct(klass, 0, mc_free, box);
|
75
|
+
}
|
76
|
+
|
77
|
+
|
78
|
+
/*
|
79
|
+
* call-seq:
|
80
|
+
* Mcrypt.new(algorithm,mode,key=nil,iv=nil,padding=nil) -> new_mcrypt
|
81
|
+
*
|
82
|
+
* Creates and initializes a new Mcrypt object with the specified +algorithm+ and +mode+.
|
83
|
+
* +key+, +iv+ and +padding+ will also be initialized if they are present.
|
84
|
+
*/
|
85
|
+
static VALUE mc_initialize(int argc, VALUE *argv, VALUE self)
|
86
|
+
{
|
87
|
+
VALUE algo, mode, key, iv, padding;
|
88
|
+
char *s_algo, *s_mode;
|
89
|
+
MCRYPT *box;
|
90
|
+
|
91
|
+
rb_scan_args(argc, argv, "23", &algo, &mode, &key, &iv, &padding);
|
92
|
+
|
93
|
+
Data_Get_Struct(self, MCRYPT, box);
|
94
|
+
|
95
|
+
/* sanity check. should be empty still */
|
96
|
+
if (*box != NULL)
|
97
|
+
rb_raise(rb_eFatal, "mcrypt binding internal error");
|
98
|
+
|
99
|
+
/* convert :rijndael_256 to "rijndael-256" */
|
100
|
+
algo = canonicalize_algorithm(algo);
|
101
|
+
mode = to_s(mode);
|
102
|
+
|
103
|
+
/* mcrypt needs null-terminated strings */
|
104
|
+
s_algo = dup_rbstring(algo, 1);
|
105
|
+
s_mode = dup_rbstring(mode, 1);
|
106
|
+
|
107
|
+
*box = mcrypt_module_open(s_algo, NULL, s_mode, NULL);
|
108
|
+
if (*box == MCRYPT_FAILED) {
|
109
|
+
/* MCRYPT_FAILED is currently 0, but we should explicitly set
|
110
|
+
to zero in case they change that. We don't want to attempt to
|
111
|
+
free it later. */
|
112
|
+
*box = 0;
|
113
|
+
char message[256];
|
114
|
+
snprintf(message, sizeof(message),
|
115
|
+
"Could not initialize using algorithm '%s' with mode "
|
116
|
+
"'%s'. Check mcrypt(3) for supported combinations.",
|
117
|
+
s_algo, s_mode);
|
118
|
+
free(s_algo);
|
119
|
+
free(s_mode);
|
120
|
+
rb_raise(cInvalidAlgorithmOrModeError, message, NULL);
|
121
|
+
}
|
122
|
+
free(s_algo);
|
123
|
+
free(s_mode);
|
124
|
+
|
125
|
+
rb_iv_set(self, "@algorithm", algo);
|
126
|
+
rb_iv_set(self, "@mode", mode);
|
127
|
+
|
128
|
+
/* post-initialization stuff that's easier done in ruby */
|
129
|
+
rb_funcall(self, rb_intern("after_init"), 3, key, iv, padding);
|
130
|
+
|
131
|
+
return self;
|
132
|
+
}
|
133
|
+
|
134
|
+
/* :nodoc: */
|
135
|
+
static VALUE mc_generic_init(VALUE self)
|
136
|
+
{
|
137
|
+
/* ruby has already validated @key and @iv */
|
138
|
+
VALUE key, iv;
|
139
|
+
int rv;
|
140
|
+
MCRYPT *box;
|
141
|
+
Data_Get_Struct(self, MCRYPT, box);
|
142
|
+
|
143
|
+
key = rb_iv_get(self, "@key");
|
144
|
+
iv = rb_iv_get(self, "@iv");
|
145
|
+
|
146
|
+
rv = mcrypt_generic_init(*box,
|
147
|
+
(void *)RSTRING_PTR(key),
|
148
|
+
RSTRING_LEN(key),
|
149
|
+
RSTR_N(iv));
|
150
|
+
if (rv < 0) {
|
151
|
+
const char *err = mcrypt_strerror(rv);
|
152
|
+
rb_raise(cMcryptRuntimeError, "Could not initialize mcrypt: %s", err);
|
153
|
+
}
|
154
|
+
|
155
|
+
return Qnil;
|
156
|
+
}
|
157
|
+
|
158
|
+
/* :nodoc: */
|
159
|
+
static VALUE mc_generic_deinit(VALUE self)
|
160
|
+
{
|
161
|
+
MCRYPT *box;
|
162
|
+
Data_Get_Struct(self, MCRYPT, box);
|
163
|
+
mcrypt_generic_deinit(*box);
|
164
|
+
return Qnil;
|
165
|
+
}
|
166
|
+
|
167
|
+
/* :nodoc: */
|
168
|
+
static VALUE mc_encrypt_generic(VALUE self, VALUE plaintext)
|
169
|
+
{
|
170
|
+
/* plaintext is encrypted in-place */
|
171
|
+
MCRYPT *box;
|
172
|
+
VALUE ciphertext;
|
173
|
+
int rv;
|
174
|
+
|
175
|
+
Data_Get_Struct(self, MCRYPT, box);
|
176
|
+
|
177
|
+
/* rb_str_dup doesn't actually copy the buffer, hence rb_str_new */
|
178
|
+
ciphertext = rb_str_new(RSTRING_PTR(plaintext), RSTRING_LEN(plaintext));
|
179
|
+
|
180
|
+
rv = mcrypt_generic(*box, (void *)RSTRING_PTR(ciphertext), RSTRING_LEN(ciphertext));
|
181
|
+
if (rv != 0)
|
182
|
+
rb_raise(cMcryptRuntimeError, "internal error: mcrypt_generic returned %d", rv);
|
183
|
+
return ciphertext;
|
184
|
+
}
|
185
|
+
|
186
|
+
/* :nodoc: */
|
187
|
+
static VALUE mc_decrypt_generic(VALUE self, VALUE ciphertext)
|
188
|
+
{
|
189
|
+
/* ciphertext is decrypted in-place */
|
190
|
+
MCRYPT *box;
|
191
|
+
VALUE plaintext;
|
192
|
+
int rv;
|
193
|
+
|
194
|
+
Data_Get_Struct(self, MCRYPT, box);
|
195
|
+
|
196
|
+
/* rb_str_dup doesn't actually copy the buffer, hence rb_str_new */
|
197
|
+
plaintext = rb_str_new(RSTRING_PTR(ciphertext), RSTRING_LEN(ciphertext));
|
198
|
+
|
199
|
+
rv = mdecrypt_generic(*box, (void *)RSTRING_PTR(plaintext), RSTRING_LEN(plaintext));
|
200
|
+
if (rv != 0)
|
201
|
+
rb_raise(cMcryptRuntimeError, "internal error: mdecrypt_generic returned %d", rv);
|
202
|
+
return plaintext;
|
203
|
+
}
|
204
|
+
|
205
|
+
/*
|
206
|
+
* call-seq:
|
207
|
+
* key_size -> Fixnum
|
208
|
+
*
|
209
|
+
* Returns the maximum key size for the algorithm in use.
|
210
|
+
*/
|
211
|
+
static VALUE mc_key_size(VALUE self)
|
212
|
+
{
|
213
|
+
MCRYPT *box;
|
214
|
+
Data_Get_Struct(self, MCRYPT, box);
|
215
|
+
return INT2FIX(mcrypt_enc_get_key_size(*box));
|
216
|
+
}
|
217
|
+
|
218
|
+
/*
|
219
|
+
* call-seq:
|
220
|
+
* block_size -> Fixnum
|
221
|
+
*
|
222
|
+
* Returns the block size (in bytes) for the algorithm in use. If it
|
223
|
+
* is a stream algorithm, this will be 1.
|
224
|
+
*/
|
225
|
+
static VALUE mc_block_size(VALUE self)
|
226
|
+
{
|
227
|
+
MCRYPT *box;
|
228
|
+
Data_Get_Struct(self, MCRYPT, box);
|
229
|
+
return INT2FIX(mcrypt_enc_get_block_size(*box));
|
230
|
+
}
|
231
|
+
|
232
|
+
/*
|
233
|
+
* call-seq:
|
234
|
+
* iv_size -> Fixnum or nil
|
235
|
+
*
|
236
|
+
* Returns the IV size (in bytes) for the mode in use. If the mode does
|
237
|
+
* not use an IV, returns nil.
|
238
|
+
*/
|
239
|
+
static VALUE mc_iv_size(VALUE self)
|
240
|
+
{
|
241
|
+
MCRYPT *box;
|
242
|
+
Data_Get_Struct(self, MCRYPT, box);
|
243
|
+
if (mcrypt_enc_mode_has_iv(*box))
|
244
|
+
return INT2FIX(mcrypt_enc_get_iv_size(*box));
|
245
|
+
else
|
246
|
+
return Qnil;
|
247
|
+
}
|
248
|
+
|
249
|
+
/*
|
250
|
+
* call-seq:
|
251
|
+
* block_algorithm? -> true or false
|
252
|
+
*
|
253
|
+
* True if the algorithm in use operates in blocks.
|
254
|
+
*/
|
255
|
+
static VALUE mc_is_block_algorithm(VALUE self)
|
256
|
+
{
|
257
|
+
MCRYPT *box;
|
258
|
+
Data_Get_Struct(self, MCRYPT, box);
|
259
|
+
return TO_RB_BOOL(mcrypt_enc_is_block_algorithm(*box));
|
260
|
+
}
|
261
|
+
|
262
|
+
/*
|
263
|
+
* call-seq:
|
264
|
+
* block_mode? -> true or false
|
265
|
+
*
|
266
|
+
* True if the encryption mode in use operates in blocks.
|
267
|
+
*/
|
268
|
+
static VALUE mc_is_block_mode(VALUE self)
|
269
|
+
{
|
270
|
+
MCRYPT *box;
|
271
|
+
Data_Get_Struct(self, MCRYPT, box);
|
272
|
+
return TO_RB_BOOL(mcrypt_enc_is_block_mode(*box));
|
273
|
+
}
|
274
|
+
|
275
|
+
/*
|
276
|
+
* call-seq:
|
277
|
+
* block_algorithm_mode? -> true or false
|
278
|
+
*
|
279
|
+
* True if the encryption mode is for use with block algorithms.
|
280
|
+
*/
|
281
|
+
static VALUE mc_is_block_algorithm_mode(VALUE self)
|
282
|
+
{
|
283
|
+
MCRYPT *box;
|
284
|
+
Data_Get_Struct(self, MCRYPT, box);
|
285
|
+
return TO_RB_BOOL(mcrypt_enc_is_block_algorithm_mode(*box));
|
286
|
+
}
|
287
|
+
|
288
|
+
/*
|
289
|
+
* call-seq:
|
290
|
+
* has_iv? -> true or false
|
291
|
+
*
|
292
|
+
* True if the the encryption mode uses an IV.
|
293
|
+
*/
|
294
|
+
static VALUE mc_mode_has_iv(VALUE self)
|
295
|
+
{
|
296
|
+
MCRYPT *box;
|
297
|
+
Data_Get_Struct(self, MCRYPT, box);
|
298
|
+
return TO_RB_BOOL(mcrypt_enc_mode_has_iv(*box));
|
299
|
+
}
|
300
|
+
|
301
|
+
/*
|
302
|
+
* call-seq:
|
303
|
+
* key_sizes -> Array
|
304
|
+
*
|
305
|
+
* An array of the key sizes supported by the algorithm.
|
306
|
+
*/
|
307
|
+
static VALUE mc_key_sizes(VALUE self)
|
308
|
+
{
|
309
|
+
MCRYPT *box;
|
310
|
+
int *sizes, num_of_sizes;
|
311
|
+
Data_Get_Struct(self, MCRYPT, box);
|
312
|
+
|
313
|
+
sizes = mcrypt_enc_get_supported_key_sizes(*box, &num_of_sizes);
|
314
|
+
return enumerate_key_sizes(sizes, num_of_sizes, mcrypt_enc_get_key_size(*box));
|
315
|
+
}
|
316
|
+
|
317
|
+
/*
|
318
|
+
* call-seq:
|
319
|
+
* algorithm_version -> Fixnum
|
320
|
+
*
|
321
|
+
* The numeric version of the algorithm implementation.
|
322
|
+
*/
|
323
|
+
static VALUE mc_algorithm_version(VALUE self)
|
324
|
+
{
|
325
|
+
int version;
|
326
|
+
VALUE algo = rb_iv_get(self,"@algorithm");
|
327
|
+
version = mcrypt_module_algorithm_version(RSTRING_PTR(algo), NULL);
|
328
|
+
return INT2FIX(version);
|
329
|
+
}
|
330
|
+
|
331
|
+
/*
|
332
|
+
* call-seq:
|
333
|
+
* mode_version -> Fixnum
|
334
|
+
*
|
335
|
+
* The numeric version of the encryption mode implementation.
|
336
|
+
*/
|
337
|
+
static VALUE mc_mode_version(VALUE self)
|
338
|
+
{
|
339
|
+
int version;
|
340
|
+
VALUE mode = rb_iv_get(self,"@mode");
|
341
|
+
version = mcrypt_module_mode_version(RSTRING_PTR(mode), NULL);
|
342
|
+
return INT2FIX(version);
|
343
|
+
}
|
344
|
+
|
345
|
+
/*
|
346
|
+
* call-seq:
|
347
|
+
* Mcrypt.algorithms -> Array
|
348
|
+
*
|
349
|
+
* Returns an array of all the supported algorithm names.
|
350
|
+
*/
|
351
|
+
static VALUE mck_algorithms(VALUE self)
|
352
|
+
{
|
353
|
+
VALUE rv;
|
354
|
+
int size, i;
|
355
|
+
char **list;
|
356
|
+
|
357
|
+
list = mcrypt_list_algorithms(NULL, &size);
|
358
|
+
rv = rb_ary_new2(size);
|
359
|
+
for (i = 0; i < size; i++) {
|
360
|
+
rb_ary_push(rv, rb_str_new2(list[i]));
|
361
|
+
}
|
362
|
+
mcrypt_free_p(list, size);
|
363
|
+
|
364
|
+
return rv;
|
365
|
+
}
|
366
|
+
|
367
|
+
/*
|
368
|
+
* call-seq:
|
369
|
+
* Mcrypt.modes -> Array
|
370
|
+
*
|
371
|
+
* Returns an array of all the supported mode names.
|
372
|
+
*/
|
373
|
+
static VALUE mck_modes(VALUE self)
|
374
|
+
{
|
375
|
+
VALUE rv;
|
376
|
+
int size, i;
|
377
|
+
char **list;
|
378
|
+
|
379
|
+
list = mcrypt_list_modes(NULL, &size);
|
380
|
+
rv = rb_ary_new2(size);
|
381
|
+
for (i = 0; i < size; i++) {
|
382
|
+
rb_ary_push(rv, rb_str_new2(list[i]));
|
383
|
+
}
|
384
|
+
mcrypt_free_p(list, size);
|
385
|
+
|
386
|
+
return rv;
|
387
|
+
}
|
388
|
+
|
389
|
+
/*
|
390
|
+
* call-seq:
|
391
|
+
* Mcrypt.block_algorithm?(algorithm) -> true or false
|
392
|
+
*
|
393
|
+
* Returns true if the specified algorithm operates in blocks.
|
394
|
+
*/
|
395
|
+
static VALUE mck_is_block_algorithm(VALUE self, VALUE algo)
|
396
|
+
{
|
397
|
+
algo = canonicalize_algorithm(algo);
|
398
|
+
return TO_RB_BOOL(mcrypt_module_is_block_algorithm(RSTRING_PTR(algo),NULL));
|
399
|
+
}
|
400
|
+
|
401
|
+
/*
|
402
|
+
* call-seq:
|
403
|
+
* Mcrypt.key_size(algorithm) -> Fixnum
|
404
|
+
*
|
405
|
+
* Returns the maximum key size of the specified algorithm.
|
406
|
+
*/
|
407
|
+
static VALUE mck_key_size(VALUE self, VALUE algo)
|
408
|
+
{
|
409
|
+
algo = canonicalize_algorithm(algo);
|
410
|
+
return INT2FIX(mcrypt_module_get_algo_key_size(RSTRING_PTR(algo),NULL));
|
411
|
+
}
|
412
|
+
|
413
|
+
/*
|
414
|
+
* call-seq:
|
415
|
+
* Mcrypt.block_size(algorithm) -> Fixnum
|
416
|
+
*
|
417
|
+
* Returns the block size of the specified algorithm.
|
418
|
+
*/
|
419
|
+
static VALUE mck_block_size(VALUE self, VALUE algo)
|
420
|
+
{
|
421
|
+
algo = canonicalize_algorithm(algo);
|
422
|
+
return INT2FIX(mcrypt_module_get_algo_block_size(RSTRING_PTR(algo),NULL));
|
423
|
+
}
|
424
|
+
|
425
|
+
/*
|
426
|
+
* call-seq:
|
427
|
+
* Mcrypt.key_sizes(algorithm) -> Array
|
428
|
+
*
|
429
|
+
* Returns the key sizes supported by the specified algorithm.
|
430
|
+
*/
|
431
|
+
static VALUE mck_key_sizes(VALUE self, VALUE algo)
|
432
|
+
{
|
433
|
+
int *sizes, num_of_sizes, max;
|
434
|
+
algo = canonicalize_algorithm(algo);
|
435
|
+
max = mcrypt_module_get_algo_key_size(RSTRING_PTR(algo), NULL);
|
436
|
+
sizes = mcrypt_module_get_algo_supported_key_sizes(RSTRING_PTR(algo), NULL, &num_of_sizes);
|
437
|
+
return enumerate_key_sizes(sizes, num_of_sizes, max);
|
438
|
+
}
|
439
|
+
|
440
|
+
/*
|
441
|
+
* call-seq:
|
442
|
+
* Mcrypt.block_algorithm_mode?(mode) -> true or false
|
443
|
+
*
|
444
|
+
* Returns true if the specified mode is for use with block algorithms.
|
445
|
+
*/
|
446
|
+
static VALUE mck_is_block_algorithm_mode(VALUE self, VALUE mode)
|
447
|
+
{
|
448
|
+
mode = to_s(mode);
|
449
|
+
return TO_RB_BOOL(mcrypt_module_is_block_algorithm_mode(RSTRING_PTR(mode),NULL));
|
450
|
+
}
|
451
|
+
|
452
|
+
/*
|
453
|
+
* call-seq:
|
454
|
+
* Mcrypt.block_mode?(mode) -> true or false
|
455
|
+
*
|
456
|
+
* Returns true if the specified mode operates in blocks.
|
457
|
+
*/
|
458
|
+
static VALUE mck_is_block_mode(VALUE self, VALUE mode)
|
459
|
+
{
|
460
|
+
mode = to_s(mode);
|
461
|
+
return TO_RB_BOOL(mcrypt_module_is_block_mode(RSTRING_PTR(mode),NULL));
|
462
|
+
}
|
463
|
+
|
464
|
+
/*
|
465
|
+
* call-seq:
|
466
|
+
* Mcrypt.algorithm_version(algorithm) -> Fixnum
|
467
|
+
*
|
468
|
+
* Returns the implementation version number of the specified algorithm.
|
469
|
+
*/
|
470
|
+
static VALUE mck_algorithm_version(VALUE self, VALUE algo)
|
471
|
+
{
|
472
|
+
algo = canonicalize_algorithm(algo);
|
473
|
+
return INT2FIX(mcrypt_module_algorithm_version(RSTRING_PTR(algo), NULL));
|
474
|
+
}
|
475
|
+
|
476
|
+
/*
|
477
|
+
* call-seq:
|
478
|
+
* Mcrypt.mode_version(mode) -> Fixnum
|
479
|
+
*
|
480
|
+
* Returns the implementation version number of the specified mode.
|
481
|
+
*/
|
482
|
+
static VALUE mck_mode_version(VALUE self, VALUE mode)
|
483
|
+
{
|
484
|
+
mode = to_s(mode);
|
485
|
+
return INT2FIX(mcrypt_module_mode_version(RSTRING_PTR(mode), NULL));
|
486
|
+
}
|
487
|
+
|
488
|
+
void Init_mcrypt()
|
489
|
+
{
|
490
|
+
/* look up once, use many */
|
491
|
+
sym_to_s = rb_intern("to_s");
|
492
|
+
sym_canonicalize_algorithm = rb_intern("canonicalize_algorithm");
|
493
|
+
|
494
|
+
/*= GLOBALS =*/
|
495
|
+
cMcrypt = rb_define_class("Mcrypt", rb_cObject);
|
496
|
+
cInvalidAlgorithmOrModeError = rb_define_class_under(cMcrypt, "InvalidAlgorithmOrModeError", rb_eArgError);
|
497
|
+
cMcryptRuntimeError = rb_define_class_under(cMcrypt, "RuntimeError", rb_eRuntimeError);
|
498
|
+
rb_define_const(cMcrypt, "LIBMCRYPT_VERSION", rb_str_new2(LIBMCRYPT_VERSION));
|
499
|
+
rb_define_alloc_func(cMcrypt, mc_alloc);
|
500
|
+
|
501
|
+
/*= INSTANCE METHODS =*/
|
502
|
+
rb_define_method(cMcrypt, "initialize", mc_initialize, -1);
|
503
|
+
rb_define_method(cMcrypt, "generic_init", mc_generic_init, 0);
|
504
|
+
rb_define_method(cMcrypt, "generic_deinit", mc_generic_deinit, 0);
|
505
|
+
rb_define_method(cMcrypt, "encrypt_generic", mc_encrypt_generic, 1);
|
506
|
+
rb_define_method(cMcrypt, "decrypt_generic", mc_decrypt_generic, 1);
|
507
|
+
rb_define_method(cMcrypt, "key_size", mc_key_size, 0);
|
508
|
+
rb_define_method(cMcrypt, "block_size", mc_block_size, 0);
|
509
|
+
rb_define_method(cMcrypt, "iv_size", mc_iv_size, 0);
|
510
|
+
rb_define_method(cMcrypt, "block_algorithm?", mc_is_block_algorithm, 0);
|
511
|
+
rb_define_method(cMcrypt, "block_mode?", mc_is_block_mode, 0);
|
512
|
+
rb_define_method(cMcrypt, "block_algorithm_mode?", mc_is_block_algorithm_mode, 0);
|
513
|
+
rb_define_method(cMcrypt, "has_iv?", mc_mode_has_iv, 0);
|
514
|
+
rb_define_method(cMcrypt, "key_sizes", mc_key_sizes, 0);
|
515
|
+
rb_define_method(cMcrypt, "algorithm_version", mc_algorithm_version, 0);
|
516
|
+
rb_define_method(cMcrypt, "mode_version", mc_mode_version, 0);
|
517
|
+
|
518
|
+
/*= CLASS METHODS =*/
|
519
|
+
rb_define_singleton_method(cMcrypt, "algorithms", mck_algorithms, 0);
|
520
|
+
rb_define_singleton_method(cMcrypt, "modes", mck_modes, 0);
|
521
|
+
rb_define_singleton_method(cMcrypt, "block_algorithm?", mck_is_block_algorithm, 1);
|
522
|
+
rb_define_singleton_method(cMcrypt, "key_size", mck_key_size, 1);
|
523
|
+
rb_define_singleton_method(cMcrypt, "block_size", mck_block_size, 1);
|
524
|
+
rb_define_singleton_method(cMcrypt, "key_sizes", mck_key_sizes, 1);
|
525
|
+
rb_define_singleton_method(cMcrypt, "block_algorithm_mode?", mck_is_block_algorithm_mode, 1);
|
526
|
+
rb_define_singleton_method(cMcrypt, "block_mode?", mck_is_block_mode, 1);
|
527
|
+
rb_define_singleton_method(cMcrypt, "algorithm_version", mck_algorithm_version, 1);
|
528
|
+
rb_define_singleton_method(cMcrypt, "mode_version", mck_mode_version, 1);
|
529
|
+
|
530
|
+
/* TODO:
|
531
|
+
Instance methods:
|
532
|
+
(for copying)
|
533
|
+
mcrypt_enc_get_state
|
534
|
+
mcrypt_enc_set_state
|
535
|
+
Maybe:
|
536
|
+
self-tests
|
537
|
+
*/
|
538
|
+
}
|
539
|
+
|
540
|
+
|
541
|
+
/* UTILITIES */
|
542
|
+
|
543
|
+
static VALUE to_s(VALUE o)
|
544
|
+
{
|
545
|
+
return rb_obj_is_kind_of(o,rb_cString)
|
546
|
+
? o : rb_funcall(o, sym_to_s, 0);
|
547
|
+
}
|
548
|
+
|
549
|
+
static VALUE canonicalize_algorithm(VALUE o)
|
550
|
+
{
|
551
|
+
return rb_funcall(cMcrypt, sym_canonicalize_algorithm, 1, o);
|
552
|
+
}
|
553
|
+
|
554
|
+
static char *dup_rbstring(VALUE o, int include_null)
|
555
|
+
{
|
556
|
+
char *rv;
|
557
|
+
VALUE str = to_s(o);
|
558
|
+
rv = malloc(RSTRING_LEN(str) + (include_null ? 1 : 0));
|
559
|
+
memcpy(rv, RSTRING_PTR(str), RSTRING_LEN(str));
|
560
|
+
if (include_null)
|
561
|
+
rv[RSTRING_LEN(str)] = '\0';
|
562
|
+
return rv;
|
563
|
+
}
|
564
|
+
|
565
|
+
static VALUE enumerate_key_sizes(int *sizes, int num_of_sizes, int max_size)
|
566
|
+
{
|
567
|
+
int i;
|
568
|
+
VALUE rv;
|
569
|
+
if (sizes == NULL && num_of_sizes == 0) {
|
570
|
+
rv = rb_ary_new2(max_size);
|
571
|
+
for (i = 1; i <= max_size; i++) {
|
572
|
+
rb_ary_push(rv, INT2FIX(i));
|
573
|
+
}
|
574
|
+
return rv;
|
575
|
+
}
|
576
|
+
else if (num_of_sizes > 0) {
|
577
|
+
rv = rb_ary_new2(num_of_sizes);
|
578
|
+
for (i = 0; i < num_of_sizes; i++) {
|
579
|
+
rb_ary_push(rv, INT2FIX(sizes[i]));
|
580
|
+
}
|
581
|
+
free(sizes);
|
582
|
+
return rv;
|
583
|
+
}
|
584
|
+
else {
|
585
|
+
rb_raise(rb_eFatal, "mcrypt_enc_get_supported_key_sizes returned invalid result.");
|
586
|
+
return Qnil; /* quell warning */
|
587
|
+
}
|
588
|
+
}
|