rendered paste body/* gcc -Wall -Wextra -O2 -Wwrite-strings -Wstrict-prototypes -DDEBUG -o RSA RSA.c -lgcrypt */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gcrypt.h>
static void
warn (const char *format, ...)
{
va_list arg_ptr;
va_start (arg_ptr, format);
vfprintf (stderr, format, arg_ptr);
va_end (arg_ptr);
}
static void
die (const char *format, ...)
{
va_list arg_ptr;
va_start (arg_ptr, format);
vfprintf (stderr, format, arg_ptr);
va_end (arg_ptr);
exit (EXIT_FAILURE);
}
/*extract sexp from filename (assuming CANON format)
* in: new_sexp: valid pointer to an sexp that will receive the new sexp
* filename: valid string representing the path of the file to open
* out: successfullness
* 0: ACK
* -1: NACK*/
int
sexp_from_file (gcry_sexp_t * new_sexp, char *filename)
{
int rc = -1;
FILE *fpkey = fopen (filename, "r");
size_t nb;
char cpkey[1024];
if (fpkey)
{
nb = fread (cpkey, 1024, 1, fpkey);
rc = gcry_sexp_new (new_sexp, cpkey, nb, 0);
if (rc)
{
warn ("new sexp from %s failed: %s,%s\n", filename,
gcry_strsource (rc), gcry_strerror (rc));
rc = -1;
}
fclose (fpkey);
}
return rc;
}
/*RSA encode plain text src to dest (CANON format)
* in: src : plain text valid string
* dest: valid buffer that will receive encoded data
* out:
* >0: lenght of coded data appended in dest
* -1: NACK*/
int
RSA_code_str (char *src, char *dest, size_t len_dest, gcry_sexp_t pub_key)
{
int rc;
gcry_sexp_t enc_ed, plain;
rc = gcry_sexp_build (&plain, NULL, "(data(value %s))", src);
if (rc)
{
warn ("can't sexp from plain: %s,%s\n", gcry_strsource (rc),
gcry_strerror (rc));
return -1;
}
#ifdef DEBUG
gcry_sexp_dump (plain);
#endif
rc = gcry_pk_encrypt (&enc_ed, plain, pub_key);
if (rc)
{
warn ("can't encrypt %s,%s\n", gcry_strsource (rc), gcry_strerror (rc));
gcry_sexp_release (plain);
return -1;
}
rc = gcry_sexp_sprint (enc_ed, GCRYSEXP_FMT_CANON, dest, len_dest);
gcry_sexp_release (plain);
gcry_sexp_release (enc_ed);
return rc;
}
/*decode RSA encoded string src to dest
* in: src : pointer to RSA encoded string in FMT_CANON format
* slen: size of src
* dest: pointer to a valid buffer where plain text decoded string will be
* appended
* dlen: size of dest
* priv_key: private RSA key
* out:
* >0: lenght of appended data into dest
* -1: NACK*/
int
RSA_decode_str (char *src, size_t slen, char *dest, size_t dlen,
gcry_sexp_t priv_key)
{
int rc;
const char *name;
gcry_sexp_t enc_ed, plain;
rc = gcry_sexp_new (&enc_ed, src, slen, 0);
if (rc)
{
warn ("can't gen enc_ed %s,%s\n", gcry_strsource (rc),
gcry_strerror (rc));
return -1;
}
rc = gcry_pk_decrypt (&plain, enc_ed, priv_key);
if (rc)
{
warn ("can't decrypt %s,%s\n", gcry_strsource (rc), gcry_strerror (rc));
return -1;
}
#ifdef DEBUG
gcry_sexp_dump (plain);
#endif
name = gcry_sexp_nth_data (plain, 0, &rc);
if (name)
{
strncpy (dest, name, dlen);
}
gcry_sexp_release (enc_ed);
gcry_sexp_release (plain);
return rc;
}
/*generate a RSA 1024bits long key and split it to a priv//pub key
* in : pointers to sexp receiving private and public keys*/
static void
get_keys_new (gcry_sexp_t * pkey, gcry_sexp_t * skey)
{
gcry_sexp_t key_spec, key, pub_key, sec_key;
int rc;
rc = gcry_sexp_new (&key_spec, "(genkey (rsa (nbits 4:1024)))", 0, 1);
if (rc)
die ("error creating S-expression: %s\n", gpg_strerror (rc));
rc = gcry_pk_genkey (&key, key_spec);
gcry_sexp_release (key_spec);
if (rc)
die ("error generating RSA key: %s\n", gpg_strerror (rc));
pub_key = gcry_sexp_find_token (key, "public-key", 0);
if (!pub_key)
die ("public part missing in key\n");
sec_key = gcry_sexp_find_token (key, "private-key", 0);
if (!sec_key)
die ("private part missing in key\n");
gcry_sexp_release (key);
*pkey = pub_key;
*skey = sec_key;
}
/* generate a public//private key pair and store them to files
* in: priv_name : string representing desired path of private key
* pub_name : string representing desired path of public key
* out: successfullness
* 0: ACK
* -1: NACK*/
int
gen_key_pair_2files (char *priv_name, char *pub_name)
{
size_t len_p, len_s;
char cpkey[1024], cskey[1024];
FILE *skey = fopen (priv_name, "w");
FILE *pkey = fopen (pub_name, "w");
if (pkey && skey)
{
gcry_sexp_t pub_key, priv_key;
get_keys_new (&pub_key, &priv_key);
len_p = gcry_sexp_sprint (pub_key, GCRYSEXP_FMT_CANON, cpkey, 1024);
len_s = gcry_sexp_sprint (priv_key, GCRYSEXP_FMT_CANON, cskey, 1024);
fwrite (cpkey, len_p, 1, pkey);
fwrite (cskey, len_s, 1, skey);
gcry_sexp_release (pub_key);
gcry_sexp_release (priv_key);
fclose (skey);
fclose (pkey);
return 0;
}
return -1;
}
int
main (int argc, char **argv)
{
char coded[1024];
char plain[1024];
size_t nb;
int ret = EXIT_SUCCESS;
gcry_sexp_t pub_key, priv_key;
if (!gcry_check_version (GCRYPT_VERSION))
warn ("version mismatch\n");
gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
#ifdef DEBUG
gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
#endif
gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
if (argc == 2 && !strcmp (argv[1], "--genkeypair"))
{
if (gen_key_pair_2files ("skey", "pkey"))
ret = EXIT_FAILURE;
goto end2;
}
if (sexp_from_file (&pub_key, "pkey"))
{
warn ("pub key not found\n");
ret = EXIT_FAILURE;
goto end2;
}
if ((nb = RSA_code_str ("woot !", coded, sizeof (coded), pub_key)) <= 0)
{
warn ("unable to code str\n");
ret = EXIT_FAILURE;
goto end1;
}
if (sexp_from_file (&priv_key, "skey"))
{
warn ("priv key not found\n");
ret = EXIT_FAILURE;
goto end1;
}
if (RSA_decode_str (coded, nb, plain, sizeof (plain), priv_key) <= 0)
{
warn ("unable to decode\n");
ret = EXIT_FAILURE;
goto end;
}
printf ("%s\n", plain);
end:
gcry_sexp_release (priv_key);
end1:
gcry_sexp_release (pub_key);
end2:
return ret;
}