sign a file with openssl in php and verify in c++ - php

I wrote a webservice that server is written in php and client is written in c++, and I used openssl package for generating rsa pair key to secure data transferming.
At the first I wrote both client an server in php for preparing services and every things goes OK. but when I started transfer client php code into c++ I face into problems with openssl methods.
The big problem is that the signed data does not match in both php and c++ codes.
I get md5 of data and use openssl_sign method for signing md5 data and then append the sign at the end of plain data and send to client (In the past public key have been sent for client). in the client I did this progress again. but the sign dos not verify correctly.
What is wrong in may program?
please help, thanks.
php side (webservice) code:
function sign($cleartext)
$msg_hash = md5($cleartext);
$sig = "";
$ok = openssl_sign($msg_hash, $sig, $this->private_key);
if ($ok == 1)
{
$signed_data = $cleartext . "----SIGNATURE:----" . base64_encode($sig);
//$signed_data = $this->encryptAES($signed_data, $this->password);
return base64_encode(mysql_real_escape_string($signed_data));
}
elseif ($ok == 0)
{
$eroor = "bad";
return base64_encode($eroor);
}
else
{
$eroor = "ugly, error checking signature";
return base64_encode($eroor);
}
}
and C++ side (client) Code:
int Crypto::rsaVerify(string msgStr, const char *pk) {
int length;
char *pkStr = new char[this->publicKey.length() + 1];
strcpy_s(pkStr, this->publicKey.length()+1,this->publicKey.c_str());
this->setPubKey((unsigned char *)pkStr,strlen(pkStr));
// Find and Splite Data
size_t current = 0;
string delimiters = "----SIGNATURE:----";
size_t next = msgStr.find( delimiters, current );
string dataStr = msgStr.substr( current, next - current );
char *msg = new char[dataStr.length() + 1];
strcpy_s(msg, dataStr.length()+1,dataStr.c_str());
// Find and Split sign
string signData = msgStr.substr(next + delimiters.length(), msgStr.length());
Coding *codingObj = new Coding();
signData = codingObj->base64_decode(signData);
char *signBuf = new char[signData.length() + 1];
strcpy_s(signBuf, signData.length()+1, signData.c_str());
unsigned char *dataMD5 = new unsigned char [MD5_DIGEST_LENGTH];
MD5((const unsigned char *)msg,strlen(msg),dataMD5);
char md5String[MD5_DIGEST_LENGTH + 1];
AsciiString2HexString(dataMD5,(unsigned char *)md5String, MD5_DIGEST_LENGTH);
md5String[MD5_DIGEST_LENGTH] = '\0';
char md5String1[MD5_DIGEST_LENGTH + 1];
AsciiString2HexString((unsigned char *)md5String1,(unsigned char *)md5String1, MD5_DIGEST_LENGTH);
md5String1[MD5_DIGEST_LENGTH] = '\0';
unsigned char * key2;
getPubKey(&key2);
unsigned int signLen = 256;//strlen(md5String);
char errorBuffer[120];
unsigned char message_digest[SHA_DIGEST_LENGTH];
SHA1((const unsigned char *)md5String1, strlen(md5String1), message_digest);
if(RSA_verify(NID_sha1,(const unsigned char *)message_digest, SHA_DIGEST_LENGTH,(const unsigned char *)signBuf,signLen,this->keyPair))
{
return 1;
}
else
{
ERR_error_string(ERR_get_error(), errorBuffer);
}
if(RSA_verify(NID_sha1,(const unsigned char *)md5String1, strlen(md5String1),(const unsigned char *)signBuf,signLen,this->keyPair))
{
return 1;
}
else
{
ERR_error_string(ERR_get_error(), errorBuffer);
}
if(RSA_verify(NID_sha1,(const unsigned char *)md5String, strlen(md5String),(const unsigned char *)signBuf,signLen,this->keyPair))
{
return 1;
}
else
{
ERR_error_string(ERR_get_error(), errorBuffer);
}
if(RSA_verify(NID_sha1,(const unsigned char *)dataMD5, strlen((char *)dataMD5),(const unsigned char *)signBuf,signLen,this->keyPair))
{
return 1;
}
else
{
ERR_error_string(ERR_get_error(), errorBuffer);
}
return 0;
}
int Crypto::getPriKey(unsigned char **priKey) {
BIO *bio = BIO_new(BIO_s_mem());
PEM_write_bio_RSAPrivateKey(bio, this->keyPair, NULL, NULL, NULL, NULL, NULL);
int priKeyLen = BIO_pending(bio);
*priKey = (unsigned char*)malloc(priKeyLen);
if(priKey == NULL) return FAILURE;
BIO_read(bio, *priKey, priKeyLen);
// Insert the NUL terminator
(*priKey)[priKeyLen-1] = '\0';
BIO_free_all(bio);
return priKeyLen;
}

Maybe because openssl_sign need data as first argument and not the hash of data. By default, the hash is caclulated by this function with OPENSSL_ALGO_SHA1.
And, if you can, prefere SHA2, 256bits and more. MD5 and SHA1 are not recommended for new projects...

Related

Check if the table "keysystem" value that was inserted has been used or no

I'm making a auth for my program and here is the code I used for a simple login:
$query = $con->query("SELECT * FROM keysystem WHERE keysystem = '$keysystem'");
$cnt2 = $query->num_rows;
if($cnt2 > 0)
{
echo "GOOD";
}
else
{
echo "BAD";
}
for C++ I use this:
string DownloadString(string URL) {
HINTERNET interwebs = InternetOpenA("Mozilla/5.0", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, NULL);
HINTERNET urlFile;
string rtn;
if (interwebs) {
urlFile = InternetOpenUrlA(interwebs, URL.c_str(), NULL, NULL, NULL, NULL);
if (urlFile) {
char buffer[2000];
DWORD bytesRead;
do {
InternetReadFile(urlFile, buffer, 2000, &bytesRead);
rtn.append(buffer, bytesRead);
memset(buffer, 0, 2000);
} while (bytesRead);
InternetCloseHandle(interwebs);
InternetCloseHandle(urlFile);
string p = replaceAll(rtn, "|n", "\r\n");
return p;
}
}
InternetCloseHandle(interwebs);
string p = replaceAll(rtn, "|n", "\r\n");
return p;
}
string login = DownloadString("http://website.com/handler.php?action=login&keysystem=" + license).c_str();
if (login.find("890") != std::string::npos)
{
char buffer[256];
print::set_text("\n Successfully logged in!\n\n", Green);
printf("\n\n");
Beep(666, 200);
Sleep(2000);
}
else if (login.find("880") != std::string::npos)
{
print::set_text("\n Failed to log in! ", Red);
Beep(666, 200);
Sleep(2000);
exit(0);
}
It works fine but I want to check if the key is already used by someone or not.
To understand if your key is used you can add a field, which stores if key is used of not, e.g. is_used with true \ false values.
Then your query becomes:
SELECT * FROM keysystem WHERE keysystem = '$keysystem' and is_used = false
Of course, don't forget to set field is_used to true when someone starts to use it.

Porting a php5 module to php 7 and zend_string issues when compiling

I'm porting a php5 tot php7, but don't understand how to correctly use zend_string since it gives me errors when compiling. I followed the phpng guide on the changes in php7. Most functions i could port easily, but this function is giving me a headache.
The php5 version of the module looks like this:
PHP_FUNCTION(swe_houses)
{
char *arg = NULL;
int hsys_len, rc;
char *hsys = NULL;
double tjd_ut, geolat, geolon;
double cusps[37], ascmc[10];
int i, houses;
zval *cusps_arr, *ascmc_arr;
if(ZEND_NUM_ARGS() != 4) WRONG_PARAM_COUNT;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ddds",
&tjd_ut, &geolat, &geolon, &hsys, &hsys_len) == FAILURE) {
return;
}
if (hsys_len < 1)
return;
rc = swe_houses(tjd_ut, geolat, geolon, hsys[0], cusps, ascmc);
/* create 2 index array, and 1 assoc array */
array_init(return_value);
MAKE_STD_ZVAL(cusps_arr);
array_init(cusps_arr);
if (hsys[0] == 'G')
houses = 37;
else
houses = 13;
for(i = 0; i < houses; i++)
add_index_double(cusps_arr, i, cusps[i]);
MAKE_STD_ZVAL(ascmc_arr);
array_init(ascmc_arr);
for(i = 0; i < 10; i++)
add_index_double(ascmc_arr, i, ascmc[i]);
add_assoc_zval(return_value, "cusps", cusps_arr);
add_assoc_zval(return_value, "ascmc", ascmc_arr);
add_assoc_long(return_value, "rc", rc);
}
So the guide says i need to replace "char *hsys" into "zend_string *hsys = null". And replaced "MAKE_STD_ZVAL" functions to "ZVAL_NEW_ARR". In the zend_parse_parameters function i changed the "s" parameter to "S".
So eventually i changed the code to look like this:
PHP_FUNCTION(swe_houses)
{
zend_string *arg = NULL;
size_t hsys_len, rc;
zend_string *hsys = NULL;
double tjd_ut, geolat, geolon;
double cusps[37], ascmc[10];
size_t i, houses;
zval *cusps_arr, *ascmc_arr;
if(ZEND_NUM_ARGS() != 4) WRONG_PARAM_COUNT;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dddS",
&tjd_ut, &geolat, &geolon, &hsys, &hsys_len) == FAILURE) {
return;
}
if (hsys_len < 1)
return;
rc = swe_houses(tjd_ut, geolat, geolon, hsys[0], cusps, ascmc);
/* create 2 index array, and 1 assoc array */
array_init(return_value);
/*******************************/
/* removed for php 7 */
/* MAKE_STD_ZVAL(cusps_arr); */
/*******************************/
ZVAL_NEW_ARR(cusps_arr);
array_init(cusps_arr);
if (hsys[0] == 'G')
houses = 37;
else
houses = 13;
for(i = 0; i < houses; i++)
add_index_double(cusps_arr, i, cusps[i]);
/*******************************/
/* removed for php 7 */
/* MAKE_STD_ZVAL(ascmc_arr); */
/*******************************/
ZVAL_NEW_ARR(ascmc_arr);
array_init(ascmc_arr);
for(i = 0; i < 10; i++)
add_index_double(ascmc_arr, i, ascmc[i]);
add_assoc_zval(return_value, "cusps", cusps_arr);
add_assoc_zval(return_value, "ascmc", ascmc_arr);
add_assoc_long(return_value, "rc", rc);
}
But on compilling it gives me the following errors:
/home/hermes/php-sweph/latest/php-sweph/sweph.c:926:42: error:
incompatible type for argument 4 of ‘swe_houses’
rc = swe_houses(tjd_ut, geolat, geolon, hsys[0], cusps, ascmc);
^
In file included from /home/hermes/php-sweph/latest/php-
sweph/sweph.c:23:0:
/usr/local/include/swephexp.h:742:16: note: expected ‘int’ but argument is
of type ‘zend_string {aka struct _zend_string}’
ext_def( int ) swe_houses(
^
/home/hermes/php-sweph/latest/php-sweph/sweph.c:939:14: error: invalid
operands to binary == (have ‘zend_string {aka struct _zend_string}’ and
‘int’)
if (hsys[0] == 'G')
First things first, zend_string is not at all like a char* or char[], therefore you cannot access elements simply by referencing an index. It's a struct not an array.
This is what zend_string is:
struct _zend_string {
zend_refcounted_h gc;
zend_ulong h; /* hash value */
size_t len;
char val[1];
};
What I would do is change hsys back to char* so you can use the regular string functions and reference the elements like an array.
Here is an example of what I think will work and I will comment what I changed about it.
PHP_FUNCTION(swe_houses) {
char *arg = NULL; /* char */
size_t hsys_len, rc;
char *hsys = NULL; /* char */
double tjd_ut, geolat, geolon;
double cusps[37], ascmc[10];
size_t i, houses;
zval cusps_arr, ascmc_arr; /* removed pointer */
if(ZEND_NUM_ARGS() != 4) WRONG_PARAM_COUNT;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ddds",
&tjd_ut, &geolat, &geolon, &hsys, &hsys_len) == FAILURE) {
return;
}
if (hsys_len < 1)
return;
rc = swe_houses(tjd_ut, geolat, geolon, hsys[0], cusps, ascmc);
/* create 2 index array, and 1 assoc array */
array_init(return_value);
/* ZVAL_NEW_ARR(cusps_arr); unneeded */
array_init(&cusps_arr); /* added & */
if (hsys[0] == 'G')
houses = 37;
else
houses = 13;
for(i = 0; i < houses; i++)
add_index_double(&cusps_arr, i, cusps[i]); /* added & */
/* ZVAL_NEW_ARR(ascmc_arr); unneeded */
array_init(&ascmc_arr); /* added & */
for(i = 0; i < 10; i++)
add_index_double(&ascmc_arr, i, ascmc[i]); /* added & */
/* this may cause issues, not sure though */
add_assoc_zval(return_value, "cusps", &cusps_arr); /* added & */
add_assoc_zval(return_value, "ascmc", &ascmc_arr); /* added & */
add_assoc_long(return_value, "rc", rc);
}

Does php file() require fclose() at the end?

Does PHP automatically close the file after a file(); function, or does it require fclose(); or similar?
Does PHP automatically close the file after a file(); function, or does it require fclose(); or similar?
No, file() doesn't require a fclose() call. You can see that in the source code of the function that it all ends nice and clean, so you don't have to call fclose() or do anything similar, you simple can call file().
Source code:
/* {{{ proto array file(string filename [, int flags[, resource context]])
Read entire file into an array */
PHP_FUNCTION(file)
{
char *filename;
size_t filename_len;
char *p, *s, *e;
register int i = 0;
char eol_marker = '\n';
zend_long flags = 0;
zend_bool use_include_path;
zend_bool include_new_line;
zend_bool skip_blank_lines;
php_stream *stream;
zval *zcontext = NULL;
php_stream_context *context = NULL;
zend_string *target_buf;
/* Parse arguments */
if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|lr!", &filename, &filename_len, &flags, &zcontext) == FAILURE) {
return;
}
if (flags < 0 || flags > (PHP_FILE_USE_INCLUDE_PATH | PHP_FILE_IGNORE_NEW_LINES | PHP_FILE_SKIP_EMPTY_LINES | PHP_FILE_NO_DEFAULT_CONTEXT)) {
php_error_docref(NULL, E_WARNING, "'" ZEND_LONG_FMT "' flag is not supported", flags);
RETURN_FALSE;
}
use_include_path = flags & PHP_FILE_USE_INCLUDE_PATH;
include_new_line = !(flags & PHP_FILE_IGNORE_NEW_LINES);
skip_blank_lines = flags & PHP_FILE_SKIP_EMPTY_LINES;
context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT);
stream = php_stream_open_wrapper_ex(filename, "rb", (use_include_path ? USE_PATH : 0) | REPORT_ERRORS, NULL, context);
if (!stream) {
RETURN_FALSE;
}
/* Initialize return array */
array_init(return_value);
if ((target_buf = php_stream_copy_to_mem(stream, PHP_STREAM_COPY_ALL, 0)) != NULL) {
s = target_buf->val;
e = target_buf->val + target_buf->len;
if (!(p = (char*)php_stream_locate_eol(stream, target_buf))) {
p = e;
goto parse_eol;
}
if (stream->flags & PHP_STREAM_FLAG_EOL_MAC) {
eol_marker = '\r';
}
/* for performance reasons the code is duplicated, so that the if (include_new_line)
* will not need to be done for every single line in the file. */
if (include_new_line) {
do {
p++;
parse_eol:
add_index_stringl(return_value, i++, s, p-s);
s = p;
} while ((p = memchr(p, eol_marker, (e-p))));
} else {
do {
int windows_eol = 0;
if (p != target_buf->val && eol_marker == '\n' && *(p - 1) == '\r') {
windows_eol++;
}
if (skip_blank_lines && !(p-s-windows_eol)) {
s = ++p;
continue;
}
add_index_stringl(return_value, i++, s, p-s-windows_eol);
s = ++p;
} while ((p = memchr(p, eol_marker, (e-p))));
}
/* handle any left overs of files without new lines */
if (s != e) {
p = e;
goto parse_eol;
}
}
if (target_buf) {
zend_string_free(target_buf);
}
php_stream_close(stream);
}
/* }}} */
See at the end 3rd line from the bottom it ends the function nice and clean:
php_stream_close(stream);

Parallel to PHP's "explode" in C: Split char* into char* using delimiter [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Split string with delimiters in C
I'm searching a good way to "explode" a char* into other char* using a delimiter.
My delimiter will be #
You can use strtok like CrazyCasta said but his/hers code is wrong.
char *tok;
char *src = malloc(strlen(srcStr) + 1);
memcpy(src, srcStr);
tok = strtok(src, "#");
if(tok == NULL)
{
printf("no tokens found");
free(src);
return ???;
}
printf("%s ; ", tok);
while((tok = strtok(NULL, "#")))
printf("%s ; ", tok);
printf("\n");
free(str);
Be aware that strtok has to be called the first time with the source pointer, after that you have to use NULL. Also src must be writeable because strtok writes \0 to terminate the found strings. Hence, depending on how you read the string (and whether you are going to use it afterwards or not), you should do a copy of it. But as I said, this is not always necessary.
EDIT:
an explode function could look like this:
char *strdup(const char *src)
{
char *tmp = malloc(strlen(src) + 1);
if(tmp)
strcpy(tmp, src);
return tmp;
}
void explode(const char *src, const char *tokens, char ***list, size_t *len)
{
if(src == NULL || list == NULL || len == NULL)
return;
char *str, *copy, **_list = NULL, **tmp;
*list = NULL;
*len = 0;
copy = strdup(src);
if(copy == NULL)
return;
str = strtok(copy, tokens);
if(str == NULL)
goto free_and_exit;
_list = realloc(NULL, sizeof *_list);
if(_list == NULL)
goto free_and_exit;
_list[*len] = strdup(str);
if(_list[*len] == NULL)
goto free_and_exit;
(*len)++;
while((str = strtok(NULL, tokens)))
{
tmp = realloc(_list, (sizeof *_list) * (*len + 1));
if(tmp == NULL)
goto free_and_exit;
_list = tmp;
_list[*len] = strdup(str);
if(_list[*len] == NULL)
goto free_and_exit;
(*len)++;
}
free_and_exit:
*list = _list;
free(copy);
}
then you have to call it:
char **list;
size_t i, len;
explode("this;is;a;string", ";", &list, &len);
for(i = 0; i < len; ++i)
printf("%d: %s\n", i+1, list[i]);
/* free list */
for(i = 0; i < len; ++i)
free(list[i]);
free(list);
this is an example running with valgrind:
valgrind ./a
==18675== Memcheck, a memory error detector
==18675== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==18675== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==18675== Command: ./a
==18675==
1: this
2: is
3: a
4: string
==18675==
==18675== HEAP SUMMARY:
==18675== in use at exit: 0 bytes in 0 blocks
==18675== total heap usage: 9 allocs, 9 frees, 114 bytes allocated
==18675==
==18675== All heap blocks were freed -- no leaks are possible
==18675==
==18675== For counts of detected and suppressed errors, rerun with: -v
==18675== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)
Generally this is what the strtok function is for:
char* tok;
tok = strtok(srcStr, "#");
while(tok != NULL)
{
// Do stuff with tok
tok = strtok(NULL, "#");
}

Make last array parameter optional in php class method (C)

I am creating a PHP extension in C to access the SPI interface. So far I have gotten pretty much everything working: php_spi on Github
However, I cannot seem to make the $options parameter in the constructor optional. My working code is like this:
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lla", &bus, &chipselect, &options) == FAILURE) {
return;
}
_this_zval = getThis();
_this_ce = Z_OBJCE_P(_this_zval);
options_hash = HASH_OF(options);
char device[32];
sprintf(device, "/dev/spidev%d.%d", bus, chipselect);
// If the device doesn't exists, error!
if(access(device, F_OK) == -1) {
char error[128];
sprintf(error, "The device %s does not exist", device);
php_error(E_ERROR, error);
}
// If we can't open it, error!
long fd = open(device, O_RDWR);
if (fd < 0) {
char error[128];
sprintf(error, "Could not open %s for read/write operations, are you running as root?", device);
php_error(E_ERROR, error);
}
// Set the file descriptor as a class property
zend_update_property_long(_this_ce, _this_zval, "device", 6, fd TSRMLS_DC);
// Default property values
uint8_t mode = SPI_MODE_0;
uint8_t bits = 8;
uint32_t speed = 500000;
uint16_t delay = 0;
// Loop through the options array
zval **data;
for(zend_hash_internal_pointer_reset(options_hash);
zend_hash_get_current_data(options_hash, (void **)&data) == SUCCESS;
zend_hash_move_forward(options_hash)) {
char *key;
int len;
long index;
long value = Z_LVAL_PP(data);
if(zend_hash_get_current_key_ex(options_hash, &key, &len, &index, 1, NULL) == HASH_KEY_IS_STRING) {
// Assign the value accordingly
if(strncmp("mode", key, len) == 0) {
switch(value) {
case SPI_MODE_1:
mode = SPI_MODE_1;
break;
case SPI_MODE_2:
mode = SPI_MODE_2;
break;
case SPI_MODE_3:
mode = SPI_MODE_3;
break;
default:
mode = SPI_MODE_0;
break;
}
}
else if(strncmp("bits", key, len) == 0) {
bits = value;
}
else if(strncmp("speed", key, len) == 0) {
speed = value;
}
else if(strncmp("delay", key, len) == 0) {
delay = value;
}
}
}
However, if I follow the suggestions of all the documentation I can find and add a pipe between the l and the a, like so:
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll|a", &bus, &chipselect, &options) == FAILURE) {
Then my extension silently fails - can anyone offer me any advice?
Assuming options is a zval*, if you do this:
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll|a", &bus, &chipselect, &options) == FAILURE) {
return;
}
...if options is not passed (that is, you omit the third optional argument), options will not be initialized or modified. Later, you do this:
options_hash = HASH_OF(options);
Therefore, you're using either an uninitialized pointer, or a NULL pointer, which is undefined behavior. This is most likely causing a segmentation fault, causing your PHP script to fail.
What you should do is something like:
zval* options = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll|a", &bus, &chipselect, &options) == FAILURE) {
return;
}
// ...
if (options != NULL) {
options_hash = HASH_OF(options);
}
...and handle every instance of options (and options_hash) with a condition that checks if it's NULL or not.

Categories