~ubuntu-branches/ubuntu/trusty/php-mcrypt/trusty

« back to all changes in this revision

Viewing changes to mcrypt_filter.c

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short
  • Date: 2010-08-03 11:25:17 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20100803112517-m2ok1wicmttf6eal
Tags: 5.3.3-0ubuntu1
New upstream release against PHP 5.3.3. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  +----------------------------------------------------------------------+
 
3
  | PHP Version 5                                                        |
 
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
  +----------------------------------------------------------------------+
 
17
 
 
18
  $Id: mcrypt_filter.c 293594 2010-01-15 21:02:20Z stas $ 
 
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
 */