This commit is contained in:
Heiko Reese
2021-08-17 20:57:58 +02:00
parent 0fe7274c92
commit 4acdfffc65
4 changed files with 178 additions and 103 deletions

View File

@ -6,9 +6,23 @@
/* Exim4 dlfunc API header */
#include <local_scan.h>
int b64decode(unsigned char * const input, const size_t input_len, unsigned char * output) {
unsigned int output_len = input_len / 4 * 3;
output = store_get(output_len);
sodium_memzero(output, output_len);
int b64err = sodium_base642bin(output, output_len, (const char *) input, input_len, NULL, NULL, NULL, sodium_base64_VARIANT_ORIGINAL);
if (b64err != 0) {
return -1;
}
return output_len;
}
/*
* Encrypt the second argument with password string from the first argument
* using crypto_secretbox_easy().
* Encrypt message using crypto_secretbox_easy().
*
* Arguments:
* 1. password
* 2. cleartext message
*/
int sodium_crypto_secretbox_encrypt_password(uschar **yield, int argc, uschar *argv[]) {
// ensure libsodium is initialized
@ -48,11 +62,14 @@ int sodium_crypto_secretbox_encrypt_password(uschar **yield, int argc, uschar *a
// encrypt message
unsigned char nonce[crypto_secretbox_NONCEBYTES];
randombytes_buf(nonce, sizeof nonce);
crypto_secretbox_easy(ciphertext, message, messagelen, nonce, keybytes);
if (crypto_secretbox_easy(ciphertext, message, messagelen, nonce, keybytes) != 0) {
*yield = string_copy((unsigned char *) "Encryption error after crypto_secretbox_easy()");
return ERROR;
}
// combine nonce and ciphertext
size_t combined_message_len = crypto_secretbox_NONCEBYTES + cipherlen;
unsigned char * combined_message = store_get(combined_message_len);
unsigned char *combined_message = store_get(combined_message_len);
memcpy(combined_message, nonce, crypto_secretbox_NONCEBYTES);
memcpy(&combined_message[crypto_secretbox_NONCEBYTES], ciphertext, cipherlen);
@ -60,7 +77,7 @@ int sodium_crypto_secretbox_encrypt_password(uschar **yield, int argc, uschar *a
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_memzero(outstring, outputsize);
sodium_bin2base64((char *const) outstring, outputsize,
combined_message, combined_message_len,
sodium_base64_VARIANT_ORIGINAL);
@ -71,26 +88,27 @@ int sodium_crypto_secretbox_encrypt_password(uschar **yield, int argc, uschar *a
}
/*
* Decrypt the second argument with password string from the first argument
* using crypto_secretbox_open_easy().
* Decrypt message encrypted by sodium_crypto_secretbox_encrypt_password(). Arguments:
* 1. password string
* 2. encrypted message
*/
int sodium_crypto_secretbox_decrypt_password(uschar ** yield, int argc, uschar * argv[])
{
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");
*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);
("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);
size_t passwordlen = strlen((const char *) password);
// Derive key from the password.
unsigned char keybytes[crypto_secretbox_KEYBYTES];
@ -106,10 +124,14 @@ int sodium_crypto_secretbox_decrypt_password(uschar ** yield, int argc, uschar *
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,
int b64err = sodium_base642bin(combined_message, combined_message_len,
(const char *) ciphertextb64, ciphertextb64len,
NULL, NULL, NULL,
sodium_base64_VARIANT_ORIGINAL);
if (b64err != 0) {
*yield = string_copy((unsigned char *) "Error decoding base64 encoded ciphertext");
return ERROR;
}
// extract nonce
unsigned char nonce[crypto_secretbox_NONCEBYTES];
@ -117,17 +139,142 @@ int sodium_crypto_secretbox_decrypt_password(uschar ** yield, int argc, uschar *
// 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);
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.");
*yield = string_copy((unsigned char *) "Decryption error after crypto_secretbox_open_easy()");
return ERROR;
}
// return base64-encoded ciphertext
// return cleartext
*yield = string_copy(cleartext);
return OK;
}
// --------------------------------
/*
* Encrypt message using crypto_box_seal().
*
* Arguments:
* 1. public key
* 2. cleartext message
*/
int sodium_crypto_box_seal(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 key, check size
unsigned char *key = argv[0];
size_t keylen = strlen((const char *) key);
if (keylen != crypto_box_PUBLICKEYBYTES) {
*yield = string_sprintf("Public key has wrong size (got %d, expected %d)", keylen, crypto_box_PUBLICKEYBYTES);
return ERROR;
};
// get cleartext message
unsigned char *message = argv[1];
size_t messagelen = strlen((const char *) message);
// prepare buffer for ciphertext
unsigned int cipherlen = messagelen + crypto_box_SEALBYTES;
unsigned char *ciphertext = store_get(cipherlen);
sodium_memzero(ciphertext, cipherlen);
// encrypt message
if (crypto_box_seal(ciphertext, message, messagelen, key) == -1) {
*yield = string_copy((unsigned char *) "Encryption error after crypto_box_seal()");
return ERROR;
}
// base64-encode the ciphertext
unsigned int outputsize = sodium_base64_ENCODED_LEN(cipherlen,
sodium_base64_VARIANT_ORIGINAL);
unsigned char *outstring = store_get(outputsize);
sodium_bin2base64((char *const) outstring, outputsize,
ciphertext, cipherlen,
sodium_base64_VARIANT_ORIGINAL);
// return base64-encoded ciphertext
*yield = string_copy(outstring);
return OK;
}
/*
* Decrypt message encrypted by sodium_crypto_box_seal().
*
* Arguments:
* 1. private key
* 2. public key
* 3. encrypted message
*/
int sodium_crypto_box_seal_open(uschar **yield, int argc, uschar *argv[]) {
if (sodium_init() == -1) {
*yield = string_copy(US
"Unable to initialize libsodium");
return ERROR;
}
if (argc != 3) {
*yield = string_sprintf("Wrong number of arguments (got %i, expected 2)", argc);
return ERROR;
}
// check private key
unsigned char *sk = argv[0];
size_t sk_len = strlen((const char *)sk);
if (sk_len != crypto_box_SECRETKEYBYTES) {
*yield = string_sprintf("Private key has wrong size (got %d, expected %d)", sk_len, crypto_box_SECRETKEYBYTES);
return ERROR;
}
// check public key
unsigned char *pk = argv[1];
size_t pk_len = strlen((const char *)pk);
if (pk_len != crypto_box_PUBLICKEYBYTES) {
*yield = string_sprintf("Private key has wrong size (got %d, expected %d)", pk_len, crypto_box_PUBLICKEYBYTES);
return ERROR;
}
// get encrypted message
unsigned char *ciphertextb64 = argv[2];
size_t ciphertextb64len = strlen((const char *) ciphertextb64);
// base64-decode the ciphertext
unsigned int ciphertextlen = ciphertextb64len / 4 * 3;
unsigned char *ciphertext = (unsigned char *) store_get(ciphertextlen);
sodium_memzero(ciphertext, ciphertextlen);
int b64err = sodium_base642bin(ciphertext, ciphertextlen,
(const char *) ciphertextb64, ciphertextb64len,
NULL, NULL, NULL,
sodium_base64_VARIANT_ORIGINAL);
if (b64err != 0) {
*yield = string_copy((unsigned char *) "Error decoding base64 encoded ciphertext");
return ERROR;
}
// prepare buffer for cleartext
unsigned int cleartextlen = ciphertextlen - crypto_box_SEALBYTES;
unsigned char *cleartext = (unsigned char *) store_get(cleartextlen + 1);
sodium_memzero(cleartext, cleartextlen + 1);
// decrypt message
if (crypto_box_seal_open(cleartext, ciphertext, ciphertextlen, pk, sk) != 0) {
*yield = string_copy((unsigned char *) "Decryption error after crypto_box_seal_open()");
return ERROR;
}
// return cleartext
*yield = string_copy(cleartext);
return OK;
}