completed crypt_rsa implementation (commented out GnuTLS for now)
authorpk910 <philipp@zoelle1.de>
Wed, 16 Jul 2014 21:16:08 +0000 (23:16 +0200)
committerpk910 <philipp@zoelle1.de>
Wed, 16 Jul 2014 21:16:08 +0000 (23:16 +0200)
src/crypt_rsa.c
src/crypt_rsa.h [new file with mode: 0644]

index 937cc2f99da33e70930f2d1a643ad30069502e0a..80450f1222cabb1a9b3b09ca84a5dd8fe4fd6cda 100644 (file)
  * You should have received a copy of the GNU General Public License 
  * along with this program. If not, see <http://www.gnu.org/licenses/>. 
  */
-
 #include "../config.h"
-struct crypt_rsa_pubkey;
-struct crypt_rsa_privkey;
+#include "crypt_rsa.h"
 
-static struct crypt_rsa_pubkey *crypt_load_pubkey(const char *key);
-static void crypt_unload_pubkey(struct crypt_rsa_pubkey *pubkey);
-static struct crypt_rsa_privkey *crypt_load_privkey(const char *key);
-static void crypt_unload_privkey(struct crypt_rsa_privkey *privkey);
+#include <stdio.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
 
-static void crypt_encrypt_data(struct crypt_rsa_pubkey *pubkey, const char *data, int datalen, char *encrypted);
-static void crypt_decrypt_data(struct crypt_rsa_privkey *privkey, const char *encrypted, int enclen, char *data);
-static int crypt_encrypt_maxlen(struct crypt_rsa_pubkey *pubkey);
-static void crypt_encrypt_free(char *encrypted);
-static void crypt_decrypt_free(char *data);
 
+int main(char *argv[], int argc) {
+       crypt_init();
+       
+       struct crypt_rsa_privkey *privkey;
+       FILE *fp;
+       if(fp = fopen("privkey.pem", "r")) {
+               char buffer[4096];
+               fread(buffer, sizeof(buffer), 1, fp);
+               fclose(fp);
+               
+               privkey = crypt_load_privkey(buffer);
+       } else {
+               privkey = crypt_generate_privkey(2048);
+               
+               fp = fopen("privkey.pem", "w");
+               char *buffer = crypt_export_privkey(privkey, 0);
+               fprintf(fp, "%s", buffer);
+               free(buffer);
+               fclose(fp);
+       }
+       
+       struct crypt_rsa_pubkey *pubkey = crypt_get_pubkey(privkey);
+       char plain[] = "Test String!!!";
+       char *crypted = NULL;
+       int len = crypt_encrypt_data(pubkey, plain, sizeof(plain), &crypted);
+       
+       printf("Crypt Len: %d\n", len);
+       printf("Crypt: ");
+       int i;
+       for(i = 0; i < len; i++) {
+               printf(" %02X", ((unsigned int)crypted[i] & 0xFF));
+       }
+       printf("\n");
+       
+       char *decrypted = NULL;
+       len = crypt_decrypt_data(privkey, crypted, len, &decrypted);
+       printf("Decrypt Len: %d\n", len);
+       printf("Decrypt: %s\n", decrypted);
+}
 
 
 
+/*
+// GnuTLS Backend not working because of gnutls_pubkey_encrypt_data doesn't exists prior to GnuTLS 3.0
+// still searching for a replacement...
 
 #if defined(HAVE_GNUTLS_GNUTLS_H)
 #include <gnutls/gnutls.h>
@@ -44,16 +79,24 @@ struct crypt_rsa_pubkey {
        unsigned int free_pubkey : 1;
        gnutls_x509_crt_t crt;
        gnutls_pubkey_t pubkey;
-}
+};
 
 struct crypt_rsa_privkey {
        unsigned int free_key : 1;
        unsigned int free_privkey : 1;
        gnutls_x509_privkey_t key;
        gnutls_privkey_t privkey;
+};
+
+void crypt_rsa_init() {
+       gnutls_global_init();
 }
 
-static struct crypt_rsa_pubkey *crypt_load_pubkey(const char *key) {
+void crypt_rsa_deinit() {
+       gnutls_global_deinit();
+}
+
+struct crypt_rsa_pubkey *crypt_rsa_load_pubkey(const char *key) {
        struct crypt_rsa_pubkey *pubkey = calloc(1, sizeof(*pubkey));
        int ret;
        const gnutls_datum_t key_dat = {(void *)key, strlen(key)};
@@ -63,68 +106,150 @@ static struct crypt_rsa_pubkey *crypt_load_pubkey(const char *key) {
        
        ret = gnutls_x509_crt_init(&pubkey->crt);
        if(ret < 0)
-               goto crypt_load_pubkey_fail;
+               goto crypt_rsa_load_pubkey_fail;
        pubkey->free_crt = 1;
        
        ret = gnutls_x509_crt_import(pubkey->crt, &key_dat, GNUTLS_X509_FMT_PEM);
        if (ret < 0)
-               goto crypt_load_pubkey_fail;
+               goto crypt_rsa_load_pubkey_fail;
        
-       ret = gnutls_pubkey_init(&pubkey.pubkey);
+       ret = gnutls_pubkey_init(&pubkey->pubkey);
        if(ret < 0)
-               goto crypt_load_pubkey_fail;
+               goto crypt_rsa_load_pubkey_fail;
        pubkey->free_pubkey = 1;
        
        ret = gnutls_pubkey_import_x509(pubkey->pubkey, pubkey->crt, 0);
        if(ret < 0)
-               goto crypt_load_pubkey_fail;
+               goto crypt_rsa_load_pubkey_fail;
        
        return pubkey;
-       crypt_load_pubkey_fail:
-       crypt_unload_pubkey(pubkey);
+       crypt_rsa_load_pubkey_fail:
+       crypt_rsa_unload_pubkey(pubkey);
        return NULL;
 }
 
-static void crypt_unload_pubkey(struct crypt_rsa_pubkey *pubkey) {
-       if(pubkey->free_key)
+void crypt_rsa_unload_pubkey(struct crypt_rsa_pubkey *pubkey) {
+       if(pubkey->free_crt)
                gnutls_x509_crt_deinit(pubkey->crt);
-       if(pubkey->free_privkey)
+       if(pubkey->free_pubkey)
                gnutls_pubkey_deinit(pubkey->pubkey);
        free(pubkey);
 }
 
-static struct crypt_rsa_privkey *crypt_load_privkey(const char *key) {
+char *crypt_rsa_export_pubkey(struct crypt_rsa_pubkey *pubkey) {
+       size_t size = 1024;
+       char *buffer = malloc(size);
+       int ret;
+       
+       ret = gnutls_pubkey_export(pubkey->pubkey, GNUTLS_X509_FMT_PEM, buffer, &size);
+       if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
+               buffer = realloc(buffer, size);
+               ret = gnutls_pubkey_export(pubkey->pubkey, GNUTLS_X509_FMT_PEM, buffer, &size);
+       }
+       if(ret < 0) {
+               free(buffer);
+               return NULL;
+       }
+       return buffer;
+}
+
+struct crypt_rsa_privkey *crypt_rsa_load_privkey(const char *key) {
        struct crypt_rsa_privkey *privkey = calloc(1, sizeof(*privkey));
        int ret;
        
        const gnutls_datum_t key_dat = {(void *)key, strlen(key)};
-       privkey.valid = 0;
        
        ret = gnutls_x509_privkey_init(&privkey->key);
        if(ret < 0)
-               goto crypt_load_privkey_fail;
+               goto crypt_rsa_load_privkey_fail;
        privkey->free_key = 1;
        
        ret = gnutls_x509_privkey_import(privkey->key, &key_dat, GNUTLS_X509_FMT_PEM);
        if (ret < 0)
-               goto crypt_load_privkey_fail;
+               goto crypt_rsa_load_privkey_fail;
        
-       ret = gnutls_privkey_init(&privkey.privkey);
+       ret = gnutls_privkey_init(&privkey->privkey);
        if(ret < 0)
-               goto crypt_load_privkey_fail;
+               goto crypt_rsa_load_privkey_fail;
        privkey->free_privkey = 1;
        
        ret = gnutls_privkey_import_x509(privkey->privkey, privkey->key, 0);
        if(ret < 0)
-               goto crypt_load_privkey_fail;
+               goto crypt_rsa_load_privkey_fail;
        
        return privkey;
-       crypt_load_privkey_fail:
-       crypt_unload_privkey(privkey);
+       crypt_rsa_load_privkey_fail:
+       crypt_rsa_unload_privkey(privkey);
        return NULL;
 }
 
-static void crypt_unload_privkey(struct crypt_rsa_privkey *privkey) {
+struct crypt_rsa_privkey *crypt_rsa_generate_privkey(const int keysize) {
+       struct crypt_rsa_privkey *privkey = calloc(1, sizeof(*privkey));
+       int ret;
+       
+       ret = gnutls_x509_privkey_init(&privkey->key);
+       if(ret < 0)
+               goto crypt_rsa_generate_privkey_fail;
+       privkey->free_key = 1;
+       
+       ret = gnutls_x509_privkey_generate(privkey->key, GNUTLS_PK_RSA, keysize, 0);
+       if (ret < 0)
+               goto crypt_rsa_generate_privkey_fail;
+       
+       ret = gnutls_privkey_init(&privkey->privkey);
+       if(ret < 0)
+               goto crypt_rsa_generate_privkey_fail;
+       privkey->free_privkey = 1;
+       
+       ret = gnutls_privkey_import_x509(privkey->privkey, privkey->key, 0);
+       if(ret < 0)
+               goto crypt_rsa_generate_privkey_fail;
+       
+       return privkey;
+       crypt_rsa_generate_privkey_fail:
+       crypt_rsa_unload_privkey(privkey);
+       return NULL;
+}
+
+char *crypt_rsa_export_privkey(struct crypt_rsa_privkey *privkey, int pubkey) {
+       size_t size = 1024;
+       char *buffer = malloc(size);
+       int ret;
+       
+       if(pubkey) {
+               gnutls_pubkey_t pkey;
+               ret = gnutls_pubkey_init(&pkey);
+               if(ret < 0) {
+                       free(buffer);
+                       return NULL;
+               }
+               ret = gnutls_pubkey_import_privkey(pkey, privkey->privkey, GNUTLS_KEY_KEY_ENCIPHERMENT | GNUTLS_KEY_DIGITAL_SIGNATURE, 0);
+               if(ret < 0) {
+                       free(buffer);
+                       gnutls_pubkey_deinit(pkey);
+                       return NULL;
+               }
+               ret = gnutls_pubkey_export(pkey, GNUTLS_X509_FMT_PEM, buffer, &size);
+               if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
+                       buffer = realloc(buffer, size);
+                       ret = gnutls_pubkey_export(pkey, GNUTLS_X509_FMT_PEM, buffer, &size);
+               }
+               gnutls_pubkey_deinit(pkey);
+       } else {
+               ret = gnutls_x509_privkey_export(privkey->key, GNUTLS_X509_FMT_PEM, buffer, &size);
+               if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
+                       buffer = realloc(buffer, size);
+                       ret = gnutls_x509_privkey_export(privkey->key, GNUTLS_X509_FMT_PEM, buffer, &size);
+               }
+       }
+       if(ret < 0) {
+               free(buffer);
+               return NULL;
+       }
+       return buffer;
+}
+
+void crypt_rsa_unload_privkey(struct crypt_rsa_privkey *privkey) {
        if(privkey->free_key)
                gnutls_x509_privkey_deinit(privkey->key);
        if(privkey->free_privkey)
@@ -132,29 +257,69 @@ static void crypt_unload_privkey(struct crypt_rsa_privkey *privkey) {
        free(privkey);
 }
 
+struct crypt_rsa_pubkey *crypt_rsa_get_pubkey(struct crypt_rsa_privkey *privkey) {
+       struct crypt_rsa_pubkey *pubkey = calloc(1, sizeof(*pubkey));
+       if(!pubkey)
+               return NULL;
+       int ret;
+       
+       ret = gnutls_pubkey_init(&pubkey->pubkey);
+       if(ret < 0)
+               goto crypt_rsa_get_pubkey_fail;
+       pubkey->free_pubkey = 1;
+       
+       ret = gnutls_pubkey_import_privkey(pubkey->pubkey, privkey->privkey, GNUTLS_KEY_KEY_ENCIPHERMENT | GNUTLS_KEY_DIGITAL_SIGNATURE, 0);
+       if(ret < 0)
+               goto crypt_rsa_get_pubkey_fail;
+       
+       return pubkey;
+       crypt_rsa_get_pubkey_fail:
+       crypt_rsa_unload_pubkey(pubkey);
+       return NULL;
+}
 
-static void crypt_encrypt_data(struct crypt_rsa_pubkey *pubkey, const char *data, int datalen, char *encrypted) {
+int crypt_rsa_encrypt_data(struct crypt_rsa_pubkey *pubkey, const char *data, int datalen, char **encrypted) {
+       const gnutls_datum_t data_dat = {(void *)data, datalen};
+       gnutls_datum_t out;
        
+       int ret = gnutls_pubkey_encrypt_data(pubkey->pubkey, 0, &data_dat, &out);
+       if(ret < 0)
+               return ret;
+       
+       *encrypted = out.data;
+       return out.size;
 }
 
-static void crypt_decrypt_data(struct crypt_rsa_privkey *privkey, const char *encrypted, int enclen, char *data) {
+int crypt_rsa_decrypt_data(struct crypt_rsa_privkey *privkey, const char *encrypted, int enclen, char **data) {
+       const gnutls_datum_t enc_dat = {(void *)encrypted, enclen};
+       gnutls_datum_t out;
+       
+       int ret = gnutls_privkey_decrypt_data(privkey->privkey, 0, &enc_dat, &out);
+       if(ret < 0)
+               return ret;
        
+       *data = out.data;
+       return out.size;
 }
 
-static int crypt_encrypt_maxlen(struct crypt_rsa_pubkey *pubkey) {
-       int size = (pubkey->pubkey->bits / 8) - 12;
+int crypt_rsa_encrypt_maxlen(struct crypt_rsa_pubkey *pubkey) {
+       //int size = (pubkey->pubkey->bits / 8) - 12;
+       //todo!
+       int size = 1024;
        return size;
 }
 
-static void crypt_encrypt_free(char *encrypted) {
-       
+void crypt_rsa_encrypt_free(char *encrypted) {
+       gnutls_free(encrypted);
 }
 
-static void crypt_decrypt_free(char *data) {
-       
+void crypt_rsa_decrypt_free(char *data) {
+       gnutls_free(data);
 }
 
 #elif defined(HAVE_OPENSSL_SSL_H)
+*/
+
 #include <openssl/pem.h>
 #include <openssl/ssl.h>
 #include <openssl/rsa.h>
@@ -164,13 +329,21 @@ static void crypt_decrypt_free(char *data) {
 
 struct crypt_rsa_pubkey {
        RSA *rsa;
-}
+};
 
 struct crypt_rsa_privkey {
        RSA *rsa;
+};
+
+void crypt_rsa_init() {
+       
+}
+
+void crypt_rsa_deinit() {
+       
 }
 
-static RSA *createRSA(unsigned char *key, int public) {
+RSA *createRSA(unsigned char *key, int public) {
     RSA *rsa= NULL;
     BIO *keybio ;
     keybio = BIO_new_mem_buf(key, -1);
@@ -184,12 +357,12 @@ static RSA *createRSA(unsigned char *key, int public) {
     return rsa;
 }
 
-static struct crypt_rsa_pubkey *crypt_load_pubkey(const char *key) {
+struct crypt_rsa_pubkey *crypt_rsa_load_pubkey(const char *key) {
        struct crypt_rsa_pubkey *pubkey = calloc(1, sizeof(*pubkey));
        if(!pubkey)
                return NULL;
        
-       RSA *rsa = createRSA((unsigned char) key, 1);
+       RSA *rsa = createRSA((unsigned char *) key, 1);
        
        if(!rsa) {
                free(pubkey);
@@ -200,17 +373,29 @@ static struct crypt_rsa_pubkey *crypt_load_pubkey(const char *key) {
        return pubkey;
 }
 
-static void crypt_unload_pubkey(struct crypt_rsa_pubkey *pubkey) {
+void crypt_rsa_unload_pubkey(struct crypt_rsa_pubkey *pubkey) {
        RSA_free(pubkey->rsa);
        free(pubkey);
 }
 
-static struct crypt_rsa_privkey *crypt_load_privkey(const char *key) {
-       struct crypt_rsa_pubkey *privkey = calloc(1, sizeof(*pubkey));
+char *crypt_rsa_export_pubkey(struct crypt_rsa_pubkey *pubkey) {
+       BIO *bio = BIO_new(BIO_s_mem());
+       PEM_write_bio_RSA_PUBKEY(bio, pubkey->rsa);
+       
+       int keylen = BIO_pending(bio);
+       char *key = calloc(1, keylen+1);
+       BIO_read(bio, key, keylen);
+       
+       BIO_free_all(bio);
+       return key;
+}
+
+struct crypt_rsa_privkey *crypt_rsa_load_privkey(const char *key) {
+       struct crypt_rsa_privkey *privkey = calloc(1, sizeof(*privkey));
        if(!privkey)
                return NULL;
        
-       RSA *rsa = createRSA((unsigned char) key, 0);
+       RSA *rsa = createRSA((unsigned char *) key, 0);
        
        if(!rsa) {
                free(privkey);
@@ -221,15 +406,62 @@ static struct crypt_rsa_privkey *crypt_load_privkey(const char *key) {
        return privkey;
 }
 
-static void crypt_unload_pubkey(struct crypt_rsa_privkey *privkey) {
+struct crypt_rsa_privkey *crypt_rsa_generate_privkey(const int keysize) {
+       struct crypt_rsa_privkey *privkey = calloc(1, sizeof(*privkey));
+       if(!privkey)
+               return NULL;
+               
+       BIGNUM *e = BN_new();
+       RSA *rsa = RSA_new();
+       
+       BN_set_word(e, 65537);
+       if (!RSA_generate_key_ex(rsa, keysize, e, NULL)) {
+               BN_free(e);
+               RSA_free(rsa);
+               free(privkey);
+               return NULL;
+       }
+       
+       privkey->rsa = rsa;
+       return privkey;
+}
+
+char *crypt_rsa_export_privkey(struct crypt_rsa_privkey *privkey, int pubkey) {
+       BIO *bio = BIO_new(BIO_s_mem());
+       if(pubkey)
+               PEM_write_bio_RSA_PUBKEY(bio, privkey->rsa);
+       else
+               PEM_write_bio_RSAPrivateKey(bio, privkey->rsa, NULL, NULL, 0, NULL, NULL);
+       
+       int keylen = BIO_pending(bio);
+       char *key = calloc(1, keylen+1);
+       BIO_read(bio, key, keylen);
+       
+       BIO_free_all(bio);
+       return key;
+}
+
+void crypt_rsa_unload_privkey(struct crypt_rsa_privkey *privkey) {
        RSA_free(privkey->rsa);
        free(privkey);
 }
 
-static int crypt_encrypt_data(struct crypt_rsa_pubkey *pubkey, const char *data, int datalen, char **encrypted) {
+struct crypt_rsa_pubkey *crypt_rsa_get_pubkey(struct crypt_rsa_privkey *privkey) {
+       struct crypt_rsa_pubkey *pubkey = calloc(1, sizeof(*pubkey));
+       if(!pubkey)
+               return NULL;
+       
+       RSA *rsa = RSA_new();
+       memcpy(rsa, privkey->rsa, sizeof(*rsa));
+       
+       pubkey->rsa = rsa;
+       return pubkey;
+}
+
+int crypt_rsa_encrypt_data(struct crypt_rsa_pubkey *pubkey, const char *data, int datalen, char **encrypted) {
        if(!pubkey)
                return 0;
-       if(datalen > crypt_encrypt_maxlen(pubkey))
+       if(datalen > crypt_rsa_encrypt_maxlen(pubkey))
                return 0;
        *encrypted = malloc(RSA_size(pubkey->rsa));
        if(!*encrypted)
@@ -240,7 +472,7 @@ static int crypt_encrypt_data(struct crypt_rsa_pubkey *pubkey, const char *data,
        return ret;
 }
 
-static int crypt_decrypt_data(struct crypt_rsa_pubkey *privkey, const char *encrypted, int enclen, char **data) {
+int crypt_rsa_decrypt_data(struct crypt_rsa_privkey *privkey, const char *encrypted, int enclen, char **data) {
        if(!privkey)
                return 0;
        if(enclen > RSA_size(privkey->rsa))
@@ -254,16 +486,16 @@ static int crypt_decrypt_data(struct crypt_rsa_pubkey *privkey, const char *encr
        return ret;
 }
 
-static int crypt_encrypt_maxlen(struct crypt_rsa_pubkey *pubkey) {
+int crypt_rsa_encrypt_maxlen(struct crypt_rsa_pubkey *pubkey) {
        return RSA_size(pubkey->rsa) - 12;
 }
 
-static void crypt_encrypt_free(char *encrypted) {
+void crypt_rsa_encrypt_free(char *encrypted) {
        free(encrypted);
 }
 
-static void crypt_decrypt_free(char *data) {
+void crypt_rsa_decrypt_free(char *data) {
        free(data);
 }
 
-#endif
+//#endif
diff --git a/src/crypt_rsa.h b/src/crypt_rsa.h
new file mode 100644 (file)
index 0000000..7e72176
--- /dev/null
@@ -0,0 +1,42 @@
+/* crypt_rsa.h - NextIRCd
+ * Copyright (C) 2012-2013  Philipp Kreil (pk910)
+ * 
+ * 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 3 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, see <http://www.gnu.org/licenses/>. 
+ */
+
+#ifndef _crypt_rsa_h
+#define _crypt_rsa_h
+
+struct crypt_rsa_pubkey;
+struct crypt_rsa_privkey;
+
+void crypt_init();
+void crypt_deinit();
+
+struct crypt_rsa_pubkey *crypt_rsa_load_pubkey(const char *key);
+void crypt_rsa_unload_pubkey(struct crypt_rsa_pubkey *pubkey);
+char *crypt_rsa_export_pubkey(struct crypt_rsa_pubkey *privkey);
+struct crypt_rsa_privkey *crypt_rsa_load_privkey(const char *key);
+struct crypt_rsa_privkey *crypt_rsa_generate_privkey(const int keysize);
+void crypt_rsa_unload_privkey(struct crypt_rsa_privkey *privkey);
+char *crypt_rsa_export_privkey(struct crypt_rsa_privkey *privkey, int pubkey);
+struct crypt_rsa_pubkey *crypt_rsa_get_pubkey(struct crypt_rsa_privkey *privkey);
+
+int crypt_rsa_encrypt_data(struct crypt_rsa_pubkey *pubkey, const char *data, int datalen, char **encrypted);
+int crypt_rsa_decrypt_data(struct crypt_rsa_privkey *privkey, const char *encrypted, int enclen, char **data);
+int crypt_rsa_encrypt_maxlen(struct crypt_rsa_pubkey *pubkey);
+void crypt_rsa_encrypt_free(char *encrypted);
+void crypt_rsa_decrypt_free(char *data);
+
+#endif