kingpong-ruby-mcrypt 0.1.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.
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
+ }