From aaad6b0e4fbde440acf51338cb8d710c944cd336 Mon Sep 17 00:00:00 2001 From: Heiko Reese Date: Mon, 6 Sep 2021 02:07:33 +0200 Subject: [PATCH 01/21] Renamed generate_encryption_keys binary to libexim-encrypt-dlfunc-genkeys. --- README.md | 4 ++-- ...ate_encryption_keys.c => libexim-encrypt-dlfunc-genkeys.c} | 0 src/meson.build | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename src/{generate_encryption_keys.c => libexim-encrypt-dlfunc-genkeys.c} (100%) diff --git a/README.md b/README.md index f18db1f..837c53b 100644 --- a/README.md +++ b/README.md @@ -74,11 +74,11 @@ Public key encryption that uses a key pair which needs to be created beforehand: * `sodium_crypto_box_seal_open(private key, public key, ciphertext) → cleartext` The second pair needs a proper key pair in the correct format. This is what the -`generate_encryption_keys` utility is for. Simply run it once to generate a pair. Be aware that every invocation will +`libexim-encrypt-dlfunc-genkeys` utility is for. Simply run it once to generate a pair. Be aware that every invocation will overwrite the previous key pair file without confirmation! Make sure to store your production keys in a safe place. ```shell -$ ./generate_encryption_keys +$ ./libexim-encrypt-dlfunc-genkeys === Creating cryptobox key pair === Wrote »cryptobox_recipient_pk_exim.conf« Wrote »cryptobox_recipient_pk.raw« diff --git a/src/generate_encryption_keys.c b/src/libexim-encrypt-dlfunc-genkeys.c similarity index 100% rename from src/generate_encryption_keys.c rename to src/libexim-encrypt-dlfunc-genkeys.c diff --git a/src/meson.build b/src/meson.build index 81ccf72..8da17bf 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,6 +1,6 @@ configure_file(output: 'config.h', configuration: conf_data) -executable('generate_encryption_keys', 'generate_encryption_keys.c', +executable('libexim-encrypt-dlfunc-genkeys', 'libexim-encrypt-dlfunc-genkeys.c', dependencies : [ sodium_deps ], install: true) From a82f6d388bf5ef9e0b69105b4d7b72156c6ccd90 Mon Sep 17 00:00:00 2001 From: Heiko Reese Date: Tue, 7 Sep 2021 12:29:58 +0200 Subject: [PATCH 02/21] =?UTF-8?q?=E2=80=9CTransport=20commit=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + ...libexim-encrypt-dlfunc-decrypt-sealedbox.c | 119 ++++++++++++++ ...libexim-encrypt-dlfunc-decrypt-secretbox.c | 149 ++++++++++++++++++ src/meson.build | 9 +- 4 files changed, 277 insertions(+), 1 deletion(-) create mode 100644 src/libexim-encrypt-dlfunc-decrypt-sealedbox.c create mode 100644 src/libexim-encrypt-dlfunc-decrypt-secretbox.c diff --git a/.gitignore b/.gitignore index a774788..24bfb13 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /build +debian/*.ex diff --git a/src/libexim-encrypt-dlfunc-decrypt-sealedbox.c b/src/libexim-encrypt-dlfunc-decrypt-sealedbox.c new file mode 100644 index 0000000..6dd0117 --- /dev/null +++ b/src/libexim-encrypt-dlfunc-decrypt-sealedbox.c @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include +#include + +/* +#define PASSWORD_MAXLEN 1024 +#define CIPHERSTRING_MAX (1024*64) + +void print_usage(char * progname) { + printf("Usage: %s [OPTIONS]\n\n", progname); + printf("Secret and public key:\n"); + printf(" -s, --secret-key FILE read secret key from file FILE\n"); + printf(" -p, --public-key FILE read public key from file FILE\n"); + printf("\n"); + printf("Select input:\n"); + printf(" -c, --input STRING decrypt contents of STRING\n"); + printf(" -f, --infile FILE decrypt contents of the first line of file FILE\n"); + printf("\n"); +} + +typedef enum { + PASSWORD = 1, + SECRETKEY = 2 +} decryption_mode; + +typedef enum { + ARGUMENT = 1, + FROMFILE = 2 +} input_source; + +int main(int argc, char *argv[]) { + int opt= 0; + char password[PASSWORD_MAXLEN]; + char secret_key[PATH_MAX]; + char cipherstring[CIPHERSTRING_MAX]; + char infile[PATH_MAX]; + bool pass_from_env = false; + + decryption_mode mode = 0; + input_source input = 0; + + if (sodium_init() < 0) { + fputs("Unable to initialize libsodium", stderr); + exit(128); + } + + // define arguments + static struct option long_options[] = { + {"password", required_argument, NULL, 'p'}, + {"pass-from-env", no_argument, NULL, 'e'}, + {"secret-key", required_argument, NULL, 'k'}, + {"public-key", required_argument, NULL, 'k'}, + {"cipherstring", required_argument, NULL, 's'}, + {"infile", required_argument, NULL, 'f'} + }; + + // parse arguments + int long_index = 0; + while ((opt = getopt_long(argc, argv,"p:ek:s:f:", + long_options, &long_index )) != -1) { + switch (opt) { + case 'p': + strncpy(password, optarg, sizeof(password)-1); + mode |= PASSWORD; + break; + case 'e': + pass_from_env = true; + mode |= PASSENV; + break; + case 'k': + strncpy(secret_key, optarg, sizeof(secret_key)-1); + mode |= SECRETKEY; + break; + case 's': + strncpy(cipherstring, optarg, sizeof(cipherstring)-1); + input |= ARGUMENT; + break; + case 'f': + strncpy(infile, optarg, sizeof(infile)-1); + input |= FROMFILE; + break; + default: + print_usage(argv[0]); + exit(EXIT_FAILURE); + } + } + + // retrieve password/key + switch (mode) { + case PASSWORD: + if (pass_from_env == true) { + + } else { + + } + break; + case SECRETKEY: + break; + default: + printf("ERROR: Please specify a password OR a key file.\n\n"); + print_usage(argv[0]); + exit(EXIT_FAILURE); + } + switch (input) { + case ARGUMENT: + case FROMFILE: + break; + default: + printf("ERROR: Please specify a ciphertext.\n\n"); + print_usage(argv[0]); + exit(EXIT_FAILURE); + } +} +*/ + +int main(void) { return 0; } \ No newline at end of file diff --git a/src/libexim-encrypt-dlfunc-decrypt-secretbox.c b/src/libexim-encrypt-dlfunc-decrypt-secretbox.c new file mode 100644 index 0000000..d9d2a75 --- /dev/null +++ b/src/libexim-encrypt-dlfunc-decrypt-secretbox.c @@ -0,0 +1,149 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include + +#define ENVVAR_PASSWORD_NAME "LIBEXIM_PASSWORD" + +void print_usage(char * progname) { + printf("Usage: %s [OPTIONS]\n\n", progname); + printf("Password:\n"); + printf(" -p, --password PASSWORD decrypt using PASSWORD\n"); + printf(" -e, --pass-from-env read password from environment variable LIBEXIM_PASSWORD\n"); + printf("\n"); + printf("Select input:\n"); + printf(" -c, --input STRING decrypt contents of STRING\n"); + printf(" -f, --infile FILE decrypt contents of the first line of file FILE\n"); + printf("\n"); +} + +typedef enum { + NONE = 0, + PASSARG = 1, + PASSENV = 2, + INSTRING = 4, + INFILE = 8 +} seen_args; + +int main(int argc, char *argv[]) { + char* prog_basename = basename(argv[0]); + int opt; + char *cipherstring; + size_t pwlen; + char *b64password; + char *password_env; + int fd; + char *endptr; + + seen_args mode = NONE; + seen_args input = NONE; + + if (sodium_init() < 0) { + fputs("Unable to initialize libsodium", stderr); + exit(128); + } + + // define arguments + const char * shortargs = "p:ef:"; + static struct option long_options[] = { + {"password", required_argument, NULL, 'p'}, + {"pass-from-env", no_argument, NULL, 'e'}, + {"infile", required_argument, NULL, 'f'}, + {0,0,0,0} + }; + + // parse arguments + int long_index = 0; + while ((opt = getopt_long(argc, argv,shortargs, + long_options, &long_index )) != -1) { + switch (opt) { + case 'p': + pwlen = strlen(optarg); + b64password = malloc(pwlen+1); + strncpy(b64password, optarg, pwlen); + mode |= PASSARG; + break; + case 'e': + password_env = getenv(ENVVAR_PASSWORD_NAME); + if (password_env == NULL) { + fprintf(stderr, "[ERROR] Environment variable %s is undefined.\n\n", ENVVAR_PASSWORD_NAME); + } + pwlen = strlen(password_env); + b64password = malloc(pwlen+1); + strncpy(b64password, password_env, pwlen); + mode |= PASSENV; + break; + case 'f': + // open file + fd = open(optarg, O_RDONLY, (mode_t)0600); + if (fd == -1) { + perror("Error opening file"); + exit(EXIT_FAILURE); + } + // get length + struct stat fileInfo = {0}; + if (fstat(fd, &fileInfo) == -1) { + perror("Error getting the file size"); + exit(EXIT_FAILURE); + } + if (fileInfo.st_size == 0) { + fprintf(stderr, "Error: File is empty, nothing to do\n"); + exit(EXIT_FAILURE); + } + // mmap file + char *map = mmap(0, fileInfo.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (map == MAP_FAILED) + { + close(fd); + perror("Error mmapping the file"); + exit(EXIT_FAILURE); + } + // find first line + endptr = strchrnul(map, 0x0a); + + size_t cipherstring_len = endptr - map; + cipherstring = malloc(cipherstring_len+1); + strncpy(cipherstring, map, cipherstring_len); + + // munmap and close file + if (munmap(map, fileInfo.st_size) == -1) + { + close(fd); + perror("Error un-mmapping the file"); + exit(EXIT_FAILURE); + } + close(fd); + + input |= INFILE; + break; + } + } + + // check if a password was provided + if (mode == NONE) { + fprintf(stderr, "[ERROR] Please specify a password.\n\n"); + print_usage(prog_basename); + exit(EXIT_FAILURE); + } + + // read first non-option argument as ciphertext + if (optind < argc) { + size_t cipherstring_len = strlen(argv[optind])+1; + cipherstring = malloc(cipherstring_len+1); + strncpy(cipherstring, argv[optind], cipherstring_len); + input |= INSTRING; + } + + if (input == NONE) { + fprintf(stderr, "[ERROR] Please specify a ciphertext source.\n\n"); + print_usage(prog_basename); + exit(EXIT_FAILURE); + } + printf("»%s«\n", cipherstring); +} \ No newline at end of file diff --git a/src/meson.build b/src/meson.build index 8da17bf..22e5ac3 100644 --- a/src/meson.build +++ b/src/meson.build @@ -4,11 +4,18 @@ executable('libexim-encrypt-dlfunc-genkeys', 'libexim-encrypt-dlfunc-genkeys.c', dependencies : [ sodium_deps ], install: true) +executable('libexim-encrypt-dlfunc-decrypt-sealedbox', 'libexim-encrypt-dlfunc-decrypt-sealedbox.c', + dependencies : [ sodium_deps ], + install: true) + +executable('libexim-encrypt-dlfunc-decrypt-secretbox', 'libexim-encrypt-dlfunc-decrypt-secretbox.c', + dependencies : [ sodium_deps ], + install: true) + shared_library('exim-encrypt-dlfunc', 'libexim-encrypt-dlfunc.c', dependencies : [ sodium_deps ], install: true) - simple_exim_test = find_program('simple_exim_test.sh') test('simple test', simple_exim_test) From 0b01283cd94a4e8293732a0c4d6d7dc42da49806 Mon Sep 17 00:00:00 2001 From: Heiko Reese Date: Wed, 8 Sep 2021 03:34:12 +0200 Subject: [PATCH 03/21] Refactored file reading into finction. --- src/common.c | 53 +++++++++++++++ src/common.h | 10 +++ ...libexim-encrypt-dlfunc-decrypt-secretbox.c | 67 +++++-------------- 3 files changed, 81 insertions(+), 49 deletions(-) create mode 100644 src/common.c create mode 100644 src/common.h diff --git a/src/common.c b/src/common.c new file mode 100644 index 0000000..821590e --- /dev/null +++ b/src/common.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include "common.h" + +char * read_first_line(const char * filename) { + int fd; + char *endptr; + char *cipherstring; + + // open file + fd = open(filename, O_RDONLY, (mode_t)0600); + if (fd == -1) { + perror("Error opening file"); + exit(EXIT_FAILURE); + } + // get length + struct stat fileInfo = {0}; + if (fstat(fd, &fileInfo) == -1) { + perror("Error getting the file size"); + exit(EXIT_FAILURE); + } + if (fileInfo.st_size == 0) { + fprintf(stderr, "Error: File is empty, nothing to do\n"); + exit(EXIT_FAILURE); + } + // mmap file + char *map = mmap(0, fileInfo.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (map == MAP_FAILED) + { + close(fd); + perror("Error mmapping the file"); + exit(EXIT_FAILURE); + } + // find first line + endptr = strchrnul(map, 0x0a); + + size_t cipherstring_len = endptr - map; + cipherstring = malloc(cipherstring_len+1); + strncpy(cipherstring, map, cipherstring_len); + + // munmap and close file + if (munmap(map, fileInfo.st_size) == -1) + { + close(fd); + perror("Error un-mmapping the file"); + exit(EXIT_FAILURE); + } + close(fd); + + return cipherstring; +} \ No newline at end of file diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..8987394 --- /dev/null +++ b/src/common.h @@ -0,0 +1,10 @@ +// +// Created by sprawl on 08/09/2021. +// + +#ifndef EXIM_ENCRYPT_DLFUNC_COMMON_H +#define EXIM_ENCRYPT_DLFUNC_COMMON_H + +char * read_first_line(const char *); + +#endif //EXIM_ENCRYPT_DLFUNC_COMMON_H diff --git a/src/libexim-encrypt-dlfunc-decrypt-secretbox.c b/src/libexim-encrypt-dlfunc-decrypt-secretbox.c index d9d2a75..1ab7779 100644 --- a/src/libexim-encrypt-dlfunc-decrypt-secretbox.c +++ b/src/libexim-encrypt-dlfunc-decrypt-secretbox.c @@ -3,11 +3,8 @@ #include #include #include -#include -#include -#include -#include #include +#include "common.c" #define ENVVAR_PASSWORD_NAME "LIBEXIM_PASSWORD" @@ -38,8 +35,6 @@ int main(int argc, char *argv[]) { size_t pwlen; char *b64password; char *password_env; - int fd; - char *endptr; seen_args mode = NONE; seen_args input = NONE; @@ -73,6 +68,7 @@ int main(int argc, char *argv[]) { password_env = getenv(ENVVAR_PASSWORD_NAME); if (password_env == NULL) { fprintf(stderr, "[ERROR] Environment variable %s is undefined.\n\n", ENVVAR_PASSWORD_NAME); + exit(EXIT_FAILURE); } pwlen = strlen(password_env); b64password = malloc(pwlen+1); @@ -80,46 +76,7 @@ int main(int argc, char *argv[]) { mode |= PASSENV; break; case 'f': - // open file - fd = open(optarg, O_RDONLY, (mode_t)0600); - if (fd == -1) { - perror("Error opening file"); - exit(EXIT_FAILURE); - } - // get length - struct stat fileInfo = {0}; - if (fstat(fd, &fileInfo) == -1) { - perror("Error getting the file size"); - exit(EXIT_FAILURE); - } - if (fileInfo.st_size == 0) { - fprintf(stderr, "Error: File is empty, nothing to do\n"); - exit(EXIT_FAILURE); - } - // mmap file - char *map = mmap(0, fileInfo.st_size, PROT_READ, MAP_SHARED, fd, 0); - if (map == MAP_FAILED) - { - close(fd); - perror("Error mmapping the file"); - exit(EXIT_FAILURE); - } - // find first line - endptr = strchrnul(map, 0x0a); - - size_t cipherstring_len = endptr - map; - cipherstring = malloc(cipherstring_len+1); - strncpy(cipherstring, map, cipherstring_len); - - // munmap and close file - if (munmap(map, fileInfo.st_size) == -1) - { - close(fd); - perror("Error un-mmapping the file"); - exit(EXIT_FAILURE); - } - close(fd); - + cipherstring = read_first_line(optarg); input |= INFILE; break; } @@ -132,18 +89,30 @@ int main(int argc, char *argv[]) { exit(EXIT_FAILURE); } - // read first non-option argument as ciphertext + // read first non-option argument as ciphertext if present if (optind < argc) { size_t cipherstring_len = strlen(argv[optind])+1; cipherstring = malloc(cipherstring_len+1); strncpy(cipherstring, argv[optind], cipherstring_len); input |= INSTRING; } - + // fail if neither argument nor filename is present if (input == NONE) { fprintf(stderr, "[ERROR] Please specify a ciphertext source.\n\n"); print_usage(prog_basename); exit(EXIT_FAILURE); } - printf("»%s«\n", cipherstring); + + // base64-decode password + size_t password_len = strlen(b64password) / 4 * 3; + unsigned char * password = malloc(password_len); + int b64err = sodium_base642bin(password, password_len, + (const char *) b64password, strlen(b64password), + NULL, &password_len, NULL, sodium_base64_VARIANT_ORIGINAL); + if (b64err != 0) { + fprintf(stderr, "[ERROR] Unable to base64-decode the password\n"); + exit(EXIT_FAILURE); + } + + printf("»%s«\n", password); } \ No newline at end of file From 41e7c43ab88cc38bc17efb2aaebe13838e0ec2bc Mon Sep 17 00:00:00 2001 From: Heiko Reese Date: Sat, 11 Sep 2021 00:24:44 +0200 Subject: [PATCH 04/21] Always read password from environment. Factored base64-decoding into its own function. --- src/common.c | 29 ++++++- ...libexim-encrypt-dlfunc-decrypt-secretbox.c | 81 +++++++++---------- 2 files changed, 62 insertions(+), 48 deletions(-) diff --git a/src/common.c b/src/common.c index 821590e..ae07d51 100644 --- a/src/common.c +++ b/src/common.c @@ -2,15 +2,17 @@ #include #include #include +#include +#include #include "common.h" -char * read_first_line(const char * filename) { +char *read_first_line(const char *filename) { int fd; char *endptr; char *cipherstring; // open file - fd = open(filename, O_RDONLY, (mode_t)0600); + fd = open(filename, O_RDONLY, (mode_t) 0600); if (fd == -1) { perror("Error opening file"); exit(EXIT_FAILURE); @@ -41,8 +43,7 @@ char * read_first_line(const char * filename) { strncpy(cipherstring, map, cipherstring_len); // munmap and close file - if (munmap(map, fileInfo.st_size) == -1) - { + if (munmap(map, fileInfo.st_size) == -1) { close(fd); perror("Error un-mmapping the file"); exit(EXIT_FAILURE); @@ -50,4 +51,24 @@ char * read_first_line(const char * filename) { close(fd); return cipherstring; +} + +typedef struct { + unsigned char *string; + size_t length; +} Password; + +Password base64_decode_string(const char *input) { + Password p; + size_t input_len = strlen(input); + size_t outmaxlen = input_len / 4 * 3; + p.string = malloc(outmaxlen); + int b64err = sodium_base642bin(p.string, outmaxlen, (const char *) input, input_len, + NULL, &p.length, NULL, sodium_base64_VARIANT_ORIGINAL); + if (b64err != 0) { + fprintf(stderr, "[ERROR] Unable to base64-decode the password\n"); + exit(EXIT_FAILURE); + } + + return p; } \ No newline at end of file diff --git a/src/libexim-encrypt-dlfunc-decrypt-secretbox.c b/src/libexim-encrypt-dlfunc-decrypt-secretbox.c index 1ab7779..f8d74b4 100644 --- a/src/libexim-encrypt-dlfunc-decrypt-secretbox.c +++ b/src/libexim-encrypt-dlfunc-decrypt-secretbox.c @@ -12,7 +12,8 @@ void print_usage(char * progname) { printf("Usage: %s [OPTIONS]\n\n", progname); printf("Password:\n"); printf(" -p, --password PASSWORD decrypt using PASSWORD\n"); - printf(" -e, --pass-from-env read password from environment variable LIBEXIM_PASSWORD\n"); + printf("\n"); + printf(" If the environment variable LIBEXIM_PASSWORD is set the password is read from it.\n"); printf("\n"); printf("Select input:\n"); printf(" -c, --input STRING decrypt contents of STRING\n"); @@ -45,36 +46,34 @@ int main(int argc, char *argv[]) { } // define arguments - const char * shortargs = "p:ef:"; + const char *shortargs = "p:ef:"; static struct option long_options[] = { - {"password", required_argument, NULL, 'p'}, - {"pass-from-env", no_argument, NULL, 'e'}, - {"infile", required_argument, NULL, 'f'}, - {0,0,0,0} + {"password", required_argument, NULL, 'p'}, + {"pass-from-env", no_argument, NULL, 'e'}, + {"infile", required_argument, NULL, 'f'}, + {0, 0, 0, 0} }; + // check environment for LIBEXIM_PASSWORD + password_env = getenv(ENVVAR_PASSWORD_NAME); + if (password_env != NULL && strlen(password_env) > 0) { + pwlen = strlen(password_env); + b64password = malloc(pwlen + 1); + strncpy(b64password, password_env, pwlen); + mode |= PASSENV; + } + // parse arguments int long_index = 0; - while ((opt = getopt_long(argc, argv,shortargs, - long_options, &long_index )) != -1) { + while ((opt = getopt_long(argc, argv, shortargs, + long_options, &long_index)) != -1) { switch (opt) { case 'p': pwlen = strlen(optarg); - b64password = malloc(pwlen+1); + b64password = malloc(pwlen + 1); strncpy(b64password, optarg, pwlen); mode |= PASSARG; break; - case 'e': - password_env = getenv(ENVVAR_PASSWORD_NAME); - if (password_env == NULL) { - fprintf(stderr, "[ERROR] Environment variable %s is undefined.\n\n", ENVVAR_PASSWORD_NAME); - exit(EXIT_FAILURE); - } - pwlen = strlen(password_env); - b64password = malloc(pwlen+1); - strncpy(b64password, password_env, pwlen); - mode |= PASSENV; - break; case 'f': cipherstring = read_first_line(optarg); input |= INFILE; @@ -82,37 +81,31 @@ int main(int argc, char *argv[]) { } } - // check if a password was provided - if (mode == NONE) { - fprintf(stderr, "[ERROR] Please specify a password.\n\n"); - print_usage(prog_basename); - exit(EXIT_FAILURE); - } - // read first non-option argument as ciphertext if present if (optind < argc) { - size_t cipherstring_len = strlen(argv[optind])+1; - cipherstring = malloc(cipherstring_len+1); + size_t cipherstring_len = strlen(argv[optind]) + 1; + cipherstring = malloc(cipherstring_len + 1); strncpy(cipherstring, argv[optind], cipherstring_len); input |= INSTRING; } - // fail if neither argument nor filename is present - if (input == NONE) { - fprintf(stderr, "[ERROR] Please specify a ciphertext source.\n\n"); - print_usage(prog_basename); - exit(EXIT_FAILURE); - } - // base64-decode password - size_t password_len = strlen(b64password) / 4 * 3; - unsigned char * password = malloc(password_len); - int b64err = sodium_base642bin(password, password_len, - (const char *) b64password, strlen(b64password), - NULL, &password_len, NULL, sodium_base64_VARIANT_ORIGINAL); - if (b64err != 0) { - fprintf(stderr, "[ERROR] Unable to base64-decode the password\n"); + // check if a password was provided + if (mode == NONE) { + fprintf(stderr, "[ERROR] Please specify a password.\n\n"); + print_usage(prog_basename); exit(EXIT_FAILURE); } - printf("»%s«\n", password); + // fail if neither argument nor filename is present + if (input == NONE) { + fprintf(stderr, "[ERROR] Please specify a ciphertext source.\n\n"); + print_usage(prog_basename); + exit(EXIT_FAILURE); + } + + // base64-decode password + Password p; + p = base64_decode_string(b64password); + + printf("»%s« [%zu]\n", p.string, p.length); } \ No newline at end of file From ad3437f5df906c3d75af59ddf3cee79476e1f738 Mon Sep 17 00:00:00 2001 From: Heiko Reese Date: Sat, 11 Sep 2021 02:06:19 +0200 Subject: [PATCH 05/21] Working version of libexim-encrypt-dlfunc-decrypt-secretbox --- src/common.c | 11 ++-- ...libexim-encrypt-dlfunc-decrypt-secretbox.c | 57 ++++++++++++++----- 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/src/common.c b/src/common.c index ae07d51..13e93a3 100644 --- a/src/common.c +++ b/src/common.c @@ -58,17 +58,14 @@ typedef struct { size_t length; } Password; -Password base64_decode_string(const char *input) { - Password p; +void base64_decode_string(const char *input, unsigned char **outstring, size_t *outlen) { size_t input_len = strlen(input); size_t outmaxlen = input_len / 4 * 3; - p.string = malloc(outmaxlen); - int b64err = sodium_base642bin(p.string, outmaxlen, (const char *) input, input_len, - NULL, &p.length, NULL, sodium_base64_VARIANT_ORIGINAL); + *outstring = malloc(outmaxlen * sizeof(unsigned char)); + int b64err = sodium_base642bin(*outstring, outmaxlen, (const char *) input, input_len, + NULL, outlen, NULL, sodium_base64_VARIANT_ORIGINAL); if (b64err != 0) { fprintf(stderr, "[ERROR] Unable to base64-decode the password\n"); exit(EXIT_FAILURE); } - - return p; } \ No newline at end of file diff --git a/src/libexim-encrypt-dlfunc-decrypt-secretbox.c b/src/libexim-encrypt-dlfunc-decrypt-secretbox.c index f8d74b4..feeb95b 100644 --- a/src/libexim-encrypt-dlfunc-decrypt-secretbox.c +++ b/src/libexim-encrypt-dlfunc-decrypt-secretbox.c @@ -30,11 +30,11 @@ typedef enum { } seen_args; int main(int argc, char *argv[]) { - char* prog_basename = basename(argv[0]); + char *prog_basename = basename(argv[0]); int opt; char *cipherstring; - size_t pwlen; - char *b64password; + size_t password_len; + char *password; char *password_env; seen_args mode = NONE; @@ -57,9 +57,9 @@ int main(int argc, char *argv[]) { // check environment for LIBEXIM_PASSWORD password_env = getenv(ENVVAR_PASSWORD_NAME); if (password_env != NULL && strlen(password_env) > 0) { - pwlen = strlen(password_env); - b64password = malloc(pwlen + 1); - strncpy(b64password, password_env, pwlen); + password_len = strlen((const char *) password_env); + password = malloc(password_len + 1); + strncpy(password, password_env, password_len); mode |= PASSENV; } @@ -69,9 +69,9 @@ int main(int argc, char *argv[]) { long_options, &long_index)) != -1) { switch (opt) { case 'p': - pwlen = strlen(optarg); - b64password = malloc(pwlen + 1); - strncpy(b64password, optarg, pwlen); + password_len = strlen((const char *) optarg); + password = malloc(password_len + 1); + strncpy(password, optarg, password_len); mode |= PASSARG; break; case 'f': @@ -96,16 +96,45 @@ int main(int argc, char *argv[]) { exit(EXIT_FAILURE); } - // fail if neither argument nor filename is present + // fail if neither argument nor filename for ciphertext is present if (input == NONE) { fprintf(stderr, "[ERROR] Please specify a ciphertext source.\n\n"); print_usage(prog_basename); exit(EXIT_FAILURE); } - // base64-decode password - Password p; - p = base64_decode_string(b64password); + // Derive key from the password. + unsigned char keybytes[crypto_secretbox_KEYBYTES]; + sodium_memzero(keybytes, crypto_secretbox_KEYBYTES); + crypto_generichash(keybytes, crypto_secretbox_KEYBYTES, + (unsigned char *) password, password_len, NULL, 0); - printf("»%s« [%zu]\n", p.string, p.length); + // base64-decode input + unsigned char *ciphertext; + size_t ciphertext_len; + base64_decode_string(cipherstring, &ciphertext, &ciphertext_len); + + // extract nonce + unsigned char nonce[crypto_secretbox_NONCEBYTES]; + memcpy(nonce, ciphertext, crypto_secretbox_NONCEBYTES); + + // prepare buffer for cleartext + if (ciphertext_len < crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES) { + fprintf(stderr, "[ERROR] Ciphertext is too small to contain any data.\n\n"); + exit(EXIT_FAILURE); + } + size_t cleartext_len = ciphertext_len - crypto_secretbox_NONCEBYTES - crypto_secretbox_MACBYTES; + unsigned char *cleartext = (unsigned char *) malloc(cleartext_len + 1); + sodium_memzero(cleartext, cleartext_len + 1); + + // decrypt + if (crypto_secretbox_open_easy(cleartext, &ciphertext[crypto_secretbox_NONCEBYTES], + ciphertext_len - crypto_secretbox_NONCEBYTES, nonce, keybytes) == 0) { + } else { + fprintf(stderr, "[ERROR] Unable to decrypt message.\n\n"); + exit(EXIT_FAILURE); + } + + // print cleartext to stdout + fprintf(stdout, "%s", (const char *) cleartext); } \ No newline at end of file From 534db3ad6e744e55c0ae7112b53722d008369394 Mon Sep 17 00:00:00 2001 From: Heiko Reese Date: Sat, 11 Sep 2021 02:13:22 +0200 Subject: [PATCH 06/21] Add option to suppress a newline at the end of the output. --- ...libexim-encrypt-dlfunc-decrypt-secretbox.c | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/libexim-encrypt-dlfunc-decrypt-secretbox.c b/src/libexim-encrypt-dlfunc-decrypt-secretbox.c index feeb95b..5a0dcfd 100644 --- a/src/libexim-encrypt-dlfunc-decrypt-secretbox.c +++ b/src/libexim-encrypt-dlfunc-decrypt-secretbox.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "common.c" #define ENVVAR_PASSWORD_NAME "LIBEXIM_PASSWORD" @@ -13,12 +14,16 @@ void print_usage(char * progname) { printf("Password:\n"); printf(" -p, --password PASSWORD decrypt using PASSWORD\n"); printf("\n"); - printf(" If the environment variable LIBEXIM_PASSWORD is set the password is read from it.\n"); + printf(" If the environment variable LIBEXIM_PASSWORD is set the password is read from there.\n"); + printf(" Setting a password with -p/--password overwrites this mechanism.\n"); printf("\n"); printf("Select input:\n"); printf(" -c, --input STRING decrypt contents of STRING\n"); printf(" -f, --infile FILE decrypt contents of the first line of file FILE\n"); printf("\n"); + printf("Output:\n"); + printf(" -n, --no-newline Do not add a newline to the output\n"); + printf("\n"); } typedef enum { @@ -36,6 +41,7 @@ int main(int argc, char *argv[]) { size_t password_len; char *password; char *password_env; + bool add_newline = true; seen_args mode = NONE; seen_args input = NONE; @@ -46,11 +52,12 @@ int main(int argc, char *argv[]) { } // define arguments - const char *shortargs = "p:ef:"; + const char *shortargs = "p:ef:n"; static struct option long_options[] = { {"password", required_argument, NULL, 'p'}, {"pass-from-env", no_argument, NULL, 'e'}, {"infile", required_argument, NULL, 'f'}, + {"no-newline", no_argument, NULL, 'n'}, {0, 0, 0, 0} }; @@ -78,6 +85,9 @@ int main(int argc, char *argv[]) { cipherstring = read_first_line(optarg); input |= INFILE; break; + case 'n': + add_newline = false; + break; } } @@ -136,5 +146,9 @@ int main(int argc, char *argv[]) { } // print cleartext to stdout - fprintf(stdout, "%s", (const char *) cleartext); + if (add_newline == true) { + fprintf(stdout, "%s\n", (const char *) cleartext); + } else { + fprintf(stdout, "%s", (const char *) cleartext); + } } \ No newline at end of file From bb67fe5ba299d8695c478772e86775225d3b38a8 Mon Sep 17 00:00:00 2001 From: Heiko Reese Date: Sat, 11 Sep 2021 02:23:47 +0200 Subject: [PATCH 07/21] Updated example in README.md to use the actual path from the Debian package. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 837c53b..e4dc229 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ meson compile -C build meson test -C build ``` -5. Copy to final destination (feel free to pick another place than `/usr/local/lib/`): +5. Copy to final destination (feel free to pick another place than `/usr/lib/x86_64-linux-gnu/`): ```shell meson install -C build @@ -107,11 +107,11 @@ original header is usually provided in these cases). Add this snippet to your DA ``` warn log_message = Removing X-Originating-IP: header condition = ${if def:h_X-originating-IP: {1}{0}} - add_header = X-Orig-IP-PKK: ${dlfunc{/usr/local/lib/libexim-encrypt-dlfunc.so} \ + add_header = X-Orig-IP-PKK: ${dlfunc{/usr/lib/x86_64-linux-gnu/libexim-encrypt-dlfunc.so} \ {sodium_crypto_box_seal} \ {ktp1OEEItrgvSfpVTtu+ybyNjzuuN8OzCdfrGAJt4j8=} \ {$h_X-originating-IP:}} - add_header = X-Orig-IP-Pass: ${dlfunc{/usr/local/lib/libexim-encrypt-dlfunc.so} \ + add_header = X-Orig-IP-Pass: ${dlfunc{/usr/lib/x86_64-linux-gnu/libexim-encrypt-dlfunc.so} \ {sodium_crypto_secretbox_encrypt_password} \ {Insert your password here} \ {$h_X-originating-IP:}} From 5a1bd58452ba898f49443e4df641b81b346f4b88 Mon Sep 17 00:00:00 2001 From: Heiko Reese Date: Sat, 11 Sep 2021 02:26:39 +0200 Subject: [PATCH 08/21] Renamed test function for library. --- src/debug_helpers.c | 2 +- src/meson.build | 2 +- src/{simple_exim_test.sh => test_libexim-encrypt-dlfunc.sh} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/{simple_exim_test.sh => test_libexim-encrypt-dlfunc.sh} (100%) diff --git a/src/debug_helpers.c b/src/debug_helpers.c index 329fd64..e596ac8 100644 --- a/src/debug_helpers.c +++ b/src/debug_helpers.c @@ -20,7 +20,7 @@ char *string2hex(unsigned char *input, size_t length) { * 1. Add this code to the first “breakpoint”: * log_write(0, LOG_MAIN, "pid: %d", getpid()); int busywait = 0; while (busywait == 0) {} * 2. Compile. - * 3. Run “exim -be […]” to call the lib; see simple_exim_test.sh for details. + * 3. Run “exim -be […]” to call the lib; see test_libexim-encrypt-dlfunc.sh for details. * 4. Read exim pid from log output. Attach to the looping exim process with “gdb -p PID” * 5. Prepare breakpoints, watches, etc. Set busywait to 1 and continue. */ \ No newline at end of file diff --git a/src/meson.build b/src/meson.build index 22e5ac3..86f24f0 100644 --- a/src/meson.build +++ b/src/meson.build @@ -16,6 +16,6 @@ shared_library('exim-encrypt-dlfunc', 'libexim-encrypt-dlfunc.c', dependencies : [ sodium_deps ], install: true) -simple_exim_test = find_program('simple_exim_test.sh') +simple_exim_test = find_program('test_libexim-encrypt-dlfunc.sh') test('simple test', simple_exim_test) diff --git a/src/simple_exim_test.sh b/src/test_libexim-encrypt-dlfunc.sh similarity index 100% rename from src/simple_exim_test.sh rename to src/test_libexim-encrypt-dlfunc.sh From 1f8aa5fc4c17f829c91bf1dabe384baa19207715 Mon Sep 17 00:00:00 2001 From: Heiko Reese Date: Sat, 11 Sep 2021 02:46:32 +0200 Subject: [PATCH 09/21] Added test fo password decryption command --- src/meson.build | 6 ++-- ...ibexim-encrypt-dlfunc-decrypt-secretbox.sh | 31 +++++++++++++++++++ src/test_libexim-encrypt-dlfunc.sh | 2 +- 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100755 src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh diff --git a/src/meson.build b/src/meson.build index 86f24f0..5d72b45 100644 --- a/src/meson.build +++ b/src/meson.build @@ -16,6 +16,8 @@ shared_library('exim-encrypt-dlfunc', 'libexim-encrypt-dlfunc.c', dependencies : [ sodium_deps ], install: true) -simple_exim_test = find_program('test_libexim-encrypt-dlfunc.sh') -test('simple test', simple_exim_test) +dlfunc_test = find_program('test_libexim-encrypt-dlfunc.sh') +test('simple test', dlfunc_test) +decrypt_secretbox_test = find_program('test_libexim-encrypt-dlfunc-decrypt-secretbox.sh') +test('decrypt-secretbox', decrypt_secretbox_test) \ No newline at end of file diff --git a/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh b/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh new file mode 100755 index 0000000..c67310f --- /dev/null +++ b/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# shellcheck disable=SC2034 + +set -e + +PATH=/sbin:/usr/sbin:$PATH + +TEST_PASSWORD='ThisIsAPassword' +TEST_CLEARTEXT='This is my cleartext' +TEST_CIPHERTEXT01='RCHI+VukmWIsVE3eixbWIAtPPBW63nmV1ITpSBEDYXC9Y5QMBd1zmGLLhE+S9yg0sHfOF/1+wmfF7YXv' +TEST_CIPHERTEXT02='sEG09WnEKIN2nyJYGNNVo14o7wV6X9HQxW+zxAxMLX9jVdashdaoHqLXQGM8lzpJhG6629lccjzAfrq8' + +LIBEXIM_PASSWORD="${TEST_PASSWORD}" +DECRYPTED01="$(src/libexim-encrypt-dlfunc-decrypt-secretbox ${TEST_CIPHERTEXT01})" + +if [ "${DECRYPTED01}" == "${TEST_CLEARTEXT}" ] ; then + echo "decryption with password from environment successful" +else + echo "decryption with password from environment unsuccessful" + exit 127 +fi + +unset LIBEXIM_PASSWORD +DECRYPTED02="$(src/libexim-encrypt-dlfunc-decrypt-secretbox -p ${TEST_PASSWORD} ${TEST_CIPHERTEXT02})" + +if [ "${DECRYPTED02}" == "${TEST_CLEARTEXT}" ] ; then + echo "decryption with password from commandline successful" +else + echo "decryption with password from commandline unsuccessful" + exit 128 +fi \ No newline at end of file diff --git a/src/test_libexim-encrypt-dlfunc.sh b/src/test_libexim-encrypt-dlfunc.sh index cf5acff..87ea4d2 100755 --- a/src/test_libexim-encrypt-dlfunc.sh +++ b/src/test_libexim-encrypt-dlfunc.sh @@ -9,7 +9,7 @@ install -t /tmp src/libexim-encrypt-dlfunc.so LIB=/tmp/libexim-encrypt-dlfunc.so CLEARTEXT="127.88.99.23" # keep short; see above -PASSWORD="`openssl rand -base64 32`" +PASSWORD="$(openssl rand -base64 32)" CIPHERTEXT=$(exim -be "\${dlfunc{${LIB}}{sodium_crypto_secretbox_encrypt_password}{${PASSWORD}}{${CLEARTEXT}}}") DECRYPTED=$(exim -be "\${dlfunc{${LIB}}{sodium_crypto_secretbox_decrypt_password}{${PASSWORD}}{${CIPHERTEXT}}}") From b8a5a2c759d51d151d8c93ca36f88e72ad248e7c Mon Sep 17 00:00:00 2001 From: Heiko Reese Date: Sat, 11 Sep 2021 02:48:55 +0200 Subject: [PATCH 10/21] =?UTF-8?q?=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh b/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh index c67310f..b9d915f 100755 --- a/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh +++ b/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh @@ -10,8 +10,7 @@ TEST_CLEARTEXT='This is my cleartext' TEST_CIPHERTEXT01='RCHI+VukmWIsVE3eixbWIAtPPBW63nmV1ITpSBEDYXC9Y5QMBd1zmGLLhE+S9yg0sHfOF/1+wmfF7YXv' TEST_CIPHERTEXT02='sEG09WnEKIN2nyJYGNNVo14o7wV6X9HQxW+zxAxMLX9jVdashdaoHqLXQGM8lzpJhG6629lccjzAfrq8' -LIBEXIM_PASSWORD="${TEST_PASSWORD}" -DECRYPTED01="$(src/libexim-encrypt-dlfunc-decrypt-secretbox ${TEST_CIPHERTEXT01})" +DECRYPTED01="$(LIBEXIM_PASSWORD="${TEST_PASSWORD}" src/libexim-encrypt-dlfunc-decrypt-secretbox ${TEST_CIPHERTEXT01})" if [ "${DECRYPTED01}" == "${TEST_CLEARTEXT}" ] ; then echo "decryption with password from environment successful" From 99ff9e359c5158a5ffa3d26db86653c174efe654 Mon Sep 17 00:00:00 2001 From: Heiko Reese Date: Sat, 11 Sep 2021 02:59:56 +0200 Subject: [PATCH 11/21] Added new files to CI artifacts --- .gitlab-ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0837428..31ef3a8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,8 +21,10 @@ stages: - cd .. artifacts: paths: - - build/src/generate_encryption_keys - build/src/libexim-encrypt-dlfunc.so + - build/src/libexim-encrypt-dlfunc-genkeys + - build/src/libexim-encrypt-dlfunc-decrypt-secretbox + #- build/src/libexim-encrypt-dlfunc-decrypt-sealedtbox .debian-package: stage: debian-package From 649932c73cc76b26e51a5c0d420ef32dcfb4bede Mon Sep 17 00:00:00 2001 From: Heiko Reese Date: Sat, 11 Sep 2021 03:16:35 +0200 Subject: [PATCH 12/21] Changed test output to conform to the TAP protocol (https://testanything.org) --- src/meson.build | 2 +- src/test_libexim-encrypt-dlfunc.sh | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/meson.build b/src/meson.build index 5d72b45..3f8540e 100644 --- a/src/meson.build +++ b/src/meson.build @@ -17,7 +17,7 @@ shared_library('exim-encrypt-dlfunc', 'libexim-encrypt-dlfunc.c', install: true) dlfunc_test = find_program('test_libexim-encrypt-dlfunc.sh') -test('simple test', dlfunc_test) +test('simple test', dlfunc_test, protocol: tap) decrypt_secretbox_test = find_program('test_libexim-encrypt-dlfunc-decrypt-secretbox.sh') test('decrypt-secretbox', decrypt_secretbox_test) \ No newline at end of file diff --git a/src/test_libexim-encrypt-dlfunc.sh b/src/test_libexim-encrypt-dlfunc.sh index 87ea4d2..fe0b3cd 100755 --- a/src/test_libexim-encrypt-dlfunc.sh +++ b/src/test_libexim-encrypt-dlfunc.sh @@ -1,9 +1,11 @@ #!/bin/bash set -e - PATH=/sbin:/usr/sbin:$PATH +# this script implements the TAP protocol (https://testanything.org) +echo 1..2 + # copy to /tmp to keep call to exim under 256 chars (prevent problems on Ubuntu) install -t /tmp src/libexim-encrypt-dlfunc.so @@ -15,9 +17,9 @@ CIPHERTEXT=$(exim -be "\${dlfunc{${LIB}}{sodium_crypto_secretbox_encrypt_passwor DECRYPTED=$(exim -be "\${dlfunc{${LIB}}{sodium_crypto_secretbox_decrypt_password}{${PASSWORD}}{${CIPHERTEXT}}}") if [ "${CLEARTEXT}" == "${DECRYPTED}" ] ; then - echo "secretbox test successful" + echo "ok 1 - secretbox test successful" else - echo "secretbox test unsuccessful" + echo "not ok 1 - secretbox test unsuccessful" exit 127 fi @@ -30,8 +32,8 @@ CIPHERTEXT=$(exim -be "\${dlfunc{${LIB}}{sodium_crypto_box_seal}{${PK}}{${CLEART DECRYPTED=$(exim -be "\${dlfunc{${LIB}}{sodium_crypto_box_seal_open}{${SK}}{${PK}}{${CIPHERTEXT}}}") if [ "${CLEARTEXT}" == "${DECRYPTED}" ] ; then - echo "sealed_box test successful" + echo "ok 2 - sealed_box test successful" else - echo "sealed_box test unsuccessful" + echo "ok 2 - sealed_box test unsuccessful" exit 128 fi From 8845aaa6536c7049dcfffbaf93f7dce79bab1547 Mon Sep 17 00:00:00 2001 From: Heiko Reese Date: Sat, 11 Sep 2021 11:41:12 +0200 Subject: [PATCH 13/21] Fixed test numbering --- src/meson.build | 4 +- ...ibexim-encrypt-dlfunc-decrypt-secretbox.sh | 39 +++++++++++++------ src/test_libexim-encrypt-dlfunc.sh | 3 -- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/meson.build b/src/meson.build index 3f8540e..57b39ce 100644 --- a/src/meson.build +++ b/src/meson.build @@ -17,7 +17,7 @@ shared_library('exim-encrypt-dlfunc', 'libexim-encrypt-dlfunc.c', install: true) dlfunc_test = find_program('test_libexim-encrypt-dlfunc.sh') -test('simple test', dlfunc_test, protocol: tap) +test('libexim-encrypt-dlfunc', dlfunc_test, protocol: 'tap') decrypt_secretbox_test = find_program('test_libexim-encrypt-dlfunc-decrypt-secretbox.sh') -test('decrypt-secretbox', decrypt_secretbox_test) \ No newline at end of file +test('decrypt-secretbox', decrypt_secretbox_test, protocol: 'tap') \ No newline at end of file diff --git a/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh b/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh index b9d915f..6c1f04e 100755 --- a/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh +++ b/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh @@ -1,30 +1,45 @@ #!/bin/bash # shellcheck disable=SC2034 -set -e - PATH=/sbin:/usr/sbin:$PATH +# this script implements the TAP protocol (https://testanything.org) +echo 1..4 + TEST_PASSWORD='ThisIsAPassword' TEST_CLEARTEXT='This is my cleartext' TEST_CIPHERTEXT01='RCHI+VukmWIsVE3eixbWIAtPPBW63nmV1ITpSBEDYXC9Y5QMBd1zmGLLhE+S9yg0sHfOF/1+wmfF7YXv' TEST_CIPHERTEXT02='sEG09WnEKIN2nyJYGNNVo14o7wV6X9HQxW+zxAxMLX9jVdashdaoHqLXQGM8lzpJhG6629lccjzAfrq8' +CIPHERTEXT_FILE01="$(mktemp)" +CIPHERTEXT_FILE02="$(mktemp)" +echo "${TEST_CIPHERTEXT01}" > "${CIPHERTEXT_FILE01}" +echo "${TEST_CIPHERTEXT02}" > "${CIPHERTEXT_FILE02}" DECRYPTED01="$(LIBEXIM_PASSWORD="${TEST_PASSWORD}" src/libexim-encrypt-dlfunc-decrypt-secretbox ${TEST_CIPHERTEXT01})" - if [ "${DECRYPTED01}" == "${TEST_CLEARTEXT}" ] ; then - echo "decryption with password from environment successful" + echo "ok 1 - decrypt commandline argument with password from environment successful" else - echo "decryption with password from environment unsuccessful" - exit 127 + echo "not ok 1 - decrypt commandline argument with password from environment unsuccessful" fi -unset LIBEXIM_PASSWORD -DECRYPTED02="$(src/libexim-encrypt-dlfunc-decrypt-secretbox -p ${TEST_PASSWORD} ${TEST_CIPHERTEXT02})" - +DECRYPTED02="$(LIBEXIM_PASSWORD="${TEST_PASSWORD}" src/libexim-encrypt-dlfunc-decrypt-secretbox --infile ${CIPHERTEXT_FILE01})" if [ "${DECRYPTED02}" == "${TEST_CLEARTEXT}" ] ; then - echo "decryption with password from commandline successful" + echo "ok 2 - decrypt file contents with password from environment successful" else - echo "decryption with password from commandline unsuccessful" - exit 128 + echo "not ok 2 - decrypt file contents with password from environment unsuccessful" +fi +unset LIBEXIM_PASSWORD + +DECRYPTED03="$(src/libexim-encrypt-dlfunc-decrypt-secretbox -p ${TEST_PASSWORD} ${TEST_CIPHERTEXT02})" +if [ "${DECRYPTED03}" == "${TEST_CLEARTEXT}" ] ; then + echo "ok 3 - decrypt commandline argument with password from commandline successful" +else + echo "not ok 3 - decrypt commandline argument with password from commandline unsuccessful" +fi + +DECRYPTED04="$(src/libexim-encrypt-dlfunc-decrypt-secretbox -p ${TEST_PASSWORD} --infile ${CIPHERTEXT_FILE02})" +if [ "${DECRYPTED04}" == "${TEST_CLEARTEXT}" ] ; then + echo "ok 4 - decrypt commandline argument with password from commandline successful" +else + echo "not ok 4 - decrypt commandline argument with password from commandline unsuccessful" fi \ No newline at end of file diff --git a/src/test_libexim-encrypt-dlfunc.sh b/src/test_libexim-encrypt-dlfunc.sh index fe0b3cd..1177e98 100755 --- a/src/test_libexim-encrypt-dlfunc.sh +++ b/src/test_libexim-encrypt-dlfunc.sh @@ -1,6 +1,5 @@ #!/bin/bash -set -e PATH=/sbin:/usr/sbin:$PATH # this script implements the TAP protocol (https://testanything.org) @@ -20,7 +19,6 @@ if [ "${CLEARTEXT}" == "${DECRYPTED}" ] ; then echo "ok 1 - secretbox test successful" else echo "not ok 1 - secretbox test unsuccessful" - exit 127 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 }; @@ -35,5 +33,4 @@ if [ "${CLEARTEXT}" == "${DECRYPTED}" ] ; then echo "ok 2 - sealed_box test successful" else echo "ok 2 - sealed_box test unsuccessful" - exit 128 fi From b6726dfcd2b2d33b4153a23d470f2fb6f8d2aeac Mon Sep 17 00:00:00 2001 From: Heiko Reese Date: Sat, 11 Sep 2021 12:04:06 +0200 Subject: [PATCH 14/21] Fixed erronous output --- src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh b/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh index 6c1f04e..0c52601 100755 --- a/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh +++ b/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh @@ -39,7 +39,7 @@ fi DECRYPTED04="$(src/libexim-encrypt-dlfunc-decrypt-secretbox -p ${TEST_PASSWORD} --infile ${CIPHERTEXT_FILE02})" if [ "${DECRYPTED04}" == "${TEST_CLEARTEXT}" ] ; then - echo "ok 4 - decrypt commandline argument with password from commandline successful" + echo "ok 4 - decrypt file contents with password from commandline successful" else - echo "not ok 4 - decrypt commandline argument with password from commandline unsuccessful" + echo "not ok 4 - decrypt file contents with password from commandline unsuccessful" fi \ No newline at end of file From 57b829737ebe06f5b88102536644aa13ce4e82b2 Mon Sep 17 00:00:00 2001 From: Heiko Reese Date: Sat, 11 Sep 2021 12:20:23 +0200 Subject: [PATCH 15/21] debugging meson build tests --- src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh b/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh index 0c52601..08de2f2 100755 --- a/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh +++ b/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh @@ -26,6 +26,8 @@ DECRYPTED02="$(LIBEXIM_PASSWORD="${TEST_PASSWORD}" src/libexim-encrypt-dlfunc-de if [ "${DECRYPTED02}" == "${TEST_CLEARTEXT}" ] ; then echo "ok 2 - decrypt file contents with password from environment successful" else + echo "${CIPHERTEXT_FILE01}" + cat "${CIPHERTEXT_FILE01}" echo "not ok 2 - decrypt file contents with password from environment unsuccessful" fi unset LIBEXIM_PASSWORD @@ -41,5 +43,7 @@ DECRYPTED04="$(src/libexim-encrypt-dlfunc-decrypt-secretbox -p ${TEST_PASSWORD} if [ "${DECRYPTED04}" == "${TEST_CLEARTEXT}" ] ; then echo "ok 4 - decrypt file contents with password from commandline successful" else + echo "${CIPHERTEXT_FILE02}" + cat "${CIPHERTEXT_FILE02}" echo "not ok 4 - decrypt file contents with password from commandline unsuccessful" fi \ No newline at end of file From 0d8fb3dd774f3bfadc328a423039d934b158d3ef Mon Sep 17 00:00:00 2001 From: Heiko Reese Date: Sat, 11 Sep 2021 12:23:15 +0200 Subject: [PATCH 16/21] debugging meson build tests --- .gitlab-ci.yml | 30 +++++++++---------- ...ibexim-encrypt-dlfunc-decrypt-secretbox.sh | 4 +-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 31ef3a8..8a25446 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -39,31 +39,23 @@ stages: - ./*.changes - ./*.buildinfo -build:buster: - extends: - - .build - - .image-buster - needs: [] - build:bullseye: extends: - .image-bullseye - .build - needs: [] + needs: [ ] build:focal: extends: - .image-focal - .build - needs: [] + needs: [ ] -debian-package:buster: +build:buster: extends: + - .build - .image-buster - - .debian-package - dependencies: - - build:buster - needs: ["build:buster"] + needs: [ ] debian-package:bullseye: extends: @@ -71,7 +63,7 @@ debian-package:bullseye: - .debian-package dependencies: - build:bullseye - needs: ["build:bullseye"] + needs: [ "build:bullseye" ] debian-package:focal: extends: @@ -79,4 +71,12 @@ debian-package:focal: - .debian-package dependencies: - build:focal - needs: ["build:focal"] + needs: [ "build:focal" ] + +debian-package:buster: + extends: + - .image-buster + - .debian-package + dependencies: + - build:buster + needs: [ "build:buster" ] diff --git a/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh b/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh index 08de2f2..97a9d03 100755 --- a/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh +++ b/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh @@ -12,8 +12,8 @@ TEST_CIPHERTEXT01='RCHI+VukmWIsVE3eixbWIAtPPBW63nmV1ITpSBEDYXC9Y5QMBd1zmGLLhE+S9 TEST_CIPHERTEXT02='sEG09WnEKIN2nyJYGNNVo14o7wV6X9HQxW+zxAxMLX9jVdashdaoHqLXQGM8lzpJhG6629lccjzAfrq8' CIPHERTEXT_FILE01="$(mktemp)" CIPHERTEXT_FILE02="$(mktemp)" -echo "${TEST_CIPHERTEXT01}" > "${CIPHERTEXT_FILE01}" -echo "${TEST_CIPHERTEXT02}" > "${CIPHERTEXT_FILE02}" +echo -n "${TEST_CIPHERTEXT01}" > "${CIPHERTEXT_FILE01}" +echo -n "${TEST_CIPHERTEXT02}" > "${CIPHERTEXT_FILE02}" DECRYPTED01="$(LIBEXIM_PASSWORD="${TEST_PASSWORD}" src/libexim-encrypt-dlfunc-decrypt-secretbox ${TEST_CIPHERTEXT01})" if [ "${DECRYPTED01}" == "${TEST_CLEARTEXT}" ] ; then From b6a350ef3ac3b2e3590f3b4ef04c9b97f14cc738 Mon Sep 17 00:00:00 2001 From: Heiko Reese Date: Sat, 11 Sep 2021 12:49:41 +0200 Subject: [PATCH 17/21] debugging meson build tests --- src/common.c | 6 +----- src/libexim-encrypt-dlfunc-decrypt-secretbox.c | 9 ++++++--- ...t_libexim-encrypt-dlfunc-decrypt-secretbox.sh | 16 ++++++++-------- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/common.c b/src/common.c index 13e93a3..12d5c90 100644 --- a/src/common.c +++ b/src/common.c @@ -53,15 +53,11 @@ char *read_first_line(const char *filename) { return cipherstring; } -typedef struct { - unsigned char *string; - size_t length; -} Password; - void base64_decode_string(const char *input, unsigned char **outstring, size_t *outlen) { size_t input_len = strlen(input); size_t outmaxlen = input_len / 4 * 3; *outstring = malloc(outmaxlen * sizeof(unsigned char)); + fprintf(stderr, " Input: |%s| [%zu]\n", input, input_len); int b64err = sodium_base642bin(*outstring, outmaxlen, (const char *) input, input_len, NULL, outlen, NULL, sodium_base64_VARIANT_ORIGINAL); if (b64err != 0) { diff --git a/src/libexim-encrypt-dlfunc-decrypt-secretbox.c b/src/libexim-encrypt-dlfunc-decrypt-secretbox.c index 5a0dcfd..66271c9 100644 --- a/src/libexim-encrypt-dlfunc-decrypt-secretbox.c +++ b/src/libexim-encrypt-dlfunc-decrypt-secretbox.c @@ -64,9 +64,12 @@ int main(int argc, char *argv[]) { // check environment for LIBEXIM_PASSWORD password_env = getenv(ENVVAR_PASSWORD_NAME); if (password_env != NULL && strlen(password_env) > 0) { - password_len = strlen((const char *) password_env); - password = malloc(password_len + 1); - strncpy(password, password_env, password_len); +// password_len = strlen((const char *) password_env); +// password = malloc(password_len); +// sodium_memzero(password, password_len); +// strncpy(password, password_env, password_len); + password = password_env; + password_len = strlen(password); mode |= PASSENV; } diff --git a/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh b/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh index 97a9d03..c255510 100755 --- a/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh +++ b/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh @@ -15,22 +15,24 @@ CIPHERTEXT_FILE02="$(mktemp)" echo -n "${TEST_CIPHERTEXT01}" > "${CIPHERTEXT_FILE01}" echo -n "${TEST_CIPHERTEXT02}" > "${CIPHERTEXT_FILE02}" -DECRYPTED01="$(LIBEXIM_PASSWORD="${TEST_PASSWORD}" src/libexim-encrypt-dlfunc-decrypt-secretbox ${TEST_CIPHERTEXT01})" +export LIBEXIM_PASSWORD="${TEST_PASSWORD}" +#DECRYPTED01="$(LIBEXIM_PASSWORD="${TEST_PASSWORD}" src/libexim-encrypt-dlfunc-decrypt-secretbox ${TEST_CIPHERTEXT01})" +DECRYPTED01="$(src/libexim-encrypt-dlfunc-decrypt-secretbox ${TEST_CIPHERTEXT01})" if [ "${DECRYPTED01}" == "${TEST_CLEARTEXT}" ] ; then echo "ok 1 - decrypt commandline argument with password from environment successful" else echo "not ok 1 - decrypt commandline argument with password from environment unsuccessful" fi -DECRYPTED02="$(LIBEXIM_PASSWORD="${TEST_PASSWORD}" src/libexim-encrypt-dlfunc-decrypt-secretbox --infile ${CIPHERTEXT_FILE01})" +#DECRYPTED02="$(LIBEXIM_PASSWORD="${TEST_PASSWORD}" src/libexim-encrypt-dlfunc-decrypt-secretbox --infile ${CIPHERTEXT_FILE01})" +DECRYPTED02="$(src/libexim-encrypt-dlfunc-decrypt-secretbox --infile ${CIPHERTEXT_FILE01})" if [ "${DECRYPTED02}" == "${TEST_CLEARTEXT}" ] ; then echo "ok 2 - decrypt file contents with password from environment successful" else - echo "${CIPHERTEXT_FILE01}" - cat "${CIPHERTEXT_FILE01}" echo "not ok 2 - decrypt file contents with password from environment unsuccessful" fi -unset LIBEXIM_PASSWORD +#unset LIBEXIM_PASSWORD +export -n LIBEXIM_PASSWORD DECRYPTED03="$(src/libexim-encrypt-dlfunc-decrypt-secretbox -p ${TEST_PASSWORD} ${TEST_CIPHERTEXT02})" if [ "${DECRYPTED03}" == "${TEST_CLEARTEXT}" ] ; then @@ -43,7 +45,5 @@ DECRYPTED04="$(src/libexim-encrypt-dlfunc-decrypt-secretbox -p ${TEST_PASSWORD} if [ "${DECRYPTED04}" == "${TEST_CLEARTEXT}" ] ; then echo "ok 4 - decrypt file contents with password from commandline successful" else - echo "${CIPHERTEXT_FILE02}" - cat "${CIPHERTEXT_FILE02}" echo "not ok 4 - decrypt file contents with password from commandline unsuccessful" -fi \ No newline at end of file +fi From a6c6169122c30ad51289e38b6c217d6a82d5c9ae Mon Sep 17 00:00:00 2001 From: Heiko Reese Date: Sat, 11 Sep 2021 14:40:43 +0200 Subject: [PATCH 18/21] Seitched mmap-based file reader against getline which also works with pipes. --- ci_container/build.sh | 2 + src/common.c | 62 +++++-------------- ...libexim-encrypt-dlfunc-decrypt-secretbox.c | 5 +- ...ibexim-encrypt-dlfunc-decrypt-secretbox.sh | 11 ++-- 4 files changed, 26 insertions(+), 54 deletions(-) diff --git a/ci_container/build.sh b/ci_container/build.sh index da63c15..945fd39 100755 --- a/ci_container/build.sh +++ b/ci_container/build.sh @@ -66,6 +66,8 @@ for i in "${images[@]}"; do git-buildpackage \ debsigs \ gpgv1; \ + DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=critical apt-get install -y \ + vim; \ rm -rf /var/lib/apt/lists/*;' buildah run "$ctr" /bin/sh -c \ 'pip3 install meson ninja; \ diff --git a/src/common.c b/src/common.c index 12d5c90..cd4569d 100644 --- a/src/common.c +++ b/src/common.c @@ -1,67 +1,37 @@ -#include -#include -#include -#include +#define _GNU_SOURCE + +#include +#include #include #include #include "common.h" char *read_first_line(const char *filename) { - int fd; - char *endptr; + FILE *stream; char *cipherstring; + size_t len = 0; + ssize_t nread; // open file - fd = open(filename, O_RDONLY, (mode_t) 0600); - if (fd == -1) { + stream = fopen(filename, "r"); + if (stream == NULL) { perror("Error opening file"); exit(EXIT_FAILURE); } - // get length - struct stat fileInfo = {0}; - if (fstat(fd, &fileInfo) == -1) { - perror("Error getting the file size"); - exit(EXIT_FAILURE); - } - if (fileInfo.st_size == 0) { - fprintf(stderr, "Error: File is empty, nothing to do\n"); - exit(EXIT_FAILURE); - } - // mmap file - char *map = mmap(0, fileInfo.st_size, PROT_READ, MAP_SHARED, fd, 0); - if (map == MAP_FAILED) - { - close(fd); - perror("Error mmapping the file"); - exit(EXIT_FAILURE); - } - // find first line - endptr = strchrnul(map, 0x0a); - size_t cipherstring_len = endptr - map; - cipherstring = malloc(cipherstring_len+1); - strncpy(cipherstring, map, cipherstring_len); + nread = getline(&cipherstring, &len, stream); - // munmap and close file - if (munmap(map, fileInfo.st_size) == -1) { - close(fd); - perror("Error un-mmapping the file"); - exit(EXIT_FAILURE); + if (nread == -1) { + perror("getline: "); } - close(fd); - + fclose(stream); return cipherstring; } -void base64_decode_string(const char *input, unsigned char **outstring, size_t *outlen) { +int base64_decode_string(const char *input, unsigned char **outstring, size_t *outlen) { size_t input_len = strlen(input); size_t outmaxlen = input_len / 4 * 3; *outstring = malloc(outmaxlen * sizeof(unsigned char)); - fprintf(stderr, " Input: |%s| [%zu]\n", input, input_len); - int b64err = sodium_base642bin(*outstring, outmaxlen, (const char *) input, input_len, - NULL, outlen, NULL, sodium_base64_VARIANT_ORIGINAL); - if (b64err != 0) { - fprintf(stderr, "[ERROR] Unable to base64-decode the password\n"); - exit(EXIT_FAILURE); - } + return sodium_base642bin(*outstring, outmaxlen, (const char *) input, input_len, + NULL, outlen, NULL, sodium_base64_VARIANT_ORIGINAL); } \ No newline at end of file diff --git a/src/libexim-encrypt-dlfunc-decrypt-secretbox.c b/src/libexim-encrypt-dlfunc-decrypt-secretbox.c index 66271c9..00da0ee 100644 --- a/src/libexim-encrypt-dlfunc-decrypt-secretbox.c +++ b/src/libexim-encrypt-dlfunc-decrypt-secretbox.c @@ -125,7 +125,10 @@ int main(int argc, char *argv[]) { // base64-decode input unsigned char *ciphertext; size_t ciphertext_len; - base64_decode_string(cipherstring, &ciphertext, &ciphertext_len); + if (base64_decode_string(cipherstring, &ciphertext, &ciphertext_len) != 0) { + fprintf(stderr, "[ERROR] Unable to base64-decode ciphertext.\n\n"); + exit(EXIT_FAILURE); + }; // extract nonce unsigned char nonce[crypto_secretbox_NONCEBYTES]; diff --git a/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh b/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh index c255510..6ec3c48 100755 --- a/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh +++ b/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh @@ -15,24 +15,21 @@ CIPHERTEXT_FILE02="$(mktemp)" echo -n "${TEST_CIPHERTEXT01}" > "${CIPHERTEXT_FILE01}" echo -n "${TEST_CIPHERTEXT02}" > "${CIPHERTEXT_FILE02}" -export LIBEXIM_PASSWORD="${TEST_PASSWORD}" -#DECRYPTED01="$(LIBEXIM_PASSWORD="${TEST_PASSWORD}" src/libexim-encrypt-dlfunc-decrypt-secretbox ${TEST_CIPHERTEXT01})" -DECRYPTED01="$(src/libexim-encrypt-dlfunc-decrypt-secretbox ${TEST_CIPHERTEXT01})" +DECRYPTED01="$(LIBEXIM_PASSWORD="${TEST_PASSWORD}" src/libexim-encrypt-dlfunc-decrypt-secretbox ${TEST_CIPHERTEXT01})" if [ "${DECRYPTED01}" == "${TEST_CLEARTEXT}" ] ; then echo "ok 1 - decrypt commandline argument with password from environment successful" else echo "not ok 1 - decrypt commandline argument with password from environment unsuccessful" fi -#DECRYPTED02="$(LIBEXIM_PASSWORD="${TEST_PASSWORD}" src/libexim-encrypt-dlfunc-decrypt-secretbox --infile ${CIPHERTEXT_FILE01})" -DECRYPTED02="$(src/libexim-encrypt-dlfunc-decrypt-secretbox --infile ${CIPHERTEXT_FILE01})" +DECRYPTED02="$(LIBEXIM_PASSWORD="${TEST_PASSWORD}" src/libexim-encrypt-dlfunc-decrypt-secretbox --infile ${CIPHERTEXT_FILE01})" if [ "${DECRYPTED02}" == "${TEST_CLEARTEXT}" ] ; then echo "ok 2 - decrypt file contents with password from environment successful" else echo "not ok 2 - decrypt file contents with password from environment unsuccessful" fi -#unset LIBEXIM_PASSWORD -export -n LIBEXIM_PASSWORD + +unset LIBEXIM_PASSWORD DECRYPTED03="$(src/libexim-encrypt-dlfunc-decrypt-secretbox -p ${TEST_PASSWORD} ${TEST_CIPHERTEXT02})" if [ "${DECRYPTED03}" == "${TEST_CLEARTEXT}" ] ; then From e1968e8f8c78bad3360eb44a451ad55e9adec8ce Mon Sep 17 00:00:00 2001 From: Heiko Reese Date: Sun, 12 Sep 2021 02:04:43 +0200 Subject: [PATCH 19/21] Added back meson from Debian packages as a build dependency for package building --- ci_container/build.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ci_container/build.sh b/ci_container/build.sh index 945fd39..10ce816 100755 --- a/ci_container/build.sh +++ b/ci_container/build.sh @@ -61,11 +61,12 @@ for i in "${images[@]}"; do openssl; \ DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=critical apt-get install -y \ debhelper \ - dh-make \ - devscripts \ - git-buildpackage \ debsigs \ - gpgv1; \ + devscripts \ + dh-make \ + git-buildpackage \ + gpgv1 \ + meson; \ DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=critical apt-get install -y \ vim; \ rm -rf /var/lib/apt/lists/*;' From e26daf675bad8d762039166a3c20c75ec8454a4d Mon Sep 17 00:00:00 2001 From: Heiko Reese Date: Sun, 12 Sep 2021 02:06:10 +0200 Subject: [PATCH 20/21] Wrote decrypt tool for sodium_crypto_box_seal plus matching tests. Lots of code cleanups. --- src/common.c | 66 ++++- src/common.h | 6 +- ...libexim-encrypt-dlfunc-decrypt-sealedbox.c | 238 ++++++++++++------ ...libexim-encrypt-dlfunc-decrypt-secretbox.c | 28 +-- src/meson.build | 14 +- ...ibexim-encrypt-dlfunc-decrypt-sealedbox.sh | 46 ++++ ...ibexim-encrypt-dlfunc-decrypt-secretbox.sh | 47 ++-- 7 files changed, 319 insertions(+), 126 deletions(-) create mode 100755 src/test_libexim-encrypt-dlfunc-decrypt-sealedbox.sh diff --git a/src/common.c b/src/common.c index cd4569d..559b8cd 100644 --- a/src/common.c +++ b/src/common.c @@ -3,31 +3,83 @@ #include #include #include +#include #include #include "common.h" +//#define MIN_KEY_SIZE (crypto_box_SECRETKEYBYTES < crypto_box_PUBLICKEYBYTES ? crypto_box_SECRETKEYBYTES : crypto_box_PUBLICKEYBYTES) +//#define MAX_KEY_SIZE (crypto_box_SECRETKEYBYTES > crypto_box_PUBLICKEYBYTES ? crypto_box_SECRETKEYBYTES : crypto_box_PUBLICKEYBYTES) + char *read_first_line(const char *filename) { FILE *stream; char *cipherstring; size_t len = 0; ssize_t nread; + bool input_is_stdin = false; - // open file - stream = fopen(filename, "r"); - if (stream == NULL) { - perror("Error opening file"); - exit(EXIT_FAILURE); + // open file (use stdin for '-') + if (!strncmp(filename, "-", 1)) { + stream = stdin; + input_is_stdin = true; + } else { + stream = fopen(filename, "r"); + if (stream == NULL) { + fprintf(stderr, "[ERROR] Error opening file %s\n\n", filename); + exit(EXIT_FAILURE); + } } nread = getline(&cipherstring, &len, stream); - if (nread == -1) { + if (nread == -1 && !feof(stream)) { perror("getline: "); } - fclose(stream); + if (input_is_stdin == false) { + fclose(stream); + } + + // remove trailing newline + cipherstring[strcspn(cipherstring, "\r\n")] = 0; + return cipherstring; } +char *read_password_file(const char *filename, size_t keysize, size_t *length) { + FILE *stream; + char *contents; + ssize_t nread; + bool input_is_stdin = false; + + contents = malloc(keysize + 1); + sodium_memzero(contents, keysize + 1); + + // open file (use stdin for '-') + if (!strncmp(filename, "-", 1)) { + stream = stdin; + input_is_stdin = true; + } else { + stream = fopen(filename, "r"); + if (stream == NULL) { + fprintf(stderr, "[ERROR] Error opening file %s\n\n", filename); + exit(EXIT_FAILURE); + } + } + + nread = fread(contents, sizeof(char), keysize, stream); + + if (nread < 0) { + fprintf(stderr, "[ERROR] reading from %s failed\n\n", filename); + exit(EXIT_FAILURE); + } else { + *length = (size_t) nread; + } + + if (input_is_stdin == false) { + fclose(stream); + } + return contents; +} + int base64_decode_string(const char *input, unsigned char **outstring, size_t *outlen) { size_t input_len = strlen(input); size_t outmaxlen = input_len / 4 * 3; diff --git a/src/common.h b/src/common.h index 8987394..7e0b6ff 100644 --- a/src/common.h +++ b/src/common.h @@ -5,6 +5,10 @@ #ifndef EXIM_ENCRYPT_DLFUNC_COMMON_H #define EXIM_ENCRYPT_DLFUNC_COMMON_H -char * read_first_line(const char *); +char *read_first_line(const char *filename); + +char *read_password_file(const char *filename, size_t keysize, size_t *length); + +int base64_decode_string(const char *input, unsigned char **outstring, size_t *outlen); #endif //EXIM_ENCRYPT_DLFUNC_COMMON_H diff --git a/src/libexim-encrypt-dlfunc-decrypt-sealedbox.c b/src/libexim-encrypt-dlfunc-decrypt-sealedbox.c index 6dd0117..eb72ab8 100644 --- a/src/libexim-encrypt-dlfunc-decrypt-sealedbox.c +++ b/src/libexim-encrypt-dlfunc-decrypt-sealedbox.c @@ -1,46 +1,62 @@ +#define _GNU_SOURCE + #include -#include #include #include -#include #include +#include +#include "common.c" -/* -#define PASSWORD_MAXLEN 1024 -#define CIPHERSTRING_MAX (1024*64) +#define ENVVAR_SK_NAME "LIBEXIM_SECRETKEY" +#define ENVVAR_PK_NAME "LIBEXIM_PUBLICKEY" -void print_usage(char * progname) { - printf("Usage: %s [OPTIONS]\n\n", progname); +void print_usage(char *progname) { + printf("Usage: %s [OPTIONS] [CIPHERTEXT]\n\n", progname); printf("Secret and public key:\n"); - printf(" -s, --secret-key FILE read secret key from file FILE\n"); - printf(" -p, --public-key FILE read public key from file FILE\n"); + printf(" -s, --secret-key SECRETKEY Secret key (base64-encoded)\n"); + printf(" -p, --public-key PUBLICKEY Public key (base64-encoded)\n"); + printf(" -S, --secret-key-file FILE Read secret key (raw) from file FILE (use - for stdin)\n"); + printf(" -P, --public-key-file FILE Read public key (raw) from file FILE (use - for stdin)\n"); + printf("\n"); + printf("The environment variables %s and %s may contain base64-encoded secret/public keys. \n", ENVVAR_SK_NAME, + ENVVAR_PK_NAME); printf("\n"); printf("Select input:\n"); - printf(" -c, --input STRING decrypt contents of STRING\n"); - printf(" -f, --infile FILE decrypt contents of the first line of file FILE\n"); + printf(" -f, --infile FILE Decrypt contents of the first line of file FILE (use - for stdin)\n"); + printf("\n"); + printf("Output:\n"); + printf(" -n, --no-newline Do not append a newline to the output\n"); + printf("\n"); + printf("Keys in arguments and environment variables are expected to be base64 encoded (as produced by the library).\n"); + printf("Keys in files need to be raw bytes with no encoding, ciphertext should always be base64-encoded.\n"); printf("\n"); } typedef enum { - PASSWORD = 1, - SECRETKEY = 2 -} decryption_mode; - -typedef enum { - ARGUMENT = 1, - FROMFILE = 2 -} input_source; + NONE = 0, + SK = 1, + PK = 2, + SKENV = 4, + PKENV = 8, + SKFILE = 16, + PKFILE = 32, + INFILE = 64, + INSTRING = 128 +} seen_sb_args; int main(int argc, char *argv[]) { - int opt= 0; - char password[PASSWORD_MAXLEN]; - char secret_key[PATH_MAX]; - char cipherstring[CIPHERSTRING_MAX]; - char infile[PATH_MAX]; - bool pass_from_env = false; + char *prog_basename = basename(argv[0]); + int opt = 0; + unsigned char *secretkey, *publickey; + size_t secretkey_len = 0, publickey_len = 0; + char *b64cipherstring; + unsigned char *cipherstring; + size_t cipherstring_len; + bool add_newline = true; - decryption_mode mode = 0; - input_source input = 0; + seen_sb_args publickey_mode = NONE; + seen_sb_args secretkey_mode = NONE; + seen_sb_args input = NONE; if (sodium_init() < 0) { fputs("Unable to initialize libsodium", stderr); @@ -49,71 +65,133 @@ int main(int argc, char *argv[]) { // define arguments static struct option long_options[] = { - {"password", required_argument, NULL, 'p'}, - {"pass-from-env", no_argument, NULL, 'e'}, - {"secret-key", required_argument, NULL, 'k'}, - {"public-key", required_argument, NULL, 'k'}, - {"cipherstring", required_argument, NULL, 's'}, - {"infile", required_argument, NULL, 'f'} + {"secret-key", required_argument, NULL, 's'}, + {"public-key", required_argument, NULL, 'p'}, + {"secret-key-file", required_argument, NULL, 'S'}, + {"public-key-file", required_argument, NULL, 'P'}, + {"infile", required_argument, NULL, 'f'}, + {"no-newline", required_argument, NULL, 'n'}, + {0, 0, 0, 0} }; + // check environment for LIBEXIM_SECRETKEY variable + char *sk_env = getenv(ENVVAR_SK_NAME); + if (sk_env != NULL && strlen(sk_env) > 0) { + if (base64_decode_string(sk_env, &secretkey, &secretkey_len) != 0) { + fprintf(stderr, "[ERROR] Unable to base64-decode secret key.\n\n"); + exit(EXIT_FAILURE); + } + secretkey_mode |= SKENV; + } + + // check environment for LIBEXIM_PUBLICKEY variable + char *pk_env = getenv(ENVVAR_PK_NAME); + if (pk_env != NULL && strlen(pk_env) > 0) { + if (base64_decode_string(pk_env, &publickey, &publickey_len) != 0) { + fprintf(stderr, "[ERROR] Unable to base64-decode public key.\n\n"); + exit(EXIT_FAILURE); + } + publickey_mode |= PKENV; + } + // parse arguments int long_index = 0; - while ((opt = getopt_long(argc, argv,"p:ek:s:f:", - long_options, &long_index )) != -1) { + while ((opt = getopt_long(argc, argv, "s:p:S:P:f:n", + long_options, &long_index)) != -1) { switch (opt) { - case 'p': - strncpy(password, optarg, sizeof(password)-1); - mode |= PASSWORD; - break; - case 'e': - pass_from_env = true; - mode |= PASSENV; - break; - case 'k': - strncpy(secret_key, optarg, sizeof(secret_key)-1); - mode |= SECRETKEY; - break; case 's': - strncpy(cipherstring, optarg, sizeof(cipherstring)-1); - input |= ARGUMENT; + if (base64_decode_string(optarg, &secretkey, &secretkey_len) != 0) { + fprintf(stderr, "[ERROR] Unable to base64-decode secret key.\n\n"); + exit(EXIT_FAILURE); + } + secretkey_mode |= SK; + break; + case 'p': + if (base64_decode_string(optarg, &publickey, &publickey_len) != 0) { + fprintf(stderr, "[ERROR] Unable to base64-decode public key.\n\n"); + exit(EXIT_FAILURE); + } + publickey_mode |= PK; + break; + case 'S': + secretkey = (unsigned char *) read_password_file(optarg, crypto_box_SECRETKEYBYTES, &secretkey_len); + secretkey_mode |= SKFILE; + break; + case 'P': + publickey = (unsigned char *) read_password_file(optarg, crypto_box_PUBLICKEYBYTES, &publickey_len); + publickey_mode |= PKFILE; break; case 'f': - strncpy(infile, optarg, sizeof(infile)-1); - input |= FROMFILE; + b64cipherstring = read_first_line(optarg); + input |= INFILE; + break; + case 'n': + add_newline = false; break; - default: - print_usage(argv[0]); - exit(EXIT_FAILURE); } } - // retrieve password/key - switch (mode) { - case PASSWORD: - if (pass_from_env == true) { - - } else { - - } - break; - case SECRETKEY: - break; - default: - printf("ERROR: Please specify a password OR a key file.\n\n"); - print_usage(argv[0]); - exit(EXIT_FAILURE); + // read first non-option argument as ciphertext if present + if (optind < argc) { + size_t b64cipherstring_len = strlen(argv[optind]); + b64cipherstring = malloc(b64cipherstring_len); + sodium_memzero(b64cipherstring, b64cipherstring_len); + strncpy(b64cipherstring, argv[optind], b64cipherstring_len); + input |= INSTRING; } - switch (input) { - case ARGUMENT: - case FROMFILE: - break; - default: - printf("ERROR: Please specify a ciphertext.\n\n"); - print_usage(argv[0]); - exit(EXIT_FAILURE); + + // check if a secret key was provided + if (secretkey_mode == NONE) { + fprintf(stderr, "[ERROR] Please specify a secret key.\n\n"); + print_usage(prog_basename); + exit(EXIT_FAILURE); + } + // check if the secret key has the correct size + if (secretkey_len != crypto_box_SECRETKEYBYTES) { + fprintf(stderr, "[ERROR] Secret key has wrong size %zu; expected %d.\n\n", secretkey_len, + crypto_box_SECRETKEYBYTES); + exit(EXIT_FAILURE); + } + + // check if a public key was provided + if (publickey_mode == NONE) { + fprintf(stderr, "[ERROR] Please specify a public key.\n\n"); + print_usage(prog_basename); + exit(EXIT_FAILURE); + } + // check if the public key has the correct size + if (publickey_len != crypto_box_PUBLICKEYBYTES) { + fprintf(stderr, "[ERROR] Secret key has wrong size %zu; expected %d.\n\n", publickey_len, + crypto_box_PUBLICKEYBYTES); + exit(EXIT_FAILURE); + } + + // check if a ciphertext was provided + if (input == NONE) { + fprintf(stderr, "[ERROR] Please specify a ciphertext source.\n\n"); + print_usage(prog_basename); + exit(EXIT_FAILURE); + } + // base64-decode ciphertext + if (base64_decode_string(b64cipherstring, &cipherstring, &cipherstring_len) != 0) { + fprintf(stderr, "[ERROR] Unable to base64-decode ciphertext.\n\n"); + exit(EXIT_FAILURE); + } + // prepare buffer for cleartext + size_t cleartext_len = cipherstring_len - crypto_box_SEALBYTES; + unsigned char *cleartext = (unsigned char *) malloc(cleartext_len + 1); + sodium_memzero(cleartext, cleartext_len + 1); + + // decrypt message + if (crypto_box_seal_open(cleartext, cipherstring, cipherstring_len, publickey, secretkey) != 0) { + fprintf(stderr, "[ERROR] Unable to decrypt ciphertext.\n\n"); + exit(EXIT_FAILURE); + } + + // print cleartext to stdout + if (add_newline == true) { + fprintf(stdout, "%s\n", (const char *) cleartext); + } else { + fprintf(stdout, "%s", (const char *) cleartext); } } -*/ - -int main(void) { return 0; } \ No newline at end of file diff --git a/src/libexim-encrypt-dlfunc-decrypt-secretbox.c b/src/libexim-encrypt-dlfunc-decrypt-secretbox.c index 00da0ee..ebcc57c 100644 --- a/src/libexim-encrypt-dlfunc-decrypt-secretbox.c +++ b/src/libexim-encrypt-dlfunc-decrypt-secretbox.c @@ -9,20 +9,21 @@ #define ENVVAR_PASSWORD_NAME "LIBEXIM_PASSWORD" -void print_usage(char * progname) { - printf("Usage: %s [OPTIONS]\n\n", progname); +void print_usage(char *progname) { + printf("Usage: %s [OPTIONS] [CIPHERTEXT]\n\n", progname); printf("Password:\n"); - printf(" -p, --password PASSWORD decrypt using PASSWORD\n"); + printf(" -p, --password PASSWORD Decrypt using PASSWORD\n"); printf("\n"); printf(" If the environment variable LIBEXIM_PASSWORD is set the password is read from there.\n"); printf(" Setting a password with -p/--password overwrites this mechanism.\n"); printf("\n"); printf("Select input:\n"); - printf(" -c, --input STRING decrypt contents of STRING\n"); - printf(" -f, --infile FILE decrypt contents of the first line of file FILE\n"); + printf(" -f, --infile FILE Decrypt contents of the first line of file FILE (use - for stdin)\n"); printf("\n"); printf("Output:\n"); - printf(" -n, --no-newline Do not add a newline to the output\n"); + printf(" -n, --no-newline Do not append a newline to the output\n"); + printf("\n"); + printf("Password and ciphertext are expected to be base64-encoded (as produced by the library).\n"); printf("\n"); } @@ -52,22 +53,17 @@ int main(int argc, char *argv[]) { } // define arguments - const char *shortargs = "p:ef:n"; + const char *shortargs = "p:f:n"; static struct option long_options[] = { - {"password", required_argument, NULL, 'p'}, - {"pass-from-env", no_argument, NULL, 'e'}, - {"infile", required_argument, NULL, 'f'}, - {"no-newline", no_argument, NULL, 'n'}, - {0, 0, 0, 0} + {"password", required_argument, NULL, 'p'}, + {"infile", required_argument, NULL, 'f'}, + {"no-newline", no_argument, NULL, 'n'}, + {0, 0, 0, 0} }; // check environment for LIBEXIM_PASSWORD password_env = getenv(ENVVAR_PASSWORD_NAME); if (password_env != NULL && strlen(password_env) > 0) { -// password_len = strlen((const char *) password_env); -// password = malloc(password_len); -// sodium_memzero(password, password_len); -// strncpy(password, password_env, password_len); password = password_env; password_len = strlen(password); mode |= PASSENV; diff --git a/src/meson.build b/src/meson.build index 57b39ce..58fa10d 100644 --- a/src/meson.build +++ b/src/meson.build @@ -16,8 +16,14 @@ shared_library('exim-encrypt-dlfunc', 'libexim-encrypt-dlfunc.c', dependencies : [ sodium_deps ], install: true) -dlfunc_test = find_program('test_libexim-encrypt-dlfunc.sh') -test('libexim-encrypt-dlfunc', dlfunc_test, protocol: 'tap') +test('libexim-encrypt-dlfunc', + find_program('test_libexim-encrypt-dlfunc.sh'), + protocol: 'tap') -decrypt_secretbox_test = find_program('test_libexim-encrypt-dlfunc-decrypt-secretbox.sh') -test('decrypt-secretbox', decrypt_secretbox_test, protocol: 'tap') \ No newline at end of file +test('decrypt-secretbox', + find_program('test_libexim-encrypt-dlfunc-decrypt-secretbox.sh'), + protocol: 'tap') + +test('decrypt-sealedbox', + find_program('test_libexim-encrypt-dlfunc-decrypt-sealedbox.sh'), + protocol: 'tap') \ No newline at end of file diff --git a/src/test_libexim-encrypt-dlfunc-decrypt-sealedbox.sh b/src/test_libexim-encrypt-dlfunc-decrypt-sealedbox.sh new file mode 100755 index 0000000..b9aa055 --- /dev/null +++ b/src/test_libexim-encrypt-dlfunc-decrypt-sealedbox.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# shellcheck disable=SC2034 +# this script implements the TAP protocol (https://testanything.org) +echo 1..3 + +TEST_PUBLICKEY='z7+GlUWgoiXJ4VK6cdLikCF7M6Mj9i4eXNE6Jh1m9yw=' +TEST_SECRETKEY='h5C/V2nzhILRmJ6UZrNK/6G8Xc4KWzLq/Qr8Xj42jus=' +TEST_CLEARTEXT='There is nothing in the middle of the road but a yellow stripe and dead armadillos. ~ Jim Hightower' +TEST_CIPHERTEXT='+UgXgarCuX3dUobgt8rRnjnxPNWHpsw98GjLZy8+2m5e/v9K/acMq+0UsFW7lwAZIRqj1F55n78y73Y6XCBEVSt8G6nntV8WuDYlr1BHcBIXNr5toUbE+CxtLoGqfD3c3nw1NkJDO1NYGzK/cG43TEEBLrQJCRLRBXOZmxG6ugFo4FtYl297/B1xNtkd9IR4TY5C' +CIPHERTEXT_FILE="$(mktemp)" +TEST_PUBLICKEY_FILE="$(mktemp)" +TEST_SECRETKEY_FILE="$(mktemp)" +echo -n "${TEST_CIPHERTEXT}" > "${CIPHERTEXT_FILE}" +echo -n "${TEST_PUBLICKEY}" | base64 -d > "${TEST_PUBLICKEY_FILE}" +echo -n "${TEST_SECRETKEY}" | base64 -d > "${TEST_SECRETKEY_FILE}" + +cleanup() { + rm -rf "${CIPHERTEXT_FILE}" "${TEST_PUBLICKEY_FILE}" "${TEST_SECRETKEY_FILE}" +} +trap cleanup EXIT INT TERM + +export LIBEXIM_PUBLICKEY="${TEST_PUBLICKEY}" +export LIBEXIM_SECRETKEY="${TEST_SECRETKEY}" + +DECRYPTED="$(src/libexim-encrypt-dlfunc-decrypt-sealedbox "${TEST_CIPHERTEXT}")" +if [ "${DECRYPTED}" == "${TEST_CLEARTEXT}" ] ; then + echo "ok 1 - decrypt commandline argument with keys from environment successful" +else + echo "not ok 1 - decrypt commandline argument with keys from environment unsuccessful" +fi + +export -n LIBEXIM_PUBLICKEY LIBEXIM_SECRETKEY + +DECRYPTED="$(src/libexim-encrypt-dlfunc-decrypt-sealedbox --secret-key "${TEST_SECRETKEY}" --public-key "${TEST_PUBLICKEY}" --infile "${CIPHERTEXT_FILE}")" +if [ "${DECRYPTED}" == "${TEST_CLEARTEXT}" ] ; then + echo "ok 2 - decrypt file contents with keys from commandline" +else + echo "not ok 2 - decrypt file contents with keys from commandline" +fi + +DECRYPTED="$(src/libexim-encrypt-dlfunc-decrypt-sealedbox --secret-key-file "${TEST_SECRETKEY_FILE}" --public-key-file "${TEST_PUBLICKEY_FILE}" --infile - < "${CIPHERTEXT_FILE}")" +if [ "${DECRYPTED}" == "${TEST_CLEARTEXT}" ] ; then + echo "ok 3 - decrypt stdin contents with keys from files" +else + echo "not ok 3 - decrypt stdin contents with keys from files" +fi diff --git a/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh b/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh index 6ec3c48..ac675ed 100755 --- a/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh +++ b/src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh @@ -1,46 +1,57 @@ #!/bin/bash # shellcheck disable=SC2034 - -PATH=/sbin:/usr/sbin:$PATH - # this script implements the TAP protocol (https://testanything.org) -echo 1..4 +echo 1..5 -TEST_PASSWORD='ThisIsAPassword' -TEST_CLEARTEXT='This is my cleartext' -TEST_CIPHERTEXT01='RCHI+VukmWIsVE3eixbWIAtPPBW63nmV1ITpSBEDYXC9Y5QMBd1zmGLLhE+S9yg0sHfOF/1+wmfF7YXv' -TEST_CIPHERTEXT02='sEG09WnEKIN2nyJYGNNVo14o7wV6X9HQxW+zxAxMLX9jVdashdaoHqLXQGM8lzpJhG6629lccjzAfrq8' +TEST_PASSWORD='be6rahqu3bukee3Aengohgoopheeyis5' +TEST_CLEARTEXT='The great thing about attackers is that there are so many to choose from! - Daniel J. Bernstein' +TEST_CIPHERTEXT01='K+TOzrbkni7wydNvF1gMRwZWQPNnNIXRG9iQgkFhszBu8ImqIrAK4wWWP02UmclITi8DZbr3sg/EVWurDzAYK+pjkcDAa78glz4qXIqrPbYvEIEHPEExFzCtwi5hqOR+KF7tsqbPvdAOIqwf/2KBomX0GS1I/1CxQMrbJd1VgXc51M4hI0I8' +TEST_CIPHERTEXT02='lAod5UhfW6fQCxd4PSktnrzwyWzcw05Svio5XqPOr/p/Ts4Pr0eEjj2TgmT2K85T2xrxCiqmE/OUcODRldEWeSqBSxx0Z6PzXqOzz5ZL6Iq1tggjihMydGz9mNS4jRF9f52k5t2i7xFrMMCRrfq/rer/ngp1h3pposCds+OmX0u+1f4Urj0b' CIPHERTEXT_FILE01="$(mktemp)" CIPHERTEXT_FILE02="$(mktemp)" echo -n "${TEST_CIPHERTEXT01}" > "${CIPHERTEXT_FILE01}" echo -n "${TEST_CIPHERTEXT02}" > "${CIPHERTEXT_FILE02}" -DECRYPTED01="$(LIBEXIM_PASSWORD="${TEST_PASSWORD}" src/libexim-encrypt-dlfunc-decrypt-secretbox ${TEST_CIPHERTEXT01})" +cleanup() { + rm -rf "${CIPHERTEXT_FILE01}" "${CIPHERTEXT_FILE02}" +} +trap cleanup EXIT INT TERM + +export LIBEXIM_PASSWORD="${TEST_PASSWORD}" + +DECRYPTED01="$(src/libexim-encrypt-dlfunc-decrypt-secretbox ${TEST_CIPHERTEXT01})" if [ "${DECRYPTED01}" == "${TEST_CLEARTEXT}" ] ; then echo "ok 1 - decrypt commandline argument with password from environment successful" else echo "not ok 1 - decrypt commandline argument with password from environment unsuccessful" fi -DECRYPTED02="$(LIBEXIM_PASSWORD="${TEST_PASSWORD}" src/libexim-encrypt-dlfunc-decrypt-secretbox --infile ${CIPHERTEXT_FILE01})" +DECRYPTED02="$(src/libexim-encrypt-dlfunc-decrypt-secretbox --infile ${CIPHERTEXT_FILE01})" if [ "${DECRYPTED02}" == "${TEST_CLEARTEXT}" ] ; then echo "ok 2 - decrypt file contents with password from environment successful" else echo "not ok 2 - decrypt file contents with password from environment unsuccessful" fi -unset LIBEXIM_PASSWORD - -DECRYPTED03="$(src/libexim-encrypt-dlfunc-decrypt-secretbox -p ${TEST_PASSWORD} ${TEST_CIPHERTEXT02})" +DECRYPTED03="$(echo -n ${TEST_CIPHERTEXT01} | src/libexim-encrypt-dlfunc-decrypt-secretbox --infile -)" if [ "${DECRYPTED03}" == "${TEST_CLEARTEXT}" ] ; then - echo "ok 3 - decrypt commandline argument with password from commandline successful" + echo "ok 3 - decrypt stdin contents with password from environment successful" else - echo "not ok 3 - decrypt commandline argument with password from commandline unsuccessful" + echo "not ok 3 - decrypt stdin file contents with password from environment unsuccessful" fi -DECRYPTED04="$(src/libexim-encrypt-dlfunc-decrypt-secretbox -p ${TEST_PASSWORD} --infile ${CIPHERTEXT_FILE02})" +export -n LIBEXIM_PASSWORD + +DECRYPTED04="$(src/libexim-encrypt-dlfunc-decrypt-secretbox -p ${TEST_PASSWORD} ${TEST_CIPHERTEXT02})" if [ "${DECRYPTED04}" == "${TEST_CLEARTEXT}" ] ; then - echo "ok 4 - decrypt file contents with password from commandline successful" + echo "ok 4 - decrypt commandline argument with password from commandline successful" else - echo "not ok 4 - decrypt file contents with password from commandline unsuccessful" + echo "not ok 4 - decrypt commandline argument with password from commandline unsuccessful" +fi + +DECRYPTED05="$(src/libexim-encrypt-dlfunc-decrypt-secretbox -p ${TEST_PASSWORD} --infile ${CIPHERTEXT_FILE02})" +if [ "${DECRYPTED05}" == "${TEST_CLEARTEXT}" ] ; then + echo "ok 5 - decrypt file contents with password from commandline successful" +else + echo "not ok 5 - decrypt file contents with password from commandline unsuccessful" fi From 32e060d88d7d9e114e1a20a4a2fa12e5376844a1 Mon Sep 17 00:00:00 2001 From: Heiko Reese Date: Sun, 12 Sep 2021 02:36:21 +0200 Subject: [PATCH 21/21] Added documentation and command help messages to decryption tools. --- README.md | 68 ++++++++++++++++++- ci_container/README.md | 2 +- ...libexim-encrypt-dlfunc-decrypt-sealedbox.c | 8 ++- ...libexim-encrypt-dlfunc-decrypt-secretbox.c | 7 +- 4 files changed, 80 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e4dc229..a8fa8af 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,9 @@ meson compile -C build meson test -C build ``` +The `ci_container` directory contains a [script](ci_container/build.sh) (and a [short README](ci_container/README.md)) +which creates the images used in continous integration for this project. + 5. Copy to final destination (feel free to pick another place than `/usr/lib/x86_64-linux-gnu/`): ```shell @@ -54,9 +57,18 @@ meson install -C build Not every build of exim is able to load libraries at runtime. Please refer to the [documentation](https://www.exim.org/exim-html-current/doc/html/spec_html/ch-string_expansions.html) - of the `${dlfunc{…}}` function for details. The Debian package [`exim4-daemon-heavy`](https://packages.debian.org/exim4-daemon-heavy) + of the `${dlfunc{…}}` function for details. The Debian + package [`exim4-daemon-heavy`](https://packages.debian.org/exim4-daemon-heavy) meets these requirements. +Try + +```shell +exim4 --version | egrep -i --color 'Expand_dlfunc|Content_Scanning' +``` + +for a preliminary test. + ## Usage There are currently two pairs of complementary functions: @@ -78,7 +90,7 @@ The second pair needs a proper key pair in the correct format. This is what the overwrite the previous key pair file without confirmation! Make sure to store your production keys in a safe place. ```shell -$ ./libexim-encrypt-dlfunc-genkeys +$ libexim-encrypt-dlfunc-genkeys === Creating cryptobox key pair === Wrote »cryptobox_recipient_pk_exim.conf« Wrote »cryptobox_recipient_pk.raw« @@ -120,3 +132,55 @@ warn log_message = Removing X-Originating-IP: header ``` Pick one of the `add_header` lines depending on which kind of encryption you want. + +### Decryption Tools + +Two additional programs are included: + +* `libexim-encrypt-dlfunc-decrypt-secretbox` +* `libexim-encrypt-dlfunc-decrypt-sealedbox` + +They can decrypt strings that were encrypted by the two respective functions. Please refer to their `--help` message +(reproduced below) for usage information and to the [test](src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh) +[scripts](src/test_libexim-encrypt-dlfunc-decrypt-sealedbox.sh) for usage examples. + +```shell +$ libexim-encrypt-dlfunc-decrypt-secretbox -h +Usage: libexim-encrypt-dlfunc-decrypt-secretbox [OPTIONS] [CIPHERTEXT] + +Password: + -p, --password PASSWORD Decrypt using PASSWORD + + If the environment variable LIBEXIM_PASSWORD is set the password is read from there. + Setting a password with -p/--password overwrites this mechanism. + +Select input: + -f, --infile FILE Decrypt contents of the first line of file FILE (use - for stdin) + +Output: + -n, --no-newline Do not append a newline to the output + +Password and ciphertext are expected to be base64-encoded (as produced by the library). +``` + +```shell +$ libexim-encrypt-dlfunc-decrypt-sealedbox -h +Usage: libexim-encrypt-dlfunc-decrypt-sealedbox [OPTIONS] [CIPHERTEXT] + +Secret and public key: + -s, --secret-key SECRETKEY Secret key (base64-encoded) + -p, --public-key PUBLICKEY Public key (base64-encoded) + -S, --secret-key-file FILE Read secret key (raw) from file FILE (use - for stdin) + -P, --public-key-file FILE Read public key (raw) from file FILE (use - for stdin) + +The environment variables LIBEXIM_SECRETKEY and LIBEXIM_PUBLICKEY may contain base64-encoded secret/public keys. + +Select input: + -f, --infile FILE Decrypt contents of the first line of file FILE (use - for stdin) + +Output: + -n, --no-newline Do not append a newline to the output + +Keys in arguments and environment variables are expected to be base64 encoded (as produced by the library). +Keys in files need to be raw bytes with no encoding, ciphertext should always be base64-encoded. +``` \ No newline at end of file diff --git a/ci_container/README.md b/ci_container/README.md index 6f54f9c..3782fb6 100644 --- a/ci_container/README.md +++ b/ci_container/README.md @@ -3,7 +3,7 @@ ## Prerequisites * [buildah](https://buildah.io/) -* {podman](https://podman.io/) +* [podman](https://podman.io/) ## Build and upload diff --git a/src/libexim-encrypt-dlfunc-decrypt-sealedbox.c b/src/libexim-encrypt-dlfunc-decrypt-sealedbox.c index eb72ab8..9a099ea 100644 --- a/src/libexim-encrypt-dlfunc-decrypt-sealedbox.c +++ b/src/libexim-encrypt-dlfunc-decrypt-sealedbox.c @@ -64,6 +64,7 @@ int main(int argc, char *argv[]) { } // define arguments + const char *shortargs = "s:p:S:P:f:nh"; static struct option long_options[] = { {"secret-key", required_argument, NULL, 's'}, {"public-key", required_argument, NULL, 'p'}, @@ -71,6 +72,7 @@ int main(int argc, char *argv[]) { {"public-key-file", required_argument, NULL, 'P'}, {"infile", required_argument, NULL, 'f'}, {"no-newline", required_argument, NULL, 'n'}, + {"help", no_argument, NULL, 'h'}, {0, 0, 0, 0} }; @@ -96,7 +98,7 @@ int main(int argc, char *argv[]) { // parse arguments int long_index = 0; - while ((opt = getopt_long(argc, argv, "s:p:S:P:f:n", + while ((opt = getopt_long(argc, argv, shortargs, long_options, &long_index)) != -1) { switch (opt) { case 's': @@ -128,6 +130,10 @@ int main(int argc, char *argv[]) { case 'n': add_newline = false; break; + case 'h': + print_usage(prog_basename); + exit(EXIT_SUCCESS); + break; } } diff --git a/src/libexim-encrypt-dlfunc-decrypt-secretbox.c b/src/libexim-encrypt-dlfunc-decrypt-secretbox.c index ebcc57c..28d17e5 100644 --- a/src/libexim-encrypt-dlfunc-decrypt-secretbox.c +++ b/src/libexim-encrypt-dlfunc-decrypt-secretbox.c @@ -53,11 +53,12 @@ int main(int argc, char *argv[]) { } // define arguments - const char *shortargs = "p:f:n"; + const char *shortargs = "p:f:nh"; static struct option long_options[] = { {"password", required_argument, NULL, 'p'}, {"infile", required_argument, NULL, 'f'}, {"no-newline", no_argument, NULL, 'n'}, + {"help", no_argument, NULL, 'h'}, {0, 0, 0, 0} }; @@ -87,6 +88,10 @@ int main(int argc, char *argv[]) { case 'n': add_newline = false; break; + case 'h': + print_usage(prog_basename); + exit(EXIT_SUCCESS); + break; } }