Reputation: 3701
I'm writing my project in NodeJS, but I'm forced to use a C shared library. Because of this I have to use Node.js Addons. Calling the C++ code works perfectly, I was also able to load the custom library, and call two C functions successfully: one gives me the version number of the library, the other method generated a key based on the data provided form JS.
The problem that I'm having is related to the generated Key. I have to use in the encrypt
and decrypt
methods.
This is the variable that I'm using to store the key:
unsigned char generated_key[256];
This is the function that generates the key:
extern "C"
{
#ifdef WIN32
VE_EXPORT int CALLBACK generate_key
#else
int generate_key
#endif
(char *variable_msg, /*!< variable seed */
char *shared_seed, /*!< shared seed */
unsigned char *generated_key, /*!< generated key */
unsigned int key_size); /*!< key size */
}
This is a function that uses the key:
extern "C"
{
#ifdef WIN32
VE_EXPORT int CALLBACK encrypt
#else
int encrypt
#endif
(const unsigned char * const plain_data, /*!< plain data */
const unsigned int plain_data_len, /*!< number bytes to be encrypted */
unsigned char *encrypted_data, /*!< encrypted data */
const unsigned int encrypted_data_size, /*!< size encrypted_data array */
unsigned int *encrypted_data_len, /*!< number of bytes encrypted */
const unsigned char * const key /*!< symmetric encryption key */
);
}
When I try to compile the code I get:
gyp info it worked if it ends with ok
gyp info using [email protected]
gyp info using [email protected] | linux | x64
gyp info spawn /usr/bin/python2
gyp info spawn args [ '/usr/local/lib/node_modules/node-gyp/gyp/gyp_main.py',
gyp info spawn args 'binding.gyp',
gyp info spawn args '-f',
gyp info spawn args 'make',
gyp info spawn args '-I',
gyp info spawn args '/home/dgatti/sequr/sequr-experiments/CPP/Sequr/build/config.gypi',
gyp info spawn args '-I',
gyp info spawn args '/usr/local/lib/node_modules/node-gyp/addon.gypi',
gyp info spawn args '-I',
gyp info spawn args '/home/dgatti/.node-gyp/6.2.0/include/node/common.gypi',
gyp info spawn args '-Dlibrary=shared_library',
gyp info spawn args '-Dvisibility=default',
gyp info spawn args '-Dnode_root_dir=/home/dgatti/.node-gyp/6.2.0',
gyp info spawn args '-Dnode_gyp_dir=/usr/local/lib/node_modules/node-gyp',
gyp info spawn args '-Dnode_lib_file=node.lib',
gyp info spawn args '-Dmodule_root_dir=/home/dgatti/sequr/sequr-experiments/CPP/Sequr',
gyp info spawn args '--depth=.',
gyp info spawn args '--no-parallel',
gyp info spawn args '--generator-output',
gyp info spawn args 'build',
gyp info spawn args '-Goutput_dir=.' ]
make: Entering directory `/home/dgatti/sequr/sequr-experiments/CPP/Sequr/build'
gyp info spawn make
gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
CXX(target) Release/obj.target/vertx/main.o
../main.cpp: In function ‘void demo::VertxEncrypt(const v8::FunctionCallbackInfo<v8::Value>&)’:
../main.cpp:127:102: error: invalid conversion from ‘char*’ to ‘const unsigned char*’ [-fpermissive]
vertx_encrypt(cPayload, sizeof(cPayload), encMessage, sizeof(encMessage), &encLength, generated_key);
^
In file included from ../main.cpp:3:0:
../libvertx_encryption.h:79:7: error: initializing argument 1 of ‘int vertx_encrypt(const unsigned char*, unsigned int, unsigned char*, unsigned int, unsigned int*, const unsigned char*)’ [-fpermissive]
int vertx_encrypt
^
make: *** [Release/obj.target/vertx/main.o] Error 1
make: Leaving directory `/home/dgatti/sequr/sequr-experiments/CPP/Sequr/build'
gyp ERR! build error
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack at ChildProcess.onExit (/usr/local/lib/node_modules/node-gyp/lib/build.js:276:23)
gyp ERR! stack at emitTwo (events.js:106:13)
gyp ERR! stack at ChildProcess.emit (events.js:191:7)
gyp ERR! stack at Process.ChildProcess._handle.onexit (internal/child_process.js:204:12)
gyp ERR! System Linux 3.10.0-327.13.1.el7.x86_64
gyp ERR! command "/usr/local/bin/node" "/usr/local/bin/node-gyp" "rebuild"
gyp ERR! cwd /home/dgatti/sequr/sequr-experiments/CPP/Sequr
gyp ERR! node -v v6.2.0
gyp ERR! node-gyp -v v3.4.0
gyp ERR! not ok
This is how I call the function, right now I'm just passing the variable as is, but I tried many different way of converting, casting and changing.
encrypt(cPayload, sizeof(cPayload), encMessage, sizeof(encMessage), &encLength, generated_key);
I wrote an example in C and everything works fine, but when I try to use this C functions in C++, things brakes. I have experience in C but defiantly not in C++. I looked for days to find a solution but uncle Google and buddy Stack weren't able to com up with a solution.
This is the complete code in C++ that I'm calling from NodeJS to access C functions:
#include <node.h>
#include <iostream>
#include "lib_encryption.h"
using namespace std;
namespace demo {
using v8::Exception;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Number;
using v8::Object;
using v8::String;
using v8::Value;
unsigned char generated_key[256];
unsigned int key_size = 32;
unsigned int encLength;
unsigned char encMessage[256] = {0};
//
// This is the implementation of the "add" method
// Input arguments are passed using the
// const FunctionCallbackInfo<Value>& args struct
//
void GenerateKey(const FunctionCallbackInfo<Value>& args)
{
v8::String::Utf8Value param1(args[0]->ToString());
std::string strMessage = std::string(*param1);
v8::String::Utf8Value param2(args[1]->ToString());
std::string strSecret = std::string(*param2);
char cMessage[4];
strcpy(cMessage, strMessage.c_str());
char cSecret[11];
strcpy(cSecret, strSecret.c_str());
//
// Creating the key
//
_generate_key(cMessage, cSecret, generated_key, key_size);
//
// 1. Create isolation storage
//
Isolate* isolate = args.GetIsolate();
//
// 2. Save the value in to a isolate storage
//
Local<Value> str = String::NewFromUtf8(isolate, "Key done");
//
// 3. Set the return value (using the passed in
// FunctionCallbackInfo<Value>&)
//
args.GetReturnValue().Set(str);
}
void Encrypt(const FunctionCallbackInfo<Value>& args)
{
Isolate* isolate = args.GetIsolate();
v8::String::Utf8Value param1(args[0]->ToString());
std::string payload = std::string(*param1);
char cPayload[4];
strcpy(cPayload, payload.c_str());
for (int i=0; i<256; i++)
{
printf("%.2X ", generated_key[i]);
}
printf("\n");
encrypt(cPayload, sizeof(cPayload), encMessage, sizeof(encMessage), &encLength, generated_key);
//
// 1. Create isolation storage
//
//
// 2. Save the value in to a isolate storage
//
Local<Value> str = String::NewFromUtf8(isolate, "Encrypt");
//
// 3. Set the return value (using the passed in
// FunctionCallbackInfo<Value>&)
//
args.GetReturnValue().Set(str);
}
//
// * Initialize the object and expose the functions that need exposure.
//
void Init(Local<Object> exports)
{
NODE_SET_METHOD(exports, "GenerateKey", GenerateKey);
NODE_SET_METHOD(exports, "Encrypt", Encrypt);
}
//
// There is no semi-colon after NODE_MODULE as it's not a function
//
NODE_MODULE(, Init)
}
Upvotes: 2
Views: 2057
Reputation: 6791
The other answers mention the background but not the specific problem, or they cast doubt on generated_key
instead, but that one is OK. [edit] I see molbdnilo's comment now; I thought someone had mentioned it, but I couldn't seem to find it! [/edit] So here is the real reason:
The object cPayload
is a char[4]
. Like any array, its name implicitly converts (often colloquially phrased as 'decays') to a char *
in several contexts, including when passing it as a function argument. You passed it to a function, encrypt()
, which expects an unsigned char *
in that place. But char *
and unsigned char *
are two distinct types. Hence the error.
Back to the background, since it's worth specifying. char
must have the same range of values as either signed char
or unsigned char
, can be static_cast
with possible truncation, and has the same aliasing powers - etc. - but, in any case, it is considered a distinct type. You can verify this without any compile error by checking typeid
results for the 3 types.
Upvotes: 3
Reputation: 213689
The default char
type has implementation-defined signedness and could either be signed or unsigned, depending on compiler. Therefore, it should never be used to store anything but strings. Never use it to store other forms of data. It is not necessarily compatible with unsigned char
.
Reason why it doesn't compile could be because the signedness if char
varies between your C and C++ compilers, but it could also be because C++ has a stricter and better type safety system than C. While a C compiler is more lax and might let the code slip through without raising a diagnostic message, even though it is always bad practice to mix these types in C and C++ both.
Simply change to unsigned char
or preferably uint8_t
and the problems will go away.
Upvotes: 0
Reputation: 926
I don't guess I understood in which part of code there is problem. But I think you are trying to cast from char* to const unsigned char* that are two different types. Try to change char* type to unsigned char* or maybe use everywhere in your code unsigned char*. Here is the one answer, that may help you where said that Plain char, signed char, and unsigned char are three distinct types.
Conversion from char* to signed char*
Upvotes: 1