Hi, I propose a patch for ext/openssl that extends support for crypto API. - it provides access to openSSL digest functions function openssl_get_md_methods(); function openssl_digest(string $data, string $method [, bool $raw]); - it provides access to openSSL digest functions function openssl_get_cipher_methods(); function openssl_encrypt(string $data, string $method, $string $password [, bool $raw]); function openssl_decrypt(string $data, string $method, $string $password [, bool $raw]); - It extends existing functions openssl_pkey_new() and openssl_pkey_get_details() to access internal values of DSA, RSA and DH keys. For example you can create DH key and then access its internal values using the following code: <?php $dh = openssl_pkey_new(array('dh' => array( 'p' => pack('H*', 'dcf93a0b883972ec'), 'g' => pack(H*', '02'))); $details = openssl_pkey_get_details($dh); var_dump(base64_encode($deteils['dh']['p'])); var_dump(base64_encode($deteils['dh']['g'])); var_dump(base64_encode($deteils['dh']['priv_key'])); var_dump(base64_encode($deteils['dh']['pub_key'])); ?> - it provides new function that computes shared secret for two DH keys function openssl_dh_compute_key(string $pub_key, resource $dh) - it also extend some functions to support string name of crypto algorith in addition to numeric constants.
This patch was written to implement OpenID protocol in PHP. It is similar to patch by Wez http://netevil.org/blog/2007/feb/openid-and-typekey-using-native-openssl-fun ctions-in-php but it provides less additional functions and works with big numbers as with strings (instead of resources). I would like to commit the path to PHP_5_2 and HEAD. Any objections? Thanks. Dmitry.
Index: ext/openssl/openssl.c =================================================================== RCS file: /repository/php-src/ext/openssl/openssl.c,v retrieving revision 1.98.2.5.2.38 diff -u -p -d -r1.98.2.5.2.38 openssl.c --- ext/openssl/openssl.c 11 Jul 2007 12:18:14 -0000 1.98.2.5.2.38 +++ ext/openssl/openssl.c 1 Aug 2007 07:20:18 -0000 @@ -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 @@ enum php_openssl_cipher_type { 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 @@ zend_function_entry openssl_functions[] 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 @@ zend_function_entry openssl_functions[] 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 @@ static EVP_MD * php_openssl_get_evp_md_f 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 @@ -2431,6 +2478,25 @@ static EVP_PKEY * php_openssl_generate_p } 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"); } @@ -2495,18 +2561,111 @@ static int php_openssl_is_private_key(EV } /* }}} */ +#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->priv_key && !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) @@ -2724,15 +2883,59 @@ PHP_FUNCTION(openssl_pkey_get_details) 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: @@ -2949,32 +3152,7 @@ PHP_FUNCTION(openssl_pkcs7_encrypt) } /* 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"); @@ -3473,7 +3651,7 @@ PHP_FUNCTION(openssl_error_string) } /* }}} */ -/* {{{ 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) { @@ -3485,10 +3663,11 @@ PHP_FUNCTION(openssl_sign) 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); @@ -3497,7 +3676,17 @@ PHP_FUNCTION(openssl_sign) 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; @@ -3523,7 +3712,7 @@ PHP_FUNCTION(openssl_sign) } /* }}} */ -/* {{{ 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) { @@ -3531,17 +3720,28 @@ PHP_FUNCTION(openssl_verify) 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; @@ -3576,9 +3776,12 @@ PHP_FUNCTION(openssl_seal) 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; } @@ -3589,6 +3792,16 @@ PHP_FUNCTION(openssl_seal) 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); @@ -3612,7 +3825,7 @@ PHP_FUNCTION(openssl_seal) i++; } - if (!EVP_EncryptInit(&ctx,EVP_rc4(),NULL,NULL)) { + if (!EVP_EncryptInit(&ctx,cipher,NULL,NULL)) { RETVAL_FALSE; goto clean_exit; } @@ -3625,7 +3838,7 @@ PHP_FUNCTION(openssl_seal) /* 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; @@ -3689,8 +3902,11 @@ PHP_FUNCTION(openssl_open) 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; } @@ -3699,9 +3915,20 @@ PHP_FUNCTION(openssl_open) 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) { @@ -3951,6 +4178,250 @@ SSL *php_SSL_new_from_context(SSL_CTX *c } /* }}} */ +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); + } +} + +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); +} + +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); +} + +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 array openssl_encryp(string data, string method, string password [, bool raw_output=false]) + Returns an array of the fields/values of the CERT */ +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 signature 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); +} +/* }}} */ + +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 signature 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); + } +} +/* }}} */ + + +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 Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php