From 6dc3e1e2f97d4e8b0b3d2b071143f1594d21cd51 Mon Sep 17 00:00:00 2001 From: Heiko Reese Date: Tue, 17 Aug 2021 03:04:58 +0200 Subject: [PATCH] First working version of sodium_crypto_secretbox_encrypt_password() and sodium_crypto_secretbox_decrypt_password(). --- src/libexim-encrypt-dlfunc.c | 168 ++++++++++++++++++++++---------- src/libexim-kitencrypt-dlfunc.c | 19 ++-- 2 files changed, 127 insertions(+), 60 deletions(-) diff --git a/src/libexim-encrypt-dlfunc.c b/src/libexim-encrypt-dlfunc.c index 1cfff78..03cd76d 100644 --- a/src/libexim-encrypt-dlfunc.c +++ b/src/libexim-encrypt-dlfunc.c @@ -3,67 +3,131 @@ #include #include -/* Local encryption key */ -#include "recipient_pk.h" - /* Exim4 dlfunc API header */ #include /* - * Encrypt the second argument with password from the first argument + * Encrypt the second argument with password string from the first argument + * using crypto_secretbox_easy(). */ -int sodium_crypto_secretbox(uschar ** yield, int argc, uschar * argv[]) -{ - if (sodium_init() == -1) { - *yield = string_copy(US "Unable to initialize libsodium"); - return ERROR; - } - if (argc != 2) { - *yield = - string_sprintf - ("Wrong number of arguments (got %i, expected 2)", argc); - return ERROR; - } - // get password - unsigned char *password = argv[0]; - size_t passwordlen = strlen((const char *)password); +int sodium_crypto_secretbox_encrypt_password(uschar **yield, int argc, uschar *argv[]) { + // ensure libsodium is initialized + if (sodium_init() == -1) { + *yield = string_copy(US + "Unable to initialize libsodium"); + return ERROR; + } + // check argument count + if (argc != 2) { + *yield = string_sprintf("Wrong number of arguments (got %i, expected 2)", argc); + return ERROR; + } + // get password argument + unsigned char *password = argv[0]; + size_t passwordlen = strlen((const char *) password); - // get cleartext message - unsigned char *message = argv[1]; - size_t messagelen = strlen((const char *)message); + // get cleartext message argument + unsigned char *message = argv[1]; + size_t messagelen = strlen((const char *) message); - /* - * Derive a key from the password. - * This operations needs to be fast (exim holds no state, this might be called once or mutliple times per email). - * Collisions avoidance or brute force arracks are not a concern here. - */ - unsigned char keybytes[crypto_secretbox_KEYBYTES]; - sodium_memzero(keybytes, crypto_secretbox_KEYBYTES); - crypto_generichash(keybytes, crypto_secretbox_KEYBYTES, - password, passwordlen, NULL, 0); + /* + * Derive a key from the password using a generic hash. + * This operations needs to be fast (exim holds no state, this might be called once or multiple times per email). + * Collisions avoidance or brute force attacks are not a concern here. + */ + unsigned char keybytes[crypto_secretbox_KEYBYTES]; + sodium_memzero(keybytes, crypto_secretbox_KEYBYTES); + crypto_generichash(keybytes, crypto_secretbox_KEYBYTES, + password, passwordlen, NULL, 0); - // prepare buffer for ciphertext - unsigned int cipherlen = messagelen + crypto_secretbox_MACBYTES; - unsigned char *ciphertext = malloc(cipherlen); - sodium_memzero(ciphertext, cipherlen); + // prepare buffer for ciphertext + unsigned int cipherlen = messagelen + crypto_secretbox_MACBYTES; + unsigned char *ciphertext = (unsigned char *) store_get(cipherlen); + sodium_memzero(ciphertext, cipherlen); - // encrypt message - unsigned char nonce[crypto_secretbox_NONCEBYTES]; - randombytes_buf(nonce, sizeof nonce); - crypto_secretbox_easy(ciphertext, message, messagelen, nonce, keybytes); + // encrypt message + unsigned char nonce[crypto_secretbox_NONCEBYTES]; + randombytes_buf(nonce, sizeof nonce); + crypto_secretbox_easy(ciphertext, message, messagelen, nonce, keybytes); - // base64-encode the ciphertext - unsigned int outputsize = sodium_base64_ENCODED_LEN(cipherlen, - sodium_base64_VARIANT_ORIGINAL); - unsigned char *outstring = malloc(outputsize); - sodium_memzero(outstring, outputsize); - sodium_bin2base64((char *const)outstring, outputsize, - ciphertext, cipherlen, - sodium_base64_VARIANT_ORIGINAL); - free(ciphertext); + // combine nonce and ciphertext + size_t combined_message_len = crypto_secretbox_NONCEBYTES + cipherlen; + unsigned char * combined_message = store_get(combined_message_len); + memcpy(combined_message, nonce, crypto_secretbox_NONCEBYTES); + memcpy(&combined_message[crypto_secretbox_NONCEBYTES], ciphertext, cipherlen); - // return base64-encoded ciphertext - *yield = string_copy(outstring); - free(outstring); - return OK; + // base64-encode the ciphertext + unsigned int outputsize = sodium_base64_ENCODED_LEN(combined_message_len, + sodium_base64_VARIANT_ORIGINAL); + unsigned char *outstring = (unsigned char *) store_get(outputsize); + sodium_memzero(outstring, outputsize); + sodium_bin2base64((char *const) outstring, outputsize, + combined_message, combined_message_len, + sodium_base64_VARIANT_ORIGINAL); + + // return base64-encoded ciphertext + *yield = string_copy(outstring); + return OK; +} + +/* + * Decrypt the second argument with password string from the first argument + * using crypto_secretbox_open_easy(). + */ +int sodium_crypto_secretbox_decrypt_password(uschar ** yield, int argc, uschar * argv[]) +{ + // ensure libsodium is initialized + if (sodium_init() == -1) { + *yield = string_copy(US "Unable to initialize libsodium"); + return ERROR; + } + // check argument count + if (argc != 2) { + *yield = + string_sprintf + ("Wrong number of arguments (got %i, expected 2)", argc); + return ERROR; + } + // get password + unsigned char *password = argv[0]; + size_t passwordlen = strlen((const char *)password); + + // Derive key from the password. + unsigned char keybytes[crypto_secretbox_KEYBYTES]; + sodium_memzero(keybytes, crypto_secretbox_KEYBYTES); + crypto_generichash(keybytes, crypto_secretbox_KEYBYTES, + password, passwordlen, NULL, 0); + + // get base64 encoded ciphertext message + unsigned char *ciphertextb64 = argv[1]; + size_t ciphertextb64len = strlen((const char *) ciphertextb64); + + // base64-decode the ciphertext + unsigned int combined_message_len = ciphertextb64len / 4 * 3; + unsigned char *combined_message = (unsigned char *) store_get(combined_message_len); + sodium_memzero(combined_message, combined_message_len); + sodium_base642bin(combined_message, combined_message_len, + (const char *) ciphertextb64, ciphertextb64len, + NULL, NULL, NULL, + sodium_base64_VARIANT_ORIGINAL); + + // extract nonce + unsigned char nonce[crypto_secretbox_NONCEBYTES]; + memcpy(nonce, combined_message, crypto_secretbox_NONCEBYTES); + + // prepare buffer for cleartext + unsigned int cleartextlen = combined_message_len - crypto_secretbox_NONCEBYTES - crypto_secretbox_MACBYTES; + unsigned char *cleartext = (unsigned char *) store_get(cleartextlen+1); + sodium_memzero(cleartext, cleartextlen+1); + + // decrypt message + if (crypto_secretbox_open_easy(cleartext, &combined_message[crypto_secretbox_NONCEBYTES], + combined_message_len - crypto_secretbox_NONCEBYTES, nonce, keybytes) != 0) { + *yield = string_copy((unsigned char *) "Unable to decrypt."); + return ERROR; + } + + // return base64-encoded ciphertext + *yield = string_copy(cleartext); + return OK; } diff --git a/src/libexim-kitencrypt-dlfunc.c b/src/libexim-kitencrypt-dlfunc.c index 7020f49..186d8e7 100644 --- a/src/libexim-kitencrypt-dlfunc.c +++ b/src/libexim-kitencrypt-dlfunc.c @@ -3,34 +3,36 @@ #include #include -/* Local encryption key */ -#include "recipient_pk.h" - /* Exim4 dlfunc API header */ #include /* - * Encrypt first argument with fixed public key from recipient_pk.h + * Encrypt the second argument with the public key from the first argument */ -int sodium_crypto_box_seal_kit(uschar ** yield, int argc, uschar * argv[]) + +/* +int sodium_crypto_box_seal(uschar ** yield, int argc, uschar * argv[]) { size_t messagelen; - unsigned char *message; + unsigned char *message, *key; if (sodium_init() == -1) { *yield = string_copy(US "Unable to initialize libsodium"); return ERROR; } - if (argc != 1) { + if (argc != 2) { *yield = string_sprintf - ("Wrong number of arguments (got %i, expected 1)", argc); + ("Wrong number of arguments (got %i, expected 2)", argc); return ERROR; } // get cleartext message message = argv[0]; messagelen = strlen((const char *)message); + // get key + key = argv[1]; + // prepare buffer for ciphertext unsigned int cipherlen = messagelen + crypto_box_SEALBYTES; unsigned char *ciphertext = malloc(cipherlen); @@ -56,3 +58,4 @@ int sodium_crypto_box_seal_kit(uschar ** yield, int argc, uschar * argv[]) return OK; } +*/ \ No newline at end of file