This commit is contained in:
Heiko Reese
2021-08-20 00:48:18 +02:00
parent 4acdfffc65
commit 4ff77be04a
4 changed files with 113 additions and 57 deletions

View File

@ -3,18 +3,20 @@
#include <strings.h>
#include <sodium.h>
#include <sys/types.h>
#include <unistd.h>
/* 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;
char * string2hex(unsigned char * input, size_t length) {
const int growth = 3;
char * outstring = store_get(growth*length+1);
memset(outstring, 0, 3*length+1);
for (int i =0; i<length; i++) {
sprintf(outstring+i*growth, "%02x ", input[i]);
}
return output_len;
return outstring;
}
/*
@ -46,7 +48,7 @@ int sodium_crypto_secretbox_encrypt_password(uschar **yield, int argc, uschar *a
/*
* 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).
* This operations needs to be fast (exim holds no state, this might be called multiple times per email).
* Collisions avoidance or brute force attacks are not a concern here.
*/
unsigned char keybytes[crypto_secretbox_KEYBYTES];
@ -118,16 +120,17 @@ int sodium_crypto_secretbox_decrypt_password(uschar **yield, int argc, uschar *a
// get base64 encoded ciphertext message
unsigned char *ciphertextb64 = argv[1];
size_t ciphertextb64len = strlen((const char *) ciphertextb64);
size_t ciphertextb64_len = 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);
int b64err = sodium_base642bin(combined_message, combined_message_len,
(const char *) ciphertextb64, ciphertextb64len,
NULL, NULL, NULL,
sodium_base64_VARIANT_ORIGINAL);
size_t combined_message_buf_len = ciphertextb64_len / 4 * 3;
size_t combined_message_len;
unsigned char *combined_message = (unsigned char *) store_get(combined_message_buf_len);
sodium_memzero(combined_message, combined_message_buf_len);
int b64err = sodium_base642bin(combined_message, combined_message_buf_len,
(const char *) ciphertextb64, ciphertextb64_len,
NULL, &combined_message_len, NULL,
sodium_base64_VARIANT_ORIGINAL);
if (b64err != 0) {
*yield = string_copy((unsigned char *) "Error decoding base64 encoded ciphertext");
return ERROR;
@ -175,29 +178,43 @@ int sodium_crypto_box_seal(uschar **yield, int argc, uschar *argv[]) {
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);
// get and convert public key
unsigned char *pkb64 = argv[0];
size_t pkb64_len = strlen((const char *) pkb64);
// reserve space for conversion
unsigned int pk_buffer_len = crypto_box_PUBLICKEYBYTES; // pkb64_len / 4 * 3 + 1;
unsigned char *pk = (unsigned char *) store_get(pk_buffer_len);
sodium_memzero(pk, pk_buffer_len);
// convert encoded key to raw form
int b64err = sodium_base642bin(pk, pk_buffer_len,
(const char *) pkb64, pkb64_len,
NULL, NULL, NULL, sodium_base64_VARIANT_ORIGINAL);
if (b64err == -1) {
*yield = string_copy((unsigned char *) "Error decoding public key");
return ERROR;
};
}
log_write(0, LOG_MAIN, "[encrypt] PK: %s", string2hex(pk, pk_buffer_len));
// get cleartext message
unsigned char *message = argv[1];
size_t messagelen = strlen((const char *) message);
log_write(0, LOG_MAIN, "[encrypt] cleartext: %s", 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) {
if (crypto_box_seal(ciphertext, message, messagelen, pk) == -1) {
*yield = string_copy((unsigned char *) "Encryption error after crypto_box_seal()");
return ERROR;
}
log_write(0, LOG_MAIN, "[encrypt] ciphertext: %s", string2hex(ciphertext, cipherlen));
// base64-encode the ciphertext
unsigned int outputsize = sodium_base64_ENCODED_LEN(cipherlen,
sodium_base64_VARIANT_ORIGINAL);
@ -230,45 +247,71 @@ int sodium_crypto_box_seal_open(uschar **yield, int argc, uschar *argv[]) {
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);
// get and convert private key
unsigned char *skb64 = argv[0];
size_t skb64_len = strlen((const char *)skb64);
// reserve space for conversion
unsigned int sk_buffer_len = crypto_box_SECRETKEYBYTES;// skb64_len / 4 * 3;
unsigned char *sk = (unsigned char *) store_get(sk_buffer_len);
sodium_memzero(sk, sk_buffer_len);
// convert encoded key to raw form
int b64err = sodium_base642bin(sk, sk_buffer_len,
(const char *) skb64, skb64_len,
NULL, NULL, NULL, sodium_base64_VARIANT_ORIGINAL);
if(b64err == -1) {
*yield = string_copy((unsigned char *) "Error decoding private key");
return ERROR;
}
log_write(0, LOG_MAIN, "[decrypt] SK: %s", string2hex(sk, sk_buffer_len));
// get and convert public key
unsigned char *pkb64 = argv[1];
size_t pkb64_len = strlen((const char *) pkb64);
// reserve space for conversion
unsigned int pk_buffer_len = crypto_box_PUBLICKEYBYTES; // pkb64_len / 4 * 3;
unsigned char *pk = (unsigned char *) store_get(pk_buffer_len);
sodium_memzero(pk, pk_buffer_len);
// convert encoded key to raw form
b64err = sodium_base642bin(pk, pk_buffer_len,
(const char *) pkb64, pkb64_len,
NULL, NULL, NULL, sodium_base64_VARIANT_ORIGINAL);
if (b64err == -1) {
*yield = string_copy((unsigned char *) "Error decoding public key");
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;
}
log_write(0, LOG_MAIN, "[decrypt] PK: %s", string2hex(pk, pk_buffer_len));
// get encrypted message
unsigned char *ciphertextb64 = argv[2];
size_t ciphertextb64len = strlen((const char *) ciphertextb64);
size_t ciphertextb64_len = 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,
unsigned int ciphertextbuflen = ciphertextb64_len / 4 * 3;
unsigned char *ciphertext = (unsigned char *) store_get(ciphertextbuflen);
size_t ciphertextlen;
sodium_memzero(ciphertext, ciphertextbuflen);
b64err = sodium_base642bin(ciphertext, ciphertextbuflen,
(const char *) ciphertextb64, ciphertextb64_len,
NULL, &ciphertextlen, NULL,
sodium_base64_VARIANT_ORIGINAL);
if (b64err != 0) {
if (b64err == -1) {
*yield = string_copy((unsigned char *) "Error decoding base64 encoded ciphertext");
return ERROR;
}
log_write(0, LOG_MAIN, "[encrypt] ciphertext: %s", string2hex(ciphertext, ciphertextlen));
// 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
//#define DEBUG
#ifdef DEBUG
log_write(0, LOG_MAIN, "pid: %d", getpid()); int busywait = 0; while (busywait == 0) {}
#endif
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;