File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / mcrypt / mcrypt_filter.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 20:03:51 2014 UTC (10 years, 1 month ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29, HEAD
php 5.4.29

    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:   | Author: Sara Golemon <pollita@php.net>                               |
   16:   +----------------------------------------------------------------------+
   17: 
   18:   $Id: mcrypt_filter.c,v 1.1.1.4 2014/06/15 20:03:51 misho Exp $ 
   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 TSRMLS_DC)
   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 || !thisfilter->abstract) {
   50: 		/* Should never happen */
   51: 		return PSFS_ERR_FATAL;
   52: 	}
   53: 
   54: 	data = (php_mcrypt_filter_data *)(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 = 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 TSRMLS_CC);
   84: 			php_stream_bucket_append(buckets_out, newbucket TSRMLS_CC);
   85: 
   86: 			exit_status = PSFS_PASS_ON;
   87: 
   88: 			php_stream_bucket_unlink(bucket TSRMLS_CC);
   89: 			php_stream_bucket_delref(bucket TSRMLS_CC);
   90: 		} else {
   91: 			/* Stream cipher */
   92: 			php_stream_bucket_make_writeable(bucket TSRMLS_CC);
   93: 			if (data->encrypt) {
   94: 				mcrypt_generic(data->module, bucket->buf, bucket->buflen);
   95: 			} else {
   96: 				mdecrypt_generic(data->module, bucket->buf, bucket->buflen);
   97: 			}
   98: 			php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
   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 TSRMLS_CC);
  115: 		php_stream_bucket_append(buckets_out, newbucket TSRMLS_CC);
  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 TSRMLS_DC)
  128: {
  129: 	if (thisfilter && thisfilter->abstract) {
  130: 		php_mcrypt_filter_data *data = (php_mcrypt_filter_data*)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 TSRMLS_DC)
  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 TSRMLS_CC, E_WARNING, "Filter parameters for %s must be an array", filtername);
  174: 		return NULL;
  175: 	}
  176: 
  177: 	if (zend_hash_find(HASH_OF(filterparams), "mode", sizeof("mode"), (void**)&tmpzval) == SUCCESS) {
  178: 		if (Z_TYPE_PP(tmpzval) == IS_STRING) {
  179: 			mode = Z_STRVAL_PP(tmpzval);
  180: 		} else {
  181: 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "mode is not a string, ignoring");
  182: 		}
  183: 	}
  184: 
  185: 	if (zend_hash_find(HASH_OF(filterparams), "algorithms_dir", sizeof("algorithms_dir"), (void**)&tmpzval) == SUCCESS) {
  186: 		if (Z_TYPE_PP(tmpzval) == IS_STRING) {
  187: 			algo_dir = Z_STRVAL_PP(tmpzval);
  188: 		} else {
  189: 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "algorithms_dir is not a string, ignoring");
  190: 		}
  191: 	}
  192: 
  193: 	if (zend_hash_find(HASH_OF(filterparams), "modes_dir", sizeof("modes_dir"), (void**)&tmpzval) == SUCCESS) {
  194: 		if (Z_TYPE_PP(tmpzval) == IS_STRING) {
  195: 			mode_dir = Z_STRVAL_PP(tmpzval);
  196: 		} else {
  197: 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "modes_dir is not a string, ignoring");
  198: 		}
  199: 	}
  200: 
  201: 	if (zend_hash_find(HASH_OF(filterparams), "key", sizeof("key"), (void**)&tmpzval) == SUCCESS &&
  202: 		Z_TYPE_PP(tmpzval) == IS_STRING) {
  203: 		key = Z_STRVAL_PP(tmpzval);
  204: 		key_len = Z_STRLEN_PP(tmpzval);
  205: 	} else {
  206: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "key not specified or is not a string");
  207: 		return NULL;
  208: 	}
  209: 
  210: 	mcrypt_module = mcrypt_module_open(cipher, algo_dir, mode, mode_dir);
  211: 	if (mcrypt_module == MCRYPT_FAILED) {
  212: 		php_error_docref(NULL TSRMLS_CC, 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 (zend_hash_find(HASH_OF(filterparams), "iv", sizeof("iv"), (void**) &tmpzval) == FAILURE ||
  222: 		Z_TYPE_PP(tmpzval) != IS_STRING) {
  223: 		php_error_docref(NULL TSRMLS_CC, 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_PP(tmpzval)) {
  230: 		memcpy(iv, Z_STRVAL_PP(tmpzval), iv_len);
  231: 	} else {
  232: 		memcpy(iv, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval));
  233: 		memset(iv + Z_STRLEN_PP(tmpzval), 0, iv_len - Z_STRLEN_PP(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 TSRMLS_CC, E_WARNING, "Key length incorrect");
  242: 				break;
  243: 			case -4:
  244: 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Memory allocation error");
  245: 				break;
  246: 			case -1:
  247: 			default:
  248: 				php_error_docref(NULL TSRMLS_CC, 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:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>