kingpong-ruby-mcrypt 0.1.0

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