pollita Wed, 19 May 2010 20:05:09 +
Revision: http://svn.php.net/viewvc?view=revisionrevision=299508
Log:
Add parameter to openssl_(en|de)crypt
Changed paths:
U php/php-src/trunk/ext/openssl/openssl.c
U php/php-src/trunk/ext/openssl/tests/011.phpt
U php/php-src/trunk/ext/openssl/tests/openssl_decrypt_error.phpt
Modified: php/php-src/trunk/ext/openssl/openssl.c
===
--- php/php-src/trunk/ext/openssl/openssl.c 2010-05-19 19:34:58 UTC (rev 299507)
+++ php/php-src/trunk/ext/openssl/openssl.c 2010-05-19 20:05:09 UTC (rev 299508)
@@ -99,6 +99,7 @@
PHP_FUNCTION(openssl_digest);
PHP_FUNCTION(openssl_encrypt);
PHP_FUNCTION(openssl_decrypt);
+PHP_FUNCTION(openssl_cipher_iv_length);
PHP_FUNCTION(openssl_dh_compute_key);
PHP_FUNCTION(openssl_random_pseudo_bytes);
@@ -347,6 +348,7 @@
ZEND_ARG_INFO(0, method)
ZEND_ARG_INFO(0, password)
ZEND_ARG_INFO(0, raw_output)
+ZEND_ARG_INFO(0, iv)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_decrypt, 0, 0, 3)
@@ -354,8 +356,13 @@
ZEND_ARG_INFO(0, method)
ZEND_ARG_INFO(0, password)
ZEND_ARG_INFO(0, raw_input)
+ZEND_ARG_INFO(0, iv)
ZEND_END_ARG_INFO()
+ZEND_BEGIN_ARG_INFO(arginfo_openssl_cipher_iv_length, 0)
+ZEND_ARG_INFO(0, method)
+ZEND_END_ARG_INFO()
+
ZEND_BEGIN_ARG_INFO(arginfo_openssl_dh_compute_key, 0)
ZEND_ARG_INFO(0, pub_key)
ZEND_ARG_INFO(0, dh_key)
@@ -408,6 +415,7 @@
PHP_FE(openssl_digest,arginfo_openssl_digest)
PHP_FE(openssl_encrypt,arginfo_openssl_encrypt)
PHP_FE(openssl_decrypt,arginfo_openssl_decrypt)
+ PHP_FE(openssl_cipher_iv_length, arginfo_openssl_cipher_iv_length)
PHP_FE(openssl_sign,arginfo_openssl_sign)
PHP_FE(openssl_verify,arginfo_openssl_verify)
PHP_FE(openssl_seal,arginfo_openssl_seal)
@@ -4585,19 +4593,54 @@
}
/* }}} */
-/* {{{ proto string openssl_encrypt(string data, string method, string password [, bool raw_output=false])
+static zend_bool php_openssl_validate_iv(char **piv, int *piv_len, int iv_required_len)
+{
+ char *iv_new;
+
+ /* Best case scenario, user behaved */
+ if (*piv_len == iv_required_len) {
+ return 0;
+ }
+
+ iv_new = ecalloc(1, iv_required_len + 1);
+
+ if (*piv_len = 0) {
+ /* BC behavior */
+ *piv_len = iv_required_len;
+ *piv = iv_new;
+ return 1;
+ }
+
+ if (*piv_len iv_required_len) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, IV passed is only %d bytes long, cipher expects an IV of precisely %d bytes, padding with \\0, *piv_len, iv_required_len);
+ memcpy(iv_new, *piv, *piv_len);
+ *piv_len = iv_required_len;
+ *piv = iv_new;
+ return 1;
+ }
+
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, IV passed is %d bytes long which is longer than the %d expected by selected cipher, truncating, *piv_len, iv_required_len);
+ memcpy(iv_new, *piv, iv_required_len);
+ *piv_len = iv_required_len;
+ *piv = iv_new;
+ return 1;
+
+}
+
+/* {{{ proto string openssl_encrypt(string data, string method, string password [, bool raw_output=false [, string $iv='']])
Encrypts given data with given method and key, returns raw or base64 encoded string */
PHP_FUNCTION(openssl_encrypt)
{
zend_bool raw_output = 0;
- char *data, *method, *password;
- int data_len, method_len, password_len;
+ char *data, *method, *password, *iv = ;
+ int data_len, method_len, password_len, iv_len = 0;
const EVP_CIPHER *cipher_type;
EVP_CIPHER_CTX cipher_ctx;
- int i, outlen, keylen, ivlen;
- unsigned char *outbuf, *key, *iv;
+ int i, outlen, keylen;
+ unsigned char *outbuf, *key;
+ zend_bool free_iv;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, sss|b, data, data_len, method, method_len, password, password_len, raw_output) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, sss|bs, data, data_len, method, method_len, password, password_len, raw_output, iv, iv_len) == FAILURE) {
return;
}
cipher_type = EVP_get_cipherbyname(method);
@@ -4615,14 +4658,15 @@
key = (unsigned char*)password;
}
- ivlen = EVP_CIPHER_iv_length(cipher_type);
- iv = emalloc(ivlen);
- memset(iv, 0, ivlen);
+ if (iv_len = 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, Using an empty Initialization Vector (iv) is potentially insecure and not recommended);
+ }
+ free_iv = php_openssl_validate_iv(iv, iv_len, EVP_CIPHER_iv_length(cipher_type));
outlen = data_len + EVP_CIPHER_block_size(cipher_type);
outbuf = emalloc(outlen + 1);
- EVP_EncryptInit(cipher_ctx, cipher_type, key, iv);
+ EVP_EncryptInit(cipher_ctx, cipher_type, key, (unsigned char *)iv);
EVP_EncryptUpdate(cipher_ctx, outbuf, i, (unsigned char *)data, data_len);
outlen = i;
if (EVP_EncryptFinal(cipher_ctx, (unsigned char *)outbuf + i, i)) {
@@ -4645,25 +4689,28 @@
if (key != (unsigned char*)password) {
efree(key);
}
- efree(iv);
+ if (free_iv) {
+ efree(iv);
+ }
}
/* }}} */
-/* {{{ proto string