diff options
author | Stanislav Malyshev <stas@php.net> | 2010-01-15 21:02:20 +0000 |
---|---|---|
committer | Stanislav Malyshev <stas@php.net> | 2010-01-15 21:02:20 +0000 |
commit | 932e276c0b4f08d63779cb4b5cfffe98cda920c9 (patch) | |
tree | e563db686fb2e88f74d80fe3f16ccc92e9d49032 /ext/mcrypt | |
parent | 15e31de034ad02c801ce0835fad12adfe636e70f (diff) | |
download | php-git-932e276c0b4f08d63779cb4b5cfffe98cda920c9.tar.gz |
add filters to mcrypt
# trunk will follow soon
Diffstat (limited to 'ext/mcrypt')
-rw-r--r-- | ext/mcrypt/config.m4 | 2 | ||||
-rw-r--r-- | ext/mcrypt/config.w32 | 2 | ||||
-rw-r--r-- | ext/mcrypt/mcrypt.c | 9 | ||||
-rw-r--r-- | ext/mcrypt/mcrypt_filter.c | 283 | ||||
-rw-r--r-- | ext/mcrypt/php_mcrypt_filter.h | 39 | ||||
-rw-r--r-- | ext/mcrypt/tests/mcrypt_filters.phpt | 41 |
6 files changed, 374 insertions, 2 deletions
diff --git a/ext/mcrypt/config.m4 b/ext/mcrypt/config.m4 index 683b260ac7..cc68d8627b 100644 --- a/ext/mcrypt/config.m4 +++ b/ext/mcrypt/config.m4 @@ -55,5 +55,5 @@ if test "$PHP_MCRYPT" != "no"; then PHP_ADD_INCLUDE($MCRYPT_DIR/include) PHP_SUBST(MCRYPT_SHARED_LIBADD) - PHP_NEW_EXTENSION(mcrypt, mcrypt.c, $ext_shared) + PHP_NEW_EXTENSION(mcrypt, mcrypt.c mcrypt_filter.c, $ext_shared) fi diff --git a/ext/mcrypt/config.w32 b/ext/mcrypt/config.w32 index 22afb95e69..1f89977013 100644 --- a/ext/mcrypt/config.w32 +++ b/ext/mcrypt/config.w32 @@ -9,7 +9,7 @@ if (PHP_MCRYPT != "no") { CHECK_LIB('libmcrypt_a.lib;libmcrypt.lib', 'mcrypt') && CHECK_LIB('Advapi32.lib', 'mcrypt') ) { - EXTENSION('mcrypt', 'mcrypt.c', false); + EXTENSION('mcrypt', 'mcrypt.c mcrypt_filter.c', false); AC_DEFINE('HAVE_LIBMCRYPT', 1); AC_DEFINE('HAVE_LIBMCRYPT24', 1); } else { diff --git a/ext/mcrypt/mcrypt.c b/ext/mcrypt/mcrypt.c index 32f83cd111..dca8dfffd5 100644 --- a/ext/mcrypt/mcrypt.c +++ b/ext/mcrypt/mcrypt.c @@ -41,6 +41,7 @@ #include "php_globals.h" #include "ext/standard/info.h" #include "ext/standard/php_rand.h" +#include "php_mcrypt_filter.h" static int le_mcrypt; @@ -469,12 +470,19 @@ static PHP_MINIT_FUNCTION(mcrypt) /* {{{ */ MCRYPT_ENTRY2_2_4(MODE_OFB, "ofb"); MCRYPT_ENTRY2_2_4(MODE_STREAM, "stream"); REGISTER_INI_ENTRIES(); + + php_stream_filter_register_factory("mcrypt.*", &php_mcrypt_filter_factory TSRMLS_CC); + php_stream_filter_register_factory("mdecrypt.*", &php_mcrypt_filter_factory TSRMLS_CC); + return SUCCESS; } /* }}} */ static PHP_MSHUTDOWN_FUNCTION(mcrypt) /* {{{ */ { + php_stream_filter_unregister_factory("mcrypt.*" TSRMLS_CC); + php_stream_filter_unregister_factory("mdecrypt.*" TSRMLS_CC); + UNREGISTER_INI_ENTRIES(); return SUCCESS; } @@ -516,6 +524,7 @@ PHP_MINFO_FUNCTION(mcrypt) /* {{{ */ php_info_print_table_start(); php_info_print_table_header(2, "mcrypt support", "enabled"); + php_info_print_table_header(2, "mcrypt_filter support", "enabled"); php_info_print_table_row(2, "Version", LIBMCRYPT_VERSION); php_info_print_table_row(2, "Api No", mcrypt_api_no); php_info_print_table_row(2, "Supported ciphers", tmp1.c); diff --git a/ext/mcrypt/mcrypt_filter.c b/ext/mcrypt/mcrypt_filter.c new file mode 100644 index 0000000000..89d11743cb --- /dev/null +++ b/ext/mcrypt/mcrypt_filter.c @@ -0,0 +1,283 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2010 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Sara Golemon <pollita@php.net> | + +----------------------------------------------------------------------+ + + $Id$ +*/ + +#include "php.h" + +#include "php_mcrypt_filter.h" +#include "php_ini.h" +#include <mcrypt.h> + +typedef struct _php_mcrypt_filter_data { + MCRYPT module; + char encrypt; + int blocksize; + char *block_buffer; + int block_used; + char persistent; +} php_mcrypt_filter_data; + +static php_stream_filter_status_t php_mcrypt_filter( + php_stream *stream, + php_stream_filter *thisfilter, + php_stream_bucket_brigade *buckets_in, + php_stream_bucket_brigade *buckets_out, + size_t *bytes_consumed, + int flags TSRMLS_DC) +{ + php_mcrypt_filter_data *data; + php_stream_bucket *bucket; + size_t consumed = 0; + php_stream_filter_status_t exit_status = PSFS_FEED_ME; + + if (!thisfilter || !thisfilter->abstract) { + /* Should never happen */ + return PSFS_ERR_FATAL; + } + + data = (php_mcrypt_filter_data *)(thisfilter->abstract); + while(buckets_in->head) { + bucket = buckets_in->head; + + consumed += bucket->buflen; + + if (data->blocksize) { + /* Blockmode cipher */ + char *outchunk; + int chunklen = bucket->buflen + data->block_used, n; + php_stream_bucket *newbucket; + + outchunk = pemalloc(chunklen, data->persistent); + if (data->block_used) { + memcpy(outchunk, data->block_buffer, data->block_used); + } + memcpy(outchunk + data->block_used, bucket->buf, bucket->buflen); + + for(n=0; (n + data->blocksize) <= chunklen; n += data->blocksize) { + + if (data->encrypt) { + mcrypt_generic(data->module, outchunk + n, data->blocksize); + } else { + mdecrypt_generic(data->module, outchunk + n, data->blocksize); + } + } + data->block_used = chunklen - n; + memcpy(data->block_buffer, outchunk + n, data->block_used); + + newbucket = php_stream_bucket_new(stream, outchunk, n, 1, data->persistent TSRMLS_CC); + php_stream_bucket_append(buckets_out, newbucket TSRMLS_CC); + + exit_status = PSFS_PASS_ON; + + php_stream_bucket_unlink(bucket TSRMLS_CC); + php_stream_bucket_delref(bucket TSRMLS_CC); + } else { + /* Stream cipher */ + php_stream_bucket_make_writeable(bucket TSRMLS_CC); + if (data->encrypt) { + mcrypt_generic(data->module, bucket->buf, bucket->buflen); + } else { + mdecrypt_generic(data->module, bucket->buf, bucket->buflen); + } + php_stream_bucket_append(buckets_out, bucket TSRMLS_CC); + + exit_status = PSFS_PASS_ON; + } + } + + if ((flags & PSFS_FLAG_FLUSH_CLOSE) && data->blocksize && data->block_used) { + php_stream_bucket *newbucket; + + memset(data->block_buffer + data->block_used, 0, data->blocksize - data->block_used); + if (data->encrypt) { + mcrypt_generic(data->module, data->block_buffer, data->blocksize); + } else { + mdecrypt_generic(data->module, data->block_buffer, data->blocksize); + } + + newbucket = php_stream_bucket_new(stream, data->block_buffer, data->blocksize, 0, data->persistent TSRMLS_CC); + php_stream_bucket_append(buckets_out, newbucket TSRMLS_CC); + + exit_status = PSFS_PASS_ON; + } + + if (bytes_consumed) { + *bytes_consumed = consumed; + } + + return exit_status; +} + +static void php_mcrypt_filter_dtor(php_stream_filter *thisfilter TSRMLS_DC) +{ + if (thisfilter && thisfilter->abstract) { + php_mcrypt_filter_data *data = (php_mcrypt_filter_data*)thisfilter->abstract; + + if (data->block_buffer) { + pefree(data->block_buffer, data->persistent); + } + + mcrypt_generic_deinit(data->module); + mcrypt_module_close(data->module); + + pefree(data, data->persistent); + } +} + +static php_stream_filter_ops php_mcrypt_filter_ops = { + php_mcrypt_filter, + php_mcrypt_filter_dtor, + "mcrypt.*" +}; + +/* {{{ php_mcrypt_filter_create + * Instantiate mcrypt filter + */ +static php_stream_filter *php_mcrypt_filter_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC) +{ + int encrypt = 1, iv_len, key_len, keyl, result; + const char *cipher = filtername + sizeof("mcrypt.") - 1; + zval **tmpzval; + MCRYPT mcrypt_module; + char *iv = NULL, *key = NULL; + char *algo_dir = INI_STR("mcrypt.algorithms_dir"); + char *mode_dir = INI_STR("mcrypt.modes_dir"); + char *mode = "cbc"; + php_mcrypt_filter_data *data; + + if (strncasecmp(filtername, "mdecrypt.", sizeof("mdecrypt.") - 1) == 0) { + encrypt = 0; + cipher += sizeof("de") - 1; + } else if (strncasecmp(filtername, "mcrypt.", sizeof("mcrypt.") - 1) != 0) { + /* Should never happen */ + return NULL; + } + + if (!filterparams || Z_TYPE_P(filterparams) != IS_ARRAY) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Filter parameters for %s must be an array", filtername); + return NULL; + } + + if (zend_hash_find(HASH_OF(filterparams), "mode", sizeof("mode"), (void**)&tmpzval) == SUCCESS) { + if (Z_TYPE_PP(tmpzval) == IS_STRING) { + mode = Z_STRVAL_PP(tmpzval); + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "mode is not a string, ignoring"); + } + } + + if (zend_hash_find(HASH_OF(filterparams), "algorithms_dir", sizeof("algorithms_dir"), (void**)&tmpzval) == SUCCESS) { + if (Z_TYPE_PP(tmpzval) == IS_STRING) { + algo_dir = Z_STRVAL_PP(tmpzval); + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "algorithms_dir is not a string, ignoring"); + } + } + + if (zend_hash_find(HASH_OF(filterparams), "modes_dir", sizeof("modes_dir"), (void**)&tmpzval) == SUCCESS) { + if (Z_TYPE_PP(tmpzval) == IS_STRING) { + mode_dir = Z_STRVAL_PP(tmpzval); + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "modes_dir is not a string, ignoring"); + } + } + + if (zend_hash_find(HASH_OF(filterparams), "key", sizeof("key"), (void**)&tmpzval) == SUCCESS && + Z_TYPE_PP(tmpzval) == IS_STRING) { + key = Z_STRVAL_PP(tmpzval); + key_len = Z_STRLEN_PP(tmpzval); + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "key not specified or is not a string"); + return NULL; + } + + mcrypt_module = mcrypt_module_open(cipher, algo_dir, mode, mode_dir); + if (mcrypt_module == MCRYPT_FAILED) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not open encryption module"); + return NULL; + } + iv_len = mcrypt_enc_get_iv_size(mcrypt_module); + keyl = mcrypt_enc_get_key_size(mcrypt_module); + if (keyl < key_len) { + key_len = keyl; + } + + if (zend_hash_find(HASH_OF(filterparams), "iv", sizeof("iv"), (void**) &tmpzval) == FAILURE || + Z_TYPE_PP(tmpzval) != IS_STRING) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Filter parameter[iv] not provided or not of type: string"); + mcrypt_module_close(mcrypt_module); + return NULL; + } + + iv = emalloc(iv_len + 1); + if (iv_len <= Z_STRLEN_PP(tmpzval)) { + memcpy(iv, Z_STRVAL_PP(tmpzval), iv_len); + } else { + memcpy(iv, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval)); + memset(iv + Z_STRLEN_PP(tmpzval), 0, iv_len - Z_STRLEN_PP(tmpzval)); + } + + result = mcrypt_generic_init(mcrypt_module, key, key_len, iv); + efree(iv); + if (result < 0) { + switch (result) { + case -3: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Key length incorrect"); + break; + case -4: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Memory allocation error"); + break; + case -1: + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error"); + break; + } + mcrypt_module_close(mcrypt_module); + return NULL; + } + + data = pemalloc(sizeof(php_mcrypt_filter_data), persistent); + data->module = mcrypt_module; + data->encrypt = encrypt; + if (mcrypt_enc_is_block_mode(mcrypt_module)) { + data->blocksize = mcrypt_enc_get_block_size(mcrypt_module); + data->block_buffer = pemalloc(data->blocksize, persistent); + } else { + data->blocksize = 0; + data->block_buffer = NULL; + } + data->block_used = 0; + data->persistent = persistent; + + return php_stream_filter_alloc(&php_mcrypt_filter_ops, data, persistent); +} +/* }}} */ + +php_stream_filter_factory php_mcrypt_filter_factory = { + php_mcrypt_filter_create +}; + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/ext/mcrypt/php_mcrypt_filter.h b/ext/mcrypt/php_mcrypt_filter.h new file mode 100644 index 0000000000..490d86c73e --- /dev/null +++ b/ext/mcrypt/php_mcrypt_filter.h @@ -0,0 +1,39 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2010 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Sara Golemon <pollita@php.net> | + +----------------------------------------------------------------------+ + + $Id$ +*/ + +#ifndef PHP_MCRYPT_FILTER_H +#define PHP_MCRYPT_FILTER_H + +extern php_stream_filter_factory php_mcrypt_filter_factory; + +PHP_MINIT_FUNCTION(mcrypt_filter); +PHP_MSHUTDOWN_FUNCTION(mcrypt_filter); +PHP_MINFO_FUNCTION(mcrypt_filter); + +#endif /* PHP_MCRYPT_FILTER_H */ + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + */ diff --git a/ext/mcrypt/tests/mcrypt_filters.phpt b/ext/mcrypt/tests/mcrypt_filters.phpt new file mode 100644 index 0000000000..f528219500 --- /dev/null +++ b/ext/mcrypt/tests/mcrypt_filters.phpt @@ -0,0 +1,41 @@ +--TEST-- +mcrypt filters +--SKIPIF-- +<?php if (!extension_loaded("mcrypt")) print "skip"; ?> +--FILE-- +<?php +foreach (stream_get_filters() as $f) { + if ($f == "mcrypt.*" || $f == "mdecrypt.*") { + echo "FOUND\n"; + } +} + +$secretfile = 'secert-file.tmp'; +$passphrase = 'My secret'; + +$iv = substr(md5('iv'.$passphrase, true), 0, 8); +$key = substr(md5('pass1'.$passphrase, true) . + md5('pass2'.$passphrase, true), 0, 24); +$opts = array('iv'=>$iv, 'key'=>$key); + +$fp = fopen($secretfile, 'wb'); +stream_filter_append($fp, 'mcrypt.tripledes', STREAM_FILTER_WRITE, $opts); +fwrite($fp, 'Secret secret secret data'); +fclose($fp); + +echo md5_file($secretfile)."\n"; + +$fp = fopen($secretfile, 'rb'); +stream_filter_append($fp, 'mdecrypt.tripledes', STREAM_FILTER_READ, $opts); +$data = stream_get_contents($fp); +fclose($fp); + +echo $data."\n"; + +@unlink($secretfile); + +--EXPECTF-- +FOUND +FOUND +32e14bd3c31f2bd666e4290ebdb166a7 +Secret secret secret data
\ No newline at end of file |