Jump to content

Asymmetric Encryption Example


Recommended Posts

I was playing around with the gmplib source and wrote a simple example of encryption, I thought that I'd share it would you

//A Simple Asymmetric Encryption Example
#include <stdio.h>
#include <string.h>
#include <gmp.h>
#include <sys/time.h>

int main(int argc, char *argv[]){
int shift, nblock_unpadded_len, nblock_padded_len = 64, i, input_str_len;
char buff[nblock_padded_len*4];
mpz_t ciphertext, nblock, encryption_exponent, modulus,
  zero, two, temp, rand_pad, decryption_exponent, result,
struct timeval tv;

if(argc < 2){
  printf("Usage: %s \"a string of text\"\n", argv[0]);
  return -1;

//send argv[1] to "buff" but in hex
input_str_len = strlen(argv[1]);
if(input_str_len >= nblock_padded_len){
  printf("Usage: %s \"a string of text\"\n", argv[0]);
  printf("Input is longer then the encryption maximum length\n");
  return -1;

memset(buff, '\0', sizeof(buff));
for(i=0; i<input_str_len; i++){
  sprintf(buff+strlen(buff), "%02x", (unsigned int)argv[1][i]);
sprintf(buff+strlen(buff), "\x00");


mpz_init_set_str(nblock, buff, 16);
mpz_init_set_str(zero, "0", 16);
mpz_init_set_str(two, "2", 16);
mpz_init_set_str(encryption_exponent, "10001", 16);
mpz_init_set_str(modulus, "c4afd144e57fa6f4308a440515eaad0933a798cad123440d9d6bddf481652c2734e282000c60095fe9244e5027cf87901d4bc2f48be431450cc7776a18140b8f9856d2a08c1f706a233933ef34894e0c9010a7c4ccc4be94e6cf7c4f735349e371b23b05a8a7b1ee67ccb6db94c71f1a6e793d92556d0f30ea87652892dbf54b", 16);

gmp_printf ("nblock              = %#Zx\n", nblock);

//pad the input with random bytes, after our cleartext
nblock_unpadded_len = strlen(mpz_get_str(NULL, 16, nblock));
if(nblock_unpadded_len % 2 == 0){
  nblock_unpadded_len = nblock_unpadded_len/2;
  nblock_unpadded_len = nblock_unpadded_len/2 + 1;

shift = nblock_padded_len-nblock_unpadded_len;

mpz_pow_ui(temp, two, 8*shift);
mpz_mul(nblock, nblock, temp);

gmp_randstate_t rstate;
gmp_randseed_ui(rstate, tv.tv_sec*1000000+tv.tv_usec);
mpz_urandomb(rand_pad, rstate, 8*(shift-1));

mpz_add(nblock, rand_pad, nblock);

mpz_powm(ciphertext, nblock, encryption_exponent, modulus);

printf(     "input_str_len       = %d\n", input_str_len);
printf(     "shift               = %d - %d = %d\n", nblock_padded_len, nblock_unpadded_len, shift);
gmp_printf ("nblock              = %#Zx\n", nblock);
gmp_printf ("encryption_exponent = %#Zx\n", encryption_exponent);
gmp_printf ("modulus             = %#Zx\n", modulus);
gmp_printf ("ciphertext          = %#Zx\n\n", ciphertext);

//delete cleartext
memset(buff, '\0', sizeof(buff));
mpz_set_str(nblock, "0", 16);

mpz_init_set_str(decryption_exponent, "13c7d6d505fbab8fbd5dfa6f4480007cff6be88ae53395c184c6776102ae691d5c4d3763c7dad4b6879cf61f4b91ac818ae0b6af9f6e08a278218b59e92802ed75db5fe5769ee61d5ee9c86daeb24583c97310819c4a93375d5b1ee45534ff5da1f9ce2a0e1e229954098e77121deaa75aeab7b0b86b0f906bc082389d434949", 16);
gmp_printf ("decryption_exponent = %#Zx\n", decryption_exponent);
mpz_powm(result, ciphertext, decryption_exponent, modulus);
gmp_printf ("result              = %#Zx\n", result);

//convert from hex to readable ascii
if(strlen(mpz_get_str(NULL, 16, result)) % 2 == 0){
  shift = strlen(mpz_get_str(NULL, 16, result))/2;
  shift = strlen(mpz_get_str(NULL, 16, result))/2 + 1;

for(i=1; i< shift; i++){
  mpz_set_str(temp, "FF", 16);
  mpz_tdiv_q_2exp(temp2, result, 8*(shift-i));
  mpz_and(temp2, temp, temp2);
  if(mpz_cmp(temp2, zero) == 0){
   printf("there are %d characters!\n", i);
  sprintf(buff+strlen(buff), "%c", mpz_get_ui(temp2));
printf("%s\n", buff);

return 0;
Edited by fugu
Link to comment
Share on other sites

if buff is allocated at 4*nblock_padded_len and populated by writing the contents of the first parameter to the program as hex, meaning 1 char = 2 hex chars, why are you rejecting the second parameter when it's nblock_padded_len in length? It can be twice that long and still fit in buff...

You shouldn't need to do sprintf(buff+strlen(buff), "\x00"); since buff was already memset to \0.

I'm surprised you apparently need to convert your input to a hex _string_ before it can be encrypted... There's a first time for everything I guess. Maybe you should elaborate a bit on what those large "modulus" and "decryption_exponent" constants are?

Which encryption algorithm is this even implementing?

Link to comment
Share on other sites

Ok, buffer sizing is not my forte. There are probably many problems with it, but his was a simple demo I was using for my self to get the hang of gmp. Im using an rsa algorithm, and those funky sets of large numbers are the pairs of encryption/decryption keys. They can be generated with openssl or I can write another simple (probably bug ridden too lol) program for generating keys. This is an fyi: my random number seeding in the above program is definitely not secure (as in the starting seed number can be predicted, which means the random numbers that are created from the generator can be predicted). I suggest changing that if before using this for anything practical. The "convert to hex" was only to load strings into gmp, which I couldn't find anyway else by looking into the doc's, which is not to say there isn't a better way to do that.

Link to comment
Share on other sites

sometimes hex or even base64 is nice(although longer) since it can negate the need to declare a character type such as utf-8 which can have many(pita) invisible characters and spaces.I had to once try and fix moving data from WordPress to octopress for someone and I could only find the bad utf-8 stuff using a hex editor. yeah. that wasfun. I ended up making a list of all the things I found so I could just automate later mass change and replace on posts but some programs and databases barf when the encoding between is different and changing to hex would preserve that in my mind so may be by design that they store data in this manner

Link to comment
Share on other sites

When you're encrypting data, you're doing just that: encrypting data. That's a far cry from encrypting text.

And in C, the typical format for a buffer of random binary data is unsigned char *

Now as fugu mentioned, the goal wasn't to make the most efficient encrypter/decrypter but instead to make one that works using GMP, so this isn't a knock against him, but if you're going to be encrypting and decrypting data kinda often this really isn't the way to go. Internally GMP will almost certainly be converting this hex string to that unsigned char * and then process it. So your program starts with data, converts it to hex text, feeds that to GMP which will convert it back to data, encrypt it, convert it to hex again and then deliver this to your program, which is probably going to convert it back to data again. That's a lot of conversions that are only required because it would seem GMP's API can only work with that (which is probably for good reason as GMP is a gnu big-number processing library rather than a crypto library).

Link to comment
Share on other sites

Here is a 1-liner for rsa 1024 key generation, haven't written code yet to do this, just been kinda lazy.

$ openssl genrsa -out temp.key 1024 && openssl rsa -in temp.key -text -noout && rm temp.key

edit: privateExponent is the decryption exponent.

Edited by fugu
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...