mirror of
https://github.com/php/php-src.git
synced 2024-09-23 02:47:26 +00:00
add filters to mcrypt
This commit is contained in:
parent
30fc597c92
commit
632be498eb
@ -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
|
||||
|
@ -8,12 +8,11 @@ if (PHP_MCRYPT != "no") {
|
||||
if (CHECK_HEADER_ADD_INCLUDE('mcrypt.h', 'CFLAGS_MCRYPT') &&
|
||||
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 {
|
||||
WARNING("mcrypt not enabled; libraries and headers not found");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
@ -414,12 +415,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;
|
||||
}
|
||||
@ -461,6 +469,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);
|
||||
|
289
ext/mcrypt/mcrypt_filter.c
Normal file
289
ext/mcrypt/mcrypt_filter.c
Normal file
@ -0,0 +1,289 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 6 |
|
||||
+----------------------------------------------------------------------+
|
||||
| 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;
|
||||
|
||||
if (bucket->buf_type == IS_UNICODE) {
|
||||
/* inflation not allowed for unicode data */
|
||||
return PSFS_ERR_FATAL;
|
||||
}
|
||||
|
||||
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.s, 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.s, bucket->buflen);
|
||||
} else {
|
||||
mdecrypt_generic(data->module, bucket->buf.s, 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.*",
|
||||
PSFO_FLAG_ACCEPTS_STRING | PSFO_FLAG_OUTPUTS_STRING
|
||||
};
|
||||
|
||||
/* {{{ 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_ascii_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_ascii_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_ascii_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_ascii_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_ascii_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
|
||||
*/
|
39
ext/mcrypt/php_mcrypt_filter.h
Normal file
39
ext/mcrypt/php_mcrypt_filter.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 6 |
|
||||
+----------------------------------------------------------------------+
|
||||
| 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:
|
||||
*/
|
41
ext/mcrypt/tests/mcrypt_filters.phpt
Normal file
41
ext/mcrypt/tests/mcrypt_filters.phpt
Normal file
@ -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, b'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
|
Loading…
Reference in New Issue
Block a user