mirror of
https://gitlab.kit.edu/kit/scc/sys/mail/exim-encrypt-dlfunc.git
synced 2025-12-06 08:43:55 +01:00
…
This commit is contained in:
@ -1,5 +1,5 @@
|
|||||||
CC=gcc
|
CC=gcc
|
||||||
CFLAGS=-Wall
|
CFLAGS=-Wall -g
|
||||||
LDFLAGS=-lsodium
|
LDFLAGS=-lsodium
|
||||||
LDFLAGS_LIB=-I/usr/include/exim4 -fpic -shared -export-dynamic
|
LDFLAGS_LIB=-I/usr/include/exim4 -fpic -shared -export-dynamic
|
||||||
|
|
||||||
|
|||||||
22
src/genkey.c
22
src/genkey.c
@ -32,6 +32,15 @@ void
|
|||||||
dump_key_as_exim_config(FILE * f, const char *name, unsigned char *key,
|
dump_key_as_exim_config(FILE * f, const char *name, unsigned char *key,
|
||||||
unsigned int keylen)
|
unsigned int keylen)
|
||||||
{
|
{
|
||||||
|
// write a comment with C variable declaration
|
||||||
|
fprintf(f, "# const unsigned char %s[%d] = { ", name, keylen);
|
||||||
|
for (int i = 0; i < keylen; i++) {
|
||||||
|
fprintf(f, "0x%02x", key[i]);
|
||||||
|
if (i < keylen - 1) {
|
||||||
|
fprintf(f, ", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(f, " }; const unsigned int %s_length = %d;\n", name, keylen);
|
||||||
// encode with base64
|
// encode with base64
|
||||||
unsigned int b64len = sodium_base64_ENCODED_LEN(keylen, sodium_base64_VARIANT_ORIGINAL);
|
unsigned int b64len = sodium_base64_ENCODED_LEN(keylen, sodium_base64_VARIANT_ORIGINAL);
|
||||||
unsigned char *b64string = malloc(b64len);
|
unsigned char *b64string = malloc(b64len);
|
||||||
@ -89,6 +98,8 @@ void create_cryptobox_keys(const char *filebase, const char *varname)
|
|||||||
unsigned char recipient_pk[crypto_box_PUBLICKEYBYTES];
|
unsigned char recipient_pk[crypto_box_PUBLICKEYBYTES];
|
||||||
unsigned char recipient_sk[crypto_box_SECRETKEYBYTES];
|
unsigned char recipient_sk[crypto_box_SECRETKEYBYTES];
|
||||||
|
|
||||||
|
crypto_box_keypair(recipient_pk, recipient_sk);
|
||||||
|
|
||||||
char pk_filename[4096];
|
char pk_filename[4096];
|
||||||
char pk_varname[4096];
|
char pk_varname[4096];
|
||||||
char sk_filename[4096];
|
char sk_filename[4096];
|
||||||
@ -106,11 +117,10 @@ void create_cryptobox_keys(const char *filebase, const char *varname)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void create_secretboy_key(const char *filebase, const char *varname) {
|
void create_secretbox_key(const char *filebase, const char *varname) {
|
||||||
unsigned char key[crypto_secretbox_KEYBYTES];
|
unsigned char key[crypto_secretbox_KEYBYTES];
|
||||||
while (key_contains_zero(key, crypto_secretbox_KEYBYTES)) {
|
|
||||||
crypto_secretbox_keygen(key);
|
crypto_secretbox_keygen(key);
|
||||||
}
|
|
||||||
|
|
||||||
char key_filename[4096];
|
char key_filename[4096];
|
||||||
char key_varname[4096];
|
char key_varname[4096];
|
||||||
@ -121,7 +131,7 @@ void create_secretboy_key(const char *filebase, const char *varname) {
|
|||||||
write_key_files(key_filename, key_varname, key, crypto_secretbox_KEYBYTES);
|
write_key_files(key_filename, key_varname, key, crypto_secretbox_KEYBYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
if (sodium_init() < 0) {
|
if (sodium_init() < 0) {
|
||||||
fputs("Unable to initialize libsodium", stderr);
|
fputs("Unable to initialize libsodium", stderr);
|
||||||
@ -130,8 +140,6 @@ int main(void)
|
|||||||
|
|
||||||
fputs("=== Creating cryptobox key pair ===\n", stderr);
|
fputs("=== Creating cryptobox key pair ===\n", stderr);
|
||||||
create_cryptobox_keys("cryptobox_recipient", "cryptobox_recipient");
|
create_cryptobox_keys("cryptobox_recipient", "cryptobox_recipient");
|
||||||
fputs("=== Creating secretbox key ===\n", stderr);
|
|
||||||
create_secretboy_key("secretbox", "secretbox");
|
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,18 +3,20 @@
|
|||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <sodium.h>
|
#include <sodium.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
/* Exim4 dlfunc API header */
|
/* Exim4 dlfunc API header */
|
||||||
#include <local_scan.h>
|
#include <local_scan.h>
|
||||||
|
|
||||||
int b64decode(unsigned char * const input, const size_t input_len, unsigned char * output) {
|
char * string2hex(unsigned char * input, size_t length) {
|
||||||
unsigned int output_len = input_len / 4 * 3;
|
const int growth = 3;
|
||||||
output = store_get(output_len);
|
char * outstring = store_get(growth*length+1);
|
||||||
sodium_memzero(output, output_len);
|
memset(outstring, 0, 3*length+1);
|
||||||
int b64err = sodium_base642bin(output, output_len, (const char *) input, input_len, NULL, NULL, NULL, sodium_base64_VARIANT_ORIGINAL);
|
for (int i =0; i<length; i++) {
|
||||||
if (b64err != 0) {
|
sprintf(outstring+i*growth, "%02x ", input[i]);
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
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.
|
* 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.
|
* Collisions avoidance or brute force attacks are not a concern here.
|
||||||
*/
|
*/
|
||||||
unsigned char keybytes[crypto_secretbox_KEYBYTES];
|
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
|
// get base64 encoded ciphertext message
|
||||||
unsigned char *ciphertextb64 = argv[1];
|
unsigned char *ciphertextb64 = argv[1];
|
||||||
size_t ciphertextb64len = strlen((const char *) ciphertextb64);
|
size_t ciphertextb64_len = strlen((const char *) ciphertextb64);
|
||||||
|
|
||||||
// base64-decode the ciphertext
|
// base64-decode the ciphertext
|
||||||
unsigned int combined_message_len = ciphertextb64len / 4 * 3;
|
size_t combined_message_buf_len = ciphertextb64_len / 4 * 3;
|
||||||
unsigned char *combined_message = (unsigned char *) store_get(combined_message_len);
|
size_t combined_message_len;
|
||||||
sodium_memzero(combined_message, combined_message_len);
|
unsigned char *combined_message = (unsigned char *) store_get(combined_message_buf_len);
|
||||||
int b64err = sodium_base642bin(combined_message, combined_message_len,
|
sodium_memzero(combined_message, combined_message_buf_len);
|
||||||
(const char *) ciphertextb64, ciphertextb64len,
|
int b64err = sodium_base642bin(combined_message, combined_message_buf_len,
|
||||||
NULL, NULL, NULL,
|
(const char *) ciphertextb64, ciphertextb64_len,
|
||||||
sodium_base64_VARIANT_ORIGINAL);
|
NULL, &combined_message_len, NULL,
|
||||||
|
sodium_base64_VARIANT_ORIGINAL);
|
||||||
if (b64err != 0) {
|
if (b64err != 0) {
|
||||||
*yield = string_copy((unsigned char *) "Error decoding base64 encoded ciphertext");
|
*yield = string_copy((unsigned char *) "Error decoding base64 encoded ciphertext");
|
||||||
return ERROR;
|
return ERROR;
|
||||||
@ -175,29 +178,43 @@ int sodium_crypto_box_seal(uschar **yield, int argc, uschar *argv[]) {
|
|||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get key, check size
|
// get and convert public key
|
||||||
unsigned char *key = argv[0];
|
unsigned char *pkb64 = argv[0];
|
||||||
size_t keylen = strlen((const char *) key);
|
size_t pkb64_len = strlen((const char *) pkb64);
|
||||||
if (keylen != crypto_box_PUBLICKEYBYTES) {
|
// reserve space for conversion
|
||||||
*yield = string_sprintf("Public key has wrong size (got %d, expected %d)", keylen, crypto_box_PUBLICKEYBYTES);
|
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;
|
return ERROR;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
log_write(0, LOG_MAIN, "[encrypt] PK: %s", string2hex(pk, pk_buffer_len));
|
||||||
|
|
||||||
// get cleartext message
|
// get cleartext message
|
||||||
unsigned char *message = argv[1];
|
unsigned char *message = argv[1];
|
||||||
size_t messagelen = strlen((const char *) message);
|
size_t messagelen = strlen((const char *) message);
|
||||||
|
|
||||||
|
log_write(0, LOG_MAIN, "[encrypt] cleartext: %s", message);
|
||||||
|
|
||||||
// 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 = store_get(cipherlen);
|
unsigned char *ciphertext = store_get(cipherlen);
|
||||||
sodium_memzero(ciphertext, cipherlen);
|
sodium_memzero(ciphertext, cipherlen);
|
||||||
|
|
||||||
// encrypt message
|
// 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()");
|
*yield = string_copy((unsigned char *) "Encryption error after crypto_box_seal()");
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_write(0, LOG_MAIN, "[encrypt] ciphertext: %s", string2hex(ciphertext, cipherlen));
|
||||||
|
|
||||||
// base64-encode the ciphertext
|
// base64-encode the ciphertext
|
||||||
unsigned int outputsize = sodium_base64_ENCODED_LEN(cipherlen,
|
unsigned int outputsize = sodium_base64_ENCODED_LEN(cipherlen,
|
||||||
sodium_base64_VARIANT_ORIGINAL);
|
sodium_base64_VARIANT_ORIGINAL);
|
||||||
@ -230,45 +247,71 @@ int sodium_crypto_box_seal_open(uschar **yield, int argc, uschar *argv[]) {
|
|||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check private key
|
// get and convert private key
|
||||||
unsigned char *sk = argv[0];
|
unsigned char *skb64 = argv[0];
|
||||||
size_t sk_len = strlen((const char *)sk);
|
size_t skb64_len = strlen((const char *)skb64);
|
||||||
if (sk_len != crypto_box_SECRETKEYBYTES) {
|
// reserve space for conversion
|
||||||
*yield = string_sprintf("Private key has wrong size (got %d, expected %d)", sk_len, crypto_box_SECRETKEYBYTES);
|
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;
|
return ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check public key
|
log_write(0, LOG_MAIN, "[decrypt] PK: %s", string2hex(pk, pk_buffer_len));
|
||||||
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
|
// get encrypted message
|
||||||
unsigned char *ciphertextb64 = argv[2];
|
unsigned char *ciphertextb64 = argv[2];
|
||||||
size_t ciphertextb64len = strlen((const char *) ciphertextb64);
|
size_t ciphertextb64_len = strlen((const char *) ciphertextb64);
|
||||||
|
|
||||||
// base64-decode the ciphertext
|
// base64-decode the ciphertext
|
||||||
unsigned int ciphertextlen = ciphertextb64len / 4 * 3;
|
unsigned int ciphertextbuflen = ciphertextb64_len / 4 * 3;
|
||||||
unsigned char *ciphertext = (unsigned char *) store_get(ciphertextlen);
|
unsigned char *ciphertext = (unsigned char *) store_get(ciphertextbuflen);
|
||||||
sodium_memzero(ciphertext, ciphertextlen);
|
size_t ciphertextlen;
|
||||||
int b64err = sodium_base642bin(ciphertext, ciphertextlen,
|
sodium_memzero(ciphertext, ciphertextbuflen);
|
||||||
(const char *) ciphertextb64, ciphertextb64len,
|
b64err = sodium_base642bin(ciphertext, ciphertextbuflen,
|
||||||
NULL, NULL, NULL,
|
(const char *) ciphertextb64, ciphertextb64_len,
|
||||||
|
NULL, &ciphertextlen, NULL,
|
||||||
sodium_base64_VARIANT_ORIGINAL);
|
sodium_base64_VARIANT_ORIGINAL);
|
||||||
if (b64err != 0) {
|
if (b64err == -1) {
|
||||||
*yield = string_copy((unsigned char *) "Error decoding base64 encoded ciphertext");
|
*yield = string_copy((unsigned char *) "Error decoding base64 encoded ciphertext");
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_write(0, LOG_MAIN, "[encrypt] ciphertext: %s", string2hex(ciphertext, ciphertextlen));
|
||||||
|
|
||||||
// prepare buffer for cleartext
|
// prepare buffer for cleartext
|
||||||
unsigned int cleartextlen = ciphertextlen - crypto_box_SEALBYTES;
|
unsigned int cleartextlen = ciphertextlen - crypto_box_SEALBYTES;
|
||||||
unsigned char *cleartext = (unsigned char *) store_get(cleartextlen + 1);
|
unsigned char *cleartext = (unsigned char *) store_get(cleartextlen + 1);
|
||||||
sodium_memzero(cleartext, cleartextlen + 1);
|
sodium_memzero(cleartext, cleartextlen + 1);
|
||||||
|
|
||||||
// decrypt message
|
// 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) {
|
if (crypto_box_seal_open(cleartext, ciphertext, ciphertextlen, pk, sk) != 0) {
|
||||||
*yield = string_copy((unsigned char *) "Decryption error after crypto_box_seal_open()");
|
*yield = string_copy((unsigned char *) "Decryption error after crypto_box_seal_open()");
|
||||||
return ERROR;
|
return ERROR;
|
||||||
|
|||||||
@ -2,14 +2,19 @@
|
|||||||
|
|
||||||
LIB=`pwd`/libexim-encrypt-dlfunc.so
|
LIB=`pwd`/libexim-encrypt-dlfunc.so
|
||||||
CLEARTEXT="X-Originating-IP: [dead:beef:dead:beef:dead:beef:dead:beef]"
|
CLEARTEXT="X-Originating-IP: [dead:beef:dead:beef:dead:beef:dead:beef]"
|
||||||
PASSWORD="mucho secr3t passW0rd"
|
PASSWORD="`openssl rand -base64 32`"
|
||||||
|
|
||||||
CIPHERTEXT=$(exim -be "\${dlfunc{${LIB}}{sodium_crypto_secretbox_encrypt_password}{${PASSWORD}}{${CLEARTEXT}}}")
|
CIPHERTEXT=$(exim -be "\${dlfunc{${LIB}}{sodium_crypto_secretbox_encrypt_password}{${PASSWORD}}{${CLEARTEXT}}}")
|
||||||
DECRYPTED=$(exim -be "\${dlfunc{${LIB}}{sodium_crypto_secretbox_decrypt_password}{${PASSWORD}}{${CIPHERTEXT}}}")
|
DECRYPTED=$(exim -be "\${dlfunc{${LIB}}{sodium_crypto_secretbox_decrypt_password}{${PASSWORD}}{${CIPHERTEXT}}}")
|
||||||
|
|
||||||
if [ "${CLEARTEXT}" == "${DECRYPTED}" ] ; then echo "Test successful"; fi
|
if [ "${CLEARTEXT}" == "${DECRYPTED}" ] ; then echo "secretbox test successful"; fi
|
||||||
|
|
||||||
|
# { 0xb6, 0x01, 0x45, 0x20, 0x9f, 0x55, 0x06, 0x74, 0x29, 0x71, 0x7b, 0x5e, 0xa9, 0x68, 0x60, 0x5e, 0x81, 0x1a, 0x54, 0x6b, 0xc9, 0x80, 0x97, 0x78, 0x41, 0xc6, 0x20, 0xae, 0x66, 0x9f, 0xd9, 0x53 };
|
||||||
|
PK="tgFFIJ9VBnQpcXteqWhgXoEaVGvJgJd4QcYgrmaf2VM="
|
||||||
|
# { 0x95, 0x8d, 0x45, 0xef, 0x45, 0x6a, 0xc1, 0xef, 0xae, 0x0a, 0x7e, 0x1c, 0xcc, 0x67, 0x70, 0xc8, 0x67, 0x6b, 0xd1, 0x62, 0xd4, 0x59, 0xd9, 0x23, 0xfc, 0x6a, 0xb7, 0xf6, 0x6d, 0xa4, 0xdc, 0xfd };
|
||||||
|
SK="lY1F70Vqwe+uCn4czGdwyGdr0WLUWdkj/Gq39m2k3P0="
|
||||||
|
|
||||||
exim -be "cryptobox_recipient_pk = \"\xa0\x32\xf6\xa8\x2a\x6c\x7b\x41\xf4\xfc\xc8\x7c\xa8\x79\x46\x24\x9c\x03\xf7\x47\xf4\x6f\x6c\xea\x90\xcb\xed\x4c\x48\x4d\x57\x63\" \\
|
CIPHERTEXT=$(exim -be "\${dlfunc{${LIB}}{sodium_crypto_box_seal}{${PK}}{${CLEARTEXT}}}")
|
||||||
cryptobox_recipient_sk = \"\xf7\x4d\x7d\x26\x90\x6a\x63\xc3\xfa\xcd\xed\x2f\xd4\xd0\x6a\x76\xf5\xc4\xe6\xd8\xcb\xcf\x4c\x0e\x2d\x7c\x99\xfd\xcb\x0b\xf5\xfe\" \\
|
DECRYPTED=$(exim -be "\${dlfunc{${LIB}}{sodium_crypto_box_seal_open}{${SK}}{${PK}}{${CIPHERTEXT}}}")
|
||||||
\${dlfunc{${LIB}}{sodium_crypto_box_seal}{cryptobox_recipient_pk}{${CLEARTEXT}}}"
|
|
||||||
|
if [ "${CLEARTEXT}" == "${DECRYPTED}" ] ; then echo "sealed_box test successful"; fi
|
||||||
|
|||||||
Reference in New Issue
Block a user