RSA algorithm is a widely used encryption tool. The algorithm was invented by Ron Rivest, Adi Shamir and Leonard Adleman in 1977 and is still in production. RSA is extensively used in various data-sensitive applications such as HTTPS protocol(SSL uses the RSA algorithm), e-Banking, and Bluetooth among many more core applications.
The RSA algorithm is an asymmetric algorithm which needs two keys for communication. Suppose A wants to send a message to B. For this, A must first have the public key of B which can be shared through a public channel on the internet without any problems. The reasoning behind it is, the message which is encrypted by the public key of B, can only be decrypted by using the private key of B which is assumed to be under their private possession. To summarise, A encrypts the message they want to send using the public key of B and sends it to B who decrypts it using their private key.
Generating private and public keys
To proceed to the program, we must first acquire public and private keys. This is done using the OpenSSL command-line utility.
The private key can be generated by the following command. Here 2048 refers to the length of the private key.
openssl genrsa -out private.pem 2048
The corresponding public key for the above-mentioned private key can be generated in the following manner:
openssl rsa -in private.pem -outform PEM -pubout -out public.pem
Libraries in C
You’ll need the following libraries before proceeding further. You must also install the OpenSSL API for C before going ahead
sudo apt-get install libssl-dev
Importing the required libraries in C:
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/rsa.h>
Other standard C libraries which we’ll be using:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
Ingesting the public/private
We must ingest the public/private key and create an RSA object to proceed with the encryption/decryption step
RSA * ingestPrivateKey(FILE *fp)
{
if(fp == NULL)
{
printf("Unable to open private key file \n");
return NULL;
}
RSA *rsa= RSA_new() ;
rsa = PEM_read_RSAPrivateKey(fp, &rsa,NULL, NULL);
//PEM_read_RSAPublicKey for public key
return rsa;
}
Encryption/Decryption step
After making the RSA object we can use this object to encrypt/decrypt according to our requirement.
void decryption(RSA* rsa,unsigned char decrypted[10000], int padding, char *file_contents, int lSize)
{
int padding = RSA_PKCS1_PADDING;
//randomized padding which improves strength
int decrypted_length = RSA_private_decrypt((int)lSize,file_contents,decrypted,rsa,padding);
//lSize is the size of the file to be decrypted
//file_contents is the file contents in a string
//RSA_public_encrypt is the symmetric function for encryption
if(decrypted_length == -1)
{
printf("Private Decryption failed. Please run again\n");
exit(0);
}
printf("Decrypted length is %d\n",decrypted_length);
printf("Decrypted data is : \n %s\n,decrypted);
}
Sample program for Encryption
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/rsa.h>
int padding = RSA_PKCS1_PADDING;
RSA* ingestPublicKey(FILE *fp)
{
if(fp == NULL)
{
printf("Unable to open public key file \n");
return NULL;
}
RSA* rsa= RSA_new() ;
rsa = PEM_read_RSA_PUBKEY(fp, &rsa,NULL, NULL);
return rsa;
}
int main(int argc, char* argv[])
{
if(argc<4)
{
printf("Not enough arguements");
exit(0);
}
FILE* filename = fopen(argv[1],"rb");
long lSize;
fseek( filename , 0L , SEEK_END);
lSize = ftell( filename );
rewind( filename );
char *file_contents;
file_contents = (char*)calloc(1,lSize+1);
fread(file_contents,lSize,1,filename);
unsigned char encrypted[10000]={};
FILE* public = fopen(argv[2],"rb");
RSA* rsa = ingestPublicKey(public);
int encrypted_length = RSA_public_encrypt((int)strlen(file_contents),file_contents,encrypted,rsa,padding);
if(encrypted_length == -1)
{
printf("Public Encryption failed");
exit(0);
}
printf("Encrypted length is %d\n",encrypted_length);
FILE* out_filename = fopen(argv[3],"wb");
fwrite(encrypted, encrypted_length, 1, out_filename);
// fprintf(out_filename,"%s", encrypted);
fclose(out_filename);
fclose(public);
fclose(filename);
free(file_contents);
return 0;
}
Sample program for decryption
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/rsa.h>
int padding = RSA_PKCS1_PADDING;
RSA * ingestPrivateKey(FILE *fp)
{
if(fp == NULL)
{
printf("Unable to open private key file \n");
return NULL;
}
RSA *rsa= RSA_new() ;
rsa = PEM_read_RSAPrivateKey(fp, &rsa,NULL, NULL);
return rsa;
}
int main(int argc, char* argv[])
{
if(argc<4)
{
printf("Not enough arguements");
exit(0);
}
FILE* filename = fopen(argv[1],"rb");
long lSize;
fseek( filename , 0L , SEEK_END);
lSize = ftell( filename );
rewind( filename );
unsigned char *file_contents;
file_contents = (unsigned char*)malloc(sizeof(char)*lSize);
fread(file_contents,lSize,1,filename);
unsigned char decrypted[10000]={};
FILE* private = fopen(argv[2],"rb");
RSA * rsa = ingestPrivateKey(private);
int decrypted_length = RSA_private_decrypt((int)lSize,file_contents,decrypted,rsa,padding);
if(decrypted_length == -1)
{
printf("Private Decryption failed. Please run again\n");
exit(0);
}
printf("Decrypted length is %d\n",decrypted_length);
FILE* out_filename = fopen(argv[3],"wb");
fprintf(out_filename,"%s", decrypted);
return 0;
}
Makefile
We need to pass in the command line arguements for input file, public key and private key. This has been handled in the Makefile for a specific example. You can modify to suit your needs
all: encrypt decrypt input.txt private.pem public.pem
./encrypt input.txt public.pem encrypt.bin
./decrypt encrypt.bin private.pem decrypt.txt
encrypt: encrypt.c
gcc encrypt.c -o encrypt -lcrypto -lssl
decrypt: decrypt.c
gcc decrypt.c -o decrypt -lcrypto -lssl
clean:
rm -rf encrypt decrypt decrypt.txt encrypt.bin
Running the files
make encrypt #for generating the encrypt binary file
make decrypt #for generating the decrypt binary file
make #for running the file with the above-mentioned testcase
Footnotes
Thanks for making it to this point. You can check out the full repository here. Feel free to contact me for any suggestions/improvements.