kingpong-ruby-mcrypt 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{ruby-mcrypt}
5
+ s.version = "0.1.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Philip Garrett"]
9
+ s.date = %q{2009-09-09}
10
+ s.description = %q{Ruby bindings for libmcrypt}
11
+ s.email = %q{philip@pastemagazine.com}
12
+ s.extensions = ["ext/extconf.rb"]
13
+ s.extra_rdoc_files = ["README.rdoc", "ext/extconf.rb", "ext/mcrypt_wrapper.c", "lib/mcrypt.rb"]
14
+ s.files = ["Manifest", "README.rdoc", "Rakefile", "ext/extconf.rb", "ext/mcrypt_wrapper.c", "lib/mcrypt.rb", "ruby-mcrypt.gemspec", "test/generate/Makefile", "test/generate/generate_testcases.c", "test/helper.rb", "test/test_all.rb", "test/test_basics.rb", "test/test_brute.rb", "test/test_reciprocity.rb"]
15
+ s.homepage = %q{http://github.com/kingpong/ruby-mcrypt}
16
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Ruby-mcrypt", "--main", "README.rdoc"]
17
+ s.require_paths = ["lib", "ext"]
18
+ s.rubyforge_project = %q{ruby-mcrypt}
19
+ s.rubygems_version = %q{1.3.3}
20
+ s.summary = %q{ruby-mcrypt 0.0.1}
21
+ s.test_files = ["test/test_all.rb"]
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 3
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ else
29
+ end
30
+ else
31
+ end
32
+ end
@@ -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", 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
+
data/test/helper.rb ADDED
@@ -0,0 +1,13 @@
1
+
2
+ $VERBOSE = false
3
+ require 'test/unit'
4
+
5
+ begin
6
+ here = File.dirname(__FILE__)
7
+ %w(lib bin test).each do |dir|
8
+ path = "#{here}/../#{dir}"
9
+ $LOAD_PATH.unshift(path) unless $LOAD_PATH.include?(path)
10
+ end
11
+ end
12
+
13
+ require 'mcrypt'