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        if (iv_len > iv_size) {
623            iv_len = iv_size;
624        }
625    }
626    memcpy(iv_s, iv, iv_len);
627
628    mcrypt_generic_deinit(pm->td);
629    result = mcrypt_generic_init(pm->td, key_s, key_size, iv_s);
630
631    /* If this function fails, close the mcrypt module to prevent crashes
632     * when further functions want to access this resource */
633    if (result < 0) {
634        zend_list_delete(Z_LVAL_P(mcryptind));
635        switch (result) {
636            case -3:
637                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Key length incorrect");
638                break;
639            case -4:
640                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Memory allocation error");
641                break;
642            case -1:
643            default:
644                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error");
645                break;
646        }
647    } else {
648        pm->init = 1;
649    }
650    RETVAL_LONG(result);
651
652    efree(iv_s);
653    efree(key_s);
654}
655/* }}} */
656
657/* {{{ proto string mcrypt_generic(resource td, string data)
658   This function encrypts the plaintext */
659PHP_FUNCTION(mcrypt_generic)
660{
661    zval *mcryptind;
662    char *data;
663    int data_len;
664    php_mcrypt *pm;
665    unsigned char* data_s;
666    int block_size, data_size;
667
668    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &mcryptind, &data, &data_len) == FAILURE) {
669        return;
670    }
671
672    ZEND_FETCH_RESOURCE(pm, php_mcrypt *, &mcryptind, -1, "MCrypt", le_mcrypt);
673    PHP_MCRYPT_INIT_CHECK
674
675    if (data_len == 0) {
676        php_error_docref(NULL TSRMLS_CC, E_WARNING, "An empty string was passed");
677        RETURN_FALSE
678    }
679
680    /* Check blocksize */
681    if (mcrypt_enc_is_block_mode(pm->td) == 1) { /* It's a block algorithm */
682        block_size = mcrypt_enc_get_block_size(pm->td);
683        data_size = (((data_len - 1) / block_size) + 1) * block_size;
684        data_s = emalloc(data_size + 1);
685        memset(data_s, 0, data_size);
686        memcpy(data_s, data, data_len);
687    } else { /* It's not a block algorithm */
688        data_size = data_len;
689        data_s = emalloc(data_size + 1);
690        memset(data_s, 0, data_size);
691        memcpy(data_s, data, data_len);
692    }
693
694    mcrypt_generic(pm->td, data_s, data_size);
695    data_s[data_size] = '\0';
696
697    RETVAL_STRINGL(data_s, data_size, 1);
698    efree(data_s);
699}
700/* }}} */
701
702/* {{{ proto string mdecrypt_generic(resource td, string data)
703   This function decrypts the plaintext */
704PHP_FUNCTION(mdecrypt_generic)
705{
706    zval *mcryptind;
707    char *data;
708    int data_len;
709    php_mcrypt *pm;
710    char* data_s;
711    int block_size, data_size;
712
713    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &mcryptind, &data, &data_len) == FAILURE) {
714        return;
715    }
716
717    ZEND_FETCH_RESOURCE(pm, php_mcrypt * , &mcryptind, -1, "MCrypt", le_mcrypt);
718    PHP_MCRYPT_INIT_CHECK
719
720    if (data_len == 0) {
721        php_error_docref(NULL TSRMLS_CC, E_WARNING, "An empty string was passed");
722        RETURN_FALSE
723    }
724
725    /* Check blocksize */
726    if (mcrypt_enc_is_block_mode(pm->td) == 1) { /* It's a block algorithm */
727        block_size = mcrypt_enc_get_block_size(pm->td);
728        data_size = (((data_len - 1) / block_size) + 1) * block_size;
729        data_s = emalloc(data_size + 1);
730        memset(data_s, 0, data_size);
731        memcpy(data_s, data, data_len);
732    } else { /* It's not a block algorithm */
733        data_size = data_len;
734        data_s = emalloc(data_size + 1);
735        memset(data_s, 0, data_size);
736        memcpy(data_s, data, data_len);
737    }
738
739    mdecrypt_generic(pm->td, data_s, data_size);
740
741    RETVAL_STRINGL(data_s, data_size, 1);
742    efree(data_s);
743}
744/* }}} */
745
746/* {{{ proto array mcrypt_enc_get_supported_key_sizes(resource td)
747   This function decrypts the crypttext */
748PHP_FUNCTION(mcrypt_enc_get_supported_key_sizes)
749{
750    int i, count = 0;
751    int *key_sizes;
752
753    MCRYPT_GET_TD_ARG
754    array_init(return_value);
755
756    key_sizes = mcrypt_enc_get_supported_key_sizes(pm->td, &count);
757
758    for (i = 0; i < count; i++) {
759        add_index_long(return_value, i, key_sizes[i]);
760    }
761
762    mcrypt_free(key_sizes);
763}
764/* }}} */
765
766/* {{{ proto int mcrypt_enc_self_test(resource td)
767   This function runs the self test on the algorithm specified by the descriptor td */
768PHP_FUNCTION(mcrypt_enc_self_test)
769{
770    MCRYPT_GET_TD_ARG
771    RETURN_LONG(mcrypt_enc_self_test(pm->td));
772}
773/* }}} */
774
775/* {{{ proto bool mcrypt_module_close(resource td)
776   Free the descriptor td */
777PHP_FUNCTION(mcrypt_module_close)
778{
779    MCRYPT_GET_TD_ARG
780    zend_list_delete(Z_LVAL_P(mcryptind));
781    RETURN_TRUE;
782}
783/* }}} */
784
785/* {{{ proto bool mcrypt_generic_deinit(resource td)
786   This function terminates encrypt specified by the descriptor td */
787PHP_FUNCTION(mcrypt_generic_deinit)
788{
789    MCRYPT_GET_TD_ARG
790
791    if (mcrypt_generic_deinit(pm->td) < 0) {
792        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not terminate encryption specifier");
793        RETURN_FALSE
794    }
795    pm->init = 0;
796    RETURN_TRUE
797}
798/* }}} */
799
800/* {{{ proto bool mcrypt_enc_is_block_algorithm_mode(resource td)
801   Returns TRUE if the mode is for use with block algorithms */
802PHP_FUNCTION(mcrypt_enc_is_block_algorithm_mode)
803{
804    MCRYPT_GET_TD_ARG
805
806    if (mcrypt_enc_is_block_algorithm_mode(pm->td) == 1) {
807        RETURN_TRUE
808    } else {
809        RETURN_FALSE
810    }
811}
812/* }}} */
813
814/* {{{ proto bool mcrypt_enc_is_block_algorithm(resource td)
815   Returns TRUE if the alrogithm is a block algorithms */
816PHP_FUNCTION(mcrypt_enc_is_block_algorithm)
817{
818    MCRYPT_GET_TD_ARG
819
820    if (mcrypt_enc_is_block_algorithm(pm->td) == 1) {
821        RETURN_TRUE
822    } else {
823        RETURN_FALSE
824    }
825}
826/* }}} */
827
828/* {{{ proto bool mcrypt_enc_is_block_mode(resource td)
829   Returns TRUE if the mode outputs blocks */
830PHP_FUNCTION(mcrypt_enc_is_block_mode)
831{
832    MCRYPT_GET_TD_ARG
833
834    if (mcrypt_enc_is_block_mode(pm->td) == 1) {
835        RETURN_TRUE
836    } else {
837        RETURN_FALSE
838    }
839}
840/* }}} */
841
842/* {{{ proto int mcrypt_enc_get_block_size(resource td)
843   Returns the block size of the cipher specified by the descriptor td */
844PHP_FUNCTION(mcrypt_enc_get_block_size)
845{
846    MCRYPT_GET_TD_ARG
847    RETURN_LONG(mcrypt_enc_get_block_size(pm->td));
848}
849/* }}} */
850
851/* {{{ proto int mcrypt_enc_get_key_size(resource td)
852   Returns the maximum supported key size in bytes of the algorithm specified by the descriptor td */
853PHP_FUNCTION(mcrypt_enc_get_key_size)
854{
855    MCRYPT_GET_TD_ARG
856    RETURN_LONG(mcrypt_enc_get_key_size(pm->td));
857}
858/* }}} */
859
860/* {{{ proto int mcrypt_enc_get_iv_size(resource td)
861   Returns the size of the IV in bytes of the algorithm specified by the descriptor td */
862PHP_FUNCTION(mcrypt_enc_get_iv_size)
863{
864    MCRYPT_GET_TD_ARG
865    RETURN_LONG(mcrypt_enc_get_iv_size(pm->td));
866}
867/* }}} */
868
869/* {{{ proto string mcrypt_enc_get_algorithms_name(resource td)
870   Returns the name of the algorithm specified by the descriptor td */
871PHP_FUNCTION(mcrypt_enc_get_algorithms_name)
872{
873    char *name;
874    MCRYPT_GET_TD_ARG
875
876    name = mcrypt_enc_get_algorithms_name(pm->td);
877    RETVAL_STRING(name, 1);
878    mcrypt_free(name);
879}
880/* }}} */
881
882/* {{{ proto string mcrypt_enc_get_modes_name(resource td)
883   Returns the name of the mode specified by the descriptor td */
884PHP_FUNCTION(mcrypt_enc_get_modes_name)
885{
886    char *name;
887    MCRYPT_GET_TD_ARG
888
889    name = mcrypt_enc_get_modes_name(pm->td);
890    RETVAL_STRING(name, 1);
891    mcrypt_free(name);
892}
893/* }}} */
894
895/* {{{ proto bool mcrypt_module_self_test(string algorithm [, string lib_dir])
896   Does a self test of the module "module" */
897PHP_FUNCTION(mcrypt_module_self_test)
898{
899    MCRYPT_GET_MODE_DIR_ARGS(algorithms_dir);
900
901    if (mcrypt_module_self_test(module, dir) == 0) {
902        RETURN_TRUE;
903    } else {
904        RETURN_FALSE;
905    }
906}
907/* }}} */
908
909/* {{{ proto bool mcrypt_module_is_block_algorithm_mode(string mode [, string lib_dir])
910   Returns TRUE if the mode is for use with block algorithms */
911PHP_FUNCTION(mcrypt_module_is_block_algorithm_mode)
912{
913    MCRYPT_GET_MODE_DIR_ARGS(modes_dir)
914
915    if (mcrypt_module_is_block_algorithm_mode(module, dir) == 1) {
916        RETURN_TRUE;
917    } else {
918        RETURN_FALSE;
919    }
920}
921/* }}} */
922
923/* {{{ proto bool mcrypt_module_is_block_algorithm(string algorithm [, string lib_dir])
924   Returns TRUE if the algorithm is a block algorithm */
925PHP_FUNCTION(mcrypt_module_is_block_algorithm)
926{
927    MCRYPT_GET_MODE_DIR_ARGS(algorithms_dir)
928
929    if (mcrypt_module_is_block_algorithm(module, dir) == 1) {
930        RETURN_TRUE;
931    } else {
932        RETURN_FALSE;
933    }
934}
935/* }}} */
936
937/* {{{ proto bool mcrypt_module_is_block_mode(string mode [, string lib_dir])
938   Returns TRUE if the mode outputs blocks of bytes */
939PHP_FUNCTION(mcrypt_module_is_block_mode)
940{
941    MCRYPT_GET_MODE_DIR_ARGS(modes_dir)
942
943    if (mcrypt_module_is_block_mode(module, dir) == 1) {
944        RETURN_TRUE;
945    } else {
946        RETURN_FALSE;
947    }
948}
949/* }}} */
950
951/* {{{ proto int mcrypt_module_get_algo_block_size(string algorithm [, string lib_dir])
952   Returns the block size of the algorithm */
953PHP_FUNCTION(mcrypt_module_get_algo_block_size)
954{
955    MCRYPT_GET_MODE_DIR_ARGS(algorithms_dir)
956
957    RETURN_LONG(mcrypt_module_get_algo_block_size(module, dir));
958}
959/* }}} */
960
961/* {{{ proto int mcrypt_module_get_algo_key_size(string algorithm [, string lib_dir])
962   Returns the maximum supported key size of the algorithm */
963PHP_FUNCTION(mcrypt_module_get_algo_key_size)
964{
965    MCRYPT_GET_MODE_DIR_ARGS(algorithms_dir);
966
967    RETURN_LONG(mcrypt_module_get_algo_key_size(module, dir));
968}
969/* }}} */
970
971/* {{{ proto array mcrypt_module_get_supported_key_sizes(string algorithm [, string lib_dir])
972   This function decrypts the crypttext */
973PHP_FUNCTION(mcrypt_module_get_supported_key_sizes)
974{
975    int i, count = 0;
976    int *key_sizes;
977
978    MCRYPT_GET_MODE_DIR_ARGS(algorithms_dir)
979    array_init(return_value);
980
981    key_sizes = mcrypt_module_get_algo_supported_key_sizes(module, dir, &count);
982
983    for (i = 0; i < count; i++) {
984        add_index_long(return_value, i, key_sizes[i]);
985    }
986    mcrypt_free(key_sizes);
987}
988/* }}} */
989
990/* {{{ proto array mcrypt_list_algorithms([string lib_dir])
991   List all algorithms in "module_dir" */
992PHP_FUNCTION(mcrypt_list_algorithms)
993{
994    char **modules;
995    char *lib_dir = MCG(algorithms_dir);
996    int   lib_dir_len;
997    int   i, count;
998
999    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s",
1000        &lib_dir, &lib_dir_len) == FAILURE) {
1001        return;
1002    }
1003
1004    array_init(return_value);
1005    modules = mcrypt_list_algorithms(lib_dir, &count);
1006
1007    if (count == 0) {
1008        php_error_docref(NULL TSRMLS_CC, E_WARNING, "No algorithms found in module dir");
1009    }
1010    for (i = 0; i < count; i++) {
1011        add_index_string(return_value, i, modules[i], 1);
1012    }
1013    mcrypt_free_p(modules, count);
1014}
1015/* }}} */
1016
1017/* {{{ proto array mcrypt_list_modes([string lib_dir])
1018   List all modes "module_dir" */
1019PHP_FUNCTION(mcrypt_list_modes)
1020{
1021    char **modules;
1022    char *lib_dir = MCG(modes_dir);
1023    int   lib_dir_len;
1024    int   i, count;
1025
1026    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s",
1027        &lib_dir, &lib_dir_len) == FAILURE) {
1028        return;
1029    }
1030
1031    array_init(return_value);
1032    modules = mcrypt_list_modes(lib_dir, &count);
1033
1034    if (count == 0) {
1035        php_error_docref(NULL TSRMLS_CC, E_WARNING, "No modes found in module dir");
1036    }
1037    for (i = 0; i < count; i++) {
1038        add_index_string(return_value, i, modules[i], 1);
1039    }
1040    mcrypt_free_p(modules, count);
1041}
1042/* }}} */
1043
1044/* {{{ proto int mcrypt_get_key_size(string cipher, string module)
1045   Get the key size of cipher */
1046PHP_FUNCTION(mcrypt_get_key_size)
1047{
1048    char *cipher;
1049    char *module;
1050    int   cipher_len, module_len;
1051    char *cipher_dir_string;
1052    char *module_dir_string;
1053    MCRYPT td;
1054
1055    MCRYPT_GET_INI
1056
1057    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss",
1058        &cipher, &cipher_len, &module, &module_len) == FAILURE) {
1059        return;
1060    }
1061
1062    td = mcrypt_module_open(cipher, cipher_dir_string, module, module_dir_string);
1063    if (td != MCRYPT_FAILED) {
1064        RETVAL_LONG(mcrypt_enc_get_key_size(td));
1065        mcrypt_module_close(td);
1066    } else {
1067        php_error_docref(NULL TSRMLS_CC, E_WARNING, MCRYPT_OPEN_MODULE_FAILED);
1068        RETURN_FALSE;
1069    }
1070}
1071/* }}} */
1072
1073/* {{{ proto int mcrypt_get_block_size(string cipher, string module)
1074   Get the key size of cipher */
1075PHP_FUNCTION(mcrypt_get_block_size)
1076{
1077    char *cipher;
1078    char *module;
1079    int   cipher_len, module_len;
1080    char *cipher_dir_string;
1081    char *module_dir_string;
1082    MCRYPT td;
1083
1084    MCRYPT_GET_INI
1085
1086    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss",
1087        &cipher, &cipher_len, &module, &module_len) == FAILURE) {
1088        return;
1089    }
1090
1091    td = mcrypt_module_open(cipher, cipher_dir_string, module, module_dir_string);
1092    if (td != MCRYPT_FAILED) {
1093        RETVAL_LONG(mcrypt_enc_get_block_size(td));
1094        mcrypt_module_close(td);
1095    } else {
1096        php_error_docref(NULL TSRMLS_CC, E_WARNING, MCRYPT_OPEN_MODULE_FAILED);
1097        RETURN_FALSE;
1098    }
1099}
1100/* }}} */
1101
1102/* {{{ proto int mcrypt_get_iv_size(string cipher, string module)
1103   Get the IV size of cipher (Usually the same as the blocksize) */
1104PHP_FUNCTION(mcrypt_get_iv_size)
1105{
1106    char *cipher;
1107    char *module;
1108    int   cipher_len, module_len;
1109    char *cipher_dir_string;
1110    char *module_dir_string;
1111    MCRYPT td;
1112
1113    MCRYPT_GET_INI
1114
1115    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss",
1116        &cipher, &cipher_len, &module, &module_len) == FAILURE) {
1117        return;
1118    }
1119
1120    td = mcrypt_module_open(cipher, cipher_dir_string, module, module_dir_string);
1121    if (td != MCRYPT_FAILED) {
1122        RETVAL_LONG(mcrypt_enc_get_iv_size(td));
1123        mcrypt_module_close(td);
1124    } else {
1125        php_error_docref(NULL TSRMLS_CC, E_WARNING, MCRYPT_OPEN_MODULE_FAILED);
1126        RETURN_FALSE;
1127    }
1128}
1129/* }}} */
1130
1131/* {{{ proto string mcrypt_get_cipher_name(string cipher)
1132   Get the key size of cipher */
1133PHP_FUNCTION(mcrypt_get_cipher_name)
1134{
1135    char *cipher_dir_string;
1136    char *module_dir_string;
1137    char *cipher_name;
1138    char *cipher;
1139    int   cipher_len;
1140    MCRYPT td;
1141
1142    MCRYPT_GET_INI
1143
1144    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
1145        &cipher, &cipher_len) == FAILURE) {
1146        return;
1147    }
1148
1149    /* The code below is actually not very nice, but I didn't see a better
1150     * method */
1151    td = mcrypt_module_open(cipher, cipher_dir_string, "ecb", module_dir_string);
1152    if (td != MCRYPT_FAILED) {
1153        cipher_name = mcrypt_enc_get_algorithms_name(td);
1154        mcrypt_module_close(td);
1155        RETVAL_STRING(cipher_name,1);
1156        mcrypt_free(cipher_name);
1157    } else {
1158        td = mcrypt_module_open(cipher, cipher_dir_string, "stream", module_dir_string);
1159        if (td != MCRYPT_FAILED) {
1160            cipher_name = mcrypt_enc_get_algorithms_name(td);
1161            mcrypt_module_close(td);
1162            RETVAL_STRING(cipher_name,1);
1163            mcrypt_free(cipher_name);
1164        } else {
1165            php_error_docref(NULL TSRMLS_CC, E_WARNING, MCRYPT_OPEN_MODULE_FAILED);
1166            RETURN_FALSE;
1167        }
1168    }
1169}
1170/* }}} */
1171
1172static 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) /* {{{ */
1173{
1174    char *cipher_dir_string;
1175    char *module_dir_string;
1176    int block_size, max_key_length, use_key_length, i, count, iv_size;
1177    unsigned long int data_size;
1178    int *key_length_sizes;
1179    char *key_s = NULL, *iv_s;
1180    char *data_s;
1181    MCRYPT td;
1182
1183    MCRYPT_GET_INI
1184
1185    td = mcrypt_module_open(cipher, cipher_dir_string, mode, module_dir_string);
1186    if (td == MCRYPT_FAILED) {
1187        php_error_docref(NULL TSRMLS_CC, E_WARNING, MCRYPT_OPEN_MODULE_FAILED);
1188        RETURN_FALSE;
1189    }
1190    /* Checking for key-length */
1191    max_key_length = mcrypt_enc_get_key_size(td);
1192    if (key_len > max_key_length) {
1193        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Size of key is too large for this algorithm");
1194    }
1195    key_length_sizes = mcrypt_enc_get_supported_key_sizes(td, &count);
1196    if (count == 0 && key_length_sizes == NULL) { /* all lengths 1 - k_l_s = OK */
1197        use_key_length = key_len;
1198        key_s = emalloc(use_key_length);
1199        memset(key_s, 0, use_key_length);
1200        memcpy(key_s, key, use_key_length);
1201    } else if (count == 1) {  /* only m_k_l = OK */
1202        key_s = emalloc(key_length_sizes[0]);
1203        memset(key_s, 0, key_length_sizes[0]);
1204        memcpy(key_s, key, MIN(key_len, key_length_sizes[0]));
1205        use_key_length = key_length_sizes[0];
1206    } else { /* dertermine smallest supported key > length of requested key */
1207        use_key_length = max_key_length; /* start with max key length */
1208        for (i = 0; i < count; i++) {
1209            if (key_length_sizes[i] >= key_len &&
1210                key_length_sizes[i] < use_key_length)
1211            {
1212                use_key_length = key_length_sizes[i];
1213            }
1214        }
1215        key_s = emalloc(use_key_length);
1216        memset(key_s, 0, use_key_length);
1217        memcpy(key_s, key, MIN(key_len, use_key_length));
1218    }
1219    mcrypt_free (key_length_sizes);
1220
1221    /* Check IV */
1222    iv_s = NULL;
1223    iv_size = mcrypt_enc_get_iv_size (td);
1224
1225    /* IV is required */
1226    if (mcrypt_enc_mode_has_iv(td) == 1) {
1227        if (argc == 5) {
1228            if (iv_size != iv_len) {
1229                php_error_docref(NULL TSRMLS_CC, E_WARNING, MCRYPT_IV_WRONG_SIZE);
1230            } else {
1231                iv_s = emalloc(iv_size + 1);
1232                memcpy(iv_s, iv, iv_size);
1233            }
1234        } else if (argc == 4) {
1235            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attempt to use an empty IV, which is NOT recommend");
1236            iv_s = emalloc(iv_size + 1);
1237            memset(iv_s, 0, iv_size + 1);
1238        }
1239    }
1240
1241    /* Check blocksize */
1242    if (mcrypt_enc_is_block_mode(td) == 1) { /* It's a block algorithm */
1243        block_size = mcrypt_enc_get_block_size(td);
1244        data_size = (((data_len - 1) / block_size) + 1) * block_size;
1245        data_s = emalloc(data_size);
1246        memset(data_s, 0, data_size);
1247        memcpy(data_s, data, data_len);
1248    } else { /* It's not a block algorithm */
1249        data_size = data_len;
1250        data_s = emalloc(data_size);
1251        memset(data_s, 0, data_size);
1252        memcpy(data_s, data, data_len);
1253    }
1254
1255    if (mcrypt_generic_init(td, key_s, use_key_length, iv_s) < 0) {
1256        php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Mcrypt initialisation failed");
1257        RETURN_FALSE;
1258    }
1259    if (dencrypt == MCRYPT_ENCRYPT) {
1260        mcrypt_generic(td, data_s, data_size);
1261    } else {
1262        mdecrypt_generic(td, data_s, data_size);
1263    }
1264
1265    RETVAL_STRINGL(data_s, data_size, 1);
1266
1267    /* freeing vars */
1268    mcrypt_generic_end(td);
1269    if (key_s != NULL) {
1270        efree (key_s);
1271    }
1272    if (iv_s != NULL) {
1273        efree (iv_s);
1274    }
1275    efree (data_s);
1276}
1277/* }}} */
1278
1279/* {{{ proto string mcrypt_encrypt(string cipher, string key, string data, string mode, string iv)
1280   OFB crypt/decrypt data using key key with cipher cipher starting with iv */
1281PHP_FUNCTION(mcrypt_encrypt)
1282{
1283    zval **mode;
1284    char *cipher, *key, *data, *iv = NULL;
1285    int cipher_len, key_len, data_len, iv_len = 0;
1286
1287    MCRYPT_GET_CRYPT_ARGS
1288
1289    convert_to_string_ex(mode);
1290
1291    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);
1292}
1293/* }}} */
1294
1295/* {{{ proto string mcrypt_decrypt(string cipher, string key, string data, string mode, string iv)
1296   OFB crypt/decrypt data using key key with cipher cipher starting with iv */
1297PHP_FUNCTION(mcrypt_decrypt)
1298{
1299    zval **mode;
1300    char *cipher, *key, *data, *iv = NULL;
1301    int cipher_len, key_len, data_len, iv_len = 0;
1302
1303    MCRYPT_GET_CRYPT_ARGS
1304
1305    convert_to_string_ex(mode);
1306
1307    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);
1308}
1309/* }}} */
1310
1311/* {{{ proto string mcrypt_ecb(int cipher, string key, string data, int mode, string iv)
1312   ECB crypt/decrypt data using key key with cipher cipher starting with iv */
1313PHP_FUNCTION(mcrypt_ecb)
1314{
1315    zval **mode;
1316    char *cipher, *key, *data, *iv = NULL;
1317    int cipher_len, key_len, data_len, iv_len = 0;
1318
1319    MCRYPT_GET_CRYPT_ARGS
1320
1321    convert_to_long_ex(mode);
1322
1323    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);
1324}
1325/* }}} */
1326
1327/* {{{ proto string mcrypt_cbc(int cipher, string key, string data, int mode, string iv)
1328   CBC crypt/decrypt data using key key with cipher cipher starting with iv */
1329PHP_FUNCTION(mcrypt_cbc)
1330{
1331    zval **mode;
1332    char *cipher, *key, *data, *iv = NULL;
1333    int cipher_len, key_len, data_len, iv_len = 0;
1334
1335    MCRYPT_GET_CRYPT_ARGS
1336
1337    convert_to_long_ex(mode);
1338
1339    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);
1340}
1341/* }}} */
1342
1343/* {{{ proto string mcrypt_cfb(int cipher, string key, string data, int mode, string iv)
1344   CFB crypt/decrypt data using key key with cipher cipher starting with iv */
1345PHP_FUNCTION(mcrypt_cfb)
1346{
1347    zval **mode;
1348    char *cipher, *key, *data, *iv = NULL;
1349    int cipher_len, key_len, data_len, iv_len = 0;
1350
1351    MCRYPT_GET_CRYPT_ARGS
1352
1353    convert_to_long_ex(mode);
1354
1355    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);
1356}
1357/* }}} */
1358
1359/* {{{ proto string mcrypt_ofb(int cipher, string key, string data, int mode, string iv)
1360   OFB crypt/decrypt data using key key with cipher cipher starting with iv */
1361PHP_FUNCTION(mcrypt_ofb)
1362{
1363    zval **mode;
1364    char *cipher, *key, *data, *iv = NULL;
1365    int cipher_len, key_len, data_len, iv_len = 0;
1366
1367    MCRYPT_GET_CRYPT_ARGS
1368
1369    convert_to_long_ex(mode);
1370
1371    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);
1372}
1373/* }}} */
1374
1375/* {{{ proto string mcrypt_create_iv(int size, int source)
1376   Create an initialization vector (IV) */
1377PHP_FUNCTION(mcrypt_create_iv)
1378{
1379    char *iv;
1380    long source = RANDOM;
1381    long size;
1382    int n = 0;
1383
1384    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &size, &source) == FAILURE) {
1385        return;
1386    }
1387
1388    if (size <= 0 || size >= INT_MAX) {
1389        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);
1390        RETURN_FALSE;
1391    }
1392
1393    iv = ecalloc(size + 1, 1);
1394
1395    if (source == RANDOM || source == URANDOM) {
1396#if PHP_WIN32
1397        /* random/urandom equivalent on Windows */
1398        BYTE *iv_b = (BYTE *) iv;
1399        if (php_win32_get_random_bytes(iv_b, (size_t) size) == FAILURE){
1400            efree(iv);
1401            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not gather sufficient random data");
1402            RETURN_FALSE;
1403        }
1404        n = size;
1405#else
1406        int    fd;
1407        size_t read_bytes = 0;
1408
1409        fd = open(source == RANDOM ? "/dev/random" : "/dev/urandom", O_RDONLY);
1410        if (fd < 0) {
1411            efree(iv);
1412            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot open source device");
1413            RETURN_FALSE;
1414        }
1415        while (read_bytes < size) {
1416            n = read(fd, iv + read_bytes, size - read_bytes);
1417            if (n < 0) {
1418                break;
1419            }
1420            read_bytes += n;
1421        }
1422        n = read_bytes;
1423        close(fd);
1424        if (n < size) {
1425            efree(iv);
1426            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not gather sufficient random data");
1427            RETURN_FALSE;
1428        }
1429#endif
1430    } else {
1431        n = size;
1432        while (size) {
1433            iv[--size] = (char) (255.0 * php_rand(TSRMLS_C) / RAND_MAX);
1434        }
1435    }
1436    RETURN_STRINGL(iv, n, 0);
1437}
1438/* }}} */
1439
1440#endif
1441
1442/*
1443 * Local variables:
1444 * tab-width: 4
1445 * c-basic-offset: 4
1446 * End:
1447 * vim600: sw=4 ts=4 fdm=marker
1448 * vim<600: sw=4 ts=4
1449 */
1450