1/*
2   +----------------------------------------------------------------------+
3   | PHP Version 5                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2014 The PHP Group                                |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.php.net/license/3_01.txt                                  |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Authors: Sascha Schumann <sascha@schumann.cx>                        |
16   |          Derick Rethans <derick@derickrethans.nl>                    |
17   +----------------------------------------------------------------------+
18 */
19/* $Id$ */
20
21#ifdef HAVE_CONFIG_H
22#include "config.h"
23#endif
24
25#include "php.h"
26
27#if HAVE_LIBMCRYPT
28
29#if PHP_WIN32
30# include "win32/winutil.h"
31#endif
32
33#include "php_mcrypt.h"
34#include "fcntl.h"
35
36#define NON_FREE
37#define MCRYPT2
38#include "mcrypt.h"
39#include "php_ini.h"
40#include "php_globals.h"
41#include "ext/standard/info.h"
42#include "ext/standard/php_rand.h"
43#include "php_mcrypt_filter.h"
44
45static int le_mcrypt;
46
47typedef struct _php_mcrypt {
48    MCRYPT td;
49    zend_bool init;
50} php_mcrypt;
51
52/* {{{ arginfo */
53ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_module_open, 0, 0, 4)
54    ZEND_ARG_INFO(0, cipher)
55    ZEND_ARG_INFO(0, cipher_directory)
56    ZEND_ARG_INFO(0, mode)
57    ZEND_ARG_INFO(0, mode_directory)
58ZEND_END_ARG_INFO()
59
60ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_generic_init, 0, 0, 3)
61    ZEND_ARG_INFO(0, td)
62    ZEND_ARG_INFO(0, key)
63    ZEND_ARG_INFO(0, iv)
64ZEND_END_ARG_INFO()
65
66ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_generic, 0, 0, 2)
67    ZEND_ARG_INFO(0, td)
68    ZEND_ARG_INFO(0, data)
69ZEND_END_ARG_INFO()
70
71ZEND_BEGIN_ARG_INFO_EX(arginfo_mdecrypt_generic, 0, 0, 2)
72    ZEND_ARG_INFO(0, td)
73    ZEND_ARG_INFO(0, data)
74ZEND_END_ARG_INFO()
75
76ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_enc_get_supported_key_sizes, 0, 0, 1)
77    ZEND_ARG_INFO(0, td)
78ZEND_END_ARG_INFO()
79
80ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_enc_self_test, 0, 0, 1)
81    ZEND_ARG_INFO(0, td)
82ZEND_END_ARG_INFO()
83
84ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_module_close, 0, 0, 1)
85    ZEND_ARG_INFO(0, td)
86ZEND_END_ARG_INFO()
87
88ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_generic_deinit, 0, 0, 1)
89    ZEND_ARG_INFO(0, td)
90ZEND_END_ARG_INFO()
91
92ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_enc_is_block_algorithm_mode, 0, 0, 1)
93    ZEND_ARG_INFO(0, td)
94ZEND_END_ARG_INFO()
95
96ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_enc_is_block_algorithm, 0, 0, 1)
97    ZEND_ARG_INFO(0, td)
98ZEND_END_ARG_INFO()
99
100ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_enc_is_block_mode, 0, 0, 1)
101    ZEND_ARG_INFO(0, td)
102ZEND_END_ARG_INFO()
103
104ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_enc_get_block_size, 0, 0, 1)
105    ZEND_ARG_INFO(0, td)
106ZEND_END_ARG_INFO()
107
108ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_enc_get_key_size, 0, 0, 1)
109    ZEND_ARG_INFO(0, td)
110ZEND_END_ARG_INFO()
111
112ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_enc_get_iv_size, 0, 0, 1)
113    ZEND_ARG_INFO(0, td)
114ZEND_END_ARG_INFO()
115
116ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_enc_get_algorithms_name, 0, 0, 1)
117    ZEND_ARG_INFO(0, td)
118ZEND_END_ARG_INFO()
119
120ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_enc_get_modes_name, 0, 0, 1)
121    ZEND_ARG_INFO(0, td)
122ZEND_END_ARG_INFO()
123
124ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_module_self_test, 0, 0, 1)
125    ZEND_ARG_INFO(0, algorithm)
126    ZEND_ARG_INFO(0, lib_dir)
127ZEND_END_ARG_INFO()
128
129ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_module_is_block_algorithm_mode, 0, 0, 1)
130    ZEND_ARG_INFO(0, mode)
131    ZEND_ARG_INFO(0, lib_dir)
132ZEND_END_ARG_INFO()
133
134ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_module_is_block_algorithm, 0, 0, 1)
135    ZEND_ARG_INFO(0, algorithm)
136    ZEND_ARG_INFO(0, lib_dir)
137ZEND_END_ARG_INFO()
138
139ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_module_is_block_mode, 0, 0, 1)
140    ZEND_ARG_INFO(0, mode)
141    ZEND_ARG_INFO(0, lib_dir)
142ZEND_END_ARG_INFO()
143
144ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_module_get_algo_block_size, 0, 0, 1)
145    ZEND_ARG_INFO(0, algorithm)
146    ZEND_ARG_INFO(0, lib_dir)
147ZEND_END_ARG_INFO()
148
149ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_module_get_algo_key_size, 0, 0, 1)
150    ZEND_ARG_INFO(0, algorithm)
151    ZEND_ARG_INFO(0, lib_dir)
152ZEND_END_ARG_INFO()
153
154ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_module_get_supported_key_sizes, 0, 0, 1)
155    ZEND_ARG_INFO(0, algorithm)
156    ZEND_ARG_INFO(0, lib_dir)
157ZEND_END_ARG_INFO()
158
159ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_list_algorithms, 0, 0, 0)
160    ZEND_ARG_INFO(0, lib_dir)
161ZEND_END_ARG_INFO()
162
163ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_list_modes, 0, 0, 0)
164    ZEND_ARG_INFO(0, lib_dir)
165ZEND_END_ARG_INFO()
166
167ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_get_key_size, 0, 0, 2)
168    ZEND_ARG_INFO(0, cipher)
169    ZEND_ARG_INFO(0, module)
170ZEND_END_ARG_INFO()
171
172ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_get_block_size, 0, 0, 2)
173    ZEND_ARG_INFO(0, cipher)
174    ZEND_ARG_INFO(0, module)
175ZEND_END_ARG_INFO()
176
177ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_get_iv_size, 0, 0, 2)
178    ZEND_ARG_INFO(0, cipher)
179    ZEND_ARG_INFO(0, module)
180ZEND_END_ARG_INFO()
181
182ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_get_cipher_name, 0, 0, 1)
183    ZEND_ARG_INFO(0, cipher)
184ZEND_END_ARG_INFO()
185
186ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_encrypt, 0, 0, 5)
187    ZEND_ARG_INFO(0, cipher)
188    ZEND_ARG_INFO(0, key)
189    ZEND_ARG_INFO(0, data)
190    ZEND_ARG_INFO(0, mode)
191    ZEND_ARG_INFO(0, iv)
192ZEND_END_ARG_INFO()
193
194ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_decrypt, 0, 0, 5)
195    ZEND_ARG_INFO(0, cipher)
196    ZEND_ARG_INFO(0, key)
197    ZEND_ARG_INFO(0, data)
198    ZEND_ARG_INFO(0, mode)
199    ZEND_ARG_INFO(0, iv)
200ZEND_END_ARG_INFO()
201
202ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_ecb, 0, 0, 5)
203    ZEND_ARG_INFO(0, cipher)
204    ZEND_ARG_INFO(0, key)
205    ZEND_ARG_INFO(0, data)
206    ZEND_ARG_INFO(0, mode)
207    ZEND_ARG_INFO(0, iv)
208ZEND_END_ARG_INFO()
209
210ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_cbc, 0, 0, 5)
211    ZEND_ARG_INFO(0, cipher)
212    ZEND_ARG_INFO(0, key)
213    ZEND_ARG_INFO(0, data)
214    ZEND_ARG_INFO(0, mode)
215    ZEND_ARG_INFO(0, iv)
216ZEND_END_ARG_INFO()
217
218ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_cfb, 0, 0, 5)
219    ZEND_ARG_INFO(0, cipher)
220    ZEND_ARG_INFO(0, key)
221    ZEND_ARG_INFO(0, data)
222    ZEND_ARG_INFO(0, mode)
223    ZEND_ARG_INFO(0, iv)
224ZEND_END_ARG_INFO()
225
226ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_ofb, 0, 0, 5)
227    ZEND_ARG_INFO(0, cipher)
228    ZEND_ARG_INFO(0, key)
229    ZEND_ARG_INFO(0, data)
230    ZEND_ARG_INFO(0, mode)
231    ZEND_ARG_INFO(0, iv)
232ZEND_END_ARG_INFO()
233
234ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_create_iv, 0, 0, 2)
235    ZEND_ARG_INFO(0, size)
236    ZEND_ARG_INFO(0, source)
237ZEND_END_ARG_INFO()
238/* }}} */
239
240const zend_function_entry mcrypt_functions[] = { /* {{{ */
241    PHP_FE(mcrypt_ecb,              arginfo_mcrypt_ecb)
242    PHP_FE(mcrypt_cbc,              arginfo_mcrypt_cbc)
243    PHP_FE(mcrypt_cfb,              arginfo_mcrypt_cfb)
244    PHP_FE(mcrypt_ofb,              arginfo_mcrypt_ofb)
245    PHP_FE(mcrypt_get_key_size,     arginfo_mcrypt_get_key_size)
246    PHP_FE(mcrypt_get_block_size,   arginfo_mcrypt_get_block_size)
247    PHP_FE(mcrypt_get_cipher_name,  arginfo_mcrypt_get_cipher_name)
248    PHP_FE(mcrypt_create_iv,        arginfo_mcrypt_create_iv)
249
250    PHP_FE(mcrypt_list_algorithms,  arginfo_mcrypt_list_algorithms)
251    PHP_FE(mcrypt_list_modes,       arginfo_mcrypt_list_modes)
252    PHP_FE(mcrypt_get_iv_size,      arginfo_mcrypt_get_iv_size)
253    PHP_FE(mcrypt_encrypt,          arginfo_mcrypt_encrypt)
254    PHP_FE(mcrypt_decrypt,          arginfo_mcrypt_decrypt)
255
256    PHP_FE(mcrypt_module_open,      arginfo_mcrypt_module_open)
257    PHP_FE(mcrypt_generic_init,     arginfo_mcrypt_generic_init)
258    PHP_FE(mcrypt_generic,          arginfo_mcrypt_generic)
259    PHP_FE(mdecrypt_generic,        arginfo_mdecrypt_generic)
260    PHP_DEP_FALIAS(mcrypt_generic_end, mcrypt_generic_deinit, arginfo_mcrypt_generic_deinit)
261    PHP_FE(mcrypt_generic_deinit,   arginfo_mcrypt_generic_deinit)
262
263    PHP_FE(mcrypt_enc_self_test,    arginfo_mcrypt_enc_self_test)
264    PHP_FE(mcrypt_enc_is_block_algorithm_mode, arginfo_mcrypt_enc_is_block_algorithm_mode)
265    PHP_FE(mcrypt_enc_is_block_algorithm,   arginfo_mcrypt_enc_is_block_algorithm)
266    PHP_FE(mcrypt_enc_is_block_mode,        arginfo_mcrypt_enc_is_block_mode)
267    PHP_FE(mcrypt_enc_get_block_size,       arginfo_mcrypt_enc_get_block_size)
268    PHP_FE(mcrypt_enc_get_key_size,         arginfo_mcrypt_enc_get_key_size)
269    PHP_FE(mcrypt_enc_get_supported_key_sizes, arginfo_mcrypt_enc_get_supported_key_sizes)
270    PHP_FE(mcrypt_enc_get_iv_size,          arginfo_mcrypt_enc_get_iv_size)
271    PHP_FE(mcrypt_enc_get_algorithms_name,  arginfo_mcrypt_enc_get_algorithms_name)
272    PHP_FE(mcrypt_enc_get_modes_name,       arginfo_mcrypt_enc_get_modes_name)
273    PHP_FE(mcrypt_module_self_test,         arginfo_mcrypt_module_self_test)
274
275    PHP_FE(mcrypt_module_is_block_algorithm_mode,   arginfo_mcrypt_module_is_block_algorithm_mode)
276    PHP_FE(mcrypt_module_is_block_algorithm,        arginfo_mcrypt_module_is_block_algorithm)
277    PHP_FE(mcrypt_module_is_block_mode,             arginfo_mcrypt_module_is_block_mode)
278    PHP_FE(mcrypt_module_get_algo_block_size,       arginfo_mcrypt_module_get_algo_block_size)
279    PHP_FE(mcrypt_module_get_algo_key_size,         arginfo_mcrypt_module_get_algo_key_size)
280    PHP_FE(mcrypt_module_get_supported_key_sizes,   arginfo_mcrypt_module_get_supported_key_sizes)
281
282    PHP_FE(mcrypt_module_close,                     arginfo_mcrypt_module_close)
283    PHP_FE_END
284};
285/* }}} */
286
287static PHP_MINFO_FUNCTION(mcrypt);
288static PHP_MINIT_FUNCTION(mcrypt);
289static PHP_MSHUTDOWN_FUNCTION(mcrypt);
290
291ZEND_DECLARE_MODULE_GLOBALS(mcrypt)
292
293zend_module_entry mcrypt_module_entry = {
294    STANDARD_MODULE_HEADER,
295    "mcrypt",
296    mcrypt_functions,
297    PHP_MINIT(mcrypt), PHP_MSHUTDOWN(mcrypt),
298    NULL, NULL,
299    PHP_MINFO(mcrypt),
300    NO_VERSION_YET,
301    PHP_MODULE_GLOBALS(mcrypt),
302    NULL,
303    NULL,
304    NULL,
305    STANDARD_MODULE_PROPERTIES_EX
306};
307
308#ifdef COMPILE_DL_MCRYPT
309ZEND_GET_MODULE(mcrypt)
310#endif
311
312#define MCRYPT_ARGS2                                            \
313    zval **cipher, **data, **key, **mode;                       \
314    int td;                                                     \
315    char *ndata;                                                \
316    size_t bsize;                                               \
317    size_t nr;                                                  \
318    size_t nsize
319
320#define MCRYPT_ARGS                                             \
321    MCRYPT_ARGS2;                                               \
322    zval **iv
323
324#define MCRYPT_SIZE                                         \
325    bsize = mcrypt_get_block_size(Z_LVAL_PP(cipher));       \
326    nr = (Z_STRLEN_PP(data) + bsize - 1) / bsize;           \
327    nsize = nr * bsize
328
329#define MCRYPT_CHECK_TD_CPY                                     \
330    if (td < 0) {                                               \
331        php_error_docref(NULL TSRMLS_CC, E_WARNING, MCRYPT_FAILED);                     \
332        RETURN_FALSE;                                           \
333    }                                                           \
334    ndata = ecalloc(nr, bsize);                                 \
335    memcpy(ndata, Z_STRVAL_PP(data), Z_STRLEN_PP(data))
336
337#define MCRYPT_CHECK_IV                                         \
338    convert_to_string_ex(iv);                                   \
339    if (Z_STRLEN_PP(iv) != bsize) {                             \
340        php_error_docref(NULL TSRMLS_CC, E_WARNING, MCRYPT_IV_WRONG_SIZE);          \
341        RETURN_FALSE;                                           \
342    }
343
344#define MCRYPT_ACTION(x)                                        \
345    if (Z_LVAL_PP(mode) == 0) {                                 \
346        mcrypt_##x(td, ndata, nsize);                           \
347    } else {                                                    \
348        mdecrypt_##x(td, ndata, nsize);                         \
349    }                                                           \
350    end_mcrypt_##x(td)
351
352#define MCRYPT_IV_WRONG_SIZE "The IV parameter must be as long as the blocksize"
353
354#define MCRYPT_ENCRYPT 0
355#define MCRYPT_DECRYPT 1
356
357#define MCRYPT_GET_INI                                          \
358    cipher_dir_string = MCG(algorithms_dir);                    \
359    module_dir_string = MCG(modes_dir);
360
361/*
362 * #warning is not ANSI C
363 * #warning Invalidate resource if the param count is wrong, or other problems
364 * #warning occurred during functions.
365 */
366
367#define MCRYPT_GET_CRYPT_ARGS                                       \
368    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sssZ|s",  \
369        &cipher, &cipher_len, &key, &key_len, &data, &data_len, &mode, &iv, &iv_len) == FAILURE) {  \
370        return;     \
371    }
372
373#define MCRYPT_GET_TD_ARG                                       \
374    zval *mcryptind;                                            \
375    php_mcrypt *pm;                                                 \
376    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &mcryptind) == FAILURE) {         \
377        return;                                                             \
378    }                                                                                       \
379    ZEND_FETCH_RESOURCE (pm, php_mcrypt *, &mcryptind, -1, "MCrypt", le_mcrypt);
380
381#define MCRYPT_GET_MODE_DIR_ARGS(DIRECTORY)                             \
382    char *dir = NULL;                                                   \
383    int   dir_len;                                                      \
384    char *module;                                                       \
385    int   module_len;                                                   \
386    if (zend_parse_parameters (ZEND_NUM_ARGS() TSRMLS_CC,               \
387        "s|s", &module, &module_len, &dir, &dir_len) == FAILURE) {      \
388        return;                                                         \
389    }
390
391#define MCRYPT_OPEN_MODULE_FAILED "Module initialization failed"
392
393#define MCRYPT_ENTRY2_2_4(a,b) REGISTER_STRING_CONSTANT("MCRYPT_" #a, b, CONST_PERSISTENT)
394#define MCRYPT_ENTRY2_4(a) MCRYPT_ENTRY_NAMED(a, a)
395
396#define PHP_MCRYPT_INIT_CHECK   \
397    if (!pm->init) {    \
398        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Operation disallowed prior to mcrypt_generic_init().");    \
399        RETURN_FALSE;   \
400    }   \
401
402PHP_INI_BEGIN()
403    STD_PHP_INI_ENTRY("mcrypt.algorithms_dir", NULL, PHP_INI_ALL, OnUpdateString, algorithms_dir, zend_mcrypt_globals, mcrypt_globals)
404    STD_PHP_INI_ENTRY("mcrypt.modes_dir",      NULL, PHP_INI_ALL, OnUpdateString, modes_dir, zend_mcrypt_globals, mcrypt_globals)
405PHP_INI_END()
406
407static void php_mcrypt_module_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
408{
409    php_mcrypt *pm = (php_mcrypt *) rsrc->ptr;
410    if (pm) {
411        mcrypt_generic_deinit(pm->td);
412        mcrypt_module_close(pm->td);
413        efree(pm);
414        pm = NULL;
415    }
416}
417/* }}} */
418
419static PHP_MINIT_FUNCTION(mcrypt) /* {{{ */
420{
421    le_mcrypt = zend_register_list_destructors_ex(php_mcrypt_module_dtor, NULL, "mcrypt", module_number);
422
423    /* modes for mcrypt_??? routines */
424    REGISTER_LONG_CONSTANT("MCRYPT_ENCRYPT", 0, CONST_PERSISTENT);
425    REGISTER_LONG_CONSTANT("MCRYPT_DECRYPT", 1, CONST_PERSISTENT);
426
427    /* sources for mcrypt_create_iv */
428    REGISTER_LONG_CONSTANT("MCRYPT_DEV_RANDOM", 0, CONST_PERSISTENT);
429    REGISTER_LONG_CONSTANT("MCRYPT_DEV_URANDOM", 1, CONST_PERSISTENT);
430    REGISTER_LONG_CONSTANT("MCRYPT_RAND", 2, CONST_PERSISTENT);
431
432    /* ciphers */
433    MCRYPT_ENTRY2_2_4(3DES, "tripledes");
434    MCRYPT_ENTRY2_2_4(ARCFOUR_IV, "arcfour-iv");
435    MCRYPT_ENTRY2_2_4(ARCFOUR, "arcfour");
436    MCRYPT_ENTRY2_2_4(BLOWFISH, "blowfish");
437    MCRYPT_ENTRY2_2_4(BLOWFISH_COMPAT, "blowfish-compat");
438    MCRYPT_ENTRY2_2_4(CAST_128, "cast-128");
439    MCRYPT_ENTRY2_2_4(CAST_256, "cast-256");
440    MCRYPT_ENTRY2_2_4(CRYPT, "crypt");
441    MCRYPT_ENTRY2_2_4(DES, "des");
442    MCRYPT_ENTRY2_2_4(ENIGNA, "crypt");
443    MCRYPT_ENTRY2_2_4(GOST, "gost");
444    MCRYPT_ENTRY2_2_4(LOKI97, "loki97");
445    MCRYPT_ENTRY2_2_4(PANAMA, "panama");
446    MCRYPT_ENTRY2_2_4(RC2, "rc2");
447    MCRYPT_ENTRY2_2_4(RIJNDAEL_128, "rijndael-128");
448    MCRYPT_ENTRY2_2_4(RIJNDAEL_192, "rijndael-192");
449    MCRYPT_ENTRY2_2_4(RIJNDAEL_256, "rijndael-256");
450    MCRYPT_ENTRY2_2_4(SAFER64, "safer-sk64");
451    MCRYPT_ENTRY2_2_4(SAFER128, "safer-sk128");
452    MCRYPT_ENTRY2_2_4(SAFERPLUS, "saferplus");
453    MCRYPT_ENTRY2_2_4(SERPENT, "serpent");
454    MCRYPT_ENTRY2_2_4(THREEWAY, "threeway");
455    MCRYPT_ENTRY2_2_4(TRIPLEDES, "tripledes");
456    MCRYPT_ENTRY2_2_4(TWOFISH, "twofish");
457    MCRYPT_ENTRY2_2_4(WAKE, "wake");
458    MCRYPT_ENTRY2_2_4(XTEA, "xtea");
459
460    MCRYPT_ENTRY2_2_4(IDEA, "idea");
461    MCRYPT_ENTRY2_2_4(MARS, "mars");
462    MCRYPT_ENTRY2_2_4(RC6, "rc6");
463    MCRYPT_ENTRY2_2_4(SKIPJACK, "skipjack");
464/* modes */
465    MCRYPT_ENTRY2_2_4(MODE_CBC, "cbc");
466    MCRYPT_ENTRY2_2_4(MODE_CFB, "cfb");
467    MCRYPT_ENTRY2_2_4(MODE_ECB, "ecb");
468    MCRYPT_ENTRY2_2_4(MODE_NOFB, "nofb");
469    MCRYPT_ENTRY2_2_4(MODE_OFB, "ofb");
470    MCRYPT_ENTRY2_2_4(MODE_STREAM, "stream");
471    REGISTER_INI_ENTRIES();
472
473    php_stream_filter_register_factory("mcrypt.*", &php_mcrypt_filter_factory TSRMLS_CC);
474    php_stream_filter_register_factory("mdecrypt.*", &php_mcrypt_filter_factory TSRMLS_CC);
475
476    return SUCCESS;
477}
478/* }}} */
479
480static PHP_MSHUTDOWN_FUNCTION(mcrypt) /* {{{ */
481{
482    php_stream_filter_unregister_factory("mcrypt.*" TSRMLS_CC);
483    php_stream_filter_unregister_factory("mdecrypt.*" TSRMLS_CC);
484
485    UNREGISTER_INI_ENTRIES();
486    return SUCCESS;
487}
488/* }}} */
489
490#include "ext/standard/php_smart_str.h"
491
492PHP_MINFO_FUNCTION(mcrypt) /* {{{ */
493{
494    char **modules;
495    char mcrypt_api_no[16];
496    int i, count;
497    smart_str tmp1 = {0};
498    smart_str tmp2 = {0};
499
500    modules = mcrypt_list_algorithms(MCG(algorithms_dir), &count);
501    if (count == 0) {
502        smart_str_appends(&tmp1, "none");
503    }
504    for (i = 0; i < count; i++) {
505        smart_str_appends(&tmp1, modules[i]);
506        smart_str_appendc(&tmp1, ' ');
507    }
508    smart_str_0(&tmp1);
509    mcrypt_free_p(modules, count);
510
511    modules = mcrypt_list_modes(MCG(modes_dir), &count);
512    if (count == 0) {
513        smart_str_appends(&tmp2, "none");
514    }
515    for (i = 0; i < count; i++) {
516        smart_str_appends(&tmp2, modules[i]);
517        smart_str_appendc(&tmp2, ' ');
518    }
519    smart_str_0 (&tmp2);
520    mcrypt_free_p (modules, count);
521
522    snprintf (mcrypt_api_no, 16, "%d", MCRYPT_API_VERSION);
523
524    php_info_print_table_start();
525    php_info_print_table_header(2, "mcrypt support", "enabled");
526    php_info_print_table_header(2, "mcrypt_filter support", "enabled");
527    php_info_print_table_row(2, "Version", LIBMCRYPT_VERSION);
528    php_info_print_table_row(2, "Api No", mcrypt_api_no);
529    php_info_print_table_row(2, "Supported ciphers", tmp1.c);
530    php_info_print_table_row(2, "Supported modes", tmp2.c);
531    smart_str_free(&tmp1);
532    smart_str_free(&tmp2);
533    php_info_print_table_end();
534
535    DISPLAY_INI_ENTRIES();
536}
537/* }}} */
538
539typedef enum {
540    RANDOM = 0,
541    URANDOM,
542    RAND
543} iv_source;
544
545/* {{{ proto resource mcrypt_module_open(string cipher, string cipher_directory, string mode, string mode_directory)
546   Opens the module of the algorithm and the mode to be used */
547PHP_FUNCTION(mcrypt_module_open)
548{
549    char *cipher, *cipher_dir;
550    char *mode,   *mode_dir;
551    int   cipher_len, cipher_dir_len;
552    int   mode_len,   mode_dir_len;
553    MCRYPT td;
554    php_mcrypt *pm;
555
556    if (zend_parse_parameters (ZEND_NUM_ARGS() TSRMLS_CC, "ssss",
557        &cipher, &cipher_len, &cipher_dir, &cipher_dir_len,
558        &mode,   &mode_len,   &mode_dir,   &mode_dir_len)) {
559        return;
560    }
561
562    td = mcrypt_module_open (
563        cipher,
564        cipher_dir_len > 0 ? cipher_dir : MCG(algorithms_dir),
565        mode,
566        mode_dir_len > 0 ? mode_dir : MCG(modes_dir)
567    );
568
569    if (td == MCRYPT_FAILED) {
570        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not open encryption module");
571        RETURN_FALSE;
572    } else {
573        pm = emalloc(sizeof(php_mcrypt));
574        pm->td = td;
575        pm->init = 0;
576        ZEND_REGISTER_RESOURCE(return_value, pm, le_mcrypt);
577    }
578}
579/* }}} */
580
581/* {{{ proto int mcrypt_generic_init(resource td, string key, string iv)
582   This function initializes all buffers for the specific module */
583PHP_FUNCTION(mcrypt_generic_init)
584{
585    char *key, *iv;
586    int key_len, iv_len;
587    zval *mcryptind;
588    unsigned char *key_s, *iv_s;
589    int max_key_size, key_size, iv_size;
590    php_mcrypt *pm;
591    int result = 0;
592
593    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &mcryptind, &key, &key_len, &iv, &iv_len) == FAILURE) {
594        return;
595    }
596
597    ZEND_FETCH_RESOURCE(pm, php_mcrypt *, &mcryptind, -1, "MCrypt", le_mcrypt);
598
599    max_key_size = mcrypt_enc_get_key_size(pm->td);
600    iv_size = mcrypt_enc_get_iv_size(pm->td);
601
602    if (key_len == 0) {
603        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Key size is 0");
604    }
605
606    key_s = emalloc(key_len);
607    memset(key_s, 0, key_len);
608
609    iv_s = emalloc(iv_size + 1);
610    memset(iv_s, 0, iv_size + 1);
611
612    if (key_len > max_key_size) {
613        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Key size too large; supplied length: %d, max: %d", key_len, max_key_size);
614        key_size = max_key_size;
615    } else {
616        key_size = key_len;
617    }
618    memcpy(key_s, key, key_len);
619
620    if (iv_len != iv_size) {
621        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Iv size incorrect; supplied length: %d, needed: %d", iv_len, iv_size);
622    }
623    memcpy(iv_s, iv, iv_size);
624
625    mcrypt_generic_deinit(pm->td);
626    result = mcrypt_generic_init(pm->td, key_s, key_size, iv_s);
627
628    /* If this function fails, close the mcrypt module to prevent crashes
629     * when further functions want to access this resource */
630    if (result < 0) {
631        zend_list_delete(Z_LVAL_P(mcryptind));
632        switch (result) {
633            case -3:
634                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Key length incorrect");
635                break;
636            case -4:
637                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Memory allocation error");
638                break;
639            case -1:
640            default:
641                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error");
642                break;
643        }
644    }
645    pm->init = 1;
646    RETVAL_LONG(result);
647
648    efree(iv_s);
649    efree(key_s);
650}
651/* }}} */
652
653/* {{{ proto string mcrypt_generic(resource td, string data)
654   This function encrypts the plaintext */
655PHP_FUNCTION(mcrypt_generic)
656{
657    zval *mcryptind;
658    char *data;
659    int data_len;
660    php_mcrypt *pm;
661    unsigned char* data_s;
662    int block_size, data_size;
663
664    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &mcryptind, &data, &data_len) == FAILURE) {
665        return;
666    }
667
668    ZEND_FETCH_RESOURCE(pm, php_mcrypt *, &mcryptind, -1, "MCrypt", le_mcrypt);
669    PHP_MCRYPT_INIT_CHECK
670
671    if (data_len == 0) {
672        php_error_docref(NULL TSRMLS_CC, E_WARNING, "An empty string was passed");
673        RETURN_FALSE
674    }
675
676    /* Check blocksize */
677    if (mcrypt_enc_is_block_mode(pm->td) == 1) { /* It's a block algorithm */
678        block_size = mcrypt_enc_get_block_size(pm->td);
679        data_size = (((data_len - 1) / block_size) + 1) * block_size;
680        data_s = emalloc(data_size + 1);
681        memset(data_s, 0, data_size);
682        memcpy(data_s, data, data_len);
683    } else { /* It's not a block algorithm */
684        data_size = data_len;
685        data_s = emalloc(data_size + 1);
686        memset(data_s, 0, data_size);
687        memcpy(data_s, data, data_len);
688    }
689
690    mcrypt_generic(pm->td, data_s, data_size);
691    data_s[data_size] = '\0';
692
693    RETVAL_STRINGL(data_s, data_size, 1);
694    efree(data_s);
695}
696/* }}} */
697
698/* {{{ proto string mdecrypt_generic(resource td, string data)
699   This function decrypts the plaintext */
700PHP_FUNCTION(mdecrypt_generic)
701{
702    zval *mcryptind;
703    char *data;
704    int data_len;
705    php_mcrypt *pm;
706    char* data_s;
707    int block_size, data_size;
708
709    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &mcryptind, &data, &data_len) == FAILURE) {
710        return;
711    }
712
713    ZEND_FETCH_RESOURCE(pm, php_mcrypt * , &mcryptind, -1, "MCrypt", le_mcrypt);
714    PHP_MCRYPT_INIT_CHECK
715
716    if (data_len == 0) {
717        php_error_docref(NULL TSRMLS_CC, E_WARNING, "An empty string was passed");
718        RETURN_FALSE
719    }
720
721    /* Check blocksize */
722    if (mcrypt_enc_is_block_mode(pm->td) == 1) { /* It's a block algorithm */
723        block_size = mcrypt_enc_get_block_size(pm->td);
724        data_size = (((data_len - 1) / block_size) + 1) * block_size;
725        data_s = emalloc(data_size + 1);
726        memset(data_s, 0, data_size);
727        memcpy(data_s, data, data_len);
728    } else { /* It's not a block algorithm */
729        data_size = data_len;
730        data_s = emalloc(data_size + 1);
731        memset(data_s, 0, data_size);
732        memcpy(data_s, data, data_len);
733    }
734
735    mdecrypt_generic(pm->td, data_s, data_size);
736
737    RETVAL_STRINGL(data_s, data_size, 1);
738    efree(data_s);
739}
740/* }}} */
741
742/* {{{ proto array mcrypt_enc_get_supported_key_sizes(resource td)
743   This function decrypts the crypttext */
744PHP_FUNCTION(mcrypt_enc_get_supported_key_sizes)
745{
746    int i, count = 0;
747    int *key_sizes;
748
749    MCRYPT_GET_TD_ARG
750    array_init(return_value);
751
752    key_sizes = mcrypt_enc_get_supported_key_sizes(pm->td, &count);
753
754    for (i = 0; i < count; i++) {
755        add_index_long(return_value, i, key_sizes[i]);
756    }
757
758    mcrypt_free(key_sizes);
759}
760/* }}} */
761
762/* {{{ proto int mcrypt_enc_self_test(resource td)
763   This function runs the self test on the algorithm specified by the descriptor td */
764PHP_FUNCTION(mcrypt_enc_self_test)
765{
766    MCRYPT_GET_TD_ARG
767    RETURN_LONG(mcrypt_enc_self_test(pm->td));
768}
769/* }}} */
770
771/* {{{ proto bool mcrypt_module_close(resource td)
772   Free the descriptor td */
773PHP_FUNCTION(mcrypt_module_close)
774{
775    MCRYPT_GET_TD_ARG
776    zend_list_delete(Z_LVAL_P(mcryptind));
777    RETURN_TRUE;
778}
779/* }}} */
780
781/* {{{ proto bool mcrypt_generic_deinit(resource td)
782   This function terminates encrypt specified by the descriptor td */
783PHP_FUNCTION(mcrypt_generic_deinit)
784{
785    MCRYPT_GET_TD_ARG
786
787    if (mcrypt_generic_deinit(pm->td) < 0) {
788        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not terminate encryption specifier");
789        RETURN_FALSE
790    }
791    pm->init = 0;
792    RETURN_TRUE
793}
794/* }}} */
795
796/* {{{ proto bool mcrypt_enc_is_block_algorithm_mode(resource td)
797   Returns TRUE if the mode is for use with block algorithms */
798PHP_FUNCTION(mcrypt_enc_is_block_algorithm_mode)
799{
800    MCRYPT_GET_TD_ARG
801
802    if (mcrypt_enc_is_block_algorithm_mode(pm->td) == 1) {
803        RETURN_TRUE
804    } else {
805        RETURN_FALSE
806    }
807}
808/* }}} */
809
810/* {{{ proto bool mcrypt_enc_is_block_algorithm(resource td)
811   Returns TRUE if the alrogithm is a block algorithms */
812PHP_FUNCTION(mcrypt_enc_is_block_algorithm)
813{
814    MCRYPT_GET_TD_ARG
815
816    if (mcrypt_enc_is_block_algorithm(pm->td) == 1) {
817        RETURN_TRUE
818    } else {
819        RETURN_FALSE
820    }
821}
822/* }}} */
823
824/* {{{ proto bool mcrypt_enc_is_block_mode(resource td)
825   Returns TRUE if the mode outputs blocks */
826PHP_FUNCTION(mcrypt_enc_is_block_mode)
827{
828    MCRYPT_GET_TD_ARG
829
830    if (mcrypt_enc_is_block_mode(pm->td) == 1) {
831        RETURN_TRUE
832    } else {
833        RETURN_FALSE
834    }
835}
836/* }}} */
837
838/* {{{ proto int mcrypt_enc_get_block_size(resource td)
839   Returns the block size of the cipher specified by the descriptor td */
840PHP_FUNCTION(mcrypt_enc_get_block_size)
841{
842    MCRYPT_GET_TD_ARG
843    RETURN_LONG(mcrypt_enc_get_block_size(pm->td));
844}
845/* }}} */
846
847/* {{{ proto int mcrypt_enc_get_key_size(resource td)
848   Returns the maximum supported key size in bytes of the algorithm specified by the descriptor td */
849PHP_FUNCTION(mcrypt_enc_get_key_size)
850{
851    MCRYPT_GET_TD_ARG
852    RETURN_LONG(mcrypt_enc_get_key_size(pm->td));
853}
854/* }}} */
855
856/* {{{ proto int mcrypt_enc_get_iv_size(resource td)
857   Returns the size of the IV in bytes of the algorithm specified by the descriptor td */
858PHP_FUNCTION(mcrypt_enc_get_iv_size)
859{
860    MCRYPT_GET_TD_ARG
861    RETURN_LONG(mcrypt_enc_get_iv_size(pm->td));
862}
863/* }}} */
864
865/* {{{ proto string mcrypt_enc_get_algorithms_name(resource td)
866   Returns the name of the algorithm specified by the descriptor td */
867PHP_FUNCTION(mcrypt_enc_get_algorithms_name)
868{
869    char *name;
870    MCRYPT_GET_TD_ARG
871
872    name = mcrypt_enc_get_algorithms_name(pm->td);
873    RETVAL_STRING(name, 1);
874    mcrypt_free(name);
875}
876/* }}} */
877
878/* {{{ proto string mcrypt_enc_get_modes_name(resource td)
879   Returns the name of the mode specified by the descriptor td */
880PHP_FUNCTION(mcrypt_enc_get_modes_name)
881{
882    char *name;
883    MCRYPT_GET_TD_ARG
884
885    name = mcrypt_enc_get_modes_name(pm->td);
886    RETVAL_STRING(name, 1);
887    mcrypt_free(name);
888}
889/* }}} */
890
891/* {{{ proto bool mcrypt_module_self_test(string algorithm [, string lib_dir])
892   Does a self test of the module "module" */
893PHP_FUNCTION(mcrypt_module_self_test)
894{
895    MCRYPT_GET_MODE_DIR_ARGS(algorithms_dir);
896
897    if (mcrypt_module_self_test(module, dir) == 0) {
898        RETURN_TRUE;
899    } else {
900        RETURN_FALSE;
901    }
902}
903/* }}} */
904
905/* {{{ proto bool mcrypt_module_is_block_algorithm_mode(string mode [, string lib_dir])
906   Returns TRUE if the mode is for use with block algorithms */
907PHP_FUNCTION(mcrypt_module_is_block_algorithm_mode)
908{
909    MCRYPT_GET_MODE_DIR_ARGS(modes_dir)
910
911    if (mcrypt_module_is_block_algorithm_mode(module, dir) == 1) {
912        RETURN_TRUE;
913    } else {
914        RETURN_FALSE;
915    }
916}
917/* }}} */
918
919/* {{{ proto bool mcrypt_module_is_block_algorithm(string algorithm [, string lib_dir])
920   Returns TRUE if the algorithm is a block algorithm */
921PHP_FUNCTION(mcrypt_module_is_block_algorithm)
922{
923    MCRYPT_GET_MODE_DIR_ARGS(algorithms_dir)
924
925    if (mcrypt_module_is_block_algorithm(module, dir) == 1) {
926        RETURN_TRUE;
927    } else {
928        RETURN_FALSE;
929    }
930}
931/* }}} */
932
933/* {{{ proto bool mcrypt_module_is_block_mode(string mode [, string lib_dir])
934   Returns TRUE if the mode outputs blocks of bytes */
935PHP_FUNCTION(mcrypt_module_is_block_mode)
936{
937    MCRYPT_GET_MODE_DIR_ARGS(modes_dir)
938
939    if (mcrypt_module_is_block_mode(module, dir) == 1) {
940        RETURN_TRUE;
941    } else {
942        RETURN_FALSE;
943    }
944}
945/* }}} */
946
947/* {{{ proto int mcrypt_module_get_algo_block_size(string algorithm [, string lib_dir])
948   Returns the block size of the algorithm */
949PHP_FUNCTION(mcrypt_module_get_algo_block_size)
950{
951    MCRYPT_GET_MODE_DIR_ARGS(algorithms_dir)
952
953    RETURN_LONG(mcrypt_module_get_algo_block_size(module, dir));
954}
955/* }}} */
956
957/* {{{ proto int mcrypt_module_get_algo_key_size(string algorithm [, string lib_dir])
958   Returns the maximum supported key size of the algorithm */
959PHP_FUNCTION(mcrypt_module_get_algo_key_size)
960{
961    MCRYPT_GET_MODE_DIR_ARGS(algorithms_dir);
962
963    RETURN_LONG(mcrypt_module_get_algo_key_size(module, dir));
964}
965/* }}} */
966
967/* {{{ proto array mcrypt_module_get_supported_key_sizes(string algorithm [, string lib_dir])
968   This function decrypts the crypttext */
969PHP_FUNCTION(mcrypt_module_get_supported_key_sizes)
970{
971    int i, count = 0;
972    int *key_sizes;
973
974    MCRYPT_GET_MODE_DIR_ARGS(algorithms_dir)
975    array_init(return_value);
976
977    key_sizes = mcrypt_module_get_algo_supported_key_sizes(module, dir, &count);
978
979    for (i = 0; i < count; i++) {
980        add_index_long(return_value, i, key_sizes[i]);
981    }
982    mcrypt_free(key_sizes);
983}
984/* }}} */
985
986/* {{{ proto array mcrypt_list_algorithms([string lib_dir])
987   List all algorithms in "module_dir" */
988PHP_FUNCTION(mcrypt_list_algorithms)
989{
990    char **modules;
991    char *lib_dir = MCG(algorithms_dir);
992    int   lib_dir_len;
993    int   i, count;
994
995    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s",
996        &lib_dir, &lib_dir_len) == FAILURE) {
997        return;
998    }
999
1000    array_init(return_value);
1001    modules = mcrypt_list_algorithms(lib_dir, &count);
1002
1003    if (count == 0) {
1004        php_error_docref(NULL TSRMLS_CC, E_WARNING, "No algorithms found in module dir");
1005    }
1006    for (i = 0; i < count; i++) {
1007        add_index_string(return_value, i, modules[i], 1);
1008    }
1009    mcrypt_free_p(modules, count);
1010}
1011/* }}} */
1012
1013/* {{{ proto array mcrypt_list_modes([string lib_dir])
1014   List all modes "module_dir" */
1015PHP_FUNCTION(mcrypt_list_modes)
1016{
1017    char **modules;
1018    char *lib_dir = MCG(modes_dir);
1019    int   lib_dir_len;
1020    int   i, count;
1021
1022    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s",
1023        &lib_dir, &lib_dir_len) == FAILURE) {
1024        return;
1025    }
1026
1027    array_init(return_value);
1028    modules = mcrypt_list_modes(lib_dir, &count);
1029
1030    if (count == 0) {
1031        php_error_docref(NULL TSRMLS_CC, E_WARNING, "No modes found in module dir");
1032    }
1033    for (i = 0; i < count; i++) {
1034        add_index_string(return_value, i, modules[i], 1);
1035    }
1036    mcrypt_free_p(modules, count);
1037}
1038/* }}} */
1039
1040/* {{{ proto int mcrypt_get_key_size(string cipher, string module)
1041   Get the key size of cipher */
1042PHP_FUNCTION(mcrypt_get_key_size)
1043{
1044    char *cipher;
1045    char *module;
1046    int   cipher_len, module_len;
1047    char *cipher_dir_string;
1048    char *module_dir_string;
1049    MCRYPT td;
1050
1051    MCRYPT_GET_INI
1052
1053    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss",
1054        &cipher, &cipher_len, &module, &module_len) == FAILURE) {
1055        return;
1056    }
1057
1058    td = mcrypt_module_open(cipher, cipher_dir_string, module, module_dir_string);
1059    if (td != MCRYPT_FAILED) {
1060        RETVAL_LONG(mcrypt_enc_get_key_size(td));
1061        mcrypt_module_close(td);
1062    } else {
1063        php_error_docref(NULL TSRMLS_CC, E_WARNING, MCRYPT_OPEN_MODULE_FAILED);
1064        RETURN_FALSE;
1065    }
1066}
1067/* }}} */
1068
1069/* {{{ proto int mcrypt_get_block_size(string cipher, string module)
1070   Get the key size of cipher */
1071PHP_FUNCTION(mcrypt_get_block_size)
1072{
1073    char *cipher;
1074    char *module;
1075    int   cipher_len, module_len;
1076    char *cipher_dir_string;
1077    char *module_dir_string;
1078    MCRYPT td;
1079
1080    MCRYPT_GET_INI
1081
1082    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss",
1083        &cipher, &cipher_len, &module, &module_len) == FAILURE) {
1084        return;
1085    }
1086
1087    td = mcrypt_module_open(cipher, cipher_dir_string, module, module_dir_string);
1088    if (td != MCRYPT_FAILED) {
1089        RETVAL_LONG(mcrypt_enc_get_block_size(td));
1090        mcrypt_module_close(td);
1091    } else {
1092        php_error_docref(NULL TSRMLS_CC, E_WARNING, MCRYPT_OPEN_MODULE_FAILED);
1093        RETURN_FALSE;
1094    }
1095}
1096/* }}} */
1097
1098/* {{{ proto int mcrypt_get_iv_size(string cipher, string module)
1099   Get the IV size of cipher (Usually the same as the blocksize) */
1100PHP_FUNCTION(mcrypt_get_iv_size)
1101{
1102    char *cipher;
1103    char *module;
1104    int   cipher_len, module_len;
1105    char *cipher_dir_string;
1106    char *module_dir_string;
1107    MCRYPT td;
1108
1109    MCRYPT_GET_INI
1110
1111    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss",
1112        &cipher, &cipher_len, &module, &module_len) == FAILURE) {
1113        return;
1114    }
1115
1116    td = mcrypt_module_open(cipher, cipher_dir_string, module, module_dir_string);
1117    if (td != MCRYPT_FAILED) {
1118        RETVAL_LONG(mcrypt_enc_get_iv_size(td));
1119        mcrypt_module_close(td);
1120    } else {
1121        php_error_docref(NULL TSRMLS_CC, E_WARNING, MCRYPT_OPEN_MODULE_FAILED);
1122        RETURN_FALSE;
1123    }
1124}
1125/* }}} */
1126
1127/* {{{ proto string mcrypt_get_cipher_name(string cipher)
1128   Get the key size of cipher */
1129PHP_FUNCTION(mcrypt_get_cipher_name)
1130{
1131    char *cipher_dir_string;
1132    char *module_dir_string;
1133    char *cipher_name;
1134    char *cipher;
1135    int   cipher_len;
1136    MCRYPT td;
1137
1138    MCRYPT_GET_INI
1139
1140    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
1141        &cipher, &cipher_len) == FAILURE) {
1142        return;
1143    }
1144
1145    /* The code below is actually not very nice, but I didn't see a better
1146     * method */
1147    td = mcrypt_module_open(cipher, cipher_dir_string, "ecb", module_dir_string);
1148    if (td != MCRYPT_FAILED) {
1149        cipher_name = mcrypt_enc_get_algorithms_name(td);
1150        mcrypt_module_close(td);
1151        RETVAL_STRING(cipher_name,1);
1152        mcrypt_free(cipher_name);
1153    } else {
1154        td = mcrypt_module_open(cipher, cipher_dir_string, "stream", module_dir_string);
1155        if (td != MCRYPT_FAILED) {
1156            cipher_name = mcrypt_enc_get_algorithms_name(td);
1157            mcrypt_module_close(td);
1158            RETVAL_STRING(cipher_name,1);
1159            mcrypt_free(cipher_name);
1160        } else {
1161            php_error_docref(NULL TSRMLS_CC, E_WARNING, MCRYPT_OPEN_MODULE_FAILED);
1162            RETURN_FALSE;
1163        }
1164    }
1165}
1166/* }}} */
1167
1168static void php_mcrypt_do_crypt(char* cipher, const char *key, int key_len, const char *data, int data_len, char *mode, const char *iv, int iv_len, int argc, int dencrypt, zval* return_value TSRMLS_DC) /* {{{ */
1169{
1170    char *cipher_dir_string;
1171    char *module_dir_string;
1172    int block_size, max_key_length, use_key_length, i, count, iv_size;
1173    unsigned long int data_size;
1174    int *key_length_sizes;
1175    char *key_s = NULL, *iv_s;
1176    char *data_s;
1177    MCRYPT td;
1178
1179    MCRYPT_GET_INI
1180
1181    td = mcrypt_module_open(cipher, cipher_dir_string, mode, module_dir_string);
1182    if (td == MCRYPT_FAILED) {
1183        php_error_docref(NULL TSRMLS_CC, E_WARNING, MCRYPT_OPEN_MODULE_FAILED);
1184        RETURN_FALSE;
1185    }
1186    /* Checking for key-length */
1187    max_key_length = mcrypt_enc_get_key_size(td);
1188    if (key_len > max_key_length) {
1189        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Size of key is too large for this algorithm");
1190    }
1191    key_length_sizes = mcrypt_enc_get_supported_key_sizes(td, &count);
1192    if (count == 0 && key_length_sizes == NULL) { /* all lengths 1 - k_l_s = OK */
1193        use_key_length = key_len;
1194        key_s = emalloc(use_key_length);
1195        memset(key_s, 0, use_key_length);
1196        memcpy(key_s, key, use_key_length);
1197    } else if (count == 1) {  /* only m_k_l = OK */
1198        key_s = emalloc(key_length_sizes[0]);
1199        memset(key_s, 0, key_length_sizes[0]);
1200        memcpy(key_s, key, MIN(key_len, key_length_sizes[0]));
1201        use_key_length = key_length_sizes[0];
1202    } else { /* dertermine smallest supported key > length of requested key */
1203        use_key_length = max_key_length; /* start with max key length */
1204        for (i = 0; i < count; i++) {
1205            if (key_length_sizes[i] >= key_len &&
1206                key_length_sizes[i] < use_key_length)
1207            {
1208                use_key_length = key_length_sizes[i];
1209            }
1210        }
1211        key_s = emalloc(use_key_length);
1212        memset(key_s, 0, use_key_length);
1213        memcpy(key_s, key, MIN(key_len, use_key_length));
1214    }
1215    mcrypt_free (key_length_sizes);
1216
1217    /* Check IV */
1218    iv_s = NULL;
1219    iv_size = mcrypt_enc_get_iv_size (td);
1220
1221    /* IV is required */
1222    if (mcrypt_enc_mode_has_iv(td) == 1) {
1223        if (argc == 5) {
1224            if (iv_size != iv_len) {
1225                php_error_docref(NULL TSRMLS_CC, E_WARNING, MCRYPT_IV_WRONG_SIZE);
1226            } else {
1227                iv_s = emalloc(iv_size + 1);
1228                memcpy(iv_s, iv, iv_size);
1229            }
1230        } else if (argc == 4) {
1231            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attempt to use an empty IV, which is NOT recommend");
1232            iv_s = emalloc(iv_size + 1);
1233            memset(iv_s, 0, iv_size + 1);
1234        }
1235    }
1236
1237    /* Check blocksize */
1238    if (mcrypt_enc_is_block_mode(td) == 1) { /* It's a block algorithm */
1239        block_size = mcrypt_enc_get_block_size(td);
1240        data_size = (((data_len - 1) / block_size) + 1) * block_size;
1241        data_s = emalloc(data_size);
1242        memset(data_s, 0, data_size);
1243        memcpy(data_s, data, data_len);
1244    } else { /* It's not a block algorithm */
1245        data_size = data_len;
1246        data_s = emalloc(data_size);
1247        memset(data_s, 0, data_size);
1248        memcpy(data_s, data, data_len);
1249    }
1250
1251    if (mcrypt_generic_init(td, key_s, use_key_length, iv_s) < 0) {
1252        php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Mcrypt initialisation failed");
1253        RETURN_FALSE;
1254    }
1255    if (dencrypt == MCRYPT_ENCRYPT) {
1256        mcrypt_generic(td, data_s, data_size);
1257    } else {
1258        mdecrypt_generic(td, data_s, data_size);
1259    }
1260
1261    RETVAL_STRINGL(data_s, data_size, 1);
1262
1263    /* freeing vars */
1264    mcrypt_generic_end(td);
1265    if (key_s != NULL) {
1266        efree (key_s);
1267    }
1268    if (iv_s != NULL) {
1269        efree (iv_s);
1270    }
1271    efree (data_s);
1272}
1273/* }}} */
1274
1275/* {{{ proto string mcrypt_encrypt(string cipher, string key, string data, string mode, string iv)
1276   OFB crypt/decrypt data using key key with cipher cipher starting with iv */
1277PHP_FUNCTION(mcrypt_encrypt)
1278{
1279    zval **mode;
1280    char *cipher, *key, *data, *iv = NULL;
1281    int cipher_len, key_len, data_len, iv_len = 0;
1282
1283    MCRYPT_GET_CRYPT_ARGS
1284
1285    convert_to_string_ex(mode);
1286
1287    php_mcrypt_do_crypt(cipher, key, key_len, data, data_len, Z_STRVAL_PP(mode), iv, iv_len, ZEND_NUM_ARGS(), MCRYPT_ENCRYPT, return_value TSRMLS_CC);
1288}
1289/* }}} */
1290
1291/* {{{ proto string mcrypt_decrypt(string cipher, string key, string data, string mode, string iv)
1292   OFB crypt/decrypt data using key key with cipher cipher starting with iv */
1293PHP_FUNCTION(mcrypt_decrypt)
1294{
1295    zval **mode;
1296    char *cipher, *key, *data, *iv = NULL;
1297    int cipher_len, key_len, data_len, iv_len = 0;
1298
1299    MCRYPT_GET_CRYPT_ARGS
1300
1301    convert_to_string_ex(mode);
1302
1303    php_mcrypt_do_crypt(cipher, key, key_len, data, data_len, Z_STRVAL_PP(mode), iv, iv_len, ZEND_NUM_ARGS(), MCRYPT_DECRYPT, return_value TSRMLS_CC);
1304}
1305/* }}} */
1306
1307/* {{{ proto string mcrypt_ecb(int cipher, string key, string data, int mode, string iv)
1308   ECB crypt/decrypt data using key key with cipher cipher starting with iv */
1309PHP_FUNCTION(mcrypt_ecb)
1310{
1311    zval **mode;
1312    char *cipher, *key, *data, *iv = NULL;
1313    int cipher_len, key_len, data_len, iv_len = 0;
1314
1315    MCRYPT_GET_CRYPT_ARGS
1316
1317    convert_to_long_ex(mode);
1318
1319    php_mcrypt_do_crypt(cipher, key, key_len, data, data_len, "ecb", iv, iv_len, ZEND_NUM_ARGS(), Z_LVAL_PP(mode), return_value TSRMLS_CC);
1320}
1321/* }}} */
1322
1323/* {{{ proto string mcrypt_cbc(int cipher, string key, string data, int mode, string iv)
1324   CBC crypt/decrypt data using key key with cipher cipher starting with iv */
1325PHP_FUNCTION(mcrypt_cbc)
1326{
1327    zval **mode;
1328    char *cipher, *key, *data, *iv = NULL;
1329    int cipher_len, key_len, data_len, iv_len = 0;
1330
1331    MCRYPT_GET_CRYPT_ARGS
1332
1333    convert_to_long_ex(mode);
1334
1335    php_mcrypt_do_crypt(cipher, key, key_len, data, data_len, "cbc", iv, iv_len, ZEND_NUM_ARGS(), Z_LVAL_PP(mode), return_value TSRMLS_CC);
1336}
1337/* }}} */
1338
1339/* {{{ proto string mcrypt_cfb(int cipher, string key, string data, int mode, string iv)
1340   CFB crypt/decrypt data using key key with cipher cipher starting with iv */
1341PHP_FUNCTION(mcrypt_cfb)
1342{
1343    zval **mode;
1344    char *cipher, *key, *data, *iv = NULL;
1345    int cipher_len, key_len, data_len, iv_len = 0;
1346
1347    MCRYPT_GET_CRYPT_ARGS
1348
1349    convert_to_long_ex(mode);
1350
1351    php_mcrypt_do_crypt(cipher, key, key_len, data, data_len, "cfb", iv, iv_len, ZEND_NUM_ARGS(), Z_LVAL_PP(mode), return_value TSRMLS_CC);
1352}
1353/* }}} */
1354
1355/* {{{ proto string mcrypt_ofb(int cipher, string key, string data, int mode, string iv)
1356   OFB crypt/decrypt data using key key with cipher cipher starting with iv */
1357PHP_FUNCTION(mcrypt_ofb)
1358{
1359    zval **mode;
1360    char *cipher, *key, *data, *iv = NULL;
1361    int cipher_len, key_len, data_len, iv_len = 0;
1362
1363    MCRYPT_GET_CRYPT_ARGS
1364
1365    convert_to_long_ex(mode);
1366
1367    php_mcrypt_do_crypt(cipher, key, key_len, data, data_len, "ofb", iv, iv_len, ZEND_NUM_ARGS(), Z_LVAL_PP(mode), return_value TSRMLS_CC);
1368}
1369/* }}} */
1370
1371/* {{{ proto string mcrypt_create_iv(int size, int source)
1372   Create an initialization vector (IV) */
1373PHP_FUNCTION(mcrypt_create_iv)
1374{
1375    char *iv;
1376    long source = RANDOM;
1377    long size;
1378    int n = 0;
1379
1380    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &size, &source) == FAILURE) {
1381        return;
1382    }
1383
1384    if (size <= 0 || size >= INT_MAX) {
1385        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot create an IV with a size of less than 1 or greater than %d", INT_MAX);
1386        RETURN_FALSE;
1387    }
1388
1389    iv = ecalloc(size + 1, 1);
1390
1391    if (source == RANDOM || source == URANDOM) {
1392#if PHP_WIN32
1393        /* random/urandom equivalent on Windows */
1394        BYTE *iv_b = (BYTE *) iv;
1395        if (php_win32_get_random_bytes(iv_b, (size_t) size) == FAILURE){
1396            efree(iv);
1397            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not gather sufficient random data");
1398            RETURN_FALSE;
1399        }
1400        n = size;
1401#else
1402        int    fd;
1403        size_t read_bytes = 0;
1404
1405        fd = open(source == RANDOM ? "/dev/random" : "/dev/urandom", O_RDONLY);
1406        if (fd < 0) {
1407            efree(iv);
1408            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot open source device");
1409            RETURN_FALSE;
1410        }
1411        while (read_bytes < size) {
1412            n = read(fd, iv + read_bytes, size - read_bytes);
1413            if (n < 0) {
1414                break;
1415            }
1416            read_bytes += n;
1417        }
1418        n = read_bytes;
1419        close(fd);
1420        if (n < size) {
1421            efree(iv);
1422            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not gather sufficient random data");
1423            RETURN_FALSE;
1424        }
1425#endif
1426    } else {
1427        n = size;
1428        while (size) {
1429            iv[--size] = (char) (255.0 * php_rand(TSRMLS_C) / RAND_MAX);
1430        }
1431    }
1432    RETURN_STRINGL(iv, n, 0);
1433}
1434/* }}} */
1435
1436#endif
1437
1438/*
1439 * Local variables:
1440 * tab-width: 4
1441 * c-basic-offset: 4
1442 * End:
1443 * vim600: sw=4 ts=4 fdm=marker
1444 * vim<600: sw=4 ts=4
1445 */
1446