ruby-mcrypt 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ .config
2
+ InstalledFiles
3
+ *.gem
4
+ doc
5
+ *.swp
@@ -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
@@ -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.
@@ -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
@@ -0,0 +1,8 @@
1
+ *.log
2
+ *.bak
3
+ *.bundle
4
+ *.o
5
+ *.swp
6
+ Makefile
7
+ mcrypt.rb
8
+ *.so
@@ -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
+ }