dmitry          Thu Sep 27 08:46:00 2007 UTC

  Modified files:              (Branch: PHP_5_3)
    /php-src    NEWS 
    /php-src/ext/openssl        openssl.c 
  Log:
  MFH: Improved ext/openssl
  . Added support for OpenSSL digest functions
  . Added support for OpenSSL cipher functions
  . Added access to internal values of DSA, RSA and DH keys
  
  
http://cvs.php.net/viewvc.cgi/php-src/NEWS?r1=1.2027.2.547.2.965.2.2&r2=1.2027.2.547.2.965.2.3&diff_format=u
Index: php-src/NEWS
diff -u php-src/NEWS:1.2027.2.547.2.965.2.2 php-src/NEWS:1.2027.2.547.2.965.2.3
--- php-src/NEWS:1.2027.2.547.2.965.2.2 Thu Sep 27 08:23:58 2007
+++ php-src/NEWS        Thu Sep 27 08:45:59 2007
@@ -1,6 +1,10 @@
 PHP                                                                        NEWS
 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
 ?? ??? 20??, PHP 5.3.0
+- Improved ext/openssl (Dmitry)
+  . Added support for OpenSSL digest functions
+  . Added support for OpenSSL cipher functions
+  . Added access to internal values of DSA, RSA and DH keys
 - Improved and cleaned CGI code. FastCGI is now always enabled and can not be
   disabled. See sapi/cgi/CHANGES for more details. (Dmitry)
 - Added support for dynamic access of static members using $foo::myFunc().
http://cvs.php.net/viewvc.cgi/php-src/ext/openssl/openssl.c?r1=1.98.2.5.2.41&r2=1.98.2.5.2.41.2.1&diff_format=u
Index: php-src/ext/openssl/openssl.c
diff -u php-src/ext/openssl/openssl.c:1.98.2.5.2.41 
php-src/ext/openssl/openssl.c:1.98.2.5.2.41.2.1
--- php-src/ext/openssl/openssl.c:1.98.2.5.2.41 Wed Aug  8 06:29:46 2007
+++ php-src/ext/openssl/openssl.c       Thu Sep 27 08:46:00 2007
@@ -20,7 +20,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: openssl.c,v 1.98.2.5.2.41 2007/08/08 06:29:46 pajoye Exp $ */
+/* $Id: openssl.c,v 1.98.2.5.2.41.2.1 2007/09/27 08:46:00 dmitry Exp $ */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -33,6 +33,8 @@
 #include "ext/standard/file.h"
 #include "ext/standard/info.h"
 #include "ext/standard/php_fopen_wrappers.h"
+#include "ext/standard/md5.h"
+#include "ext/standard/base64.h"
 
 /* OpenSSL includes */
 #include <openssl/evp.h>
@@ -88,6 +90,15 @@
        PHP_OPENSSL_CIPHER_DEFAULT = PHP_OPENSSL_CIPHER_RC2_40
 };
 
+PHP_FUNCTION(openssl_get_md_methods);
+PHP_FUNCTION(openssl_get_cipher_methods);
+
+PHP_FUNCTION(openssl_digest);
+PHP_FUNCTION(openssl_encrypt);
+PHP_FUNCTION(openssl_decrypt);
+
+PHP_FUNCTION(openssl_dh_compute_key);
+
 /* {{{ openssl_functions[]
  */
 zend_function_entry openssl_functions[] = {
@@ -126,10 +137,13 @@
        PHP_FE(openssl_csr_get_subject,         NULL)
        PHP_FE(openssl_csr_get_public_key,      NULL)
 
-       PHP_FE(openssl_sign,            second_arg_force_ref)
-       PHP_FE(openssl_verify,          NULL)
-       PHP_FE(openssl_seal,            arg2and3_force_ref)
-       PHP_FE(openssl_open,            second_arg_force_ref)
+       PHP_FE(openssl_digest,                          NULL)
+       PHP_FE(openssl_encrypt,                         NULL)
+       PHP_FE(openssl_decrypt,                         NULL)
+       PHP_FE(openssl_sign,                            second_arg_force_ref)
+       PHP_FE(openssl_verify,                          NULL)
+       PHP_FE(openssl_seal,                            arg2and3_force_ref)
+       PHP_FE(openssl_open,                            second_arg_force_ref)
 
 /* for S/MIME handling */
        PHP_FE(openssl_pkcs7_verify,            NULL)
@@ -142,6 +156,11 @@
        PHP_FE(openssl_public_encrypt,          second_arg_force_ref)
        PHP_FE(openssl_public_decrypt,          second_arg_force_ref)
 
+       PHP_FE(openssl_get_md_methods,          NULL)
+       PHP_FE(openssl_get_cipher_methods,      NULL)
+
+       PHP_FE(openssl_dh_compute_key,      NULL)
+
        PHP_FE(openssl_error_string, NULL)
        {NULL, NULL, NULL}
 };
@@ -645,6 +664,34 @@
        return mdtype;
 }
 /* }}} */
+
+static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(long algo) { /* 
{{{ */
+       switch (algo) {
+#ifndef OPENSSL_NO_RC2
+               case PHP_OPENSSL_CIPHER_RC2_40:
+                       return EVP_rc2_40_cbc();
+                       break;
+               case PHP_OPENSSL_CIPHER_RC2_64:
+                       return EVP_rc2_64_cbc();
+                       break;
+               case PHP_OPENSSL_CIPHER_RC2_128:
+                       return EVP_rc2_cbc();
+                       break;
+#endif
+
+#ifndef OPENSSL_NO_DES
+               case PHP_OPENSSL_CIPHER_DES:
+                       return EVP_des_cbc();
+                       break;
+               case PHP_OPENSSL_CIPHER_3DES:
+                       return EVP_des_ede3_cbc();
+                       break;
+#endif
+               default:
+                       return NULL;
+                       break;
+       }
+}
 /* }}} */
 
 /* {{{ PHP_MINIT_FUNCTION
@@ -2433,6 +2480,25 @@
                                }
                                break;
 #endif
+#if !defined(NO_DH)
+                       case OPENSSL_KEYTYPE_DH:
+                               {
+                                       DH *dhpar = 
DH_generate_parameters(req->priv_key_bits, 2, NULL, NULL);
+                                       int codes = 0;
+
+                                       if (dhpar) {
+                                               DH_set_method(dhpar, 
DH_get_default_method());
+                                               if (DH_check(dhpar, &codes) && 
codes == 0 && DH_generate_key(dhpar)) {
+                                                       if 
(EVP_PKEY_assign_DH(req->priv_key, dhpar)) {
+                                                               return_val = 
req->priv_key;
+                                                       }
+                                               } else {
+                                                       DH_free(dhpar);
+                                               }
+                                       }
+                               }
+                               break;
+#endif
                        default:
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, 
"Unsupported private key type");
                }
@@ -2497,18 +2563,111 @@
 }
 /* }}} */
 
+#define OPENSSL_PKEY_GET_BN(_type, _name) do {                                 
                \
+               if (pkey->pkey._type->_name != NULL) {                          
                        \
+                       int len = BN_num_bytes(pkey->pkey._type->_name);        
                \
+                       char *str = emalloc(len + 1);                           
                                \
+                       BN_bn2bin(pkey->pkey._type->_name, (unsigned 
char*)str);        \
+                       str[len] = 0;                                           
        \
+                       add_assoc_stringl(_type, #_name, str, len, 0);          
                \
+               }                                                               
                                                                \
+       } while (0)
+
+#define OPENSSL_PKEY_SET_BN(_ht, _type, _name) do {                            
                \
+               zval **bn;                                                      
                                                        \
+               if (zend_hash_find(_ht, #_name, sizeof(#_name), (void**)&bn) == 
SUCCESS && \
+                               Z_TYPE_PP(bn) == IS_STRING) {                   
                                \
+                       _type->_name = BN_bin2bn(                               
                                        \
+                               (unsigned char*)Z_STRVAL_PP(bn),                
                                \
+                               Z_STRLEN_PP(bn), NULL);                         
                                        \
+           }                                                               \
+       } while (0);
+
+
 /* {{{ proto resource openssl_pkey_new([array configargs])
    Generates a new private key */
 PHP_FUNCTION(openssl_pkey_new)
 {
        struct php_x509_request req;
        zval * args = NULL;
+       zval **data;
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!", &args) == 
FAILURE) {
                return;
        }
        RETVAL_FALSE;
-       
+
+       if (args && Z_TYPE_P(args) == IS_ARRAY) {
+               EVP_PKEY *pkey;
+
+               if (zend_hash_find(Z_ARRVAL_P(args), "rsa", sizeof("rsa"), 
(void**)&data) == SUCCESS &&
+                   Z_TYPE_PP(data) == IS_ARRAY) {
+                   pkey = EVP_PKEY_new();
+                   if (pkey) {
+                               RSA *rsa = RSA_new();
+                               if (rsa) {
+                                       OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), 
rsa, n);
+                                       OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), 
rsa, e);
+                                       OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), 
rsa, d);
+                                       OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), 
rsa, p);
+                                       OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), 
rsa, q);
+                                       OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), 
rsa, dmp1);
+                                       OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), 
rsa, dmq1);
+                                       OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), 
rsa, iqmp);
+                                       if (EVP_PKEY_assign_RSA(pkey, rsa)) {
+                                               
RETURN_RESOURCE(zend_list_insert(pkey, le_key));
+                                       }
+                                       RSA_free(rsa);
+                               }
+                               EVP_PKEY_free(pkey);
+                       }
+                       RETURN_FALSE;
+               } else if (zend_hash_find(Z_ARRVAL_P(args), "dsa", 
sizeof("dsa"), (void**)&data) == SUCCESS &&
+                          Z_TYPE_PP(data) == IS_ARRAY) {
+                   pkey = EVP_PKEY_new();
+                   if (pkey) {
+                               DSA *dsa = DSA_new();
+                               if (dsa) {
+                                       OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), 
dsa, p);
+                                       OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), 
dsa, q);
+                                       OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), 
dsa, g);
+                                       OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), 
dsa, priv_key);
+                                       OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), 
dsa, pub_key);
+                                       if (!dsa->priv_key && !dsa->pub_key) {
+                                               DSA_generate_key(dsa);
+                                       }
+                                       if (EVP_PKEY_assign_DSA(pkey, dsa)) {
+                                               
RETURN_RESOURCE(zend_list_insert(pkey, le_key));
+                                       }
+                                       DSA_free(dsa);
+                               }
+                               EVP_PKEY_free(pkey);
+                       }
+                       RETURN_FALSE;
+               } else if (zend_hash_find(Z_ARRVAL_P(args), "dh", sizeof("dh"), 
(void**)&data) == SUCCESS &&
+                          Z_TYPE_PP(data) == IS_ARRAY) {
+                   pkey = EVP_PKEY_new();
+                   if (pkey) {
+                               DH *dh = DH_new();
+                               if (dh) {
+                                       OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), 
dh, p);
+                                       OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), 
dh, g);
+                                       OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), 
dh, priv_key);
+                                       OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), 
dh, pub_key);
+                                       if (!dh->pub_key) {
+                                               DH_generate_key(dh);
+                                       }
+                                       if (EVP_PKEY_assign_DH(pkey, dh)) {
+                                               
RETURN_RESOURCE(zend_list_insert(pkey, le_key));
+                                       }
+                                       DH_free(dh);
+                               }
+                               EVP_PKEY_free(pkey);
+                       }
+                       RETURN_FALSE;
+               }
+       } 
+
        PHP_SSL_REQ_INIT(&req);
 
        if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS)
@@ -2726,15 +2885,59 @@
                case EVP_PKEY_RSA:
                case EVP_PKEY_RSA2:
                        ktype = OPENSSL_KEYTYPE_RSA;
+
+                       if (pkey->pkey.rsa != NULL) {
+                               zval *rsa;
+
+                               ALLOC_INIT_ZVAL(rsa);
+                               array_init(rsa);
+                               OPENSSL_PKEY_GET_BN(rsa, n);
+                               OPENSSL_PKEY_GET_BN(rsa, e);
+                               OPENSSL_PKEY_GET_BN(rsa, d);
+                               OPENSSL_PKEY_GET_BN(rsa, p);
+                               OPENSSL_PKEY_GET_BN(rsa, q);
+                               OPENSSL_PKEY_GET_BN(rsa, dmp1);
+                               OPENSSL_PKEY_GET_BN(rsa, dmq1);
+                               OPENSSL_PKEY_GET_BN(rsa, iqmp);
+                               add_assoc_zval(return_value, "rsa", rsa);
+                       }
+
                        break;  
                case EVP_PKEY_DSA:
                case EVP_PKEY_DSA2:
                case EVP_PKEY_DSA3:
                case EVP_PKEY_DSA4:
                        ktype = OPENSSL_KEYTYPE_DSA;
+
+                       if (pkey->pkey.dsa != NULL) {
+                               zval *dsa;
+
+                               ALLOC_INIT_ZVAL(dsa);
+                               array_init(dsa);
+                               OPENSSL_PKEY_GET_BN(dsa, p);
+                               OPENSSL_PKEY_GET_BN(dsa, q);
+                               OPENSSL_PKEY_GET_BN(dsa, g);
+                               OPENSSL_PKEY_GET_BN(dsa, priv_key);
+                               OPENSSL_PKEY_GET_BN(dsa, pub_key);
+                               add_assoc_zval(return_value, "dsa", dsa);
+                       }
                        break;
                case EVP_PKEY_DH:
+                       
                        ktype = OPENSSL_KEYTYPE_DH;
+
+                       if (pkey->pkey.dh != NULL) {
+                               zval *dh;
+
+                               ALLOC_INIT_ZVAL(dh);
+                               array_init(dh);
+                               OPENSSL_PKEY_GET_BN(dh, p);
+                               OPENSSL_PKEY_GET_BN(dh, g);
+                               OPENSSL_PKEY_GET_BN(dh, priv_key);
+                               OPENSSL_PKEY_GET_BN(dh, pub_key);
+                               add_assoc_zval(return_value, "dh", dh);
+                       }
+
                        break;
 #ifdef EVP_PKEY_EC 
                case EVP_PKEY_EC:
@@ -2951,32 +3154,7 @@
        }
 
        /* sanity check the cipher */
-       switch (cipherid) {
-#ifndef OPENSSL_NO_RC2
-               case PHP_OPENSSL_CIPHER_RC2_40:
-                       cipher = EVP_rc2_40_cbc();
-                       break;
-               case PHP_OPENSSL_CIPHER_RC2_64:
-                       cipher = EVP_rc2_64_cbc();
-                       break;
-               case PHP_OPENSSL_CIPHER_RC2_128:
-                       cipher = EVP_rc2_cbc();
-                       break;
-#endif
-
-#ifndef OPENSSL_NO_DES
-               case PHP_OPENSSL_CIPHER_DES:
-                       cipher = EVP_des_cbc();
-                       break;
-               case PHP_OPENSSL_CIPHER_3DES:
-                       cipher = EVP_des_ede3_cbc();
-                       break;
-#endif
-
-               default:
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid 
cipher type `%ld'", cipherid);
-                       goto clean_exit;
-       }
+       cipher = php_openssl_get_evp_cipher_from_algo(cipherid);
        if (cipher == NULL) {
                /* shouldn't happen */
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to get 
cipher");
@@ -3475,7 +3653,7 @@
 }
 /* }}} */
 
-/* {{{ proto bool openssl_sign(string data, &string signature, mixed key[, int 
signature_alg])
+/* {{{ proto bool openssl_sign(string data, &string signature, mixed key[, 
mixed method])
    Signs data */
 PHP_FUNCTION(openssl_sign)
 {
@@ -3487,10 +3665,11 @@
        char * data;
        int data_len;
        EVP_MD_CTX md_ctx;
+       zval *method = NULL;
        long signature_algo = OPENSSL_ALGO_SHA1;
-       EVP_MD *mdtype;
+       const EVP_MD *mdtype;
 
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|l", &data, 
&data_len, &signature, &key, &signature_algo) == FAILURE) {
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|z", &data, 
&data_len, &signature, &key, &method) == FAILURE) {
                return;
        }
        pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource TSRMLS_CC);
@@ -3499,7 +3678,17 @@
                RETURN_FALSE;
        }
 
-       mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
+       if (method == NULL || Z_TYPE_P(method) == IS_LONG) {
+               if (Z_TYPE_P(method) == IS_LONG) {
+                       signature_algo = Z_LVAL_P(method);
+               }
+               mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
+       } else if (Z_TYPE_P(method) == IS_STRING) {
+               mdtype = EVP_get_digestbyname(Z_STRVAL_P(method));
+       } else {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature 
algorithm.");
+               RETURN_FALSE;
+       }
        if (!mdtype) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature 
algorithm.");
                RETURN_FALSE;
@@ -3525,7 +3714,7 @@
 }
 /* }}} */
 
-/* {{{ proto int openssl_verify(string data, string signature, mixed key)
+/* {{{ proto int openssl_verify(string data, string signature, mixed key[, 
mixed method])
    Verifys data */
 PHP_FUNCTION(openssl_verify)
 {
@@ -3533,17 +3722,28 @@
        EVP_PKEY *pkey;
        int err;
        EVP_MD_CTX     md_ctx;
-       EVP_MD *mdtype;
+       const EVP_MD *mdtype;
        long keyresource = -1;
        char * data;    int data_len;
        char * signature;       int signature_len;
+       zval *method = NULL;
        long signature_algo = OPENSSL_ALGO_SHA1;
        
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssZ|l", &data, 
&data_len, &signature, &signature_len, &key, &signature_algo) == FAILURE) {
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssZ|z", &data, 
&data_len, &signature, &signature_len, &key, &method) == FAILURE) {
                return;
        }
 
-       mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
+       if (method == NULL || Z_TYPE_P(method) == IS_LONG) {
+               if (Z_TYPE_P(method) == IS_LONG) {
+                       signature_algo = Z_LVAL_P(method);
+               }
+               mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
+       } else if (Z_TYPE_P(method) == IS_STRING) {
+               mdtype = EVP_get_digestbyname(Z_STRVAL_P(method));
+       } else {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature 
algorithm.");
+               RETURN_FALSE;
+       }
        if (!mdtype) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature 
algorithm.");
                RETURN_FALSE;
@@ -3578,9 +3778,12 @@
        int i, len1, len2, *eksl, nkeys;
        unsigned char *buf = NULL, **eks;
        char * data; int data_len;
+       char *method =NULL;
+       int method_len;
+       const EVP_CIPHER *cipher;
        EVP_CIPHER_CTX ctx;
 
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szza/", &data, 
&data_len, &sealdata, &ekeys, &pubkeys) == FAILURE) {
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szza/|s", &data, 
&data_len, &sealdata, &ekeys, &pubkeys, &method, &method_len) == FAILURE) {
                return;
        }
        
@@ -3591,6 +3794,16 @@
                RETURN_FALSE;
        }
 
+       if (method) {
+               cipher = EVP_get_cipherbyname(method);
+               if (!cipher) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown 
signature algorithm.");
+                       RETURN_FALSE;
+               }
+       } else {
+               cipher = EVP_rc4();
+       }
+
        pkeys = safe_emalloc(nkeys, sizeof(*pkeys), 0);
        eksl = safe_emalloc(nkeys, sizeof(*eksl), 0);
        eks = safe_emalloc(nkeys, sizeof(*eks), 0);
@@ -3614,7 +3827,7 @@
                i++;
        }
 
-       if (!EVP_EncryptInit(&ctx,EVP_rc4(),NULL,NULL)) {
+       if (!EVP_EncryptInit(&ctx,cipher,NULL,NULL)) {
                RETVAL_FALSE;
                goto clean_exit;
        }
@@ -3627,7 +3840,7 @@
        /* allocate one byte extra to make room for \0 */
        buf = emalloc(data_len + EVP_CIPHER_CTX_block_size(&ctx));
 
-       if (!EVP_SealInit(&ctx, EVP_rc4(), eks, eksl, NULL, pkeys, nkeys) || 
!EVP_SealUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len)) {
+       if (!EVP_SealInit(&ctx, cipher, eks, eksl, NULL, pkeys, nkeys) || 
!EVP_SealUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len)) {
                RETVAL_FALSE;
                efree(buf);
                goto clean_exit;
@@ -3691,8 +3904,11 @@
        EVP_CIPHER_CTX ctx;
        char * data;    int data_len;
        char * ekey;    int ekey_len;
+       char *method =NULL;
+       int method_len;
+       const EVP_CIPHER *cipher;
 
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szsZ", &data, 
&data_len, &opendata, &ekey, &ekey_len, &privkey) == FAILURE) {
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szsZ|s", &data, 
&data_len, &opendata, &ekey, &ekey_len, &privkey, &method, &method_len) == 
FAILURE) {
                return;
        }
 
@@ -3701,9 +3917,20 @@
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to coerce 
parameter 4 into a private key");
                RETURN_FALSE;
        }
+
+       if (method) {
+               cipher = EVP_get_cipherbyname(method);
+               if (!cipher) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown 
signature algorithm.");
+                       RETURN_FALSE;
+               }
+       } else {
+               cipher = EVP_rc4();
+       }
+       
        buf = emalloc(data_len + 1);
 
-       if (EVP_OpenInit(&ctx, EVP_rc4(), (unsigned char *)ekey, ekey_len, 
NULL, pkey) && EVP_OpenUpdate(&ctx, buf, &len1, (unsigned char *)data, 
data_len)) {
+       if (EVP_OpenInit(&ctx, cipher, (unsigned char *)ekey, ekey_len, NULL, 
pkey) && EVP_OpenUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len)) {
                if (!EVP_OpenFinal(&ctx, buf + len1, &len2) || (len1 + len2 == 
0)) {
                        efree(buf);
                        if (keyresource == -1) { 
@@ -3953,6 +4180,266 @@
 }
 /* }}} */
 
+static void openssl_add_method_or_alias(const OBJ_NAME *name, void *arg) /* 
{{{ */
+{
+       add_next_index_string((zval*)arg, (char*)name->name, 1);
+}
+/* }}} */
+
+static void openssl_add_method(const OBJ_NAME *name, void *arg) /* {{{ */
+{
+       if (name->alias == 0) {
+               add_next_index_string((zval*)arg, (char*)name->name, 1);
+       }
+}
+/* }}} */
+
+/* {{{ proto array openssl_get_md_methods([bool aliases = false])
+   Return array of available digest methods */
+PHP_FUNCTION(openssl_get_md_methods)
+{
+       zend_bool aliases = 0;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &aliases) == 
FAILURE) {
+               return;
+       }
+       array_init(return_value);
+       OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH,
+               aliases ? openssl_add_method_or_alias: openssl_add_method, 
+               return_value);
+}
+/* }}} */
+
+/* {{{ proto array openssl_get_cipher_methods([bool aliases = false])
+   Return array of available cipher methods */
+PHP_FUNCTION(openssl_get_cipher_methods)
+{
+       zend_bool aliases = 0;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &aliases) == 
FAILURE) {
+               return;
+       }
+       array_init(return_value);
+       OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH,
+               aliases ? openssl_add_method_or_alias: openssl_add_method, 
+               return_value);
+}
+/* }}} */
+
+/* {{{ proto string openssl_digest(string data, string method [, bool 
raw_output=false])
+   Computes digest hash value for given data using given method, returns raw 
or binhex encoded string */
+PHP_FUNCTION(openssl_digest)
+{
+       zend_bool raw_output = 0;
+       char *data, *method;
+       int data_len, method_len;
+       const EVP_MD *mdtype;
+       EVP_MD_CTX md_ctx;
+       int siglen;
+       unsigned char *sigbuf;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|b", &data, 
&data_len, &method, &method_len, &raw_output) == FAILURE) {
+               return;
+       }
+       mdtype = EVP_get_digestbyname(method);
+       if (!mdtype) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature 
algorithm");
+               RETURN_FALSE;
+       }
+
+       siglen = EVP_MD_size(mdtype);
+       sigbuf = emalloc(siglen + 1);
+
+       EVP_DigestInit(&md_ctx, mdtype);
+       EVP_DigestUpdate(&md_ctx, (unsigned char *)data, data_len);
+       if (EVP_DigestFinal (&md_ctx, (unsigned char *)sigbuf, (unsigned int 
*)&siglen)) {
+               if (raw_output) {
+                       sigbuf[siglen] = '\0';
+                       RETVAL_STRINGL((char *)sigbuf, siglen, 0);
+               } else {
+                       int digest_str_len = siglen * 2;
+                       char *digest_str = emalloc(digest_str_len + 1);
+
+                       make_digest_ex(digest_str, sigbuf, siglen);
+                       efree(sigbuf);
+                       RETVAL_STRINGL(digest_str, digest_str_len, 0);
+               }
+       } else {
+               efree(sigbuf);
+               RETVAL_FALSE;
+       }
+}
+/* }}} */
+
+/* {{{ proto string openssl_encrypt(string data, string method, string 
password [, bool raw_output=false])
+   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;
+       const EVP_CIPHER *cipher_type;
+       EVP_CIPHER_CTX cipher_ctx;
+       int i, outlen, keylen, ivlen;
+       unsigned char *outbuf, *key, *iv;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|b", &data, 
&data_len, &method, &method_len, &password, &password_len, &raw_output) == 
FAILURE) {
+               return;
+       }
+       cipher_type = EVP_get_cipherbyname(method);
+       if (!cipher_type) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher 
algorithm");
+               RETURN_FALSE;
+       }
+
+       keylen = EVP_CIPHER_key_length(cipher_type);
+       if (keylen > password_len) {
+               key = emalloc(keylen);
+               memset(key, 0, keylen);
+               memcpy(key, password, password_len);
+       } else {
+               key = (unsigned char*)password;
+       }
+
+       ivlen = EVP_CIPHER_iv_length(cipher_type);
+       iv = emalloc(ivlen);
+       memset(iv, 0, ivlen);
+
+       outlen = data_len + EVP_CIPHER_block_size(cipher_type);
+       outbuf = emalloc(outlen + 1);
+
+       EVP_EncryptInit(&cipher_ctx, cipher_type, key, iv);
+       EVP_EncryptUpdate(&cipher_ctx, outbuf, &i, (unsigned char *)data, 
data_len);
+       outlen = i;
+       if (EVP_EncryptFinal(&cipher_ctx, (unsigned char *)outbuf + i, &i)) {
+               outlen += i;
+               if (raw_output) {
+                       outbuf[outlen] = '\0';
+                       RETVAL_STRINGL((char *)outbuf, outlen, 0);
+               } else {
+                       int base64_str_len;
+                       char *base64_str;
+
+                       base64_str = (char*)php_base64_encode(outbuf, outlen, 
&base64_str_len);
+                       efree(outbuf);
+                       RETVAL_STRINGL(base64_str, base64_str_len, 0);
+               }
+       } else {
+               efree(outbuf);
+               RETVAL_FALSE;
+       }
+       if (key != (unsigned char*)password) {
+               efree(key);
+       }
+       efree(iv);
+}
+/* }}} */
+
+/* {{{ proto string openssl_decrypt(string data, string method, string 
password [, bool raw_input=false])
+   Takes raw or base64 encoded string and dectupt it using given method and 
key */
+PHP_FUNCTION(openssl_decrypt)
+{
+       zend_bool raw_input = 0;
+       char *data, *method, *password;
+       int data_len, method_len, password_len;
+       const EVP_CIPHER *cipher_type;
+       EVP_CIPHER_CTX cipher_ctx;
+       int i, outlen, keylen, ivlen;
+       unsigned char *outbuf, *key, *iv;
+       int base64_str_len;
+       char *base64_str = NULL;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|b", &data, 
&data_len, &method, &method_len, &password, &password_len, &raw_input) == 
FAILURE) {
+               return;
+       }
+
+       if (!raw_input) {
+               base64_str = (char*)php_base64_decode((unsigned char*)data, 
data_len, &base64_str_len);
+               data_len = base64_str_len;
+               data = base64_str;
+       }
+
+       cipher_type = EVP_get_cipherbyname(method);
+       if (!cipher_type) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher 
algorithm");
+               RETURN_FALSE;
+       }
+
+       keylen = EVP_CIPHER_key_length(cipher_type);
+       if (keylen > password_len) {
+               key = emalloc(keylen);
+               memset(key, 0, keylen);
+               memcpy(key, password, password_len);
+       } else {
+               key = (unsigned char*)password;
+       }
+
+       ivlen = EVP_CIPHER_iv_length(cipher_type);
+       iv = emalloc(ivlen);
+       memset(iv, 0, ivlen);
+
+       outlen = data_len + EVP_CIPHER_block_size(cipher_type);
+       outbuf = emalloc(outlen + 1);
+
+       EVP_DecryptInit(&cipher_ctx, cipher_type, key, iv);
+       EVP_DecryptUpdate(&cipher_ctx, outbuf, &i, (unsigned char *)data, 
data_len);
+       outlen = i;
+       if (EVP_DecryptFinal(&cipher_ctx, (unsigned char *)outbuf + i, &i)) {
+               outlen += i;
+               outbuf[outlen] = '\0';
+               RETVAL_STRINGL((char *)outbuf, outlen, 0);
+       } else {
+               efree(outbuf);
+               RETVAL_FALSE;
+       }
+       if (key != (unsigned char*)password) {
+               efree(key);
+       }
+       efree(iv);
+       if (base64_str) {
+               efree(base64_str);
+       }
+}
+/* }}} */
+
+
+/* {{{ proto string openssl_dh_compute_key(string pub_key, resource dh_key)
+   Computes shared sicret for public value of remote DH key and local DH key */
+PHP_FUNCTION(openssl_dh_compute_key)
+{
+       zval *key;
+       char *pub_str;
+       int pub_len;
+       EVP_PKEY *pkey;
+       BIGNUM *pub;
+       char *data;
+       int len;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sr", &pub_str, 
&pub_len, &key) == FAILURE) {
+               return;
+       }
+       ZEND_FETCH_RESOURCE(pkey, EVP_PKEY *, &key, -1, "OpenSSL key", le_key);
+       if (!pkey || EVP_PKEY_type(pkey->type) != EVP_PKEY_DH || 
!pkey->pkey.dh) {
+               RETURN_FALSE;
+       }
+
+       pub = BN_bin2bn((unsigned char*)pub_str, pub_len, NULL);
+
+       data = emalloc(DH_size(pkey->pkey.dh) + 1);
+       len = DH_compute_key((unsigned char*)data, pub, pkey->pkey.dh);
+
+       if (len >= 0) {
+               data[len] = 0;
+               RETVAL_STRINGL(data, len, 0);
+       } else {
+               efree(data);
+               RETVAL_FALSE;
+       }
+
+       BN_free(pub);
+}
+/* }}} */
+
 /*
  * Local variables:
  * tab-width: 8

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to