From b35aaec684eb339a08b47be1f8d56e9f8e241539 Mon Sep 17 00:00:00 2001 From: pk910 Date: Wed, 16 Jul 2014 23:16:08 +0200 Subject: [PATCH] completed crypt_rsa implementation (commented out GnuTLS for now) --- src/crypt_rsa.c | 348 ++++++++++++++++++++++++++++++++++++++++-------- src/crypt_rsa.h | 42 ++++++ 2 files changed, 332 insertions(+), 58 deletions(-) create mode 100644 src/crypt_rsa.h diff --git a/src/crypt_rsa.c b/src/crypt_rsa.c index 937cc2f..80450f1 100644 --- a/src/crypt_rsa.c +++ b/src/crypt_rsa.c @@ -14,25 +14,60 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - #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 +#include +#include +#include -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 @@ -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 #include #include @@ -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 index 0000000..7e72176 --- /dev/null +++ b/src/crypt_rsa.h @@ -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 . + */ + +#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 -- 2.20.1