1

I'm trying to make a c++ program which will use openssl to generate a key, encrypt any input data and decrypt it further, on looking for any such example i came across this article. Below is the code for it.

#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/crypto.h>

#include <bits/stdc++.h>

using namespace std;

int padding = RSA_PKCS1_PADDING;
 
RSA * createRSA(unsigned char * key, int public1)
{
    RSA *rsa= NULL;
    BIO *keybio ;
    keybio = BIO_new_mem_buf(key, -1);
    if (keybio==NULL)
    {
        printf( "Failed to create key BIO");
        return 0;
    }
    if( public1 )
    {
        rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa,NULL, NULL);
    }
    else
    {
        rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa,NULL, NULL);
    }
    if(rsa == NULL)
    {
        printf( "Failed to create RSA");
    }
 
    return rsa;
}
 
int public_encrypt(unsigned char * data,int data_len,unsigned char * key, unsigned char *encrypted)
{
    RSA * rsa = createRSA(key,1);
    int result = RSA_public_encrypt(data_len,data,encrypted,rsa,padding);
    return result;
}
int private_decrypt(unsigned char * enc_data,int data_len,unsigned char * key, unsigned char *decrypted)
{
    RSA * rsa = createRSA(key,0);
    int  result = RSA_private_decrypt(data_len,enc_data,decrypted,rsa,padding);
    return result;
}
 
 
int private_encrypt(unsigned char * data,int data_len,unsigned char * key, unsigned char *encrypted)
{
    RSA * rsa = createRSA(key,0);
    int result = RSA_private_encrypt(data_len,data,encrypted,rsa,padding);
    return result;
}
int public_decrypt(unsigned char * enc_data,int data_len,unsigned char * key, unsigned char *decrypted)
{
    RSA * rsa = createRSA(key,1);
    int  result = RSA_public_decrypt(data_len,enc_data,decrypted,rsa,padding);
    return result;
}
 
void printLastError(char *msg)
{
    char * err = (char *)malloc(130);;
    ERR_load_crypto_strings();
    ERR_error_string(ERR_get_error(), err);
    printf("%s ERROR: %s\n",msg, err);
    free(err);
}
 
int main(){
 
unsigned char plainText[2048/8] = "Hello this is Ravi"; //key length : 2048
 
unsigned char publicKey[]="-----BEGIN PUBLIC KEY-----\n"\
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy8Dbv8prpJ/0kKhlGeJY\n"\
"ozo2t60EG8L0561g13R29LvMR5hyvGZlGJpmn65+A4xHXInJYiPuKzrKUnApeLZ+\n"\
"vw1HocOAZtWK0z3r26uA8kQYOKX9Qt/DbCdvsF9wF8gRK0ptx9M6R13NvBxvVQAp\n"\
"fc9jB9nTzphOgM4JiEYvlV8FLhg9yZovMYd6Wwf3aoXK891VQxTr/kQYoq1Yp+68\n"\
"i6T4nNq7NWC+UNVjQHxNQMQMzU6lWCX8zyg3yH88OAQkUXIXKfQ+NkvYQ1cxaMoV\n"\
"PpY72+eVthKzpMeyHkBn7ciumk5qgLTEJAfWZpe4f4eFZj/Rc8Y8Jj2IS5kVPjUy\n"\
"wQIDAQAB\n"\
"-----END PUBLIC KEY-----\n";
  
unsigned char privateKey[]="-----BEGIN RSA PRIVATE KEY-----\n"\
"MIIEowIBAAKCAQEAy8Dbv8prpJ/0kKhlGeJYozo2t60EG8L0561g13R29LvMR5hy\n"\
"vGZlGJpmn65+A4xHXInJYiPuKzrKUnApeLZ+vw1HocOAZtWK0z3r26uA8kQYOKX9\n"\
"Qt/DbCdvsF9wF8gRK0ptx9M6R13NvBxvVQApfc9jB9nTzphOgM4JiEYvlV8FLhg9\n"\
"yZovMYd6Wwf3aoXK891VQxTr/kQYoq1Yp+68i6T4nNq7NWC+UNVjQHxNQMQMzU6l\n"\
"WCX8zyg3yH88OAQkUXIXKfQ+NkvYQ1cxaMoVPpY72+eVthKzpMeyHkBn7ciumk5q\n"\
"gLTEJAfWZpe4f4eFZj/Rc8Y8Jj2IS5kVPjUywQIDAQABAoIBADhg1u1Mv1hAAlX8\n"\
"omz1Gn2f4AAW2aos2cM5UDCNw1SYmj+9SRIkaxjRsE/C4o9sw1oxrg1/z6kajV0e\n"\
"N/t008FdlVKHXAIYWF93JMoVvIpMmT8jft6AN/y3NMpivgt2inmmEJZYNioFJKZG\n"\
"X+/vKYvsVISZm2fw8NfnKvAQK55yu+GRWBZGOeS9K+LbYvOwcrjKhHz66m4bedKd\n"\
"gVAix6NE5iwmjNXktSQlJMCjbtdNXg/xo1/G4kG2p/MO1HLcKfe1N5FgBiXj3Qjl\n"\
"vgvjJZkh1as2KTgaPOBqZaP03738VnYg23ISyvfT/teArVGtxrmFP7939EvJFKpF\n"\
"1wTxuDkCgYEA7t0DR37zt+dEJy+5vm7zSmN97VenwQJFWMiulkHGa0yU3lLasxxu\n"\
"m0oUtndIjenIvSx6t3Y+agK2F3EPbb0AZ5wZ1p1IXs4vktgeQwSSBdqcM8LZFDvZ\n"\
"uPboQnJoRdIkd62XnP5ekIEIBAfOp8v2wFpSfE7nNH2u4CpAXNSF9HsCgYEA2l8D\n"\
"JrDE5m9Kkn+J4l+AdGfeBL1igPF3DnuPoV67BpgiaAgI4h25UJzXiDKKoa706S0D\n"\
"4XB74zOLX11MaGPMIdhlG+SgeQfNoC5lE4ZWXNyESJH1SVgRGT9nBC2vtL6bxCVV\n"\
"WBkTeC5D6c/QXcai6yw6OYyNNdp0uznKURe1xvMCgYBVYYcEjWqMuAvyferFGV+5\n"\
"nWqr5gM+yJMFM2bEqupD/HHSLoeiMm2O8KIKvwSeRYzNohKTdZ7FwgZYxr8fGMoG\n"\
"PxQ1VK9DxCvZL4tRpVaU5Rmknud9hg9DQG6xIbgIDR+f79sb8QjYWmcFGc1SyWOA\n"\
"SkjlykZ2yt4xnqi3BfiD9QKBgGqLgRYXmXp1QoVIBRaWUi55nzHg1XbkWZqPXvz1\n"\
"I3uMLv1jLjJlHk3euKqTPmC05HoApKwSHeA0/gOBmg404xyAYJTDcCidTg6hlF96\n"\
"ZBja3xApZuxqM62F6dV4FQqzFX0WWhWp5n301N33r0qR6FumMKJzmVJ1TA8tmzEF\n"\
"yINRAoGBAJqioYs8rK6eXzA8ywYLjqTLu/yQSLBn/4ta36K8DyCoLNlNxSuox+A5\n"\
"w6z2vEfRVQDq4Hm4vBzjdi3QfYLNkTiTqLcvgWZ+eX44ogXtdTDO7c+GeMKWz4XX\n"\
"uJSUVL5+CVjKLjZEJ6Qc2WZLl94xSwL71E41H4YciVnSCQxVc4Jw\n"\
"-----END RSA PRIVATE KEY-----\n";
 
    
unsigned char  encrypted[4098]={};
unsigned char decrypted[4098]={};
 
int encrypted_length= public_encrypt(plainText,strlen((char *)plainText),publicKey,encrypted);
if(encrypted_length == -1)
{
    printLastError("Public Encrypt failed ");
    exit(0);
}
printf("Encrypted length =%d\n",encrypted_length);
 
int decrypted_length = private_decrypt(encrypted,encrypted_length,privateKey, decrypted);
if(decrypted_length == -1)
{
    printLastError("Private Decrypt failed ");
    exit(0);
}
printf("Decrypted Text =%s\n",decrypted);
printf("Decrypted Length =%d\n",decrypted_length);
 
 
encrypted_length= private_encrypt(plainText,strlen((char *)plainText),privateKey,encrypted);
if(encrypted_length == -1)
{
    printLastError("Private Encrypt failed");
    exit(0);
}
printf("Encrypted length =%d\n",encrypted_length);
 
decrypted_length = public_decrypt(encrypted,encrypted_length,publicKey, decrypted);
if(decrypted_length == -1)
{
    printLastError("Public Decrypt failed");
    exit(0);
}
printf("Decrypted Text =%s\n",decrypted);
printf("Decrypted Length =%d\n",decrypted_length);
 
}

However on compiling i'm getting these errors, specifically /usr/bin/ld errors, rest are not so much of concern:

rsa2.cpp: In function ‘int main()’:
rsa2.cpp:126:20: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
  126 |     printLastError("Public Encrypt failed ");
      |                    ^~~~~~~~~~~~~~~~~~~~~~~~
rsa2.cpp:134:20: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
  134 |     printLastError("Private Decrypt failed ");
      |                    ^~~~~~~~~~~~~~~~~~~~~~~~~
rsa2.cpp:144:20: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
  144 |     printLastError("Private Encrypt failed");
      |                    ^~~~~~~~~~~~~~~~~~~~~~~~
rsa2.cpp:152:20: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
  152 |     printLastError("Public Decrypt failed");
      |                    ^~~~~~~~~~~~~~~~~~~~~~~
/usr/bin/ld: /tmp/ccevoLwx.o: in function `createRSA(unsigned char*, int)':
rsa2.cpp:(.text+0x37): undefined reference to `BIO_new_mem_buf'
/usr/bin/ld: rsa2.cpp:(.text+0x7a): undefined reference to `PEM_read_bio_RSA_PUBKEY'
/usr/bin/ld: rsa2.cpp:(.text+0x9a): undefined reference to `PEM_read_bio_RSAPrivateKey'
/usr/bin/ld: /tmp/ccevoLwx.o: in function `public_encrypt(unsigned char*, int, unsigned char*, unsigned char*)':
rsa2.cpp:(.text+0x121): undefined reference to `RSA_public_encrypt'
/usr/bin/ld: /tmp/ccevoLwx.o: in function `private_decrypt(unsigned char*, int, unsigned char*, unsigned char*)':
rsa2.cpp:(.text+0x178): undefined reference to `RSA_private_decrypt'
/usr/bin/ld: /tmp/ccevoLwx.o: in function `private_encrypt(unsigned char*, int, unsigned char*, unsigned char*)':
rsa2.cpp:(.text+0x1cf): undefined reference to `RSA_private_encrypt'
/usr/bin/ld: /tmp/ccevoLwx.o: in function `public_decrypt(unsigned char*, int, unsigned char*, unsigned char*)':
rsa2.cpp:(.text+0x226): undefined reference to `RSA_public_decrypt'
/usr/bin/ld: /tmp/ccevoLwx.o: in function `printLastError(char*)':
rsa2.cpp:(.text+0x25b): undefined reference to `OPENSSL_init_crypto'
/usr/bin/ld: rsa2.cpp:(.text+0x260): undefined reference to `ERR_get_error'
/usr/bin/ld: rsa2.cpp:(.text+0x272): undefined reference to `ERR_error_string'
collect2: error: ld returned 1 exit status

In createRSA function, earlier in the code, public1 was named as public and for that compiler was giving these below errors:

rsa2.cpp:15:42: error: expected ‘,’ or ‘...’ before ‘public’
   15 | RSA * createRSA(unsigned char * key, int public)
      |                                          ^~~~~~
rsa2.cpp: In function ‘RSA* createRSA(unsigned char*, int)’:
rsa2.cpp:25:9: error: expected primary-expression before ‘public’
   25 |     if( public )
      |         ^~~~~~
rsa2.cpp:25:8: error: expected ‘)’ before ‘public’
   25 |     if( public )
      |       ~^~~~~~~
      |        )

so on replacing it with public1 i was able to mitigate these errors but still couln't understand what was the problem with the public variable. I know it is an access specifier when using classes and objects but don't think, that is what creating problem here.

user14610638
  • 161
  • 7
  • 1
    You can't use reserved word `public` as a variable name in C++, hence the error. – Arty Apr 01 '21 at 16:21
  • `void printLastError(char *msg)` should be `void printLastError(const char *msg)` – drescherjm Apr 01 '21 at 16:22
  • 1
    `ld` errors are due to openssl library not linked in, you have to provide binary library path to linker. Or if you have GCC/Clang in Linux then you provide flag `-lopenssl` to compiler to force library linkage. – Arty Apr 01 '21 at 16:23
  • @Arty how to provide binary path to the linker? – user14610638 Apr 01 '21 at 16:30
  • In linux you may do two things, one way you do `clang++ main.cpp -lopenssl` (same for GCC), i.e. add `-lopenssl` if you have standard installation of OpenSLL installed via APT. Or you can do `clang++ main.cpp /path/to/openssl/openssl.a`, i.e. put full path to `.a` or `.so` file of your openssl, path and file name here are imaginary, you have to put your path. Providing path is needed only if you have non-standard openssl installation, if you copied or compiled openssl manually, otherwise `-lopenssl` is enough. – Arty Apr 01 '21 at 16:36
  • It says `/usr/bin/ld: cannot find -lopenssl` – user14610638 Apr 01 '21 at 16:38
  • This is how i compiled `g++ -o rsa2 -lcrypto -lopenssl rsa2.cpp` – user14610638 Apr 01 '21 at 16:38
  • That means the openssl library is not in the system locations (probably did not install via your package manager) and you need to specify the path if it is in some non-standard location because you put it there. – drescherjm Apr 01 '21 at 16:39
  • Then first you have to install openssl, I don't remember exact APT package name but you can search for it by commandline in bash `apt search openssl`, then install it via `apt install openssl-dev` here `openssl-dev` is package name, you may need to correct it, but possibly I guessed the correct name `openssl-dev`. – Arty Apr 01 '21 at 16:40
  • I didn't know this apt search command but there are lots of packages it is showing on `apt search openssl`, how can i judge which is correct one? there are python, javascript, haskell, Ocaml, perl, android, and one is named as `C-Implementation of CoAP ` but nowhere it is showing c++ bindings for openssl. There is one though named as `libghc-openssl-streams-dev/unknown 1.2.2.0-1build1 amd64 OpenSSL network support for io-streams` which is similar to what you have suggested – user14610638 Apr 01 '21 at 16:50
  • I ran command `sudo apt-get install openssl` and i think openssl is already there by looking at the output. am i correct? `Reading package lists... Done Building dependency tree Reading state information... Done openssl is already the newest version (1.1.1c-1ubuntu4.1).` – user14610638 Apr 01 '21 at 16:53
  • Seems that openssl is linked via `-lssl`, my appologies. – Arty Apr 01 '21 at 16:57
  • No earlier i was doing it with `-lssl` only, and again checked it but still same error. – user14610638 Apr 01 '21 at 17:01
  • 1
    Try adding `-lssl -lcrypto` to the very end of you command line i.e. `g++ main.cpp -lssl -lcrypto`. You have to add `-l` options after all `.cpp` files. – Arty Apr 01 '21 at 17:04
  • Also looks like APT package `openssl` is just an executable tool. You have to do `sudo apt install libssl-dev`. – Arty Apr 01 '21 at 17:10
  • @Arty many many thanks, adding `-lssl`, `-lcrypto` at the end worked, could have saved lot of time if known this in the first place. I was adding both these options but before .cpp files. anyway what's the reason for this? – user14610638 Apr 01 '21 at 17:18
  • @Arty to me too, actually i looked for location of `openssl.so` and `openssl.a` but did not find such file, there's only `openssl` file under `usr/bin` directory. there is one `_openssl.abi3.so` but that is present in /usr/bin/python3 directory. – user14610638 Apr 01 '21 at 17:21
  • 2
    The reason for adding `-l` options to the very end is next - compiler (gcc/clang) executes all options left to right, as soon as it meets next `.cpp` file it compiles just it, as soon as it meet `-l` option it links library. So if you place `-l` before `.cpp` then library is linked to nowhere, there are no symbols that need to be linked, after that when `.cpp` is met then new unresolved symbols appear but there is no `-l` to the right from it so those symbols can't be resolved and linked with real library. MS Visual Studio works differently, theirs `cl` compiler works with any options order. – Arty Apr 01 '21 at 17:44

0 Answers0