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,147 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ruby-mcrypt}
8
+ s.version = "0.1.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Philip Garrett"]
12
+ s.date = %q{2010-08-23}
13
+ s.description = %q{= Mcrypt - libmcrypt bindings for Ruby
14
+
15
+ Mcrypt provides Ruby-language bindings for libmcrypt(3), a
16
+ symmetric cryptography library. {Libmcrypt}[http://mcrypt.sourceforge.net/]
17
+ supports lots of different ciphers and encryption modes.
18
+
19
+ == You will need
20
+
21
+ * A working Ruby installation (>= 1.8.6 or 1.9)
22
+ * A working libmcrypt installation (2.5.x or 2.6.x, tested with 2.5.8)
23
+ * A sane build environment
24
+
25
+ == Installation
26
+
27
+ Install the gem:
28
+ gem install ruby-mcrypt --test -- --with-mcrypt-dir=/path/to/mcrypt/prefix
29
+
30
+ If you want to run the longer test suite, do this instead:
31
+ MCRYPT_TEST_BRUTE=1 \
32
+ gem install ruby-mcrypt --test -- --with-mcrypt-dir=/path/to/mcrypt/prefix
33
+
34
+ Put this in your code:
35
+ require 'rubygems'
36
+ require 'mcrypt'
37
+
38
+ Or in Rails' environment.rb:
39
+ gem "ruby-mcrypt", :lib => "mcrypt"
40
+
41
+ == Usage
42
+
43
+ crypto = Mcrypt.new(:twofish, :cbc, MY_KEY, MY_IV, :pkcs)
44
+
45
+ # encryption and decryption in one step
46
+ ciphertext = crypto.encrypt(plaintext)
47
+ plaintext = crypto.decrypt(ciphertext)
48
+
49
+ # encrypt in smaller steps
50
+ while chunk = $stdin.read(4096)
51
+ $stdout << crypto.encrypt_more(chunk)
52
+ end
53
+ $stdout << crypto.encrypt_finish
54
+
55
+ # or decrypt:
56
+ while chunk = $stdin.read(4096)
57
+ $stdout << crypto.decrypt_more(chunk)
58
+ end
59
+ $stdout << crypto.decrypt_finish
60
+
61
+ == Known Issues
62
+
63
+ * Test coverage is lacking.
64
+
65
+ If you find any bugs, please let the author know.
66
+
67
+ == Wish List
68
+
69
+ * IO-like behavior, e.g. crypto.open($stdin) { |stream| ... }
70
+
71
+ == Author
72
+
73
+ * Philip Garrett <philgarr at gmail.com>
74
+
75
+ == Copyright and License
76
+
77
+ Copyright (c) 2009-2010 Philip Garrett.
78
+
79
+ Permission is hereby granted, free of charge, to any person obtaining a
80
+ copy of this software and associated documentation files (the
81
+ "Software"), to deal in the Software without restriction, including
82
+ without limitation the rights to use, copy, modify, merge, publish,
83
+ distribute, sublicense, and/or sell copies of the Software, and to
84
+ permit persons to whom the Software is furnished to do so, subject to
85
+ the following conditions:
86
+
87
+ The above copyright notice and this permission notice shall be included
88
+ in all copies or substantial portions of the Software.
89
+
90
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
91
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
92
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
93
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
94
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
95
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
96
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
97
+ }
98
+ s.email = %q{philgarr@gmail.com}
99
+ s.extensions = ["ext/extconf.rb"]
100
+ s.extra_rdoc_files = [
101
+ "README.rdoc"
102
+ ]
103
+ s.files = [
104
+ ".gitignore",
105
+ "Manifest",
106
+ "README.rdoc",
107
+ "Rakefile",
108
+ "VERSION",
109
+ "ext/.gitignore",
110
+ "ext/extconf.rb",
111
+ "ext/mcrypt_wrapper.c",
112
+ "lib/.gitignore",
113
+ "lib/mcrypt.rb",
114
+ "ruby-mcrypt.gemspec",
115
+ "test/generate/.gitignore",
116
+ "test/generate/Makefile",
117
+ "test/generate/generate_testcases.c",
118
+ "test/helper.rb",
119
+ "test/test_basics.rb",
120
+ "test/test_brute.rb",
121
+ "test/test_reciprocity.rb"
122
+ ]
123
+ s.homepage = %q{http://github.com/kingpong/ruby-mcrypt}
124
+ s.rdoc_options = ["--charset=UTF-8"]
125
+ s.require_paths = ["lib"]
126
+ s.required_ruby_version = Gem::Requirement.new(">= 1.8.6")
127
+ s.requirements = ["libmcrypt (2.5.x or 2.6.x, tested with 2.5.8)"]
128
+ s.rubygems_version = %q{1.3.7}
129
+ s.summary = %q{Ruby bindings for libmcrypt}
130
+ s.test_files = [
131
+ "test/helper.rb",
132
+ "test/test_basics.rb",
133
+ "test/test_brute.rb",
134
+ "test/test_reciprocity.rb"
135
+ ]
136
+
137
+ if s.respond_to? :specification_version then
138
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
139
+ s.specification_version = 3
140
+
141
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
142
+ else
143
+ end
144
+ else
145
+ end
146
+ end
147
+
@@ -0,0 +1,3 @@
1
+ generate_testcases
2
+ generate_testcases.o
3
+ generate_testcases.dSYM
@@ -0,0 +1,11 @@
1
+
2
+ LOADLIBES=-lmcrypt
3
+ CFLAGS=-O2
4
+
5
+ CPPFLAGS=-I/opt/local/include
6
+ LDFLAGS=-L/opt/local/lib
7
+
8
+ generate_testcases: generate_testcases.c
9
+
10
+ memcheck: generate_testcases
11
+ valgrind --leak-check=yes ./generate_testcases > /dev/null
@@ -0,0 +1,389 @@
1
+ /*
2
+ * generate_testcases.c
3
+ *
4
+ * Generates a list of known-good inputs/outputs to be compared against the
5
+ * output of ruby-mcrypt.
6
+ *
7
+ * Copyright (c) 2009 Philip Garrett.
8
+ *
9
+ * Permission is hereby granted, free of charge, to any person obtaining a
10
+ * copy of this software and associated documentation files (the
11
+ * "Software"), to deal in the Software without restriction, including
12
+ * without limitation the rights to use, copy, modify, merge, publish,
13
+ * distribute, sublicense, and/or sell copies of the Software, and to
14
+ * permit persons to whom the Software is furnished to do so, subject to
15
+ * the following conditions:
16
+ *
17
+ * The above copyright notice and this permission notice shall be included
18
+ * in all copies or substantial portions of the Software.
19
+ *
20
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
+ */
28
+
29
+ #include <stdio.h>
30
+ #include <stdlib.h>
31
+ #include <string.h>
32
+
33
+ #include <mcrypt.h>
34
+
35
+ typedef enum { PADDING_NONE, PADDING_PKCS7, PADDING_ZEROS } padding_t;
36
+ const char *padding_name(padding_t padding);
37
+
38
+ unsigned char *gen_rand_data(unsigned int len);
39
+ char *dump_value(void *buffer, int len);
40
+
41
+ void dump_testcase(char *algo, char *mode);
42
+ void dump_testcase_keysize(MCRYPT td, int key_size);
43
+ void dump_testcase_block(MCRYPT td, unsigned char *key, int key_size,
44
+ unsigned char *iv, int iv_size, int block_size,
45
+ padding_t padding);
46
+
47
+ int *list_key_sizes(MCRYPT td);
48
+
49
+ static char testing_algo[128];
50
+ static char testing_mode[128];
51
+
52
+ int main() {
53
+ char **algos, **modes;
54
+ int n_algos, n_modes,
55
+ i_algo, i_mode;
56
+
57
+ /* get consistent output even though it's "random" */
58
+ srand48(1153616166L);
59
+
60
+ algos = mcrypt_list_algorithms(NULL, &n_algos);
61
+ if (algos == NULL) {
62
+ fprintf(stderr, "Unable to list algorithms.\n");
63
+ exit(1);
64
+ }
65
+
66
+ modes = mcrypt_list_modes(NULL, &n_modes);
67
+ if (modes == NULL) {
68
+ fprintf(stderr, "Unable to list modes.\n");
69
+ exit(1);
70
+ }
71
+
72
+ for (i_algo = 0; i_algo < n_algos; i_algo++) {
73
+ for (i_mode = 0; i_mode < n_modes; i_mode++) {
74
+ dump_testcase(algos[i_algo],modes[i_mode]);
75
+ }
76
+ }
77
+
78
+ mcrypt_free_p(algos, n_algos);
79
+ mcrypt_free_p(modes, n_modes);
80
+
81
+ return 0;
82
+ }
83
+
84
+ void dump_testcase(char *algo, char *mode) {
85
+ MCRYPT td;
86
+ int *key_sizes, *cur_size;
87
+
88
+ /* globalize this for easier access below */
89
+ strcpy(testing_algo, algo);
90
+ strcpy(testing_mode, mode);
91
+
92
+ td = mcrypt_module_open(algo, NULL, mode, NULL);
93
+ if (td == MCRYPT_FAILED) {
94
+ /* assume that this algorithm just doesn't support this mode */
95
+ return;
96
+ }
97
+
98
+ cur_size = key_sizes = list_key_sizes(td);
99
+ if (key_sizes == NULL) {
100
+ return;
101
+ }
102
+
103
+ while (*cur_size != 0) {
104
+ dump_testcase_keysize(td, *cur_size);
105
+ cur_size++;
106
+ }
107
+ free(key_sizes);
108
+
109
+ mcrypt_module_close(td);
110
+ }
111
+
112
+ void dump_testcase_keysize(MCRYPT td, int key_size) {
113
+ unsigned char *key, *iv = NULL;
114
+ int iv_size, block_size;
115
+ int mc_ret;
116
+ padding_t padding;
117
+
118
+ key = gen_rand_data(key_size);
119
+
120
+ iv_size = mcrypt_enc_get_iv_size(td);
121
+ if (iv_size != 0) {
122
+ iv = gen_rand_data(iv_size);
123
+ }
124
+
125
+ /*
126
+ * Generate a test case for these plaintext sizes:
127
+ *
128
+ * * empty: test behavior of padding on empty blocks
129
+ * * 5-byte: odd, and smaller than any block size
130
+ * * block_size - 1: edge case
131
+ * * block_size: generally guaranteed to work
132
+ * * block_size * 2 - 1: multiblock edge case
133
+ * * block_size * 3: more multiblock
134
+ */
135
+ block_size = mcrypt_enc_get_block_size(td);
136
+
137
+ padding = mcrypt_enc_is_block_mode(td) ? PADDING_PKCS7 : PADDING_NONE;
138
+
139
+ for (; padding <= PADDING_ZEROS; padding++) {
140
+ dump_testcase_block(td, key, key_size, iv, iv_size, 0, padding);
141
+ dump_testcase_block(td, key, key_size, iv, iv_size, 5, padding);
142
+ dump_testcase_block(td, key, key_size, iv, iv_size, block_size - 1,
143
+ padding);
144
+ dump_testcase_block(td, key, key_size, iv, iv_size, block_size,
145
+ padding);
146
+ dump_testcase_block(td, key, key_size, iv, iv_size,
147
+ block_size * 2 - 1, padding);
148
+ dump_testcase_block(td, key, key_size, iv, iv_size, block_size * 3,
149
+ padding);
150
+ }
151
+
152
+ free(key);
153
+ if (iv) free(iv);
154
+
155
+ return;
156
+ }
157
+
158
+ void dump_testcase_block(MCRYPT td, unsigned char *key, int key_size,
159
+ unsigned char *iv, int iv_size, int data_size,
160
+ padding_t padding) {
161
+ int mc_ret;
162
+ int is_block, block_size, block_overlap, block_fill;
163
+ int i;
164
+ unsigned char *plaintext, *ciphertext;
165
+
166
+ mc_ret = mcrypt_generic_init(td, (void *)key, key_size, (void *)iv);
167
+ if (mc_ret < 0) {
168
+ mcrypt_perror(mc_ret);
169
+ return;
170
+ }
171
+
172
+ plaintext = gen_rand_data(data_size);
173
+ if (plaintext == NULL) {
174
+ return;
175
+ }
176
+
177
+ is_block = mcrypt_enc_is_block_mode(td);
178
+ if (is_block) {
179
+ block_size = mcrypt_enc_get_block_size(td);
180
+ block_overlap = data_size % block_size;
181
+ block_fill = block_size - block_overlap;
182
+ if (padding == PADDING_NONE) {
183
+ /* do nothing */
184
+ }
185
+ else if (padding == PADDING_PKCS7) {
186
+ if (block_fill == 0) {
187
+ /* ALWAYS add padding */
188
+ block_fill = block_size;
189
+ }
190
+ plaintext = (unsigned char *)realloc(plaintext,
191
+ data_size + block_fill);
192
+ for (i = 0; i < block_fill; i++) {
193
+ plaintext[data_size+i] = block_fill;
194
+ }
195
+ data_size = data_size + block_fill;
196
+ if ((data_size % block_size) != 0) {
197
+ fprintf(stderr, "bad data size!\n");
198
+ exit(1);
199
+ }
200
+ }
201
+ else if (padding == PADDING_ZEROS) {
202
+ if (block_overlap != 0) {
203
+ plaintext = (unsigned char *)realloc(plaintext,
204
+ data_size + block_fill);
205
+ for (i = 0; i < block_fill; i++) {
206
+ plaintext[data_size+i] = '\0';
207
+ }
208
+ data_size = data_size + block_fill;
209
+ }
210
+ }
211
+ else {
212
+ fprintf(stderr, "bad error\n");
213
+ exit(1);
214
+ }
215
+ }
216
+
217
+ ciphertext = malloc(data_size);
218
+ if (ciphertext == NULL) {
219
+ fprintf(stderr, "Out of memory\n");
220
+ return;
221
+ }
222
+
223
+ memcpy( (void *)ciphertext, (void *)plaintext, data_size);
224
+
225
+ mc_ret = mcrypt_generic(td, ciphertext, data_size);
226
+ if (mc_ret == 0) {
227
+ char *enc_key, *enc_iv, *enc_pt, *enc_ct;
228
+ enc_key = dump_value( (void *)key, key_size );
229
+ enc_iv = dump_value( (void *)iv, iv_size );
230
+ enc_pt = dump_value( (void *)plaintext, data_size );
231
+ enc_ct = dump_value( (void *)ciphertext, data_size );
232
+
233
+ printf("algo=%s,mode=%s,key=%s,iv=%s,padding=%s,pt=%s,ct=%s\n",
234
+ testing_algo, testing_mode, enc_key, enc_iv,
235
+ padding_name(padding), enc_pt, enc_ct);
236
+
237
+ free(enc_key);
238
+ free(enc_iv);
239
+ free(enc_pt);
240
+ free(enc_ct);
241
+ }
242
+
243
+ free(plaintext);
244
+ free(ciphertext);
245
+
246
+ mc_ret = mcrypt_generic_deinit(td);
247
+ if (mc_ret < 0) {
248
+ fprintf(stderr, "Error %d during deinit of %s in %s mode"
249
+ " (%d-byte key)\n", mc_ret, testing_algo, testing_mode, key_size);
250
+ return;
251
+ }
252
+ }
253
+
254
+ /*
255
+ * padding_name(padding)
256
+ *
257
+ * Returns the string name for the padding type.
258
+ *
259
+ */
260
+
261
+ const char *padding_name(padding_t padding) {
262
+ switch(padding) {
263
+ case PADDING_NONE: return "none";
264
+ case PADDING_PKCS7: return "pkcs";
265
+ case PADDING_ZEROS: return "zeros";
266
+ default: fprintf(stderr, "Invalid padding type\n");
267
+ exit(1);
268
+ }
269
+ }
270
+
271
+
272
+ /*
273
+ * list_key_sizes(td)
274
+ *
275
+ * Returns a pointer to an array of integer key sizes for the mcrypt
276
+ * handle. This returns the actual list, as opposed to
277
+ * mcrypt_enc_get_supported_key_sizes which sometimes just returns a
278
+ * formula to create the list.
279
+ *
280
+ * The list is terminated with a zero.
281
+ *
282
+ */
283
+ int *list_key_sizes(MCRYPT td) {
284
+ int *list;
285
+ int *key_sizes, n_key_sizes, i;
286
+
287
+ key_sizes = mcrypt_enc_get_supported_key_sizes(td, &n_key_sizes);
288
+
289
+ if (!key_sizes && !n_key_sizes) {
290
+ int max_size = mcrypt_enc_get_key_size(td);
291
+ list = malloc( (max_size + 1) * sizeof(int) );
292
+ if (!list) {
293
+ fprintf(stderr, "Out of memory\n");
294
+ return NULL;
295
+ }
296
+
297
+ for (i = 0; i < max_size; i++) {
298
+ list[i] = i;
299
+ }
300
+ list[max_size] = 0;
301
+ }
302
+ else {
303
+ list = malloc( (n_key_sizes + 1) * sizeof(int) );
304
+ if (!list) {
305
+ fprintf(stderr, "Out of memory\n");
306
+ return NULL;
307
+ }
308
+
309
+ for (i = 0; i < n_key_sizes; i++) {
310
+ list[i] = key_sizes[i];
311
+ }
312
+ list[n_key_sizes] = 0;
313
+
314
+ free(key_sizes);
315
+ }
316
+
317
+ return list;
318
+ }
319
+
320
+
321
+ /*
322
+ * gen_rand_data(len)
323
+ *
324
+ * Returns a random key of byte length len. You need to free it when
325
+ * you're done with it.
326
+ *
327
+ * This isn't truly random but it doesn't have to be as it's just
328
+ * generating test cases.
329
+ *
330
+ */
331
+ unsigned char *gen_rand_data(unsigned int len) {
332
+ unsigned char *key, *p;
333
+ unsigned int i;
334
+
335
+ p = key = malloc(len);
336
+ if (key == NULL) {
337
+ return NULL;
338
+ }
339
+
340
+ for (i = 0; i < len; i++) {
341
+ *p++ = (unsigned char)(255L * drand48());
342
+ }
343
+
344
+ return key;
345
+ }
346
+
347
+
348
+ /*
349
+ * dump_value(void *buffer, int len)
350
+ *
351
+ * Returns a string containing the buffer's contents encoded as
352
+ * two-character hexadecimal bytes separated by spaces.
353
+ *
354
+ * Free it when you're done.
355
+ *
356
+ */
357
+
358
+ char *dump_value(void *buffer, int len) {
359
+ char *enc, *p;
360
+ unsigned char *buf;
361
+ int i;
362
+ const char hex_digits[] = { '0','1','2','3','4','5','6','7','8','9',
363
+ 'a','b','c','d','e','f' };
364
+
365
+ buf = (unsigned char *)buffer;
366
+
367
+ if (len == 0) {
368
+ return strdup("");
369
+ }
370
+
371
+ p = enc = malloc(len * 3);
372
+ if (enc == NULL) {
373
+ return NULL;
374
+ }
375
+
376
+ *p = '\0';
377
+
378
+ for(i = 0; i < len; i++) {
379
+ if (i != 0) {
380
+ (*p++) = ' ';
381
+ }
382
+ (*p++) = hex_digits[buf[i] >> 4];
383
+ (*p++) = hex_digits[buf[i] & 0xF];
384
+ }
385
+ (*p++) = '\0';
386
+
387
+ return enc;
388
+ }
389
+