-2

I am trying to store the public key (PK) and signature (generated by crypto++ library) to sqlite database. I first encoded the keys as:

pk[node].BEREncode(CryptoPP::StringSink(pkstring).Ref());

and then store them in the database. But as the PK and signature have special characteres, they are not stored correctly into the database. What I used for storing is:

char * PK = (char*) malloc (BC.trans[l].PK.length()+1);   //use malloc to manually manage the memory 
std::strcpy(PK,BC.trans[l].PK.c_str());
char *zSQL = sqlite3_mprintf("INSERT INTO BC (PK  VALUES ('%q');", PK);
rc = sqlite3_exec(db, zSQL, callback, (void*)data, &zErrMsg);// executes the command in sqlite and returns the status (whether stroing was successful or not. 
free(PK);

The string should be copied to the char, and the issue happens exactly here in copying the content into the char. I think its because the string has special characters. For hash I have the same follow but it works perfectly fine. Only for PK and signature. I used memcpy and strncpy as well. Nothing works for this and still the keys are not stored correctly in the database.

Any thoughts?

I've updated with the full code. Now I can store the PK and its seems to be fine, but when I ask the database to remove a bunch of records, nothing happens. That means something is wrong again.


Here is the code:

int Network_Nodes =10;   
int Block_Size=10;        
int BC_lenght=0;           
int Fin_BC_size =50; 

std::vector<CryptoPP::RSA::PrivateKey> prk;
std::vector<CryptoPP::RSA::PublicKey> pk;
std::vector<std::string> prev_t;           
struct Block {

    std::string block_hash;

    std::string block_num;

    struct transactions {
        std::string TransactionID;
        std::string previousTransactionID;
        std::string PK;
        std::string Sign;
    };
    std::vector<transactions> trans;
} BC;

int generatekey()
{    
    for (int i=0;i<Network_Nodes;i++)    
    {
        CryptoPP::AutoSeededRandomPool rng;
        CryptoPP::InvertibleRSAFunction param;
        param.GenerateRandomWithKeySize(rng,3072);
        CryptoPP::RSA::PrivateKey privatekey(param);
        CryptoPP::RSA::PublicKey publickey (param);
        prk.push_back(privatekey);
        pk.push_back(publickey);
    }
    return 0;
}
///////////////////////////////////////////////////////////////


void  initialization()
{    
    for (int i=0;i<=Network_Nodes;i++)
    {
        prev_t.push_back("NULL");
    }        

    //Creating database
    sqlite3 *db;
        char *zErrMsg = 0;
        int rc;
        char *sql;
        const char* data = "Callback function called";

        /* Open database */
        rc = sqlite3_open("RemovableBC.db", &db);
        if( rc ) {
                  fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
                  return;
               } else {
             //     fprintf(stdout, "Opened database successfully\n");
               }


        sql = "DROP TABLE BC";
        rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg);

        /* Create a table in the data base to be used for storing data. Create SQL statement */
          sql = "CREATE TABLE BC("  \
                "T_ID          TEXT    ," \
                "P_T_ID           TEXT   ," \
                "PK            BLOB    ," \
                "Signature        BLOB      ," \
                "Block_ID         TEXT       );";

          /* Execute SQL statement */
          rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
          if( rc != SQLITE_OK ){
                   fprintf(stderr, "SQL error: %s\n", zErrMsg);
                      sqlite3_free(zErrMsg);
                   } else {
             //         fprintf(stdout, "Table created successfully\n");
                   }
          sqlite3_close(db);    
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
void fill_the_block(std::string block_content)
{        
        const char* data = "Callback function called";
        SHA256 hash;
        string digest;
        sqlite3 *db=NULL;
        char *sql;
        char *zErrMsg = 0;
        int rc;
        char sqlStr[2000];
        /* Open database */
        rc = sqlite3_open("RemovableBC.db", &db);
           if( rc ) {
                  fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
                  return;
                  } else {
                  //  fprintf(stdout, "Opened database successfully\n");
                 }
         StringSource s(block_content, true, new HashFilter(hash, new HexEncoder(new StringSink(digest))));
         BC.block_hash=digest;
         for (int l=0 ; l<Block_Size ; l++)
               {
                                    char *begin = sqlStr;
                                    char *end = begin + sizeof(sqlStr);
                                    std::fill(begin, end, 0);
                                    char *zSQL = sqlite3_mprintf("INSERT INTO BC ( T_ID , P_T_ID , PK , Signature , Block_ID ) VALUES ('%q','%q','%q','%q','%q');", BC.trans[l].TransactionID.c_str() ,BC.trans[l].previousTransactionID.c_str() ,BC.trans[l].PK.c_str() ,BC.trans[l].Sign.c_str(),BC.block_hash.c_str());

                                     rc = sqlite3_exec(db, zSQL, callback, (void*)data, &zErrMsg);

                                   sqlite3_free(zSQL);
                                   if( rc != SQLITE_OK ) {
                                       fprintf(stderr, "SQL error in populating : %s\n", zErrMsg);
                                       sqlite3_free(zErrMsg);
                                        } else {       
                 }


                                sqlite3_close(db);          //We close the connection we have with the database
}
///////////////////////////////////////////////////////////////////////////
void populate_bc ()
{        
        int generated_blocks=0;
        int stored_trans_in_block=0;                
        int node=0;                                               
        std::string block_content,trans_cont;                        
        std::string pkstring;  
        std::string signature;
        std::string mes ="This message is going to be singed";


        while (BC_lenght <=Fin_BC_size )
           {
            if (generated_blocks <= 10){
                 if (node >= Network_Nodes)
                        {
                            node=0; //cout << "step 4" <<endl;
                        }
                 if (stored_trans_in_block >= Block_Size)
                        {
                       cout << "block size is "<< BC_lenght<<endl;
                       fill_the_block(block_content);
                       BC_lenght++;
                       block_content.clear();
                       stored_trans_in_block=0;


                        for(int o=0; o<stored_trans_in_block;o++)
                                                {
                                                    BC.trans[o] = {};
                                                }
                                                 BC.trans = {};
                                                 BC ={};

                        }
                 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                 if (prev_t[node]=="NULL")
                        {
                          // cout << "We are populating on behafe of "<< node<< endl;
                          trans_cont="";
                          BC.trans.push_back(Block::transactions());

                          BC.trans[stored_trans_in_block].previousTransactionID ="NULL";
                        //  byte public_key[] = pk[node];

                          std::string endoced_pub;
                          Base64Encoder pubKeySink(new StringSink(endoced_pub));
                          pk[node].DEREncode(pubKeySink);
                      pk[node].BEREncode(CryptoPP::StringSink(pkstring).Ref());
                          BC.trans[stored_trans_in_block].PK=endoced_pub;

                          CryptoPP::AutoSeededRandomPool rng;
                          CryptoPP::RSASSA_PKCS1v15_SHA_Signer signer(prk[node]);
                          CryptoPP::StringSource ss1(mes, true,
                                                   new CryptoPP::SignerFilter(rng, signer,
                                                                              new CryptoPP::StringSink(signature)
                                                          ) // SignerFilter
                                         ); // StringSource
                      //    cout << "step 1" <<endl;
                          BC.trans[stored_trans_in_block].Sign=signature;
                          trans_cont = "NULL" + pkstring + signature;
                          SHA256 hash;
                          string digest;
                          StringSource s(trans_cont, true, new HashFilter(hash, new HexEncoder(new StringSink(digest))));
                      //    cout << "step 2" <<endl;
                          BC.trans[stored_trans_in_block].TransactionID=digest;
                          prev_t[node] =digest;                     // This keeps the previous transaction of each node in an array and thus we can later use to populate the BC
                          block_content+=digest;                    // This is to calculate the ID of the block which is the hash of all TIDs (hash of hash of all trnasctions)
                          node++;
                          stored_trans_in_block++;
                        //  cout << "step 3" <<endl;
                        }//end of  if (prev_t[node]=="NULL")
                    else
                        {// cout << "step 6" <<endl;
                                  trans_cont="";
                                  BC.trans.push_back(Block::transactions());

                                  BC.trans[stored_trans_in_block].previousTransactionID =prev_t[node];
                                std::string endoced_pub;
                                                          Base64Encoder pubKeySink(new StringSink(endoced_pub));
                                                          pk[node].DEREncode(pubKeySink);
                                                    //       pubKeySink.MessageEnd();

                              //    pk[node].BEREncode(CryptoPP::StringSink(pkstring).Ref());
                                  BC.trans[stored_trans_in_block].PK = endoced_pub;
                        //      BC.trans[stored_trans_in_block].PK= pk[node];
                                  CryptoPP::AutoSeededRandomPool rng;
                                  CryptoPP::RSASSA_PKCS1v15_SHA_Signer signer(prk[node]);
                                  CryptoPP::StringSource ss1(mes, true,
                                                           new CryptoPP::SignerFilter(rng, signer,
                                                                                      new CryptoPP::StringSink(signature)
                                                                  ) // SignerFilter
                                                 ); // StringSource
                                  BC.trans[stored_trans_in_block].Sign=signature;
                                  trans_cont = prev_t[node] + pkstring + signature;
                                  SHA256 hash;
                                  string digest;
                                  StringSource s(trans_cont, true, new HashFilter(hash, new HexEncoder(new StringSink(digest))));
                                  BC.trans[stored_trans_in_block].TransactionID=digest;
                                  prev_t[node] =digest;                     
                                  block_content+=digest;                    
                                  node++;
                                  stored_trans_in_block++;
                        }

                generated_blocks++;
            }


        else
        {

            generated_blocks=0;

        }
           }

}
//////////////////////////////////////////////////////////////////////////////////////

void remove_node (int i)
{


        std::string search_node;                    //This is the ID of the transaction that we need to search for in the BC,
        sqlite3 *db;

        std::string endoced_pub;
        Base64Encoder pubKeySink(new StringSink(endoced_pub));
         pk[i].DEREncode(pubKeySink);
    //    pubKeySink.MessageEnd();
        char *sql;
        int rc;
        char *zErrMsg = 0;

        const char* data = "Callback function called";
        /* Open database */
           rc = sqlite3_open("RemovableBC.db", &db);

           if( rc ) {
              fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
              return;
           } else {
            //  fprintf(stderr, "Opened database successfully\n");
           }
         /* Execute SQL statement */
        //   char *zSQL = sqlite3_mprintf("DELETE from BC");


            char * Search_NODE = (char*) malloc (endoced_pub.length()+1);
            std::strcpy(Search_NODE,endoced_pub.c_str());
                            std::strcpy(Search_NODE,search_node.c_str());

         //  char *zSQL = sqlite3_mprintf("DELETE from  BC  where PK = '%q';", Search_NODE);

                   char *zSQL = sqlite3_mprintf("UPDATE BC set Signature = null  and PK = null   where PK = '%q';", endoced_pub.c_str());
                   rc = sqlite3_exec(db, zSQL, callback, (void*)data, &zErrMsg);

cout<< endoced_pub.c_str()<<endl;


           if( rc != SQLITE_OK ) {
              fprintf(stderr, "SQL error in removing a record: %s\n", zErrMsg);
              sqlite3_free(zErrMsg);
           } else {
            //  fprintf(stdout, "Operation done successfully\n");
           }
           sqlite3_close(db);
           free(Search_NODE);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
int main() {

    auto initial = std::chrono::high_resolution_clock::now();
    generatekey();
    cout << "Keys are generated for " <<Network_Nodes << "  nodes..." << endl;

    clock_t begin_block_pup = clock();
    initialization();
    cout << "Initializing previous transaction vector..." << endl;

    //clock_t ti =clock();
    //double time = double (ti)/CLOCKS_PER_SEC;


    clock_t ti2 =clock();
        double time2 = double (ti2)/CLOCKS_PER_SEC;
    //cout << "second time is  " << done <<endl;
    populate_bc();
    cout << "BC has been populated with "<< BC_lenght <<" blocks..." << endl;
    return 0;
}
jww
  • 97,681
  • 90
  • 411
  • 885
Ali Dorri
  • 31
  • 1
  • 1
    You need to [edit] your question to include a [mcve]. As it is, things like `data` and `callback` aren't defined. What does `sqlite3_exec` return? What's with the `malloc`? Consider just using `std::string` – Tas Aug 29 '17 at 02:18
  • INSERT INTO BC (PK VALUES ('%q') - there is a ( without closing ) – Artemy Vysotsky Aug 29 '17 at 03:25
  • Why do you even `malloc` ? Do you really need to copy the string instead of just passing it via `c_str()` directly ? Seems like an unnecessary memory allocation. Please provide a fully working sample. – Blacktempel Aug 29 '17 at 05:03
  • It looks like you would have done better to stay on the [Crypto++ mailing list](https://groups.google.com/d/msg/cryptopp-users/bx6Mn4jxm6Y/vxQpIFVOCgAJ). Is there any reason you are not using either (1) the BLOB type in SQLite or (2) the encoders and decoders as suggested in the reply to your message? – jww Aug 29 '17 at 18:07
  • You have embedded NULLs, And things like `strcpy` and `PK.c_str()` and not working as expected. Also see [Having trouble decrypting a well-formed cipher text using Crypto++](https://stackoverflow.com/q/34167305/608639), [Getting exception “RSA/OAEP-MGF1(SHA-1): ciphertext length of 154 doesn't match the required length of 192 for this key” during decrypting session key](https://stackoverflow.com/q/38545180/608639), etc. When using `std::string`, you must use both `ptr` and `len`. – jww Aug 29 '17 at 21:35

1 Answers1

1

The problem with your system, is that you need to store the PK data as either a BLOB or encode it into 7 bit ASCII.

Sqlite has some internationalization support, and may convert raw binary data stored as a string into a different form. (e.g. UTF-8 conversion)

So either use a blob as in the answer to this question SO : sqlite blob,

or first convert the bytes to 7 bit ascii (e.g. b64 encode), then store the data.

Remembering you would need to b64 decode the results afterwards.

mksteve
  • 12,614
  • 3
  • 28
  • 50