fugu Posted April 14, 2015 Share Posted April 14, 2015 (edited) 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, temp2; 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(ciphertext); mpz_init(temp); mpz_init(temp2); mpz_init(rand_pad); mpz_init(result); 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; }else{ 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_randinit_mt(rstate); gettimeofday(&tv,NULL); 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); //encrypt 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_clear(nblock); //decrypt 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; }else{ 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); break; } sprintf(buff+strlen(buff), "%c", mpz_get_ui(temp2)); } printf("%s\n", buff); mpz_clear(ciphertext); mpz_clear(encryption_exponent); mpz_clear(decryption_exponent); mpz_clear(modulus); mpz_clear(zero); mpz_clear(two); mpz_clear(temp); mpz_clear(temp2); mpz_clear(rand_pad); mpz_clear(result); return 0; } Edited April 14, 2015 by fugu Quote Link to comment Share on other sites More sharing options...
cooper Posted April 15, 2015 Share Posted April 15, 2015 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? Quote Link to comment Share on other sites More sharing options...
fugu Posted April 16, 2015 Author Share Posted April 16, 2015 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. Quote Link to comment Share on other sites More sharing options...
digip Posted April 16, 2015 Share Posted April 16, 2015 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 Quote Link to comment Share on other sites More sharing options...
cooper Posted April 16, 2015 Share Posted April 16, 2015 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). Quote Link to comment Share on other sites More sharing options...
fugu Posted April 19, 2015 Author Share Posted April 19, 2015 (edited) 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 April 19, 2015 by fugu Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.