First working version of sodium_crypto_secretbox_encrypt_password() and

sodium_crypto_secretbox_decrypt_password().
This commit is contained in:
Heiko Reese
2021-08-17 03:04:58 +02:00
parent 9112222ac9
commit 6dc3e1e2f9
2 changed files with 127 additions and 60 deletions

View File

@ -3,21 +3,85 @@
#include <strings.h> #include <strings.h>
#include <sodium.h> #include <sodium.h>
/* Local encryption key */
#include "recipient_pk.h"
/* Exim4 dlfunc API header */ /* Exim4 dlfunc API header */
#include <local_scan.h> #include <local_scan.h>
/* /*
* 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[]) 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 argument
unsigned char *message = argv[1];
size_t messagelen = strlen((const char *) message);
/*
* 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 = (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);
// 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);
// 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) { if (sodium_init() == -1) {
*yield = string_copy(US "Unable to initialize libsodium"); *yield = string_copy(US "Unable to initialize libsodium");
return ERROR; return ERROR;
} }
// check argument count
if (argc != 2) { if (argc != 2) {
*yield = *yield =
string_sprintf string_sprintf
@ -28,42 +92,42 @@ int sodium_crypto_secretbox(uschar ** yield, int argc, uschar * argv[])
unsigned char *password = argv[0]; unsigned char *password = argv[0];
size_t passwordlen = strlen((const char *)password); size_t passwordlen = strlen((const char *)password);
// get cleartext message // Derive key from the password.
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]; unsigned char keybytes[crypto_secretbox_KEYBYTES];
sodium_memzero(keybytes, crypto_secretbox_KEYBYTES); sodium_memzero(keybytes, crypto_secretbox_KEYBYTES);
crypto_generichash(keybytes, crypto_secretbox_KEYBYTES, crypto_generichash(keybytes, crypto_secretbox_KEYBYTES,
password, passwordlen, NULL, 0); password, passwordlen, NULL, 0);
// prepare buffer for ciphertext // get base64 encoded ciphertext message
unsigned int cipherlen = messagelen + crypto_secretbox_MACBYTES; unsigned char *ciphertextb64 = argv[1];
unsigned char *ciphertext = malloc(cipherlen); size_t ciphertextb64len = strlen((const char *) ciphertextb64);
sodium_memzero(ciphertext, cipherlen);
// encrypt message // 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]; unsigned char nonce[crypto_secretbox_NONCEBYTES];
randombytes_buf(nonce, sizeof nonce); memcpy(nonce, combined_message, crypto_secretbox_NONCEBYTES);
crypto_secretbox_easy(ciphertext, message, messagelen, nonce, keybytes);
// base64-encode the ciphertext // prepare buffer for cleartext
unsigned int outputsize = sodium_base64_ENCODED_LEN(cipherlen, unsigned int cleartextlen = combined_message_len - crypto_secretbox_NONCEBYTES - crypto_secretbox_MACBYTES;
sodium_base64_VARIANT_ORIGINAL); unsigned char *cleartext = (unsigned char *) store_get(cleartextlen+1);
unsigned char *outstring = malloc(outputsize); sodium_memzero(cleartext, cleartextlen+1);
sodium_memzero(outstring, outputsize);
sodium_bin2base64((char *const)outstring, outputsize, // decrypt message
ciphertext, cipherlen, if (crypto_secretbox_open_easy(cleartext, &combined_message[crypto_secretbox_NONCEBYTES],
sodium_base64_VARIANT_ORIGINAL); combined_message_len - crypto_secretbox_NONCEBYTES, nonce, keybytes) != 0) {
free(ciphertext); *yield = string_copy((unsigned char *) "Unable to decrypt.");
return ERROR;
}
// return base64-encoded ciphertext // return base64-encoded ciphertext
*yield = string_copy(outstring); *yield = string_copy(cleartext);
free(outstring);
return OK; return OK;
} }

View File

@ -3,34 +3,36 @@
#include <strings.h> #include <strings.h>
#include <sodium.h> #include <sodium.h>
/* Local encryption key */
#include "recipient_pk.h"
/* Exim4 dlfunc API header */ /* Exim4 dlfunc API header */
#include <local_scan.h> #include <local_scan.h>
/* /*
* 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; size_t messagelen;
unsigned char *message; unsigned char *message, *key;
if (sodium_init() == -1) { if (sodium_init() == -1) {
*yield = string_copy(US "Unable to initialize libsodium"); *yield = string_copy(US "Unable to initialize libsodium");
return ERROR; return ERROR;
} }
if (argc != 1) { if (argc != 2) {
*yield = *yield =
string_sprintf string_sprintf
("Wrong number of arguments (got %i, expected 1)", argc); ("Wrong number of arguments (got %i, expected 2)", argc);
return ERROR; return ERROR;
} }
// get cleartext message // get cleartext message
message = argv[0]; message = argv[0];
messagelen = strlen((const char *)message); messagelen = strlen((const char *)message);
// get key
key = argv[1];
// prepare buffer for ciphertext // prepare buffer for ciphertext
unsigned int cipherlen = messagelen + crypto_box_SEALBYTES; unsigned int cipherlen = messagelen + crypto_box_SEALBYTES;
unsigned char *ciphertext = malloc(cipherlen); unsigned char *ciphertext = malloc(cipherlen);
@ -56,3 +58,4 @@ int sodium_crypto_box_seal_kit(uschar ** yield, int argc, uschar * argv[])
return OK; return OK;
} }
*/