Logo Search packages:      
Sourcecode: qingy version File versions  Download package

crypto_libgcrypt.c

/***************************************************************************
                      crypto-libgcrypt.c  -  description
                            --------------------
    begin                : Nov 23 2005
    copyright            : (C) 2005 by Noberasco Michele
    e-mail               : michele.noberasco@tiscali.it
***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.              *
 *                                                                         *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <gcrypt.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "memmgmt.h"
#include "misc.h"
#include "qingy_constants.h"
#include "load_settings.h"
#include "logger.h"


#define CHECK1(x)                                                                         \
  error = x;                                                                              \
      if (error)                                                                              \
      {                                                                                       \
            WRITELOG(ERROR, "Failure: %s/%s\n", gcry_strsource (error), gcry_strerror (error)); \
            sleep(2);                                                                             \
            exit(EXIT_FAILURE);                                                                                                                       \
      }

#define CHECK2(x)                                                                 \
      x;                                                                              \
      if (!temp)                                                                      \
      {                                                                               \
            writelog(ERROR, "Something is wrong with your libgcrypt!\n"); \
            sleep(2);                                                                     \
            exit(EXIT_FAILURE);                                                           \
      }

#define CHECK3(x)                                                                         \
  error = x;                                                                              \
      if (error)                                                                              \
      {                                                                                       \
            if (!exit_on_failure) return 0;                                                       \
            WRITELOG(ERROR, "Failure: %s/%s\n", gcry_strsource (error), gcry_strerror (error));  \
            sleep(2);                                                                             \
            exit(EXIT_FAILURE);                                                                                                                       \
      }

#define CHECK4(x)         \
      temp = x;               \
      if (!temp) return 0;    \
      buflen = temp-filebuf;  



static gcry_sexp_t *public_key       = NULL;
static gcry_sexp_t *private_key      = NULL;
static char        *public_key_file  = NULL;
static char        *private_key_file = NULL;


void set_key_files(char *path)
{
      if (!path) path = datadir;

      public_key_file  = StrApp((char**)NULL, path, "public_key",  (char*)NULL);
      private_key_file = StrApp((char**)NULL, path, "private_key", (char*)NULL);
}

static void dump_data(FILE *fp, char *tagname, char *buf, size_t len)
{
      size_t written;

      if (!tagname) return;

      /* fp is assumed to be a FILE pointer, pointing to an open (for writing) file */

      fprintf(fp, "<%s>", tagname);
      written = fwrite(buf, sizeof(char), len, fp);
      if (written != len)
      {
            writelog(ERROR, "Error writing public key to file\n");
            sleep(2);
            exit(EXIT_FAILURE);
      }
      fprintf(fp, "</%s>\n", tagname);
}

static char *find_token(char *haystack, char *needle, size_t haystack_size)
{
      int     i=0;
      size_t  needle_length;
      int     my_limit;
      char   *my_haystack;

      if (!haystack)      return NULL;
      if (!needle)        return NULL;
      if (!haystack_size) return NULL;

      needle_length = strlen(needle);
      my_limit      = haystack_size-needle_length;
      my_haystack   = haystack;

      for (; i<my_limit; i++)
      {
            if (!strncmp(my_haystack, needle, needle_length))
                  return my_haystack;

            my_haystack++;
      }

      return NULL;
}

static char *find_item(FILE *fp, char *begin_tag, char *end_tag, size_t *token_length)
{
      char    buf[255];
      size_t  len1;
      size_t  len2;
      size_t  len  = 0;
      char   *pos1 = NULL;
      char   *pos2 = NULL;
      char   *retval;
      int     c;

      if (!fp)        return NULL;
      if (!begin_tag) return NULL;
      if (!end_tag)   return NULL;

      len1 = strlen(begin_tag);
      len2 = strlen(end_tag);

      while ( (c=fgetc(fp)) != EOF )
      {
            buf[len++] = (char)c;
            
            if (!pos2 && len >= len2)
            {
                  char *temp = buf + len - len2;
                  if (!strncmp(temp, end_tag, len2))
                  {
                        pos2 = temp;
                        break;
                  }
            }

            if (!pos1 && len >= len1)
            {
                  char *temp = buf + len - len1;
                  if (!strncmp(temp, begin_tag, len1))
                  {
                        pos1 = temp;
                  }
            }           
            
      }

      if (!pos1 || !pos2)
            return NULL;

      pos1 += len1;
      len   = pos2-pos1;

      *token_length = len;
      retval = (char*)calloc(len,sizeof(char));

      memcpy(retval, pos1, len);

      return retval;
}

void encrypt_item(FILE *fp, char *item)
{
      gcry_error_t error;
      gcry_sexp_t *temp;
      gcry_sexp_t *encrypted;
      char        *buf;
      size_t       len;

      if (!fp)         return;
      if (!item)       return;
      if (!public_key) return;

      buf       = StrApp((char**)NULL,"(data(flags raw)(value \"", item, "\"))", (char*)NULL);
      len       = strlen(buf);
      temp      = (gcry_sexp_t *)calloc(1, sizeof(gcry_sexp_t));
      encrypted = (gcry_sexp_t *)calloc(1, sizeof(gcry_sexp_t));

      CHECK1(gcry_sexp_new(temp, buf, len, 1));
      CHECK1(gcry_pk_encrypt(encrypted, *temp, *public_key));

      gcry_sexp_release( *temp );
      free(buf);

      /* save encrypted data to file */

      /* first get a pointer to the raw encrypted data... */
      *temp = gcry_sexp_find_token (*encrypted, "a", sizeof(char));
      buf   = (char *)gcry_sexp_nth_data (*temp, 1, &len);

      /* ...then dump it to file */
      dump_data(fp, "item", buf, len);

      /* clean up */
      gcry_sexp_release( *encrypted );
      gcry_sexp_release( *temp      );
      free(encrypted);
      free(temp);
}

char *decrypt_item(FILE *fp)
{
      gcry_error_t   error;
      gcry_sexp_t   *encrypted;
      gcry_sexp_t   *decrypted;
      size_t         erroffset;
      char          *item = NULL;
      char          *temp;
      size_t         len_item;
      size_t         len_decitem;

      if (!private_key) return NULL;
      if (!fp)          return NULL;

      item = find_item(fp, "<item>", "</item>", &len_item);

      if (!item)
            return NULL;

      encrypted = (gcry_sexp_t *)calloc(1, sizeof(gcry_sexp_t));
      decrypted = (gcry_sexp_t *)calloc(1, sizeof(gcry_sexp_t));

      /* build an expression based on the raw encrypted item */
      CHECK1(gcry_sexp_build (encrypted, &erroffset, "(enc-val(rsa(a %b)))", len_item, item));
      free(item);

      /* decrypt the item */
      CHECK1(gcry_pk_decrypt (decrypted, *encrypted, *private_key));

      /* get a pointer to the raw decrypted data */
      temp = (char*)gcry_sexp_nth_data (*decrypted, 0, &len_decitem);

      /* almost there ;-) */
      item = (char*)calloc(len_decitem+1, sizeof(char));
      memcpy(item, temp, len_decitem);

      gcry_sexp_release( *encrypted );
      gcry_sexp_release( *decrypted );
      free(encrypted);
      free(decrypted);

      return item;
}

void save_public_key(FILE *fp)
{
      gcry_sexp_t *n;
      gcry_sexp_t *e;
      char        *temp;
      size_t       len;

      if (!fp)         return;
      if (!public_key) return;

      n = (gcry_sexp_t *)calloc(1, sizeof(gcry_sexp_t));
      e = (gcry_sexp_t *)calloc(1, sizeof(gcry_sexp_t));

      /* get public key modulus */
      *n = gcry_sexp_find_token (*public_key, "n", sizeof(char));

      /* get public key exponent */
      *e = gcry_sexp_find_token (*public_key, "e", sizeof(char));

      /* save public key modulus to file */
      CHECK2(temp = (char *)gcry_sexp_nth_data (*n, 1, &len));
      dump_data(fp, "modulus", temp, len);

      /* save public key exponent to file */
      CHECK2(temp = (char *)gcry_sexp_nth_data (*e, 1, &len));
      dump_data(fp, "exponent", temp, len);

      /* clean up */
      gcry_sexp_release( *n );
      gcry_sexp_release( *e );
      free(n);
      free(e);
}

static void save_private_key(FILE *fp)
{
      gcry_sexp_t *n;
      gcry_sexp_t *e;
      gcry_sexp_t *d;
      gcry_sexp_t *p;
      gcry_sexp_t *q;
      gcry_sexp_t *u;
      char        *temp;
      size_t       len;

      if (!fp)      return;
      if (!private_key) return;

      n = (gcry_sexp_t *)calloc(1, sizeof(gcry_sexp_t));
      e = (gcry_sexp_t *)calloc(1, sizeof(gcry_sexp_t));
      d = (gcry_sexp_t *)calloc(1, sizeof(gcry_sexp_t));
      p = (gcry_sexp_t *)calloc(1, sizeof(gcry_sexp_t));
      q = (gcry_sexp_t *)calloc(1, sizeof(gcry_sexp_t));
      u = (gcry_sexp_t *)calloc(1, sizeof(gcry_sexp_t));

      /* get the various private key components... */
      *n = gcry_sexp_find_token (*private_key, "n", sizeof(char));
      *e = gcry_sexp_find_token (*private_key, "e", sizeof(char));
      *d = gcry_sexp_find_token (*private_key, "d", sizeof(char));
      *p = gcry_sexp_find_token (*private_key, "p", sizeof(char));
      *q = gcry_sexp_find_token (*private_key, "q", sizeof(char));
      *u = gcry_sexp_find_token (*private_key, "u", sizeof(char));

      /* ...and save them to file */
      CHECK2(temp = (char *)gcry_sexp_nth_data (*n, 1, &len));
      dump_data(fp, "nn", temp, len);
      CHECK2(temp = (char *)gcry_sexp_nth_data (*e, 1, &len));
      dump_data(fp, "ee", temp, len);
      CHECK2(temp = (char *)gcry_sexp_nth_data (*d, 1, &len));
      dump_data(fp, "dd", temp, len);
      CHECK2(temp = (char *)gcry_sexp_nth_data (*p, 1, &len));
      dump_data(fp, "pp", temp, len);
      CHECK2(temp = (char *)gcry_sexp_nth_data (*q, 1, &len));
      dump_data(fp, "qq", temp, len);
      CHECK2(temp = (char *)gcry_sexp_nth_data (*u, 1, &len));
      dump_data(fp, "uu", temp, len);

      /* clean up */
      gcry_sexp_release( *n );
      gcry_sexp_release( *e );
      gcry_sexp_release( *d );
      gcry_sexp_release( *p );
      gcry_sexp_release( *q );
      gcry_sexp_release( *u );
      free(n);
      free(e);
      free(d);
      free(p);
      free(q);
      free(u);
}

static char *get_mpi_from_buf(gcry_mpi_t *mpi, char *tag, char *buf, size_t buflen, int exit_on_failure)
{
      gcry_error_t  error;
      char         *begin_tag = StrApp((char**)NULL, "<",  tag, ">", (char*)NULL);
      char         *end_tag   = StrApp((char**)NULL, "</", tag, ">", (char*)NULL);
      size_t        taglen    = strlen(begin_tag);
      char         *temp1     = find_token(buf,   begin_tag, buflen);
      char         *temp2     = find_token(temp1, end_tag,   buflen);
      size_t        nscanned;
      char         *temp;
      size_t        len;

      free(begin_tag);
      free(end_tag);

      if (!temp1 || !temp2) return NULL;

      len  = temp2-temp1-taglen;
      temp = (char *)calloc(len, sizeof(char));
      memcpy(temp, temp1+taglen, len);
      CHECK3(gcry_mpi_scan(mpi, GCRYMPI_FMT_STD, temp, len, &nscanned));
      free(temp);

      return temp2;
}

static int int_restore_public_key(FILE *fp, int exit_on_failure)
{
      gcry_error_t  error;
      char         *temp;
      gcry_mpi_t   *modulus_mpi  = (gcry_mpi_t *)calloc(1, sizeof(gcry_mpi_t));
      gcry_mpi_t   *exponent_mpi = (gcry_mpi_t *)calloc(1, sizeof(gcry_mpi_t));
      char          filebuf[255];
      size_t        buflen;
      size_t        erroff;

      if (!fp) return 0;

      if (public_key) free(public_key);
      public_key = (gcry_sexp_t *)calloc(1, sizeof(gcry_sexp_t));

      buflen=fread(filebuf, sizeof(char), 255, fp);
      if (!buflen)
      {
            if (!exit_on_failure) return 0;
            writelog(ERROR, "Failure: could not retrieve public key\n");
            sleep(3);
            exit(EXIT_FAILURE);
      }

      CHECK4(get_mpi_from_buf(modulus_mpi,  "modulus",  filebuf, buflen, exit_on_failure));
      CHECK4(get_mpi_from_buf(exponent_mpi, "exponent", temp,    buflen, exit_on_failure));

      CHECK3(gcry_sexp_build (public_key, &erroff, "(public-key(rsa(n %m)(e %m)))", *modulus_mpi, *exponent_mpi));

      gcry_mpi_release (*modulus_mpi);
      gcry_mpi_release (*exponent_mpi);

      free(modulus_mpi);
      free(exponent_mpi);

      return 1;
}

static int restore_private_key(FILE *fp)
{
      gcry_error_t  error;
      size_t        erroff;
      size_t        buflen;
      char          filebuf[1023];
      char         *temp;
      gcry_mpi_t   *n_mpi = (gcry_mpi_t *)calloc(1, sizeof(gcry_mpi_t));
      gcry_mpi_t   *e_mpi = (gcry_mpi_t *)calloc(1, sizeof(gcry_mpi_t));
      gcry_mpi_t   *d_mpi = (gcry_mpi_t *)calloc(1, sizeof(gcry_mpi_t));
      gcry_mpi_t   *p_mpi = (gcry_mpi_t *)calloc(1, sizeof(gcry_mpi_t));
      gcry_mpi_t   *q_mpi = (gcry_mpi_t *)calloc(1, sizeof(gcry_mpi_t));
      gcry_mpi_t   *u_mpi = (gcry_mpi_t *)calloc(1, sizeof(gcry_mpi_t));
      int           exit_on_failure = 0;

      if (!fp) return 0;

      if (private_key) free(private_key);
      private_key = (gcry_sexp_t *)calloc(1, sizeof(gcry_sexp_t));

      buflen=fread(filebuf, sizeof(char), 1023, fp);
      if (!buflen) return 0;

      CHECK4(get_mpi_from_buf(n_mpi, "nn", filebuf, buflen, exit_on_failure));
      CHECK4(get_mpi_from_buf(e_mpi, "ee", temp,    buflen, exit_on_failure));
      CHECK4(get_mpi_from_buf(d_mpi, "dd", temp,    buflen, exit_on_failure));
      CHECK4(get_mpi_from_buf(p_mpi, "pp", temp,    buflen, exit_on_failure));
      CHECK4(get_mpi_from_buf(q_mpi, "qq", temp,    buflen, exit_on_failure));
      CHECK4(get_mpi_from_buf(u_mpi, "uu", temp,    buflen, exit_on_failure));

      CHECK3(gcry_sexp_build (private_key, &erroff, "(private-key(rsa(n %m)(e %m)(d %m)(p %m)(q %m)(u %m)))", *n_mpi, *e_mpi, *d_mpi, *p_mpi, *q_mpi, *u_mpi));

      gcry_mpi_release (*n_mpi);
      gcry_mpi_release (*e_mpi);
      gcry_mpi_release (*d_mpi);
      gcry_mpi_release (*p_mpi);
      gcry_mpi_release (*q_mpi);
      gcry_mpi_release (*u_mpi);

      free(n_mpi);
      free(e_mpi);
      free(d_mpi);
      free(p_mpi);
      free(q_mpi);
      free(u_mpi);

      return 1;
}

void restore_public_key(FILE *fp)
{
      srand((unsigned int)time(NULL));
      gcry_check_version(NULL);
      gcry_control( GCRYCTL_INIT_SECMEM, 16384, 0 );

      int_restore_public_key(fp, 1);
}

static int restore_keys()
{
      FILE *fp = fopen(public_key_file, "r");

      /* restore public key... */
      if (!fp) return 0;
      if (!int_restore_public_key(fp, 0))
      {
            fclose(fp);
            return 0;
      }
      fclose(fp);

      /* restore private key... */
      fp = fopen(private_key_file, "r");
      if (!fp)
      {
            gcry_sexp_release( *public_key );
            free(public_key);
            return 0;
      }
      if (!restore_private_key(fp))
      {
            gcry_sexp_release( *public_key );
            free(public_key);
            fclose(fp);
            return 0;
      }
      fclose(fp);

      return 1;
}

int int_generate_keys(int try_to_restore, int fail_if_restore_fail)
{
      FILE         *fp;
      gcry_error_t  error;
      gcry_sexp_t  *parms    = calloc(1, sizeof(gcry_sexp_t));
      char         *buf      = "(genkey(rsa(nbits 4:1024)))";
      size_t        len      = strlen(buf);
      gcry_sexp_t  *keypair;

      /* try to load key pair from disc... */
      if (try_to_restore)
            if (restore_keys())
                  return 1;

      if (fail_if_restore_fail)
            return 0;

      /* ...otherwise we generate a new key pair and save it */
      keypair = (gcry_sexp_t *)calloc(1, sizeof(gcry_sexp_t));

      CHECK1(gcry_sexp_new(parms, buf, len, 1));
      error = 1;
      while (error)
      {
            error = gcry_pk_genkey(keypair, *parms);
            if (!error)
                  error = gcry_pk_testkey (*keypair);
      }
      gcry_sexp_release( *parms );
      free(parms);

      /* divide keypair into public and private keys */
      public_key   = (gcry_sexp_t *)calloc(1, sizeof(gcry_sexp_t));     
      *public_key  = gcry_sexp_find_token (*keypair, "public-key", strlen("public-key"));
      private_key  = (gcry_sexp_t *)calloc(1, sizeof(gcry_sexp_t));     
      *private_key = gcry_sexp_find_token (*keypair, "private-key", strlen("private-key"));
      gcry_sexp_release( *keypair );
      free(keypair);

      /* save public key to file */
      fp = fopen(public_key_file, "w");
      if (!fp)
      {
            WRITELOG(ERROR, "Could not open file %s to save public key!\n", public_key_file);
            sleep(2);
            exit(EXIT_FAILURE);
      }
      chmod(public_key_file, S_IRUSR|S_IWUSR); /* Fix file permissions */
      save_public_key(fp);
      fclose(fp);

      /* save private key to file */
      fp = fopen(private_key_file, "w");
      if (!fp)
      {
            WRITELOG(ERROR, "Could not open file %s to save private key!\n", private_key_file);
            sleep(2);
            exit(EXIT_FAILURE);
      }
      chmod(private_key_file, S_IRUSR|S_IWUSR); /* Fix file permissions */
      save_private_key(fp);
      fclose(fp);

      return 1;
}

int generate_keys()
{
      /* initialize stuff */
      srand((unsigned int)time(NULL));
      gcry_check_version(NULL);
      gcry_control( GCRYCTL_INIT_SECMEM, 16384, 0 );

      set_key_files(NULL);

      return int_generate_keys(1, 1);
}

void flush_keys()
{
      if (public_key)
      {
            gcry_sexp_release( *public_key );
            free (public_key);
            public_key = NULL;
      }
      if (private_key)
      {
            gcry_sexp_release( *private_key );
            free (private_key);
            private_key = NULL;
      }
}

Generated by  Doxygen 1.6.0   Back to index