root/ext/mcrypt/mcrypt_filter.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_mcrypt_filter
  2. php_mcrypt_filter_dtor
  3. php_mcrypt_filter_create

   1 /*
   2   +----------------------------------------------------------------------+
   3   | PHP Version 7                                                        |
   4   +----------------------------------------------------------------------+
   5   | Copyright (c) 1997-2016 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   | Author: Sara Golemon <pollita@php.net>                               |
  16   +----------------------------------------------------------------------+
  17 
  18   $Id$
  19 */
  20 
  21 #include "php.h"
  22 
  23 #include "php_mcrypt_filter.h"
  24 #include "php_ini.h"
  25 #include <mcrypt.h>
  26 
  27 typedef struct _php_mcrypt_filter_data {
  28         MCRYPT module;
  29         char encrypt;
  30         int blocksize;
  31         char *block_buffer;
  32         int block_used;
  33         char persistent;
  34 } php_mcrypt_filter_data;
  35 
  36 static php_stream_filter_status_t php_mcrypt_filter(
  37         php_stream *stream,
  38         php_stream_filter *thisfilter,
  39         php_stream_bucket_brigade *buckets_in,
  40         php_stream_bucket_brigade *buckets_out,
  41         size_t *bytes_consumed,
  42         int flags)
  43 {
  44         php_mcrypt_filter_data *data;
  45         php_stream_bucket *bucket;
  46         size_t consumed = 0;
  47         php_stream_filter_status_t exit_status = PSFS_FEED_ME;
  48 
  49         if (!thisfilter || !Z_PTR(thisfilter->abstract)) {
  50                 /* Should never happen */
  51                 return PSFS_ERR_FATAL;
  52         }
  53 
  54         data = (php_mcrypt_filter_data *)(Z_PTR(thisfilter->abstract));
  55         while(buckets_in->head) {
  56                 bucket = buckets_in->head;
  57 
  58                 consumed += bucket->buflen;
  59 
  60                 if (data->blocksize) {
  61                         /* Blockmode cipher */
  62                         char *outchunk;
  63                         int chunklen = (int)(bucket->buflen + data->block_used), n;
  64                         php_stream_bucket *newbucket;
  65 
  66                         outchunk = pemalloc(chunklen, data->persistent);
  67                         if (data->block_used) {
  68                                 memcpy(outchunk, data->block_buffer, data->block_used);
  69                         }
  70                         memcpy(outchunk + data->block_used, bucket->buf, bucket->buflen);
  71 
  72                         for(n=0; (n + data->blocksize) <= chunklen; n += data->blocksize) {
  73 
  74                                 if (data->encrypt) {
  75                                         mcrypt_generic(data->module, outchunk + n, data->blocksize);
  76                                 } else {
  77                                         mdecrypt_generic(data->module, outchunk + n, data->blocksize);
  78                                 }
  79                         }
  80                         data->block_used = chunklen - n;
  81                         memcpy(data->block_buffer, outchunk + n, data->block_used);
  82 
  83                         newbucket = php_stream_bucket_new(stream, outchunk, n, 1, data->persistent);
  84                         php_stream_bucket_append(buckets_out, newbucket);
  85 
  86                         exit_status = PSFS_PASS_ON;
  87 
  88                         php_stream_bucket_unlink(bucket);
  89                         php_stream_bucket_delref(bucket);
  90                 } else {
  91                         /* Stream cipher */
  92                         php_stream_bucket_make_writeable(bucket);
  93                         if (data->encrypt) {
  94                                 mcrypt_generic(data->module, bucket->buf, (int)bucket->buflen);
  95                         } else {
  96                                 mdecrypt_generic(data->module, bucket->buf, (int)bucket->buflen);
  97                         }
  98                         php_stream_bucket_append(buckets_out, bucket);
  99 
 100                         exit_status = PSFS_PASS_ON;
 101                 }
 102         }
 103 
 104         if ((flags & PSFS_FLAG_FLUSH_CLOSE) && data->blocksize && data->block_used) {
 105                 php_stream_bucket *newbucket;
 106 
 107                 memset(data->block_buffer + data->block_used, 0, data->blocksize - data->block_used);
 108                 if (data->encrypt) {
 109                         mcrypt_generic(data->module, data->block_buffer, data->blocksize);
 110                 } else {
 111                         mdecrypt_generic(data->module, data->block_buffer, data->blocksize);
 112                 }
 113 
 114                 newbucket = php_stream_bucket_new(stream, data->block_buffer, data->blocksize, 0, data->persistent);
 115                 php_stream_bucket_append(buckets_out, newbucket);
 116 
 117                 exit_status = PSFS_PASS_ON;
 118         }
 119 
 120         if (bytes_consumed) {
 121                 *bytes_consumed = consumed;
 122         }
 123 
 124         return exit_status;
 125 }
 126 
 127 static void php_mcrypt_filter_dtor(php_stream_filter *thisfilter)
 128 {
 129         if (thisfilter && Z_PTR(thisfilter->abstract)) {
 130                 php_mcrypt_filter_data *data = (php_mcrypt_filter_data*) Z_PTR(thisfilter->abstract);
 131 
 132                 if (data->block_buffer) {
 133                         pefree(data->block_buffer, data->persistent);
 134                 }
 135 
 136                 mcrypt_generic_deinit(data->module);
 137                 mcrypt_module_close(data->module);
 138 
 139                 pefree(data, data->persistent);
 140         }
 141 }
 142 
 143 static php_stream_filter_ops php_mcrypt_filter_ops = {
 144     php_mcrypt_filter,
 145     php_mcrypt_filter_dtor,
 146     "mcrypt.*"
 147 };
 148 
 149 /* {{{ php_mcrypt_filter_create
 150  * Instantiate mcrypt filter
 151  */
 152 static php_stream_filter *php_mcrypt_filter_create(const char *filtername, zval *filterparams, int persistent)
 153 {
 154         int encrypt = 1, iv_len, key_len, keyl, result;
 155         const char *cipher = filtername + sizeof("mcrypt.") - 1;
 156         zval *tmpzval;
 157         MCRYPT mcrypt_module;
 158         char *iv = NULL, *key = NULL;
 159         char *algo_dir = INI_STR("mcrypt.algorithms_dir");
 160         char *mode_dir = INI_STR("mcrypt.modes_dir");
 161         char *mode = "cbc";
 162         php_mcrypt_filter_data *data;
 163 
 164         if (strncasecmp(filtername, "mdecrypt.", sizeof("mdecrypt.") - 1) == 0) {
 165                 encrypt = 0;
 166                 cipher += sizeof("de") - 1;
 167         } else if (strncasecmp(filtername, "mcrypt.", sizeof("mcrypt.") - 1) != 0) {
 168                 /* Should never happen */
 169                 return NULL;
 170         }
 171 
 172         if (!filterparams || Z_TYPE_P(filterparams) != IS_ARRAY) {
 173                 php_error_docref(NULL, E_WARNING, "Filter parameters for %s must be an array", filtername);
 174                 return NULL;
 175         }
 176 
 177         if ((tmpzval = zend_hash_str_find(Z_ARRVAL_P(filterparams), ZEND_STRL("mode")))) {
 178                 if (Z_TYPE_P(tmpzval) == IS_STRING) {
 179                         mode = Z_STRVAL_P(tmpzval);
 180                 } else {
 181                         php_error_docref(NULL, E_WARNING, "mode is not a string, ignoring");
 182                 }
 183         }
 184 
 185         if ((tmpzval=zend_hash_str_find(Z_ARRVAL_P(filterparams), ZEND_STRL("algorithms_dir")))) {
 186                 if (Z_TYPE_P(tmpzval) == IS_STRING) {
 187                         algo_dir = Z_STRVAL_P(tmpzval);
 188                 } else {
 189                         php_error_docref(NULL, E_WARNING, "algorithms_dir is not a string, ignoring");
 190                 }
 191         }
 192 
 193         if ((tmpzval=zend_hash_str_find(Z_ARRVAL_P(filterparams), ZEND_STRL("modes_dir")))) {
 194                 if (Z_TYPE_P(tmpzval) == IS_STRING) {
 195                         mode_dir = Z_STRVAL_P(tmpzval);
 196                 } else {
 197                         php_error_docref(NULL, E_WARNING, "modes_dir is not a string, ignoring");
 198                 }
 199         }
 200 
 201         if ((tmpzval = zend_hash_str_find(Z_ARRVAL_P(filterparams), ZEND_STRL("key"))) &&
 202                 Z_TYPE_P(tmpzval) == IS_STRING) {
 203                 key = Z_STRVAL_P(tmpzval);
 204                 key_len = (int)Z_STRLEN_P(tmpzval);
 205         } else {
 206                 php_error_docref(NULL, E_WARNING, "key not specified or is not a string");
 207                 return NULL;
 208         }
 209 
 210         mcrypt_module = mcrypt_module_open((char *)cipher, algo_dir, mode, mode_dir);
 211         if (mcrypt_module == MCRYPT_FAILED) {
 212                 php_error_docref(NULL, E_WARNING, "Could not open encryption module");
 213                 return NULL;
 214         }
 215         iv_len = mcrypt_enc_get_iv_size(mcrypt_module);
 216         keyl = mcrypt_enc_get_key_size(mcrypt_module);
 217         if (keyl < key_len) {
 218                 key_len = keyl;
 219         }
 220 
 221         if (!(tmpzval = zend_hash_str_find(Z_ARRVAL_P(filterparams), ZEND_STRL("iv"))) ||
 222                 Z_TYPE_P(tmpzval) != IS_STRING) {
 223                 php_error_docref(NULL, E_WARNING, "Filter parameter[iv] not provided or not of type: string");
 224                 mcrypt_module_close(mcrypt_module);
 225                 return NULL;
 226         }
 227 
 228         iv = emalloc(iv_len + 1);
 229         if (iv_len <= Z_STRLEN_P(tmpzval)) {
 230                 memcpy(iv, Z_STRVAL_P(tmpzval), iv_len);
 231         } else {
 232                 memcpy(iv, Z_STRVAL_P(tmpzval), Z_STRLEN_P(tmpzval));
 233                 memset(iv + Z_STRLEN_P(tmpzval), 0, iv_len - Z_STRLEN_P(tmpzval));
 234         }
 235 
 236         result = mcrypt_generic_init(mcrypt_module, key, key_len, iv);
 237         efree(iv);
 238         if (result < 0) {
 239                 switch (result) {
 240                         case -3:
 241                                 php_error_docref(NULL, E_WARNING, "Key length incorrect");
 242                                 break;
 243                         case -4:
 244                                 php_error_docref(NULL, E_WARNING, "Memory allocation error");
 245                                 break;
 246                         case -1:
 247                         default:
 248                                 php_error_docref(NULL, E_WARNING, "Unknown error");
 249                                 break;
 250                 }
 251                 mcrypt_module_close(mcrypt_module);
 252                 return NULL;
 253         }
 254 
 255         data = pemalloc(sizeof(php_mcrypt_filter_data), persistent);
 256         data->module = mcrypt_module;
 257         data->encrypt = encrypt;
 258         if (mcrypt_enc_is_block_mode(mcrypt_module)) {
 259                 data->blocksize = mcrypt_enc_get_block_size(mcrypt_module);
 260                 data->block_buffer = pemalloc(data->blocksize, persistent);
 261         } else {
 262                 data->blocksize = 0;
 263                 data->block_buffer = NULL;
 264         }
 265         data->block_used = 0;
 266         data->persistent = persistent;
 267 
 268         return php_stream_filter_alloc(&php_mcrypt_filter_ops, data, persistent);
 269 }
 270 /* }}} */
 271 
 272 php_stream_filter_factory php_mcrypt_filter_factory = {
 273         php_mcrypt_filter_create
 274 };
 275 
 276 /*
 277  * Local variables:
 278  * tab-width: 4
 279  * c-basic-offset: 4
 280  * End:
 281  * vim600: noet sw=4 ts=4 fdm=marker
 282  * vim<600: noet sw=4 ts=4
 283  */

/* [<][>][^][v][top][bottom][index][help] */