SlunkCrypt/frontend/src/main.c

691 lines
19 KiB
C
Raw Normal View History

/******************************************************************************/
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
#define _CRT_SECURE_NO_WARNINGS 1
#include <slunkcrypt.h>
2020-10-13 15:04:59 +02:00
#include "utils.h"
#include "crc.h"
2020-10-15 21:56:36 +02:00
#include "test.h"
#include <string.h>
#include <time.h>
2020-10-13 15:37:40 +02:00
#include <inttypes.h>
#include <ctype.h>
#include <signal.h>
2020-10-20 15:21:00 +02:00
#define BUFFER_SIZE 4096U
#define OP_MODE_NONE 0
#define OP_MODE_HELP 1
#define OP_MODE_VERS 2
#define OP_MODE_ENCR 3
#define OP_MODE_DECR 4
#define OP_MODE_TEST 5
static const CHR *const ENVV_PASSWD_NAME = T("SLUNK_PASSPHRASE");
2020-10-20 15:21:00 +02:00
// ==========================================================================
// Auxiliary functions
// ==========================================================================
static int parse_mode(const CHR* const command)
{
if ((!STRICMP(command, T("-h"))) || (!STRICMP(command, T("/?"))) || (!STRICMP(command, T("--help"))))
{
return OP_MODE_HELP;
}
else if ((!STRICMP(command, T("-v"))) || (!STRICMP(command, T("--version"))))
{
return OP_MODE_VERS;
}
else if ((!STRICMP(command, T("-e"))) || (!STRICMP(command, T("--encrypt"))))
{
return OP_MODE_ENCR;
}
else if ((!STRICMP(command, T("-d"))) || (!STRICMP(command, T("--decrypt"))))
{
return OP_MODE_DECR;
}
else if ((!STRICMP(command, T("-t"))) || (!STRICMP(command, T("--self-test"))))
{
return OP_MODE_TEST;
}
else
{
FPRINTF(stderr, T("Error: The specified command \"%") T(PRISTR) T("\" is unknown!\n\n"), command);
return -1;
}
}
static void print_manpage(const CHR *const program)
{
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"), stderr);
FPUTS(T("====================================================================\n\n"), stderr);
FPUTS(T("Synopsis:\n"), stderr);
FPRINTF(stderr, T(" %") T(PRISTR) T(" --encrypt [[@][:]<passphrase>] <input.txt> <output.enc>\n"), program);
FPRINTF(stderr, T(" %") T(PRISTR) T(" --decrypt [[@][:]<passphrase>] <input.enc> <output.txt>\n\n"), program);
FPUTS(T("Options:\n"), stderr);
FPUTS(T("- If <passphrase> is prefixed with a '@' character, then it specifies the file\n"), stderr);
FPUTS(T(" to read the passphrase from; only the first line in that file is used!\n"), stderr);
FPUTS(T("- If <passphrase> is prefixed with a ':' character, then the leading character\n"), stderr);
FPUTS(T(" is skipped and the remainder of the argument is used as passphrase.\n"), stderr);
FPUTS(T("- If argument <passphrase> is omitted, then the passphrase is read from the\n"), stderr);
FPRINTF(stderr, T(" environment variable \"%") T(PRISTR) T("\" instead.\n"), ENVV_PASSWD_NAME);
FPUTS(T("- Specify \"@-\" in order to read the passphrase from the standard input stream!\n\n"), stderr);
}
static char* read_passphrase(const CHR* const file_name)
{
2020-10-20 15:21:00 +02:00
const size_t max_len = SLUNKCRYPT_PWDLEN_MAX + 3U;
char *buffer = (char*) malloc(max_len * sizeof(char));
if (!buffer)
{
return NULL;
}
const int use_stdin = (STRICMP(file_name, T("-")) == 0);
FILE *const file = use_stdin ? stdin : FOPEN(file_name, T("rb"));
2020-10-14 21:55:39 +02:00
if (!file)
{
free(buffer);
return NULL;
}
do
{
2020-10-20 15:21:00 +02:00
if (!fgets(buffer, (int)max_len, file))
{
free(buffer);
buffer = NULL;
goto finish;
}
size_t length = strlen(buffer);
while ((length > 0U) && ((buffer[length - 1U] == '\r') || (buffer[length - 1U] == '\n')))
{
buffer[--length] = '\0';
}
}
while (!buffer[0U]);
finish:
if ((!use_stdin) && file)
{
fclose(file);
}
return buffer;
}
static int weak_passphrase(const char *str)
{
int flags[4U] = { 0, 0, 0, 0 };
while (*str)
{
const CHR c = *str++;
if (isalpha(c))
{
flags[isupper(c) ? 0U : 1U] = 1;
}
else
{
flags[isdigit(c) ? 2U : 3U] = 1;
}
}
const int strong = flags[0U] && flags[1U] && flags[2U] && flags[3U];
return !strong;
}
2020-10-14 21:55:39 +02:00
static int open_files(FILE **const file_in, FILE **const file_out, const CHR* const input_path, const CHR* const output_path)
{
2020-10-14 21:55:39 +02:00
*file_in = FOPEN(input_path, T("rb"));
if (!(*file_in))
{
2020-10-13 15:04:59 +02:00
FPUTS(T("Error: Failed to open input file for reading!\n\n"), stderr);
return 1;
}
2020-10-14 21:55:39 +02:00
*file_out = FOPEN(output_path, T("wb"));
if (!(*file_out))
{
2020-10-13 15:04:59 +02:00
FPUTS(T("Error: Failed to open output file for writing!\n\n"), stderr);
2020-10-14 21:55:39 +02:00
fclose(*file_out);
return 1;
}
2020-10-13 00:43:57 +02:00
return 0;
}
2020-10-20 15:21:00 +02:00
static void sigint_handler(const int sig)
{
if (sig == SIGINT)
{
g_slunkcrypt_abort_flag = 1;
signal(SIGINT, sigint_handler);
}
}
// ==========================================================================
// Encrypt
// ==========================================================================
2020-10-14 21:55:39 +02:00
static int encrypt(const char* const passphrase, const CHR* const input_path, const CHR* const output_path)
2020-10-13 00:43:57 +02:00
{
slunkcrypt_t ctx = SLUNKCRYPT_NULL;
2020-10-14 21:55:39 +02:00
FILE * file_in = NULL, * file_out = NULL;
2020-10-14 13:14:47 +02:00
int result = 1;
2020-10-13 00:43:57 +02:00
2020-10-14 21:55:39 +02:00
if (open_files(&file_in, &file_out, input_path, output_path) != 0)
2020-10-13 00:43:57 +02:00
{
goto clean_up;;
}
2020-10-14 21:55:39 +02:00
const uint64_t file_size = get_file_size(file_in);
2020-10-13 15:04:59 +02:00
if (file_size == UINT64_MAX)
{
FPUTS(T("I/O error: Failed to determine size of input file!\n\n"), stderr);
goto clean_up;
}
2020-10-14 21:55:39 +02:00
else if (file_size < 1U)
2020-10-13 15:04:59 +02:00
{
2020-10-14 21:55:39 +02:00
FPUTS(T("Error: Input file is empty or an unsupported type!\n\n"), stderr);
2020-10-13 15:04:59 +02:00
goto clean_up;
}
FPUTS(T("Encrypting file contents, please be patient... "), stderr);
fflush(stderr);
uint64_t seed;
if (slunkcrypt_generate_seed(&seed) != SLUNKCRYPT_SUCCESS)
{
FPUTS(T("\n\nSlunkCrypt error: Failed to generate seed!\n\n"), stderr);
2020-10-13 00:43:57 +02:00
goto clean_up;
}
2020-10-14 21:55:39 +02:00
if (fwrite(&seed, sizeof(uint64_t), 1U, file_out) < 1U)
{
FPUTS(T("\n\nI/O error: Failed to write seed value!\n\n"), stderr);
2020-10-13 00:43:57 +02:00
goto clean_up;
}
ctx = slunkcrypt_alloc(seed, (const uint8_t*)passphrase, strlen(passphrase));
if (!ctx)
{
FPUTS(g_slunkcrypt_abort_flag ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to initialize encryption!\n\n"), stderr);
2020-10-13 00:43:57 +02:00
goto clean_up;
}
2020-10-13 15:04:59 +02:00
clock_t clk_now, clk_update = clock();
uint64_t crc_actual = CRC_INITIALIZER, bytes_read = 0U;
2020-10-20 15:21:00 +02:00
uint8_t buffer[BUFFER_SIZE];
FPRINTF(stderr, T("%5.1f%% "), 0.0);
fflush(stderr);
2020-10-14 21:55:39 +02:00
while (bytes_read < file_size)
{
2020-10-14 21:55:39 +02:00
const uint64_t bytes_remaining = file_size - bytes_read;
2020-10-20 15:21:00 +02:00
const size_t request_len = (bytes_remaining < BUFFER_SIZE) ? ((size_t)bytes_remaining) : BUFFER_SIZE;
2020-10-14 21:55:39 +02:00
const size_t count = fread(buffer, sizeof(uint8_t), request_len, file_in);
if (count > 0U)
{
2020-10-13 15:04:59 +02:00
crc_actual = crc64_update(crc_actual, buffer, count);
bytes_read += count;
const int status = slunkcrypt_encrypt_inplace(ctx, buffer, count);
if (status != SLUNKCRYPT_SUCCESS)
{
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to encrypt data!\n\n"), stderr);
2020-10-13 00:43:57 +02:00
goto clean_up;
}
2020-10-14 21:55:39 +02:00
if (fwrite(buffer, sizeof(uint8_t), count, file_out) < count)
{
2020-10-13 15:04:59 +02:00
FPUTS(T("\n\nI/O error: Failed to write encrypted data!\n\n"), stderr);
2020-10-13 00:43:57 +02:00
goto clean_up;
}
}
2020-10-14 21:55:39 +02:00
if (count < request_len)
{
break; /*EOF*/
}
2020-10-13 15:04:59 +02:00
if ((clk_now = clock()) - clk_update > CLOCKS_PER_SEC)
{
FPRINTF(stderr, T("\b\b\b\b\b\b\b%5.1f%% "), (bytes_read / ((double)file_size)) * 100.0);
2020-10-13 15:04:59 +02:00
fflush(stderr);
clk_update = clk_now;
}
}
2020-10-14 21:55:39 +02:00
if (ferror(file_in))
{
FPUTS(T("\n\nI/O error: Failed to read input data!\n\n"), stderr);
goto clean_up;
}
2020-10-13 15:04:59 +02:00
if (bytes_read < file_size)
{
FPUTS(T("\n\nI/O error: Input file could not be fully read!\n\n"), stderr);
goto clean_up;
}
2020-10-14 21:55:39 +02:00
crc_actual = crc64_finish(crc_actual);
2020-10-20 15:21:00 +02:00
FPRINTF(stderr, T("\b\b\b\b\b\b\b%5.1f%%\n\n"), 100.0);
2020-10-16 18:07:45 +02:00
fflush(stderr);
2020-10-14 21:55:39 +02:00
if (fwrite(&crc_actual, sizeof(uint64_t), 1U, file_out) < 1U)
{
2020-10-13 15:04:59 +02:00
FPUTS(T("I/O error: Failed to write CRC checksum!\n\n"), stderr);
2020-10-13 00:43:57 +02:00
goto clean_up;
}
result = 0;
2020-10-13 15:04:59 +02:00
FPUTS(T("All is done.\n\n"), stderr);
2020-10-13 00:43:57 +02:00
fflush(stderr);
clean_up:
if (ctx)
{
slunkcrypt_free(ctx);
2020-10-13 00:43:57 +02:00
}
2020-10-14 21:55:39 +02:00
if (file_out)
2020-10-13 00:43:57 +02:00
{
2020-10-14 21:55:39 +02:00
fclose(file_out);
2020-10-13 00:43:57 +02:00
}
2020-10-14 21:55:39 +02:00
if (file_in)
2020-10-13 00:43:57 +02:00
{
2020-10-14 21:55:39 +02:00
fclose(file_in);
}
2020-10-13 00:43:57 +02:00
return result;
}
2020-10-20 15:21:00 +02:00
// ==========================================================================
// Decrypt
// ==========================================================================
2020-10-14 21:55:39 +02:00
static int decrypt(const char* const passphrase, const CHR* const input_path, const CHR* const output_path)
{
slunkcrypt_t ctx = SLUNKCRYPT_NULL;
2020-10-14 21:55:39 +02:00
FILE *file_in = NULL, *file_out = NULL;
2020-10-14 13:14:47 +02:00
int result = 1;
2020-10-13 00:43:57 +02:00
2020-10-14 21:55:39 +02:00
if (open_files(&file_in, &file_out, input_path, output_path) != 0)
{
2020-10-13 00:43:57 +02:00
goto clean_up;
}
2020-10-14 21:55:39 +02:00
const uint64_t file_size = get_file_size(file_in);
2020-10-13 00:43:57 +02:00
if (file_size == UINT64_MAX)
{
2020-10-13 15:04:59 +02:00
FPUTS(T("I/O error: Failed to determine size of input file!\n\n"), stderr);
2020-10-13 00:43:57 +02:00
goto clean_up;
}
2020-10-14 21:55:39 +02:00
else if (file_size < 16U)
{
2020-10-13 15:04:59 +02:00
FPUTS(T("Error: Input file is too small! Truncated?\n\n"), stderr);
2020-10-13 00:43:57 +02:00
goto clean_up;
}
FPUTS(T("Decrypting file contents, please be patient... "), stderr);
fflush(stderr);
uint64_t seed;
2020-10-14 21:55:39 +02:00
if (fread(&seed, sizeof(uint64_t), 1U, file_in) < 1U)
{
FPUTS(T("\n\nI/O error: Failed to read seed value!\n\n"), stderr);
2020-10-13 00:43:57 +02:00
goto clean_up;
}
ctx = slunkcrypt_alloc(seed, (const uint8_t*)passphrase, strlen(passphrase));
if (!ctx)
{
FPUTS(g_slunkcrypt_abort_flag ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to initialize decryption!\n\n"), stderr);
2020-10-13 00:43:57 +02:00
goto clean_up;
}
2020-10-13 15:04:59 +02:00
clock_t clk_now, clk_update = clock();
uint64_t crc_actual = CRC_INITIALIZER, bytes_read = sizeof(uint64_t);
2020-10-20 15:21:00 +02:00
uint8_t buffer[BUFFER_SIZE];
2020-10-13 15:04:59 +02:00
const uint64_t read_limit = file_size - sizeof(uint64_t);
FPRINTF(stderr, T("%5.1f%% "), 0.0);
fflush(stderr);
2020-10-14 21:55:39 +02:00
while (bytes_read < read_limit)
{
2020-10-13 15:04:59 +02:00
const uint64_t bytes_remaining = read_limit - bytes_read;
2020-10-20 15:21:00 +02:00
const size_t request_len = (bytes_remaining < BUFFER_SIZE) ? ((size_t)bytes_remaining) : BUFFER_SIZE;
2020-10-14 21:55:39 +02:00
const size_t count = fread(buffer, sizeof(uint8_t), request_len, file_in);
if (count > 0U)
{
bytes_read += count;
const int status = slunkcrypt_decrypt_inplace(ctx, buffer, count);
if (status != SLUNKCRYPT_SUCCESS)
{
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to decrypt data!\n\n"), stderr);
2020-10-13 00:43:57 +02:00
goto clean_up;
}
2020-10-13 15:04:59 +02:00
crc_actual = crc64_update(crc_actual, buffer, count);
2020-10-14 21:55:39 +02:00
if (fwrite(buffer, sizeof(uint8_t), count, file_out) < count)
{
2020-10-13 15:04:59 +02:00
FPUTS(T("failed!\n\nI/O error: Failed to write decrypted data!\n\n"), stderr);
2020-10-13 00:43:57 +02:00
goto clean_up;
}
}
2020-10-14 21:55:39 +02:00
if (count < request_len)
{
break; /*EOF*/
}
2020-10-13 15:04:59 +02:00
if ((clk_now = clock()) - clk_update > CLOCKS_PER_SEC)
{
FPRINTF(stderr, T("\b\b\b\b\b\b\b%5.1f%% "), (bytes_read / ((double)read_limit)) * 100.0);
2020-10-13 15:04:59 +02:00
fflush(stderr);
clk_update = clk_now;
}
}
2020-10-14 21:55:39 +02:00
if (ferror(file_in))
{
FPUTS(T("\n\nI/O error: Failed to read input data!\n\n"), stderr);
goto clean_up;
}
2020-10-13 00:43:57 +02:00
if (bytes_read < read_limit)
{
2020-10-13 15:04:59 +02:00
FPUTS(T("\n\nI/O error: Input file could not be fully read!\n\n"), stderr);
2020-10-13 00:43:57 +02:00
goto clean_up;
}
2020-10-14 21:55:39 +02:00
crc_actual = crc64_finish(crc_actual);
2020-10-20 15:21:00 +02:00
FPRINTF(stderr, T("\b\b\b\b\b\b\b%5.1f%%\n\n"), 100.0);
2020-10-16 18:07:45 +02:00
fflush(stderr);
2020-10-13 15:04:59 +02:00
uint64_t crc_expected;
2020-10-14 21:55:39 +02:00
if (fread(&crc_expected, sizeof(uint64_t), 1U, file_in) < 1U)
{
2020-10-13 15:04:59 +02:00
FPUTS(T("I/O error: Failed to read CRC checksum!\n\n"), stderr);
2020-10-13 00:43:57 +02:00
goto clean_up;
}
if (crc_actual != crc_expected)
{
2020-10-13 15:37:40 +02:00
FPRINTF(stderr, T("CRC error: Checksum mismatch detected! [expected: 0x%016") T(PRIX64) T(", actual: 0x%016") T(PRIX64) T("]\n\n"), crc_actual, crc_expected);
FPUTS(T("Wrong passphrase or corrupted file?\n\n"), stderr);
2020-10-13 00:43:57 +02:00
goto clean_up;
}
result = 0;
2020-10-13 15:37:40 +02:00
FPUTS(T("CRC checksum is correct.\n\n"), stderr);
2020-10-13 00:43:57 +02:00
fflush(stderr);
clean_up:
if (ctx)
{
slunkcrypt_free(ctx);
2020-10-13 00:43:57 +02:00
}
2020-10-14 21:55:39 +02:00
if (file_out)
2020-10-13 00:43:57 +02:00
{
2020-10-14 21:55:39 +02:00
fclose(file_out);
2020-10-13 00:43:57 +02:00
}
2020-10-14 21:55:39 +02:00
if (file_in)
2020-10-13 00:43:57 +02:00
{
2020-10-14 21:55:39 +02:00
fclose(file_in);
}
2020-10-13 00:43:57 +02:00
return result;
}
2020-10-20 15:21:00 +02:00
// ==========================================================================
// Self-test
// ==========================================================================
static int run_test_case(const char *const message)
2020-10-14 13:14:47 +02:00
{
static const char* const passphrase = "OrpheanBeh0lderScry!Doubt";
2020-10-15 21:56:36 +02:00
const size_t length = strlen(message) + 1U;
2020-10-18 20:41:02 +02:00
int status, result = 1;
slunkcrypt_t ctx = SLUNKCRYPT_NULL;
2020-10-14 13:14:47 +02:00
uint64_t seed;
if (slunkcrypt_generate_seed(&seed) != SLUNKCRYPT_SUCCESS)
2020-10-14 13:14:47 +02:00
{
2020-10-15 23:11:07 +02:00
FPUTS(T("\n\nWhoops: Failed to generate seed!\n\n"), stderr);
2020-10-15 22:41:28 +02:00
return 1;
2020-10-14 13:14:47 +02:00
}
2020-10-15 21:56:36 +02:00
char* const text_temp = strdup(message);
2020-10-14 13:14:47 +02:00
if (!text_temp)
{
2020-10-15 23:11:07 +02:00
FPUTS(T("\n\nWhoops: Failed to allocate text buffer!\n\n"), stderr);
2020-10-14 13:14:47 +02:00
goto clean_up;
}
ctx = slunkcrypt_alloc(seed, (const uint8_t*)passphrase, strlen(passphrase));
2020-10-14 17:57:40 +02:00
if (!ctx)
2020-10-14 13:14:47 +02:00
{
FPUTS(g_slunkcrypt_abort_flag ? T("\n\nProcess interrupted!\n\n") : T("\n\nWhoops: Failed to initialize encoder!\n\n"), stderr);
2020-10-14 13:14:47 +02:00
goto clean_up;
}
status = slunkcrypt_encrypt_inplace(ctx, (uint8_t*)text_temp, length);
if (status != SLUNKCRYPT_SUCCESS)
2020-10-14 13:14:47 +02:00
{
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nWhoops: Failed to encrypt the message!\n\n"), stderr);
2020-10-14 13:14:47 +02:00
goto clean_up;
}
2020-10-15 21:56:36 +02:00
if (strncmp(message, text_temp, length) == 0)
2020-10-14 13:14:47 +02:00
{
2020-10-15 23:11:07 +02:00
FPUTS(T("\n\nWhoops: Encrypted message equals the original message!\n\n"), stderr);
2020-10-14 13:14:47 +02:00
goto clean_up;
}
status = slunkcrypt_reset(ctx, seed, (const uint8_t*)passphrase, strlen(passphrase));
if (status != SLUNKCRYPT_SUCCESS)
2020-10-14 13:14:47 +02:00
{
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nWhoops: Failed to initialize decoder!\n\n"), stderr);
2020-10-14 13:14:47 +02:00
goto clean_up;
}
status = slunkcrypt_decrypt_inplace(ctx, (uint8_t*)text_temp, length);
if (status != SLUNKCRYPT_SUCCESS)
2020-10-14 13:14:47 +02:00
{
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nWhoops: Failed to decrypt the message!\n\n"), stderr);
2020-10-14 13:14:47 +02:00
goto clean_up;
}
2020-10-15 21:56:36 +02:00
if (strncmp(message, text_temp, length) != 0)
2020-10-14 13:14:47 +02:00
{
2020-10-15 23:11:07 +02:00
FPUTS(T("\n\nWhoops: Decrypted message does *not* match the original message!\n\n"), stderr);
2020-10-14 13:14:47 +02:00
goto clean_up;
}
result = 0;
clean_up:
2020-10-14 17:57:40 +02:00
if (ctx)
2020-10-14 13:14:47 +02:00
{
slunkcrypt_free(ctx);
2020-10-14 13:14:47 +02:00
}
if (text_temp)
{
slunkcrypt_bzero(text_temp, strlen(text_temp));
2020-10-14 13:14:47 +02:00
free(text_temp);
}
return result;
}
2020-10-20 15:21:00 +02:00
static int run_self_test(void)
2020-10-15 21:56:36 +02:00
{
2020-10-15 23:11:07 +02:00
static const size_t total = 32U;
const char* const test_data[] = { TEST_DATA_0, TEST_DATA_1, TEST_DATA_2, TEST_DATA_3, NULL };
size_t completed = 0U;
FPRINTF(stderr, T("Self-test is running, please be patient... %2u/%2u "), (unsigned int)completed, (unsigned int)total);
fflush(stderr);
2020-10-15 21:56:36 +02:00
for (size_t i = 0U; i < 8U; ++i)
{
for (size_t j = 0U; test_data[j]; ++j)
{
FPRINTF(stderr, T("\b\b\b\b\b\b%2u/%2u "), (unsigned int)++completed, (unsigned int)total);
fflush(stderr);
2020-10-20 15:21:00 +02:00
if (run_test_case(test_data[j]))
2020-10-15 21:56:36 +02:00
{
return 1;
}
}
}
2020-10-16 18:07:45 +02:00
FPRINTF(stderr, T("\b\b\b\b\b\b%2u/%2u\n\nCompleted successfully.\n\n"), (unsigned int)total, (unsigned int)total);
fflush(stderr);
2020-10-15 21:56:36 +02:00
return 0;
}
2020-10-20 15:21:00 +02:00
// ==========================================================================
// Main function
// ==========================================================================
2020-10-20 15:21:00 +02:00
int MAIN(const int argc, CHR *const argv[])
{
2020-10-13 19:33:01 +02:00
init_terminal();
signal(SIGINT, sigint_handler);
2020-10-20 15:21:00 +02:00
int result = -1;
FPRINTF(stderr, T("SlunkCrypt Utility (%") T(PRIstr) T("-%") T(PRIstr) T("), by LoRd_MuldeR <MuldeR2@GMX.de>\n"), OS_TYPE, CPU_ARCH);
2020-10-20 15:21:00 +02:00
FPRINTF(stderr, T("Using libSlunkCrypt v%u.%u.%u [%") T(PRIstr) T("]\n\n"), SLUNKCRYPT_VERSION_MAJOR, SLUNKCRYPT_VERSION_MINOR, SLUNKCRYPT_VERSION_PATCH, SLUNKCRYPT_BUILD);
2020-10-13 19:33:01 +02:00
2020-10-20 15:21:00 +02:00
/* ----------------------------------------------------- */
/* Parse arguments */
/* ----------------------------------------------------- */
const int mode = (argc > 1) ? parse_mode(argv[1U]) : OP_MODE_NONE;
switch (mode)
2020-10-14 13:14:47 +02:00
{
2020-10-20 15:21:00 +02:00
case OP_MODE_NONE:
FPRINTF(stderr, T("Error: Nothing to do. Please type '%") T(PRISTR) T(" --help' for details!\n\n"), get_file_name(argv[0U]));
return 1;
case OP_MODE_HELP:
print_manpage(get_file_name(argv[0U]));
return 0;
case OP_MODE_ENCR:
case OP_MODE_DECR:
break;
case OP_MODE_TEST:
return run_self_test();
default:
return -1;
2020-10-14 13:14:47 +02:00
}
if (argc < 4)
{
2020-10-20 15:21:00 +02:00
FPRINTF(stderr, T("Error: Required argument is missing. Please type '%") T(PRISTR) T(" --help' for details!\n\n"), get_file_name(argv[0U]));
2020-10-15 21:56:36 +02:00
return 1;
}
2020-10-20 15:21:00 +02:00
const CHR* const passphrase = (argc > 4) ? argv[2U] : GETENV(ENVV_PASSWD_NAME);
const CHR* const input_file = argv[(argc > 4) ? 3U : 2U], * const output_file = argv[(argc > 4) ? 4U : 3U];
if ((!passphrase) || (!passphrase[0U]) || (((passphrase[0U] == T('@')) || (passphrase[0U] == T(':'))) && (!passphrase[1U])))
{
2020-10-20 15:21:00 +02:00
FPUTS(T("Error: The specified passphrase must not be empty!\n\n"), stderr);
return 1;
}
2020-10-13 19:33:01 +02:00
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;
}
2020-10-20 15:21:00 +02:00
/* ----------------------------------------------------- */
/* Initialize passphrase */
/* ----------------------------------------------------- */
char *const passphrase_buffer = (passphrase[0U] == T('@')) ? read_passphrase(passphrase + 1U) : CHR_to_utf8((passphrase[0U] == T(':')) ? (passphrase + 1U) : passphrase);
if (!passphrase_buffer)
2020-10-13 19:33:01 +02:00
{
2020-10-20 15:21:00 +02:00
FPUTS(T("Error: Failed to read the passphrase!\n\n"), stderr);
2020-10-13 19:33:01 +02:00
return 1;
}
slunkcrypt_bzero((CHR*)passphrase, STRLEN(passphrase) * sizeof(CHR));
2020-10-20 15:21:00 +02:00
const size_t passphrase_len = strlen(passphrase_buffer);
if (passphrase_len < SLUNKCRYPT_PWDLEN_MIN)
{
FPRINTF(stderr, T("Error: Passphrase must be at least %") T(PRIu64) T(" characters in length!\n\n"), (uint64_t)SLUNKCRYPT_PWDLEN_MIN);
goto exiting;
}
else if (passphrase_len > SLUNKCRYPT_PWDLEN_MAX)
{
FPRINTF(stderr, T("Error: Passphrase must be at most %") T(PRIu64) T(" characters in length!\n\n"), (uint64_t)SLUNKCRYPT_PWDLEN_MAX);
goto exiting;
}
if (passphrase_len < 12U)
{
FPUTS(T("Warning: Using a *short* passphrase; a length of 12 characters or more is recommended!\n\n"), stderr);
}
else if (weak_passphrase(passphrase_buffer))
{
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);
}
2020-10-20 15:21:00 +02:00
/* ----------------------------------------------------- */
/* Encrypt or decrypt */
/* ----------------------------------------------------- */
const clock_t clk_start = clock();
2020-10-20 15:21:00 +02:00
switch (mode)
{
2020-10-20 15:21:00 +02:00
case OP_MODE_ENCR:
result = encrypt(passphrase_buffer, input_file, output_file);
2020-10-20 15:21:00 +02:00
break;
case OP_MODE_DECR:
result = decrypt(passphrase_buffer, input_file, output_file);
2020-10-20 15:21:00 +02:00
break;
default:
abort(); /*not supposed to happen!*/
}
if (!g_slunkcrypt_abort_flag)
2020-10-14 21:55:39 +02:00
{
FPUTS(T("--------\n\n"), stderr);
fflush(stderr);
const clock_t clk_end = clock();
FPRINTF(stderr, T("Operation completed after %.1f seconds.\n\n"), (clk_end - clk_start) / ((double)CLOCKS_PER_SEC));
}
2020-10-13 19:33:01 +02:00
2020-10-20 15:21:00 +02:00
/* ----------------------------------------------------- */
/* Final clean-up */
/* ----------------------------------------------------- */
2020-10-13 19:33:01 +02:00
exiting:
if (passphrase_buffer)
2020-10-13 19:50:29 +02:00
{
slunkcrypt_bzero(passphrase_buffer, strlen(passphrase_buffer));
free(passphrase_buffer);
2020-10-13 19:50:29 +02:00
}
2020-10-15 22:41:28 +02:00
return result;
}