diff --git a/frontend/src/main.c b/frontend/src/main.c index 8e30ec2..11e3008 100644 --- a/frontend/src/main.c +++ b/frontend/src/main.c @@ -58,28 +58,12 @@ static int weak_passphrase(const CHR *str) return !strong; } -static int encrypt(const CHR* const passphrase, const CHR* const input, const CHR* const output) +static int encrypt(const char* const passphrase, const CHR* const input, const CHR* const output) { mcrypt_t ctx = NULL; FILE *fin = NULL, *fout = NULL; int result = -1; - if (STRLEN(passphrase) < 8U) - { - FPUTS(T("Warning: Using a short passphrase. Eight characters or more are recommended!\n\n"), stderr); - } - else if (weak_passphrase(passphrase)) - { - FPUTS(T("Warning: Using a weak passphrase. A mix of upper-case characters, lower-case characters, digits and 'special' characters is recommended!\n\n"), stderr); - } - - char *const passphrase_utf8 = utf16_to_bytes(passphrase, CP_UTF8); - if (!passphrase_utf8) - { - FPUTS(T("Error: Failed to convert passphrase to UTF-8 format!\n\n"), stderr); - goto clean_up; - } - if (open_files(&fin, &fout, input, output) != 0) { goto clean_up;; @@ -110,7 +94,7 @@ static int encrypt(const CHR* const passphrase, const CHR* const input, const CH goto clean_up; } - ctx = mcrypt_alloc(seed, passphrase_utf8); + ctx = mcrypt_alloc(seed, passphrase); if (!ctx) { FPUTS(T("MCrypt error: Failed to initialize encryption!\n\n"), stderr); @@ -192,28 +176,15 @@ clean_up: fclose(fin); } - if (passphrase_utf8) - { - erase(passphrase_utf8, strlen(passphrase_utf8)); - free(passphrase_utf8); - } - return result; } -static int decrypt(const CHR* const passphrase, const CHR* const input, const CHR* const output) +static int decrypt(const char* const passphrase, const CHR* const input, const CHR* const output) { mcrypt_t ctx = NULL; FILE *fin = NULL, *fout = NULL; int result = -1; - char *const passphrase_utf8 = utf16_to_bytes(passphrase, CP_UTF8); - if (!passphrase_utf8) - { - FPUTS(T("Error: Failed to convert passphrase to UTF-8 format!\n\n"), stderr); - goto clean_up; - } - if (open_files(&fin, &fout, input, output) != 0) { goto clean_up; @@ -238,7 +209,7 @@ static int decrypt(const CHR* const passphrase, const CHR* const input, const CH goto clean_up; } - ctx = mcrypt_alloc(seed, passphrase_utf8); + ctx = mcrypt_alloc(seed, passphrase); if (!ctx) { FPUTS(T("MCrypt error: Failed to initialize decryption!\n\n"), stderr); @@ -331,27 +302,26 @@ clean_up: fclose(fin); } - if (passphrase_utf8) - { - erase(passphrase_utf8, strlen(passphrase_utf8)); - free(passphrase_utf8); - } - return result; } int MAIN(int argc, CHR* argv[]) { - FPRINTF(stderr, T("MCrypt Utility [%") T(PRIstr) T("]\n"), __DATE__", "__TIME__); - FPRINTF(stderr, T("Powered by libMCrypt v%") T(PRIstr) T(" [%") T(PRIstr) T("]\n\n"), LIBMCRYPT_VERSION, LIBMCRYPT_BUILDNO); + init_terminal(); - if ((argc < 5) || (!STRICMP(argv[1U], T("--help"))) || (!STRICMP(argv[1U], T("--version")))) + FPRINTF(stderr, T("MCrypt Utility (%") T(PRIstr) T("-%") T(PRIstr) T("), by LoRd_MuldeR \n"), OS_TYPE, CPU_ARCH); + FPRINTF(stderr, T("Using libMCrypt v%") T(PRIstr) T(" [%") T(PRIstr) T("]\n\n"), LIBMCRYPT_VERSION, LIBMCRYPT_BUILDNO); + + const int help_requested = (argc > 1) && ((!STRICMP(argv[1U], T("/?"))) || (!STRICMP(argv[1U], T("--help"))) || (!STRICMP(argv[1U], T("--version")))); + if ((argc < 5) || help_requested) { + FPUTS(T("--------------------------------------------------------------------\n"), stderr); FPUTS(T("This software has been released under the CC0 1.0 Universal license:\n"), stderr); - FPUTS(T("https://creativecommons.org/publicdomain/zero/1.0/legalcode\n\n"), stderr); - if (argc < 2) + FPUTS(T("https://creativecommons.org/publicdomain/zero/1.0/legalcode\n"), stderr); + FPUTS(T("--------------------------------------------------------------------\n\n"), stderr); + if (!help_requested) { - FPUTS(T("Nothing to do!\n\n"), stderr); + FPUTS(T("Error: Required argument is missing!\n\n"), stderr); } FPUTS(T("Usage:\n"), stderr); FPRINTF(stderr, T(" %") T(PRISTR) T(" --encrypt \n"), argv[0U]); @@ -359,34 +329,62 @@ int MAIN(int argc, CHR* argv[]) return 1; } - if (!argv[1U][0U]) + const CHR *const command = argv[1U], *const passphrase = argv[2U], *const input_file = argv[3U], *const output_file = argv[4U]; + if (!passphrase[0U]) { FPUTS(T("Error: The passphrase must not be empty!\n\n"), stderr); return 1; } + else + { + if (STRLEN(passphrase) < 12U) + { + FPUTS(T("Warning: Using a *short* passphrase; a length of 12 characters or more is recommended!\n\n"), stderr); + } + if (weak_passphrase(passphrase)) + { + FPUTS(T("Warning: Using a *weak* passphrase; a mix of upper-case letters, lower-case letters, digits and 'special' characters is recommended!\n\n"), stderr); + } + } + + if ((!input_file[0U]) || (!output_file[0U])) + { + FPUTS(T("Error: The input file and/or output file must not be empty!\n\n"), stderr); + return 1; + } + + char* const passphrase_utf8 = CHR_to_utf8(passphrase); + if (!passphrase_utf8) + { + FPUTS(T("Error: Failed to convert passphrase to the UTF-8 format!\n\n"), stderr); + return 1; + } const clock_t clk_start = clock(); int result = -1; - if (!STRICMP(argv[1U], T("--encrypt"))) + if (!STRICMP(command, T("--encrypt"))) { - result = encrypt(argv[2U], argv[3U], argv[4U]); + result = encrypt(passphrase_utf8, input_file, output_file); } - else if (!STRICMP(argv[1U], T("--decrypt"))) + else if (!STRICMP(command, T("--decrypt"))) { - result = decrypt(argv[2U], argv[3U], argv[4U]); + result = decrypt(passphrase_utf8, input_file, output_file); } else { - FPRINTF(stderr, T("Error: Command \"%") T(PRISTR) T("\" is unknown!\n\n"), argv[1U]); - erase(argv[2U], STRLEN(argv[2U]) * sizeof(CHR)); - return 1; + FPRINTF(stderr, T("Error: Command \"%") T(PRISTR) T("\" is unknown!\n\n"), command); + goto exiting; } FPUTS(T("--------\n\n"), stderr); fflush(stderr); - erase(argv[2U], STRLEN(argv[2U]) * sizeof(CHR)); const clock_t clk_end = clock(); FPRINTF(stderr, T("Operation completed after %.1f seconds.\n\n"), (clk_end - clk_start) / ((double)CLOCKS_PER_SEC)); + +exiting: + + free_utf8(passphrase_utf8); + mcrypt_bzero((CHR*)passphrase, STRLEN(passphrase) * sizeof(CHR)); } diff --git a/frontend/src/platform.h b/frontend/src/platform.h index b41a172..7485523 100644 --- a/frontend/src/platform.h +++ b/frontend/src/platform.h @@ -6,6 +6,42 @@ #ifndef INC_PLATFORM_H #define INC_PLATFORM_H +#ifdef _WIN32 +#define OS_TYPE "Win" +#else +#ifdef __linux__ +#define OS_TYPE "Linux" +#else +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +#define OS_TYPE "BSD" +#else +#if defined(__APPLE__) && defined(__MACH__) +#define OS_TYPE "macOS" +#else +#error Unknown operating system! +#endif +#endif +#endif +#endif + +#if defined(__x86_64__) || defined(_M_X64) +#define CPU_ARCH "x64" +#else +#if defined(__i386__) || defined(_M_IX86) +#define CPU_ARCH "x86" +#else +#if defined(__aarch64__) || defined(_M_ARM64) +#define CPU_ARCH "arm64" +#else +#if defined(__arm__) || defined(_M_ARM) +#define CPU_ARCH "arm" +#else +#error Unknown CPU architecture! +#endif +#endif +#endif +#endif + #ifdef _WIN32 #define MAIN wmain #define CHR wchar_t diff --git a/frontend/src/utils.c b/frontend/src/utils.c index d6e2ed2..6dc6a68 100644 --- a/frontend/src/utils.c +++ b/frontend/src/utils.c @@ -11,34 +11,27 @@ #endif #include "utils.h" +#include #include #include #include #ifdef _WIN32 #include +#include #include #define S_IFMT _S_IFMT #define S_IFDIR _S_IFDIR #define S_IFIFO _S_IFIFO #endif -void erase(void *const ptr, const size_t length) -{ - volatile uint8_t* buffer = ptr; - for (size_t i = 0U; i < length; ++i) - { - buffer[i] = 0U; - } -} - -char* utf16_to_bytes(const CHR*const input, const uint32_t code_page) +char* CHR_to_utf8(const CHR*const input) { #ifdef _WIN32 char* buffer; DWORD buffer_size = 0U, result = 0U; - buffer_size = WideCharToMultiByte(code_page, 0, input, -1, NULL, 0, NULL, NULL); + buffer_size = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, NULL, NULL); if (buffer_size < 1U) { return NULL; @@ -50,7 +43,7 @@ char* utf16_to_bytes(const CHR*const input, const uint32_t code_page) return NULL; } - result = WideCharToMultiByte(code_page, 0, input, -1, (LPSTR)buffer, buffer_size, NULL, NULL); + result = WideCharToMultiByte(CP_UTF8, 0, input, -1, (LPSTR)buffer, buffer_size, NULL, NULL); if ((result > 0U) && (result <= buffer_size)) { return buffer; @@ -59,7 +52,18 @@ char* utf16_to_bytes(const CHR*const input, const uint32_t code_page) free(buffer); return NULL; #else - return strdup(input); + return input; /*nothing to do*/ +#endif +} + +void free_utf8(char *const str_utf8) +{ +#ifdef _WIN32 + if (str_utf8) + { + mcrypt_bzero(str_utf8, strlen(str_utf8)); + free(str_utf8); + } #endif } @@ -77,3 +81,11 @@ uint64_t get_file_size(FILE *const file) } return 0U; } + +void init_terminal(void) +{ +#ifdef _WIN32 + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); + _setmode(_fileno(stderr), _O_U8TEXT); +#endif +} diff --git a/frontend/src/utils.h b/frontend/src/utils.h index dddae8c..ed83052 100644 --- a/frontend/src/utils.h +++ b/frontend/src/utils.h @@ -11,12 +11,9 @@ #include #include "platform.h" -#ifndef CP_UTF8 -#define CP_UTF8 65001 -#endif - -void erase(void *const ptr, const size_t length); +char* CHR_to_utf8(const CHR *const input); +void free_utf8(char* const str_utf8); uint64_t get_file_size(FILE* const file); -char* utf16_to_bytes(const CHR *const input, const uint32_t code_page); +void init_terminal(void); #endif diff --git a/libMCrypt/include/mcrypt.h b/libMCrypt/include/mcrypt.h index d7ad7e0..bc41307 100644 --- a/libMCrypt/include/mcrypt.h +++ b/libMCrypt/include/mcrypt.h @@ -12,18 +12,38 @@ extern const char *const LIBMCRYPT_VERSION; extern const char* const LIBMCRYPT_BUILDNO; +/* + * Opaque handle to internal state + */ typedef void* mcrypt_t; +/* + * Seed generator + */ int mcrypt_generate_seed(uint64_t* const seed); +/* + * Allocate or free state + */ mcrypt_t mcrypt_alloc(const uint64_t salt, const char* const passphrase); void mcrypt_free(const mcrypt_t context); +/* + * Encryption routines + */ int mcrypt_enc_process(const mcrypt_t context, const uint8_t* const input, uint8_t* const output, size_t length); int mcrypt_enc_process_inplace(const mcrypt_t context, uint8_t* const buffer, size_t length); +/* + * Decryption routines + */ int mcrypt_dec_process(const mcrypt_t context, const uint8_t* const input, uint8_t* const output, size_t length); int mcrypt_dec_process_inplace(const mcrypt_t context, uint8_t* const buffer, size_t length); +/* + * Auxiliary functions + */ +int mcrypt_random_bytes(uint8_t* const buffer, const size_t length); +void mcrypt_bzero(void* const ptr, const size_t length); #endif diff --git a/libMCrypt/libMCrypt.vcxproj b/libMCrypt/libMCrypt.vcxproj index 5371631..a7ab06a 100644 --- a/libMCrypt/libMCrypt.vcxproj +++ b/libMCrypt/libMCrypt.vcxproj @@ -20,11 +20,10 @@ - + - 16.0 diff --git a/libMCrypt/libMCrypt.vcxproj.filters b/libMCrypt/libMCrypt.vcxproj.filters index d050e06..2b0f3be 100644 --- a/libMCrypt/libMCrypt.vcxproj.filters +++ b/libMCrypt/libMCrypt.vcxproj.filters @@ -18,7 +18,7 @@ Source Files - + Source Files @@ -26,8 +26,5 @@ Header Files - - Header Files - \ No newline at end of file diff --git a/libMCrypt/src/utils.c b/libMCrypt/src/internal.c similarity index 77% rename from libMCrypt/src/utils.c rename to libMCrypt/src/internal.c index be25463..0796d3b 100644 --- a/libMCrypt/src/utils.c +++ b/libMCrypt/src/internal.c @@ -5,11 +5,14 @@ #ifdef _WIN32 #define _CRT_RAND_S 1 +#define WIN32_LEAN_AND_MEAN 1 #endif -#include "utils.h" +#include -#ifdef __unix__ +#ifdef _WIN32 +#include +#else #include #include #if (defined(__GLIBC__) && defined(__GLIBC_MINOR__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 25)) || (defined(__FreeBSD__) && (__FreeBSD__ >= 12)) @@ -18,6 +21,12 @@ #else #undef HAVE_GENRANDOM_SYSCALL #endif +#if (defined(__GLIBC__) && defined(__GLIBC_MINOR__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 25)) || (defined(__FreeBSD__) && (__FreeBSD__ >= 11)) +#define HAVE_EXPLICIT_BZERO 1 +#include +#else +#undef HAVE_EXPLICIT_BZERO +#endif #endif int mcrypt_random_bytes(uint8_t* const buffer, const size_t length) @@ -41,7 +50,6 @@ int mcrypt_random_bytes(uint8_t* const buffer, const size_t length) } return 0; #else -#ifdef __unix__ #ifdef HAVE_GENRANDOM_SYSCALL if (getrandom(buffer, length, 0U) >= length) { @@ -65,17 +73,22 @@ int mcrypt_random_bytes(uint8_t* const buffer, const size_t length) } return result; #endif -#else -#error Unsupported target platform! -#endif #endif } -void mcrypt_erase(void* const ptr, const size_t length) +void mcrypt_bzero(void* const ptr, const size_t length) { +#ifdef _WIN32 + SecureZeroMemory(ptr, length); +#else +#ifdef HAVE_EXPLICIT_BZERO + explicit_bzero(ptr, length); +#else volatile uint8_t* buffer = ptr; for (size_t i = 0U; i < length; ++i) { buffer[i] = 0U; } +#endif +#endif } diff --git a/libMCrypt/src/mcrypt.c b/libMCrypt/src/mcrypt.c index d221ad5..047ffb6 100644 --- a/libMCrypt/src/mcrypt.c +++ b/libMCrypt/src/mcrypt.c @@ -8,7 +8,6 @@ #endif #include -#include "utils.h" #include const char* const LIBMCRYPT_VERSION = "1.0.0"; @@ -118,7 +117,7 @@ static void initialize_state(crypt_state_t* const crypt_state, const uint64_t sa } random_seed(&rand_state, salt, 0x0100, key, key_len); crypt_state->pos = (uint8_t)random_next(&rand_state); - mcrypt_erase(&rand_state, sizeof(rand_state_t)); + mcrypt_bzero(&rand_state, sizeof(rand_state_t)); } // ========================================================================== @@ -236,7 +235,7 @@ void mcrypt_free(const mcrypt_t context) crypt_state_t* const state = (crypt_state_t*)context; if (context) { - mcrypt_erase((void*)context, sizeof(crypt_state_t)); + mcrypt_bzero((void*)context, sizeof(crypt_state_t)); free(context); } } diff --git a/libMCrypt/src/utils.h b/libMCrypt/src/utils.h deleted file mode 100644 index 589d1e8..0000000 --- a/libMCrypt/src/utils.h +++ /dev/null @@ -1,15 +0,0 @@ -/******************************************************************************/ -/* MCrypt, by LoRd_MuldeR */ -/* This work has been released under the CC0 1.0 Universal license! */ -/******************************************************************************/ - -#ifndef INC_MCRYPT_UTILS_H -#define INC_MCRYPT_UTILS_H - -#include -#include - -int mcrypt_random_bytes(uint8_t* const buffer, const size_t length); -void mcrypt_erase(void* const ptr, const size_t length); - -#endif