summaryrefslogtreecommitdiff
path: root/ext/mcrypt/mcrypt.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/mcrypt/mcrypt.c')
-rw-r--r--ext/mcrypt/mcrypt.c294
1 files changed, 157 insertions, 137 deletions
diff --git a/ext/mcrypt/mcrypt.c b/ext/mcrypt/mcrypt.c
index 89ad83f6bf..5fc632b050 100644
--- a/ext/mcrypt/mcrypt.c
+++ b/ext/mcrypt/mcrypt.c
@@ -40,6 +40,7 @@
#include "php_globals.h"
#include "ext/standard/info.h"
#include "ext/standard/php_rand.h"
+#include "ext/standard/php_smart_str.h"
#include "php_mcrypt_filter.h"
static int le_mcrypt;
@@ -231,7 +232,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_ofb, 0, 0, 5)
ZEND_ARG_INFO(0, iv)
ZEND_END_ARG_INFO()
-ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_create_iv, 0, 0, 2)
+ZEND_BEGIN_ARG_INFO_EX(arginfo_mcrypt_create_iv, 0, 0, 1)
ZEND_ARG_INFO(0, size)
ZEND_ARG_INFO(0, source)
ZEND_END_ARG_INFO()
@@ -309,51 +310,15 @@ zend_module_entry mcrypt_module_entry = {
ZEND_GET_MODULE(mcrypt)
#endif
-#define MCRYPT_ARGS2 \
- zval **cipher, **data, **key, **mode; \
- int td; \
- char *ndata; \
- size_t bsize; \
- size_t nr; \
- size_t nsize
-
-#define MCRYPT_ARGS \
- MCRYPT_ARGS2; \
- zval **iv
-
-#define MCRYPT_SIZE \
- bsize = mcrypt_get_block_size(Z_LVAL_PP(cipher)); \
- nr = (Z_STRLEN_PP(data) + bsize - 1) / bsize; \
- nsize = nr * bsize
-
-#define MCRYPT_CHECK_TD_CPY \
- if (td < 0) { \
- php_error_docref(NULL TSRMLS_CC, E_WARNING, MCRYPT_FAILED); \
- RETURN_FALSE; \
- } \
- ndata = ecalloc(nr, bsize); \
- memcpy(ndata, Z_STRVAL_PP(data), Z_STRLEN_PP(data))
-
-#define MCRYPT_CHECK_IV \
- convert_to_string_ex(iv); \
- if (Z_STRLEN_PP(iv) != bsize) { \
- php_error_docref(NULL TSRMLS_CC, E_WARNING, MCRYPT_IV_WRONG_SIZE); \
- RETURN_FALSE; \
- }
-
-#define MCRYPT_ACTION(x) \
- if (Z_LVAL_PP(mode) == 0) { \
- mcrypt_##x(td, ndata, nsize); \
- } else { \
- mdecrypt_##x(td, ndata, nsize); \
- } \
- end_mcrypt_##x(td)
-
-#define MCRYPT_IV_WRONG_SIZE "The IV parameter must be as long as the blocksize"
-
#define MCRYPT_ENCRYPT 0
#define MCRYPT_DECRYPT 1
+typedef enum {
+ RANDOM = 0,
+ URANDOM,
+ RAND
+} iv_source;
+
#define MCRYPT_GET_INI \
cipher_dir_string = MCG(algorithms_dir); \
module_dir_string = MCG(modes_dir);
@@ -425,9 +390,9 @@ static PHP_MINIT_FUNCTION(mcrypt) /* {{{ */
REGISTER_LONG_CONSTANT("MCRYPT_DECRYPT", 1, CONST_PERSISTENT);
/* sources for mcrypt_create_iv */
- REGISTER_LONG_CONSTANT("MCRYPT_DEV_RANDOM", 0, CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("MCRYPT_DEV_URANDOM", 1, CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("MCRYPT_RAND", 2, CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("MCRYPT_DEV_RANDOM", RANDOM, CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("MCRYPT_DEV_URANDOM", URANDOM, CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("MCRYPT_RAND", RAND, CONST_PERSISTENT);
/* ciphers */
MCRYPT_ENTRY2_2_4(3DES, "tripledes");
@@ -536,12 +501,6 @@ PHP_MINFO_FUNCTION(mcrypt) /* {{{ */
}
/* }}} */
-typedef enum {
- RANDOM = 0,
- URANDOM,
- RAND
-} iv_source;
-
/* {{{ proto resource mcrypt_module_open(string cipher, string cipher_directory, string mode, string mode_directory)
Opens the module of the algorithm and the mode to be used */
PHP_FUNCTION(mcrypt_module_open)
@@ -658,7 +617,7 @@ PHP_FUNCTION(mcrypt_generic)
char *data;
int data_len;
php_mcrypt *pm;
- unsigned char* data_s;
+ char* data_s;
int block_size, data_size;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &mcryptind, &data, &data_len) == FAILURE) {
@@ -1165,14 +1124,120 @@ PHP_FUNCTION(mcrypt_get_cipher_name)
}
/* }}} */
-static void php_mcrypt_do_crypt(char* cipher, const char *key, int key_len, const char *data, int data_len, char *mode, const char *iv, int iv_len, int argc, int dencrypt, zval* return_value TSRMLS_DC) /* {{{ */
+static char *php_mcrypt_get_key_size_str(
+ int max_key_size, const int *key_sizes, int key_size_count) /* {{{ */
+{
+ if (key_size_count == 0) {
+ char *str;
+ spprintf(&str, 0, "Only keys of size 1 to %d supported", max_key_size);
+ return str;
+ } else if (key_size_count == 1) {
+ char *str;
+ spprintf(&str, 0, "Only keys of size %d supported", key_sizes[0]);
+ return str;
+ } else {
+ int i;
+ smart_str str = {0};
+ smart_str_appends(&str, "Only keys of sizes ");
+
+ for (i = 0; i < key_size_count; ++i) {
+ if (i == key_size_count - 1) {
+ smart_str_appends(&str, " or ");
+ } else if (i != 0) {
+ smart_str_appends(&str, ", ");
+ }
+
+ smart_str_append_long(&str, key_sizes[i]);
+ }
+
+ smart_str_appends(&str, " supported");
+ smart_str_0(&str);
+ return str.c;
+ }
+}
+/* }}} */
+
+static zend_bool php_mcrypt_is_valid_key_size(
+ int key_size, int max_key_size, int *key_sizes, int key_size_count) /* {{{ */
+{
+ int i;
+
+ if (key_size <= 0 || key_size > max_key_size) {
+ return 0;
+ }
+
+ if (key_size_count == 0) {
+ /* All key sizes are valid */
+ return 1;
+ }
+
+ for (i = 0; i < key_size_count; i++) {
+ if (key_sizes[i] == key_size) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+/* }}} */
+
+static int php_mcrypt_ensure_valid_key_size(MCRYPT td, int key_size TSRMLS_DC) /* {{{ */
+{
+ int key_size_count;
+ int max_key_size = mcrypt_enc_get_key_size(td);
+ int *key_sizes = mcrypt_enc_get_supported_key_sizes(td, &key_size_count);
+
+ zend_bool is_valid_key_size = php_mcrypt_is_valid_key_size(
+ key_size, max_key_size, key_sizes, key_size_count
+ );
+ if (!is_valid_key_size) {
+ char *key_size_str = php_mcrypt_get_key_size_str(
+ max_key_size, key_sizes, key_size_count
+ );
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "Key of size %d not supported by this algorithm. %s", key_size, key_size_str
+ );
+ efree(key_size_str);
+ }
+
+ if (key_sizes) {
+ mcrypt_free(key_sizes);
+ }
+
+ return is_valid_key_size ? SUCCESS : FAILURE;
+}
+/* }}} */
+
+static int php_mcrypt_ensure_valid_iv(MCRYPT td, const char *iv, int iv_size TSRMLS_DC) /* {{{ */
+{
+ if (mcrypt_enc_mode_has_iv(td) == 1) {
+ int expected_iv_size = mcrypt_enc_get_iv_size(td);
+
+ if (!iv) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "Encryption mode requires an initialization vector of size %d", expected_iv_size
+ );
+ return FAILURE;
+ }
+
+ if (iv_size != expected_iv_size) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "Received initialization vector of size %d, but size %d is required "
+ "for this encryption mode", iv_size, expected_iv_size
+ );
+ return FAILURE;
+ }
+ }
+
+ return SUCCESS;
+}
+/* }}} */
+
+static void php_mcrypt_do_crypt(char* cipher, const char *key, int key_len, const char *data, int data_len, char *mode, const char *iv, int iv_len, int dencrypt, zval* return_value TSRMLS_DC) /* {{{ */
{
char *cipher_dir_string;
char *module_dir_string;
- int block_size, max_key_length, use_key_length, i, count, iv_size;
unsigned long int data_size;
- int *key_length_sizes;
- char *key_s = NULL, *iv_s;
char *data_s;
MCRYPT td;
@@ -1183,92 +1248,47 @@ static void php_mcrypt_do_crypt(char* cipher, const char *key, int key_len, cons
php_error_docref(NULL TSRMLS_CC, E_WARNING, MCRYPT_OPEN_MODULE_FAILED);
RETURN_FALSE;
}
- /* Checking for key-length */
- max_key_length = mcrypt_enc_get_key_size(td);
- if (key_len > max_key_length) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Size of key is too large for this algorithm");
- }
- key_length_sizes = mcrypt_enc_get_supported_key_sizes(td, &count);
- if (count == 0 && key_length_sizes == NULL) { /* all lengths 1 - k_l_s = OK */
- use_key_length = key_len;
- key_s = emalloc(use_key_length);
- memset(key_s, 0, use_key_length);
- memcpy(key_s, key, use_key_length);
- } else if (count == 1) { /* only m_k_l = OK */
- key_s = emalloc(key_length_sizes[0]);
- memset(key_s, 0, key_length_sizes[0]);
- memcpy(key_s, key, MIN(key_len, key_length_sizes[0]));
- use_key_length = key_length_sizes[0];
- } else { /* dertermine smallest supported key > length of requested key */
- use_key_length = max_key_length; /* start with max key length */
- for (i = 0; i < count; i++) {
- if (key_length_sizes[i] >= key_len &&
- key_length_sizes[i] < use_key_length)
- {
- use_key_length = key_length_sizes[i];
- }
- }
- key_s = emalloc(use_key_length);
- memset(key_s, 0, use_key_length);
- memcpy(key_s, key, MIN(key_len, use_key_length));
+
+ if (php_mcrypt_ensure_valid_key_size(td, key_len TSRMLS_CC) == FAILURE) {
+ mcrypt_module_close(td);
+ RETURN_FALSE;
}
- mcrypt_free (key_length_sizes);
-
- /* Check IV */
- iv_s = NULL;
- iv_size = mcrypt_enc_get_iv_size (td);
-
- /* IV is required */
- if (mcrypt_enc_mode_has_iv(td) == 1) {
- if (argc == 5) {
- if (iv_size != iv_len) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, MCRYPT_IV_WRONG_SIZE);
- } else {
- iv_s = emalloc(iv_size + 1);
- memcpy(iv_s, iv, iv_size);
- }
- } else if (argc == 4) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attempt to use an empty IV, which is NOT recommend");
- iv_s = emalloc(iv_size + 1);
- memset(iv_s, 0, iv_size + 1);
- }
+
+ if (php_mcrypt_ensure_valid_iv(td, iv, iv_len TSRMLS_CC) == FAILURE) {
+ mcrypt_module_close(td);
+ RETURN_FALSE;
}
/* Check blocksize */
if (mcrypt_enc_is_block_mode(td) == 1) { /* It's a block algorithm */
- block_size = mcrypt_enc_get_block_size(td);
+ int block_size = mcrypt_enc_get_block_size(td);
data_size = (((data_len - 1) / block_size) + 1) * block_size;
- data_s = emalloc(data_size);
+ data_s = emalloc(data_size + 1);
memset(data_s, 0, data_size);
memcpy(data_s, data, data_len);
} else { /* It's not a block algorithm */
data_size = data_len;
- data_s = emalloc(data_size);
- memset(data_s, 0, data_size);
+ data_s = emalloc(data_size + 1);
memcpy(data_s, data, data_len);
}
- if (mcrypt_generic_init(td, key_s, use_key_length, iv_s) < 0) {
+ if (mcrypt_generic_init(td, (void *) key, key_len, (void *) iv) < 0) {
php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Mcrypt initialisation failed");
+ mcrypt_module_close(td);
RETURN_FALSE;
}
+
if (dencrypt == MCRYPT_ENCRYPT) {
mcrypt_generic(td, data_s, data_size);
} else {
mdecrypt_generic(td, data_s, data_size);
}
- RETVAL_STRINGL(data_s, data_size, 1);
+ data_s[data_size] = 0;
+ RETVAL_STRINGL(data_s, data_size, 0);
/* freeing vars */
mcrypt_generic_end(td);
- if (key_s != NULL) {
- efree (key_s);
- }
- if (iv_s != NULL) {
- efree (iv_s);
- }
- efree (data_s);
}
/* }}} */
@@ -1276,15 +1296,15 @@ static void php_mcrypt_do_crypt(char* cipher, const char *key, int key_len, cons
OFB crypt/decrypt data using key key with cipher cipher starting with iv */
PHP_FUNCTION(mcrypt_encrypt)
{
- zval **mode;
- char *cipher, *key, *data, *iv = NULL;
- int cipher_len, key_len, data_len, iv_len = 0;
-
- MCRYPT_GET_CRYPT_ARGS
+ char *cipher, *key, *data, *mode, *iv = NULL;
+ int cipher_len, key_len, data_len, mode_len, iv_len = 0;
- convert_to_string_ex(mode);
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssss|s", &cipher, &cipher_len,
+ &key, &key_len, &data, &data_len, &mode, &mode_len, &iv, &iv_len) == FAILURE) {
+ return;
+ }
- php_mcrypt_do_crypt(cipher, key, key_len, data, data_len, Z_STRVAL_PP(mode), iv, iv_len, ZEND_NUM_ARGS(), MCRYPT_ENCRYPT, return_value TSRMLS_CC);
+ php_mcrypt_do_crypt(cipher, key, key_len, data, data_len, mode, iv, iv_len, MCRYPT_ENCRYPT, return_value TSRMLS_CC);
}
/* }}} */
@@ -1292,15 +1312,15 @@ PHP_FUNCTION(mcrypt_encrypt)
OFB crypt/decrypt data using key key with cipher cipher starting with iv */
PHP_FUNCTION(mcrypt_decrypt)
{
- zval **mode;
- char *cipher, *key, *data, *iv = NULL;
- int cipher_len, key_len, data_len, iv_len = 0;
+ char *cipher, *key, *data, *mode, *iv = NULL;
+ int cipher_len, key_len, data_len, mode_len, iv_len = 0;
- MCRYPT_GET_CRYPT_ARGS
-
- convert_to_string_ex(mode);
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssss|s", &cipher, &cipher_len,
+ &key, &key_len, &data, &data_len, &mode, &mode_len, &iv, &iv_len) == FAILURE) {
+ return;
+ }
- php_mcrypt_do_crypt(cipher, key, key_len, data, data_len, Z_STRVAL_PP(mode), iv, iv_len, ZEND_NUM_ARGS(), MCRYPT_DECRYPT, return_value TSRMLS_CC);
+ php_mcrypt_do_crypt(cipher, key, key_len, data, data_len, mode, iv, iv_len, MCRYPT_DECRYPT, return_value TSRMLS_CC);
}
/* }}} */
@@ -1316,7 +1336,7 @@ PHP_FUNCTION(mcrypt_ecb)
convert_to_long_ex(mode);
- php_mcrypt_do_crypt(cipher, key, key_len, data, data_len, "ecb", iv, iv_len, ZEND_NUM_ARGS(), Z_LVAL_PP(mode), return_value TSRMLS_CC);
+ php_mcrypt_do_crypt(cipher, key, key_len, data, data_len, "ecb", iv, iv_len, Z_LVAL_PP(mode), return_value TSRMLS_CC);
}
/* }}} */
@@ -1332,7 +1352,7 @@ PHP_FUNCTION(mcrypt_cbc)
convert_to_long_ex(mode);
- php_mcrypt_do_crypt(cipher, key, key_len, data, data_len, "cbc", iv, iv_len, ZEND_NUM_ARGS(), Z_LVAL_PP(mode), return_value TSRMLS_CC);
+ php_mcrypt_do_crypt(cipher, key, key_len, data, data_len, "cbc", iv, iv_len, Z_LVAL_PP(mode), return_value TSRMLS_CC);
}
/* }}} */
@@ -1348,7 +1368,7 @@ PHP_FUNCTION(mcrypt_cfb)
convert_to_long_ex(mode);
- php_mcrypt_do_crypt(cipher, key, key_len, data, data_len, "cfb", iv, iv_len, ZEND_NUM_ARGS(), Z_LVAL_PP(mode), return_value TSRMLS_CC);
+ php_mcrypt_do_crypt(cipher, key, key_len, data, data_len, "cfb", iv, iv_len, Z_LVAL_PP(mode), return_value TSRMLS_CC);
}
/* }}} */
@@ -1364,7 +1384,7 @@ PHP_FUNCTION(mcrypt_ofb)
convert_to_long_ex(mode);
- php_mcrypt_do_crypt(cipher, key, key_len, data, data_len, "ofb", iv, iv_len, ZEND_NUM_ARGS(), Z_LVAL_PP(mode), return_value TSRMLS_CC);
+ php_mcrypt_do_crypt(cipher, key, key_len, data, data_len, "ofb", iv, iv_len, Z_LVAL_PP(mode), return_value TSRMLS_CC);
}
/* }}} */
@@ -1373,7 +1393,7 @@ PHP_FUNCTION(mcrypt_ofb)
PHP_FUNCTION(mcrypt_create_iv)
{
char *iv;
- long source = RANDOM;
+ long source = URANDOM;
long size;
int n = 0;