From 1bb2a9d33e8cd193c21f9995fb7852c7562cafcf Mon Sep 17 00:00:00 2001 From: Simeon Simeonov Date: Tue, 27 Feb 2018 21:52:12 +0100 Subject: First prototype --- libsylph/ssl.c | 377 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 377 insertions(+) (limited to 'libsylph/ssl.c') diff --git a/libsylph/ssl.c b/libsylph/ssl.c index 8413925..5a76b8b 100644 --- a/libsylph/ssl.c +++ b/libsylph/ssl.c @@ -32,6 +32,11 @@ #include "ssl.h" #include "ssl_hostname_validation.h" +#define SALT_SIZE 16 +#define CIPHER EVP_aes_256_cfb() +#define KEY_HASH EVP_sha256() +#define DIGEST_HASH EVP_sha256() + static SSL_CTX *ssl_ctx_SSLv23 = NULL; static SSL_CTX *ssl_ctx_TLSv1 = NULL; @@ -402,4 +407,376 @@ void ssl_set_verify_func(SSLVerifyFunc func) verify_ui_func = func; } +/* master password related functions */ +static gint secure_derive_key(guchar *key, + gint length_key, + const gchar *passphrase, + const guchar *salt) { + + guint length_buffer, length_hash; + guchar *buffer, *ptr_hash; + + EVP_MD_CTX *mdctx; + + OPENSSL_cleanse(key, length_key); + + length_buffer = SALT_SIZE + strlen(passphrase); + buffer = OPENSSL_malloc(length_buffer); + OPENSSL_cleanse(buffer, length_buffer); + + memcpy(buffer, salt, SALT_SIZE); + memcpy(buffer + SALT_SIZE, passphrase, strlen(passphrase)); + + mdctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(mdctx, KEY_HASH, NULL); + EVP_DigestUpdate(mdctx, buffer, length_buffer); + OPENSSL_cleanse(buffer, length_buffer); + + ptr_hash = OPENSSL_malloc(EVP_MD_size(KEY_HASH)); + EVP_DigestFinal_ex(mdctx, ptr_hash, &length_hash); + + memcpy(key, + ptr_hash, + (length_hash > length_key) ? length_key : length_hash); + + OPENSSL_cleanse(ptr_hash, length_hash); + OPENSSL_free(ptr_hash); + OPENSSL_free(buffer); + EVP_MD_CTX_destroy(mdctx); + + return RC_OK; + +} + + +gint encrypt_data(gchar **encrypted, + gint *length_encrypted, + const gchar *data, + const gchar *passphrase, + gint length_data, + guint min_data_length, + gboolean rnd_salt) { + + gint crypt_buffer_cnt, rc; + guint key_size, length_hash; + guint length_cleartext, length_ciphertext, length_total; + guchar salt[SALT_SIZE]; + guchar *ciphertext_buffer, *total_buffer; + /* sensitive buffers and counters */ + guint length_data_payload, length_padding; + gchar str_data_size[3]; + guchar *data_payload_buffer, *hash_buffer, *padding_buffer, *key; + guchar *cleartext_buffer; + + EVP_CIPHER_CTX *ctx; + EVP_MD_CTX *mdctx; + + rc = RC_ERROR; + + if (length_data < 1) { + return -1; + } + if (rnd_salt) { + if (RAND_bytes(salt, SALT_SIZE) != 1) { + debug_print("Random problems...\n"); + goto cleanup; + } + } else { + strncpy((gchar *)salt, "FOR TESTING ONLY", SALT_SIZE); + } + + key_size = EVP_CIPHER_key_length(CIPHER); + key = OPENSSL_malloc(key_size); + OPENSSL_cleanse(key, key_size); + if (secure_derive_key(key, + key_size, + passphrase, + salt) != RC_OK) { + OPENSSL_cleanse(key, key_size); + debug_print("Could not generate secure key\n"); + goto cleanup; + } + + /* prepare the data-buffer */ + length_padding = 0; + if (length_data < min_data_length) { + g_snprintf(str_data_size, 3, "%02d", length_data); + length_padding = min_data_length - length_data; + padding_buffer = OPENSSL_malloc(length_padding); + OPENSSL_cleanse(padding_buffer, length_padding); + if (RAND_bytes(padding_buffer, length_padding) != 1) { + debug_print("Random problems...\n"); + goto cleanup; + } + } else { + g_snprintf(str_data_size, 3, "-1"); + } + + length_data_payload = 2 + length_data + length_padding; + data_payload_buffer = OPENSSL_malloc(length_data_payload); + OPENSSL_cleanse(data_payload_buffer, length_data_payload); + + memcpy(data_payload_buffer, str_data_size, 2); + memcpy(data_payload_buffer + 2, data, length_data); + if (length_padding > 0) { + memcpy(data_payload_buffer + (2 + length_data), + padding_buffer, + length_padding); + } + + mdctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(mdctx, DIGEST_HASH, NULL); + EVP_DigestUpdate(mdctx, data_payload_buffer, length_data_payload); + + length_hash = EVP_MD_size(DIGEST_HASH); + hash_buffer = OPENSSL_malloc(length_hash); + OPENSSL_cleanse(hash_buffer, length_hash); + EVP_DigestFinal_ex(mdctx, hash_buffer, NULL); + + length_cleartext = length_hash + length_data_payload; + + cleartext_buffer = OPENSSL_malloc(length_cleartext); + OPENSSL_cleanse(cleartext_buffer, length_cleartext); + + /* assemble cleartext-buffer */ + memcpy(cleartext_buffer, hash_buffer, length_hash); + memcpy(cleartext_buffer + length_hash, + data_payload_buffer, + length_data_payload); + OPENSSL_cleanse(data_payload_buffer, length_data_payload); /* sensitive */ + + /* encryption */ + if (!(ctx = EVP_CIPHER_CTX_new())) { + debug_print("New ctx failed\n"); + goto cleanup; + } + + length_ciphertext = 0; + if (EVP_EncryptInit_ex(ctx, CIPHER, NULL, key, salt) != 1) { + debug_print("EVP_EncryptInit_ex failed\n"); + goto cleanup; + } + + ciphertext_buffer = OPENSSL_malloc(length_cleartext); + + crypt_buffer_cnt = 0; + while(1) { + if (EVP_EncryptUpdate(ctx, + ciphertext_buffer + length_ciphertext, + &crypt_buffer_cnt, + cleartext_buffer + length_ciphertext, + 1) != 1) { /* one byte at a time */ + debug_print("EVP_EncryptUpdate failed\n"); + goto cleanup; + } + + if (crypt_buffer_cnt != 1) { /* paranoia */ + debug_print("The sizes of enc and dec text do not correspond\n"); + goto cleanup; + } + + ++length_ciphertext; + + if (length_ciphertext >= length_cleartext) { + break; + } + } + /* No padding required for the CFB mode */ + + OPENSSL_cleanse(cleartext_buffer, length_cleartext); /* sensitive */ + length_total = SALT_SIZE + length_ciphertext; + total_buffer = OPENSSL_malloc(length_total); + + memcpy(total_buffer, salt, SALT_SIZE); + memcpy(total_buffer + SALT_SIZE, ciphertext_buffer, length_ciphertext); + + *encrypted = g_base64_encode(total_buffer, length_total); + *length_encrypted = strlen(*encrypted); + + rc = RC_OK; + +cleanup: + /* key */ + OPENSSL_cleanse(key, key_size); + OPENSSL_free(key); + /* cleartext buffer */ + OPENSSL_cleanse(cleartext_buffer, length_cleartext); + OPENSSL_free(cleartext_buffer); + /* payload buffer */ + OPENSSL_cleanse(data_payload_buffer, length_data_payload); + OPENSSL_free(data_payload_buffer); + /* hash */ + OPENSSL_cleanse(hash_buffer, length_hash); + OPENSSL_free(hash_buffer); + /* padding */ + if (length_padding > 0) { + OPENSSL_cleanse(padding_buffer, length_padding); + OPENSSL_free(padding_buffer); + } + + OPENSSL_cleanse(str_data_size, 3); /* paranoia */ + + /* ciphertext buffer */ + OPENSSL_free(ciphertext_buffer); + + /* total buffer */ + OPENSSL_free(total_buffer); + + length_data_payload = 0; + length_padding = 0; + + EVP_CIPHER_CTX_free(ctx); + EVP_MD_CTX_destroy(mdctx); + + return rc; + +} + + +gint decrypt_data(gchar **decrypted, + const gchar *data, + const gchar *passphrase, + gint length_data) { + + gint rc; /* return code */ + gint decrypt_buffer_cnt, length_ciphertext, length_decrypted; + guint key_size, length_hash, length_cleartext; + gsize length_total; + guchar salt[SALT_SIZE]; + guchar *ciphertext_buffer, *total_buffer; + /* sensitive buffers and counters */ + gint data_size; + guint length_data_payload; + gchar str_data_size[3]; + guchar *data_payload_buffer, *hash_buffer, *key; + guchar *cleartext_buffer; + + EVP_CIPHER_CTX *ctx; + EVP_MD_CTX *mdctx; + + rc = -1; + + if (length_data < 1) { + return -1; + } + + total_buffer = g_base64_decode(data, &length_total); + length_ciphertext = length_total - SALT_SIZE; + ciphertext_buffer = OPENSSL_malloc(length_ciphertext); + OPENSSL_cleanse(ciphertext_buffer, length_ciphertext); + + memcpy(salt, total_buffer, SALT_SIZE); + memcpy(ciphertext_buffer, total_buffer + SALT_SIZE, length_ciphertext); + + key_size = EVP_CIPHER_key_length(CIPHER); + + /* decryption */ + if(!(ctx = EVP_CIPHER_CTX_new())) { + debug_print("New ctx failed\n"); + goto cleanup; + } + + key = OPENSSL_malloc(key_size); + OPENSSL_cleanse(key, key_size); + if (secure_derive_key(key, + key_size, + passphrase, + salt) != 0) { + OPENSSL_cleanse(key, key_size); + debug_print("Could not generate secure key\n"); + goto cleanup; + } + + if (EVP_DecryptInit_ex(ctx, CIPHER, NULL, key, salt) != 1) { + debug_print("EVP_DecryptInit_ex failed\n"); + goto cleanup; + } + OPENSSL_cleanse(key, key_size); /* highly sensitive */ + cleartext_buffer = OPENSSL_malloc(length_ciphertext); + OPENSSL_cleanse(cleartext_buffer, length_ciphertext); + + length_cleartext = 0; + decrypt_buffer_cnt = 0; + + while(1) { + if (EVP_DecryptUpdate(ctx, + cleartext_buffer + length_cleartext, + &decrypt_buffer_cnt, + ciphertext_buffer + length_cleartext, + 1) != 1) { /* one byte at a time */ + debug_print("EVP_EncryptUpdate failed\n"); + goto cleanup; + } + + if (decrypt_buffer_cnt != 1) { /* paranoia */ + debug_print("The sizes of enc and dec text do not correspond"); + goto cleanup; + } + + ++length_cleartext; + + if (length_cleartext >= length_ciphertext) { + break; + } + } + + + length_hash = EVP_MD_size(DIGEST_HASH); + hash_buffer = OPENSSL_malloc(length_hash); + length_data_payload = length_cleartext - length_hash; + data_payload_buffer = OPENSSL_malloc(length_data_payload); + OPENSSL_cleanse(data_payload_buffer, length_data_payload); + + memcpy(data_payload_buffer, + cleartext_buffer + length_hash, + length_data_payload); + + mdctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(mdctx, DIGEST_HASH, NULL); + EVP_DigestUpdate(mdctx, data_payload_buffer, length_data_payload); + EVP_DigestFinal_ex(mdctx, hash_buffer, &length_hash); + + if (strncmp((const gchar*) hash_buffer, + (const gchar*) cleartext_buffer, + length_hash) != 0) { + debug_print("Invalid hash\n"); + rc = RC_WRONG_HASH_OR_KEY; + goto cleanup; + } + + memcpy(str_data_size, cleartext_buffer + length_hash, 2); + data_size = atoi(str_data_size); + + if (data_size < 0) { + length_decrypted = length_data_payload - 2; + } else { + length_decrypted = data_size; + } + *decrypted = OPENSSL_malloc(length_decrypted); + memcpy(*decrypted, data_payload_buffer + 2, length_decrypted); + + rc = RC_OK; + +cleanup: + + /* key */ + OPENSSL_cleanse(key, key_size); + OPENSSL_free(key); + /* payload buffer */ + OPENSSL_cleanse(data_payload_buffer, length_data_payload); + OPENSSL_free(data_payload_buffer); + /* hash */ + OPENSSL_cleanse(hash_buffer, length_hash); + OPENSSL_free(hash_buffer); + /* ciphertext */ + OPENSSL_free(ciphertext_buffer); + OPENSSL_free(total_buffer); + + EVP_CIPHER_CTX_free(ctx); + EVP_MD_CTX_destroy(mdctx); + + return rc; + +} + #endif /* USE_SSL */ -- cgit v1.3