Back to index

php5  5.3.10
mcrypt_filter.c
Go to the documentation of this file.
00001 /*
00002   +----------------------------------------------------------------------+
00003   | PHP Version 5                                                        |
00004   +----------------------------------------------------------------------+
00005   | Copyright (c) 1997-2012 The PHP Group                                |
00006   +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014   +----------------------------------------------------------------------+
00015   | Author: Sara Golemon <pollita@php.net>                               |
00016   +----------------------------------------------------------------------+
00017 
00018   $Id: mcrypt_filter.c 321634 2012-01-01 13:15:04Z felipe $ 
00019 */
00020 
00021 #include "php.h"
00022 
00023 #include "php_mcrypt_filter.h"
00024 #include "php_ini.h"
00025 #include <mcrypt.h>
00026 
00027 typedef struct _php_mcrypt_filter_data {
00028        MCRYPT module;
00029        char encrypt;
00030        int blocksize;
00031        char *block_buffer;
00032        int block_used;
00033        char persistent;
00034 } php_mcrypt_filter_data;
00035 
00036 static php_stream_filter_status_t php_mcrypt_filter(
00037        php_stream *stream,
00038        php_stream_filter *thisfilter,
00039        php_stream_bucket_brigade *buckets_in,
00040        php_stream_bucket_brigade *buckets_out,
00041        size_t *bytes_consumed,
00042        int flags TSRMLS_DC)
00043 {
00044        php_mcrypt_filter_data *data;
00045        php_stream_bucket *bucket;
00046        size_t consumed = 0;
00047        php_stream_filter_status_t exit_status = PSFS_FEED_ME;
00048 
00049        if (!thisfilter || !thisfilter->abstract) {
00050               /* Should never happen */
00051               return PSFS_ERR_FATAL;
00052        }
00053 
00054        data = (php_mcrypt_filter_data *)(thisfilter->abstract);
00055        while(buckets_in->head) {
00056               bucket = buckets_in->head;
00057 
00058               consumed += bucket->buflen;
00059 
00060               if (data->blocksize) {
00061                      /* Blockmode cipher */
00062                      char *outchunk;
00063                      int chunklen = bucket->buflen + data->block_used, n;
00064                      php_stream_bucket *newbucket;
00065 
00066                      outchunk = pemalloc(chunklen, data->persistent);
00067                      if (data->block_used) {
00068                             memcpy(outchunk, data->block_buffer, data->block_used);
00069                      }
00070                      memcpy(outchunk + data->block_used, bucket->buf, bucket->buflen);
00071 
00072                      for(n=0; (n + data->blocksize) <= chunklen; n += data->blocksize) {
00073 
00074                             if (data->encrypt) {
00075                                    mcrypt_generic(data->module, outchunk + n, data->blocksize);
00076                             } else {
00077                                    mdecrypt_generic(data->module, outchunk + n, data->blocksize);
00078                             }
00079                      }
00080                      data->block_used = chunklen - n;
00081                      memcpy(data->block_buffer, outchunk + n, data->block_used);
00082 
00083                      newbucket = php_stream_bucket_new(stream, outchunk, n, 1, data->persistent TSRMLS_CC);
00084                      php_stream_bucket_append(buckets_out, newbucket TSRMLS_CC);
00085 
00086                      exit_status = PSFS_PASS_ON;
00087 
00088                      php_stream_bucket_unlink(bucket TSRMLS_CC);
00089                      php_stream_bucket_delref(bucket TSRMLS_CC);
00090               } else {
00091                      /* Stream cipher */
00092                      php_stream_bucket_make_writeable(bucket TSRMLS_CC);
00093                      if (data->encrypt) {
00094                             mcrypt_generic(data->module, bucket->buf, bucket->buflen);
00095                      } else {
00096                             mdecrypt_generic(data->module, bucket->buf, bucket->buflen);
00097                      }
00098                      php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
00099 
00100                      exit_status = PSFS_PASS_ON;
00101               }
00102        }
00103 
00104        if ((flags & PSFS_FLAG_FLUSH_CLOSE) && data->blocksize && data->block_used) {
00105               php_stream_bucket *newbucket;
00106 
00107               memset(data->block_buffer + data->block_used, 0, data->blocksize - data->block_used);
00108               if (data->encrypt) {
00109                      mcrypt_generic(data->module, data->block_buffer, data->blocksize);
00110               } else {
00111                      mdecrypt_generic(data->module, data->block_buffer, data->blocksize);
00112               }
00113 
00114               newbucket = php_stream_bucket_new(stream, data->block_buffer, data->blocksize, 0, data->persistent TSRMLS_CC);
00115               php_stream_bucket_append(buckets_out, newbucket TSRMLS_CC);
00116 
00117               exit_status = PSFS_PASS_ON;
00118        }
00119 
00120        if (bytes_consumed) {
00121               *bytes_consumed = consumed;
00122        }
00123 
00124        return exit_status;
00125 }
00126 
00127 static void php_mcrypt_filter_dtor(php_stream_filter *thisfilter TSRMLS_DC)
00128 {
00129        if (thisfilter && thisfilter->abstract) {
00130               php_mcrypt_filter_data *data = (php_mcrypt_filter_data*)thisfilter->abstract;
00131 
00132               if (data->block_buffer) {
00133                      pefree(data->block_buffer, data->persistent);
00134               }
00135 
00136               mcrypt_generic_deinit(data->module);
00137               mcrypt_module_close(data->module);
00138 
00139               pefree(data, data->persistent);
00140        }
00141 }
00142 
00143 static php_stream_filter_ops php_mcrypt_filter_ops = {
00144     php_mcrypt_filter,
00145     php_mcrypt_filter_dtor,
00146     "mcrypt.*"
00147 };
00148 
00149 /* {{{ php_mcrypt_filter_create
00150  * Instantiate mcrypt filter
00151  */
00152 static php_stream_filter *php_mcrypt_filter_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
00153 {
00154        int encrypt = 1, iv_len, key_len, keyl, result;
00155        const char *cipher = filtername + sizeof("mcrypt.") - 1;
00156        zval **tmpzval;
00157        MCRYPT mcrypt_module;
00158        char *iv = NULL, *key = NULL;
00159        char *algo_dir = INI_STR("mcrypt.algorithms_dir");
00160        char *mode_dir = INI_STR("mcrypt.modes_dir");
00161        char *mode = "cbc";
00162        php_mcrypt_filter_data *data;
00163 
00164        if (strncasecmp(filtername, "mdecrypt.", sizeof("mdecrypt.") - 1) == 0) {
00165               encrypt = 0;
00166               cipher += sizeof("de") - 1;
00167        } else if (strncasecmp(filtername, "mcrypt.", sizeof("mcrypt.") - 1) != 0) {
00168               /* Should never happen */
00169               return NULL;
00170        }
00171 
00172        if (!filterparams || Z_TYPE_P(filterparams) != IS_ARRAY) {
00173               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Filter parameters for %s must be an array", filtername);
00174               return NULL;
00175        }
00176 
00177        if (zend_hash_find(HASH_OF(filterparams), "mode", sizeof("mode"), (void**)&tmpzval) == SUCCESS) {
00178               if (Z_TYPE_PP(tmpzval) == IS_STRING) {
00179                      mode = Z_STRVAL_PP(tmpzval);
00180               } else {
00181                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "mode is not a string, ignoring");
00182               }
00183        }
00184 
00185        if (zend_hash_find(HASH_OF(filterparams), "algorithms_dir", sizeof("algorithms_dir"), (void**)&tmpzval) == SUCCESS) {
00186               if (Z_TYPE_PP(tmpzval) == IS_STRING) {
00187                      algo_dir = Z_STRVAL_PP(tmpzval);
00188               } else {
00189                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "algorithms_dir is not a string, ignoring");
00190               }
00191        }
00192 
00193        if (zend_hash_find(HASH_OF(filterparams), "modes_dir", sizeof("modes_dir"), (void**)&tmpzval) == SUCCESS) {
00194               if (Z_TYPE_PP(tmpzval) == IS_STRING) {
00195                      mode_dir = Z_STRVAL_PP(tmpzval);
00196               } else {
00197                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "modes_dir is not a string, ignoring");
00198               }
00199        }
00200 
00201        if (zend_hash_find(HASH_OF(filterparams), "key", sizeof("key"), (void**)&tmpzval) == SUCCESS &&
00202               Z_TYPE_PP(tmpzval) == IS_STRING) {
00203               key = Z_STRVAL_PP(tmpzval);
00204               key_len = Z_STRLEN_PP(tmpzval);
00205        } else {
00206               php_error_docref(NULL TSRMLS_CC, E_WARNING, "key not specified or is not a string");
00207               return NULL;
00208        }
00209 
00210        mcrypt_module = mcrypt_module_open(cipher, algo_dir, mode, mode_dir);
00211        if (mcrypt_module == MCRYPT_FAILED) {
00212               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not open encryption module");
00213               return NULL;
00214        }
00215        iv_len = mcrypt_enc_get_iv_size(mcrypt_module);
00216        keyl = mcrypt_enc_get_key_size(mcrypt_module);
00217        if (keyl < key_len) {
00218               key_len = keyl;
00219        }
00220 
00221        if (zend_hash_find(HASH_OF(filterparams), "iv", sizeof("iv"), (void**) &tmpzval) == FAILURE ||
00222               Z_TYPE_PP(tmpzval) != IS_STRING) {
00223               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Filter parameter[iv] not provided or not of type: string");
00224               mcrypt_module_close(mcrypt_module);
00225               return NULL;
00226        }
00227 
00228        iv = emalloc(iv_len + 1);
00229        if (iv_len <= Z_STRLEN_PP(tmpzval)) {
00230               memcpy(iv, Z_STRVAL_PP(tmpzval), iv_len);
00231        } else {
00232               memcpy(iv, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval));
00233               memset(iv + Z_STRLEN_PP(tmpzval), 0, iv_len - Z_STRLEN_PP(tmpzval));
00234        }
00235 
00236        result = mcrypt_generic_init(mcrypt_module, key, key_len, iv);
00237        efree(iv);
00238        if (result < 0) {
00239               switch (result) {
00240                      case -3:
00241                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Key length incorrect");
00242                             break;
00243                      case -4:
00244                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Memory allocation error");
00245                             break;
00246                      case -1:
00247                      default:
00248                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error");
00249                             break;
00250               }
00251               mcrypt_module_close(mcrypt_module);
00252               return NULL;
00253        }
00254 
00255        data = pemalloc(sizeof(php_mcrypt_filter_data), persistent);
00256        data->module = mcrypt_module;
00257        data->encrypt = encrypt;
00258        if (mcrypt_enc_is_block_mode(mcrypt_module)) {
00259               data->blocksize = mcrypt_enc_get_block_size(mcrypt_module);
00260               data->block_buffer = pemalloc(data->blocksize, persistent);
00261        } else {
00262               data->blocksize = 0;
00263               data->block_buffer = NULL;
00264        }
00265        data->block_used = 0;
00266        data->persistent = persistent;
00267 
00268        return php_stream_filter_alloc(&php_mcrypt_filter_ops, data, persistent);
00269 }
00270 /* }}} */
00271 
00272 php_stream_filter_factory php_mcrypt_filter_factory = {
00273        php_mcrypt_filter_create
00274 };
00275 
00276 /*
00277  * Local variables:
00278  * tab-width: 4
00279  * c-basic-offset: 4
00280  * End:
00281  * vim600: noet sw=4 ts=4 fdm=marker
00282  * vim<600: noet sw=4 ts=4
00283  */