/* gcc -Wall -Wextra -O2 -Wwrite-strings -Wstrict-prototypes -DDEBUG -o RSA RSA.c -lgcrypt */ #include #include #include #include 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; }