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