2
+----------------------------------------------------------------------+
4
+----------------------------------------------------------------------+
5
| Copyright (c) 1997-2010 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
+----------------------------------------------------------------------+
18
$Id: mcrypt_filter.c 293594 2010-01-15 21:02:20Z stas $
23
#include "php_mcrypt_filter.h"
27
typedef struct _php_mcrypt_filter_data {
34
} php_mcrypt_filter_data;
36
static php_stream_filter_status_t php_mcrypt_filter(
38
php_stream_filter *thisfilter,
39
php_stream_bucket_brigade *buckets_in,
40
php_stream_bucket_brigade *buckets_out,
41
size_t *bytes_consumed,
44
php_mcrypt_filter_data *data;
45
php_stream_bucket *bucket;
47
php_stream_filter_status_t exit_status = PSFS_FEED_ME;
49
if (!thisfilter || !thisfilter->abstract) {
50
/* Should never happen */
51
return PSFS_ERR_FATAL;
54
data = (php_mcrypt_filter_data *)(thisfilter->abstract);
55
while(buckets_in->head) {
56
bucket = buckets_in->head;
58
consumed += bucket->buflen;
60
if (data->blocksize) {
61
/* Blockmode cipher */
63
int chunklen = bucket->buflen + data->block_used, n;
64
php_stream_bucket *newbucket;
66
outchunk = pemalloc(chunklen, data->persistent);
67
if (data->block_used) {
68
memcpy(outchunk, data->block_buffer, data->block_used);
70
memcpy(outchunk + data->block_used, bucket->buf, bucket->buflen);
72
for(n=0; (n + data->blocksize) <= chunklen; n += data->blocksize) {
75
mcrypt_generic(data->module, outchunk + n, data->blocksize);
77
mdecrypt_generic(data->module, outchunk + n, data->blocksize);
80
data->block_used = chunklen - n;
81
memcpy(data->block_buffer, outchunk + n, data->block_used);
83
newbucket = php_stream_bucket_new(stream, outchunk, n, 1, data->persistent TSRMLS_CC);
84
php_stream_bucket_append(buckets_out, newbucket TSRMLS_CC);
86
exit_status = PSFS_PASS_ON;
88
php_stream_bucket_unlink(bucket TSRMLS_CC);
89
php_stream_bucket_delref(bucket TSRMLS_CC);
92
php_stream_bucket_make_writeable(bucket TSRMLS_CC);
94
mcrypt_generic(data->module, bucket->buf, bucket->buflen);
96
mdecrypt_generic(data->module, bucket->buf, bucket->buflen);
98
php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
100
exit_status = PSFS_PASS_ON;
104
if ((flags & PSFS_FLAG_FLUSH_CLOSE) && data->blocksize && data->block_used) {
105
php_stream_bucket *newbucket;
107
memset(data->block_buffer + data->block_used, 0, data->blocksize - data->block_used);
109
mcrypt_generic(data->module, data->block_buffer, data->blocksize);
111
mdecrypt_generic(data->module, data->block_buffer, data->blocksize);
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);
117
exit_status = PSFS_PASS_ON;
120
if (bytes_consumed) {
121
*bytes_consumed = consumed;
127
static void php_mcrypt_filter_dtor(php_stream_filter *thisfilter TSRMLS_DC)
129
if (thisfilter && thisfilter->abstract) {
130
php_mcrypt_filter_data *data = (php_mcrypt_filter_data*)thisfilter->abstract;
132
if (data->block_buffer) {
133
pefree(data->block_buffer, data->persistent);
136
mcrypt_generic_deinit(data->module);
137
mcrypt_module_close(data->module);
139
pefree(data, data->persistent);
143
static php_stream_filter_ops php_mcrypt_filter_ops = {
145
php_mcrypt_filter_dtor,
149
/* {{{ php_mcrypt_filter_create
150
* Instantiate mcrypt filter
152
static php_stream_filter *php_mcrypt_filter_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
154
int encrypt = 1, iv_len, key_len, keyl, result;
155
const char *cipher = filtername + sizeof("mcrypt.") - 1;
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");
162
php_mcrypt_filter_data *data;
164
if (strncasecmp(filtername, "mdecrypt.", sizeof("mdecrypt.") - 1) == 0) {
166
cipher += sizeof("de") - 1;
167
} else if (strncasecmp(filtername, "mcrypt.", sizeof("mcrypt.") - 1) != 0) {
168
/* Should never happen */
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);
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);
181
php_error_docref(NULL TSRMLS_CC, E_WARNING, "mode is not a string, ignoring");
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);
189
php_error_docref(NULL TSRMLS_CC, E_WARNING, "algorithms_dir is not a string, ignoring");
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);
197
php_error_docref(NULL TSRMLS_CC, E_WARNING, "modes_dir is not a string, ignoring");
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);
206
php_error_docref(NULL TSRMLS_CC, E_WARNING, "key not specified or is not a string");
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");
215
iv_len = mcrypt_enc_get_iv_size(mcrypt_module);
216
keyl = mcrypt_enc_get_key_size(mcrypt_module);
217
if (keyl < key_len) {
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);
228
iv = emalloc(iv_len + 1);
229
if (iv_len <= Z_STRLEN_PP(tmpzval)) {
230
memcpy(iv, Z_STRVAL_PP(tmpzval), iv_len);
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));
236
result = mcrypt_generic_init(mcrypt_module, key, key_len, iv);
241
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Key length incorrect");
244
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Memory allocation error");
248
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error");
251
mcrypt_module_close(mcrypt_module);
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);
263
data->block_buffer = NULL;
265
data->block_used = 0;
266
data->persistent = persistent;
268
return php_stream_filter_alloc(&php_mcrypt_filter_ops, data, persistent);
272
php_stream_filter_factory php_mcrypt_filter_factory = {
273
php_mcrypt_filter_create
281
* vim600: noet sw=4 ts=4 fdm=marker
282
* vim<600: noet sw=4 ts=4