All pastes #438430 Raw Edit

Someone

public text v1 · immutable
·published 2007-04-13 16:47 UTC
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;
}