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.
@@ -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
+