Refactored encryption/decryption routines as well as the self-test routine into separate files.
This commit is contained in:
parent
2e93d8dc28
commit
46dc28f3ca
@ -44,14 +44,18 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="src\blake2.c" />
|
<ClCompile Include="src\blake2.c" />
|
||||||
<ClCompile Include="src\test.c" />
|
<ClCompile Include="src\crypt.c" />
|
||||||
|
<ClCompile Include="src\selftest.c" />
|
||||||
|
<ClCompile Include="src\test_data.c" />
|
||||||
<ClCompile Include="src\main.c" />
|
<ClCompile Include="src\main.c" />
|
||||||
<ClCompile Include="src\utils.c" />
|
<ClCompile Include="src\utils.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="src\blake2.h" />
|
<ClInclude Include="src\blake2.h" />
|
||||||
|
<ClInclude Include="src\crypt.h" />
|
||||||
<ClInclude Include="src\platform.h" />
|
<ClInclude Include="src\platform.h" />
|
||||||
<ClInclude Include="src\test.h" />
|
<ClInclude Include="src\selftest.h" />
|
||||||
|
<ClInclude Include="src\test_data.h" />
|
||||||
<ClInclude Include="src\utils.h" />
|
<ClInclude Include="src\utils.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -21,12 +21,18 @@
|
|||||||
<ClCompile Include="src\utils.c">
|
<ClCompile Include="src\utils.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="src\test.c">
|
<ClCompile Include="src\test_data.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="src\blake2.c">
|
<ClCompile Include="src\blake2.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\crypt.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\selftest.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="src\utils.h">
|
<ClInclude Include="src\utils.h">
|
||||||
@ -35,12 +41,18 @@
|
|||||||
<ClInclude Include="src\platform.h">
|
<ClInclude Include="src\platform.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="src\test.h">
|
<ClInclude Include="src\test_data.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="src\blake2.h">
|
<ClInclude Include="src\blake2.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\crypt.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\selftest.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Manifest Include="res\compatibility.manifest">
|
<Manifest Include="res\compatibility.manifest">
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
https://blake2.net.
|
https://blake2.net.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef BLAKE2_H
|
#ifndef INC_SLUNKAPP_BLAKE2_H
|
||||||
#define BLAKE2_H
|
#define INC_SLUNKAPP_BLAKE2_H
|
||||||
|
|
||||||
#define BLAKE2S_BLOCKBYTES 64
|
#define BLAKE2S_BLOCKBYTES 64
|
||||||
|
|
||||||
|
435
frontend/src/crypt.c
Normal file
435
frontend/src/crypt.c
Normal file
@ -0,0 +1,435 @@
|
|||||||
|
/******************************************************************************/
|
||||||
|
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
|
||||||
|
/* This work has been released under the CC0 1.0 Universal license! */
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
# define _CRT_SECURE_NO_WARNINGS 1
|
||||||
|
#else
|
||||||
|
# define _GNU_SOURCE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Internal */
|
||||||
|
#include "crypt.h"
|
||||||
|
#include <slunkcrypt.h>
|
||||||
|
#include "utils.h"
|
||||||
|
#include "blake2.h"
|
||||||
|
|
||||||
|
/* CRT */
|
||||||
|
#include <time.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
// Constants
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
|
static const uint64_t MAGIC_NUMBER = 0x243F6A8885A308D3ull;
|
||||||
|
static const clock_t UPDATE_INTERVAL = (clock_t)(1.5708 * CLOCKS_PER_SEC);
|
||||||
|
|
||||||
|
#define BUFFER_SIZE 4096U
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
// Auxiliary functions
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
|
static int open_files(FILE **const file_in, FILE **const file_out, const CHR *const input_path, const CHR *const output_path)
|
||||||
|
{
|
||||||
|
if (!(*file_in = FOPEN(input_path, T("rb"))))
|
||||||
|
{
|
||||||
|
FPRINTF(stderr, T("Error: Failed to open input file \"%") T(PRISTR) T("\" for reading!\n\n"), input_path);
|
||||||
|
*file_out = NULL;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(*file_out = FOPEN(output_path, T("wb"))))
|
||||||
|
{
|
||||||
|
FPRINTF(stderr, T("Error: Failed to open output file \"%") T(PRISTR) T("\" for writing!\n\n"), output_path);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
// Encrypt
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
|
int encrypt(const char *const passphrase, const CHR *const input_path, const CHR *const output_path, const int keep_incomplete)
|
||||||
|
{
|
||||||
|
slunkcrypt_t ctx = SLUNKCRYPT_NULL;
|
||||||
|
FILE* file_in = NULL, * file_out = NULL;
|
||||||
|
int result = EXIT_FAILURE, status;
|
||||||
|
|
||||||
|
if (open_files(&file_in, &file_out, input_path, output_path) != EXIT_SUCCESS)
|
||||||
|
{
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t file_size = get_file_size(file_in);
|
||||||
|
if (file_size == UINT64_MAX)
|
||||||
|
{
|
||||||
|
FPUTS(T("I/O error: Failed to determine size of input file!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
else if (file_size < 1U)
|
||||||
|
{
|
||||||
|
FPUTS(T("Error: Input file is empty or an unsupported type!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
FPUTS(T("Encrypting file contents, please be patient... "), stderr);
|
||||||
|
fflush(stderr);
|
||||||
|
|
||||||
|
uint64_t nonce;
|
||||||
|
if (slunkcrypt_generate_nonce(&nonce) != SLUNKCRYPT_SUCCESS)
|
||||||
|
{
|
||||||
|
FPUTS(T("\n\nSlunkCrypt error: Failed to generate nonce!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = slunkcrypt_alloc(nonce, (const uint8_t*)passphrase, strlen(passphrase), SLUNKCRYPT_ENCRYPT);
|
||||||
|
if (!ctx)
|
||||||
|
{
|
||||||
|
FPUTS(g_slunkcrypt_abort_flag ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to initialize encryption!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fwrite_ui64(nonce ^ MAGIC_NUMBER, file_out) < 1U)
|
||||||
|
{
|
||||||
|
FPUTS(T("\n\nI/O error: Failed to write nonce value!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned refresh_cycles = 0U;
|
||||||
|
clock_t clk_update = clock();
|
||||||
|
uint64_t bytes_read = 0U;
|
||||||
|
uint8_t buffer[BUFFER_SIZE];
|
||||||
|
|
||||||
|
blake2s_t blake2s_state;
|
||||||
|
blake2s_init(&blake2s_state);
|
||||||
|
|
||||||
|
FPRINTF(stderr, T("%5.1f%% "), 0.0);
|
||||||
|
fflush(stderr);
|
||||||
|
|
||||||
|
while (bytes_read < file_size)
|
||||||
|
{
|
||||||
|
const uint64_t bytes_remaining = file_size - bytes_read;
|
||||||
|
const size_t request_len = (bytes_remaining < BUFFER_SIZE) ? ((size_t)bytes_remaining) : BUFFER_SIZE;
|
||||||
|
const size_t count = fread(buffer, sizeof(uint8_t), request_len, file_in);
|
||||||
|
if (count > 0U)
|
||||||
|
{
|
||||||
|
blake2s_update(&blake2s_state, buffer, count);
|
||||||
|
bytes_read += count;
|
||||||
|
if ((status = slunkcrypt_inplace(ctx, buffer, count)) != SLUNKCRYPT_SUCCESS)
|
||||||
|
{
|
||||||
|
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to encrypt data!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
if (fwrite(buffer, sizeof(uint8_t), count, file_out) < count)
|
||||||
|
{
|
||||||
|
FPUTS(T("\n\nI/O error: Failed to write encrypted data!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count < request_len)
|
||||||
|
{
|
||||||
|
break; /*EOF*/
|
||||||
|
}
|
||||||
|
if (!(++refresh_cycles & 0x1F))
|
||||||
|
{
|
||||||
|
const clock_t clk_now = clock();
|
||||||
|
if ((clk_now < clk_update) || (clk_now - clk_update > UPDATE_INTERVAL))
|
||||||
|
{
|
||||||
|
FPRINTF(stderr, T("\b\b\b\b\b\b\b%5.1f%% "), (bytes_read / ((double)file_size)) * 100.0);
|
||||||
|
fflush(stderr);
|
||||||
|
clk_update = clk_now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ferror(file_in))
|
||||||
|
{
|
||||||
|
FPUTS(T("\n\nI/O error: Failed to read input data!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes_read != file_size)
|
||||||
|
{
|
||||||
|
FPUTS(T("\n\nI/O error: Input file could not be fully read!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t padding = sizeof(uint64_t) - (file_size % sizeof(uint64_t));
|
||||||
|
assert(padding && (padding <= sizeof(uint64_t)));
|
||||||
|
if (slunkcrypt_random_bytes(buffer, padding) < padding)
|
||||||
|
{
|
||||||
|
FPUTS(T("\n\nSlunkCrypt error: Failed to generate random data!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
SET_LOWBITS(buffer[padding - 1U], padding - 1U);
|
||||||
|
if ((status = slunkcrypt_inplace(ctx, buffer, padding)) != SLUNKCRYPT_SUCCESS)
|
||||||
|
{
|
||||||
|
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to encrypt data!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fwrite(buffer, sizeof(uint8_t), padding, file_out) < padding)
|
||||||
|
{
|
||||||
|
FPUTS(T("\n\nI/O error: Failed to write padding data!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t checksum_buffer[sizeof(uint64_t)];
|
||||||
|
store_ui64(checksum_buffer, blake2s_final(&blake2s_state));
|
||||||
|
|
||||||
|
if ((status = slunkcrypt_inplace(ctx, checksum_buffer, sizeof(uint64_t))) != SLUNKCRYPT_SUCCESS)
|
||||||
|
{
|
||||||
|
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to encrypt checksum!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fwrite(checksum_buffer, sizeof(uint8_t), sizeof(uint64_t), file_out) < sizeof(uint64_t))
|
||||||
|
{
|
||||||
|
FPUTS(T("\n\nI/O error: Failed to write the checksum!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
FPRINTF(stderr, T("\b\b\b\b\b\b\b%5.1f%%\n\n"), 100.0);
|
||||||
|
|
||||||
|
result = EXIT_SUCCESS;
|
||||||
|
|
||||||
|
FPUTS(T("All is done.\n\n"), stderr);
|
||||||
|
fflush(stderr);
|
||||||
|
|
||||||
|
clean_up:
|
||||||
|
|
||||||
|
if (ctx)
|
||||||
|
{
|
||||||
|
slunkcrypt_free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_out)
|
||||||
|
{
|
||||||
|
fclose(file_out);
|
||||||
|
if ((result != EXIT_SUCCESS) && (!keep_incomplete))
|
||||||
|
{
|
||||||
|
if (REMOVE(output_path))
|
||||||
|
{
|
||||||
|
FPUTS(T("Warning: Failed to remove incomplete output file!\n\n"), stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_in)
|
||||||
|
{
|
||||||
|
fclose(file_in);
|
||||||
|
}
|
||||||
|
|
||||||
|
slunkcrypt_bzero(buffer, BUFFER_SIZE);
|
||||||
|
slunkcrypt_bzero(checksum_buffer, sizeof(uint64_t));
|
||||||
|
slunkcrypt_bzero(&blake2s_state, sizeof(blake2s_t));
|
||||||
|
slunkcrypt_bzero(&nonce, sizeof(uint64_t));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
// Decrypt
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
|
int decrypt(const char *const passphrase, const CHR *const input_path, const CHR *const output_path, const int keep_incomplete)
|
||||||
|
{
|
||||||
|
slunkcrypt_t ctx = SLUNKCRYPT_NULL;
|
||||||
|
FILE* file_in = NULL, * file_out = NULL;
|
||||||
|
int result = EXIT_FAILURE, status;
|
||||||
|
|
||||||
|
if (open_files(&file_in, &file_out, input_path, output_path) != EXIT_SUCCESS)
|
||||||
|
{
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t file_size = get_file_size(file_in);
|
||||||
|
if (file_size == UINT64_MAX)
|
||||||
|
{
|
||||||
|
FPUTS(T("I/O error: Failed to determine size of input file!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
else if (file_size < (3U * sizeof(uint64_t)))
|
||||||
|
{
|
||||||
|
FPUTS(T("Error: Input file is too small! Truncated?\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
else if ((file_size % sizeof(uint64_t)) != 0)
|
||||||
|
{
|
||||||
|
FPRINTF(stderr, T("Warning: File size is *not* an integer multiple of %u, ignoring excess bytes!\n\n"), (unsigned)sizeof(uint64_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
FPUTS(T("Decrypting file contents, please be patient... "), stderr);
|
||||||
|
fflush(stderr);
|
||||||
|
|
||||||
|
uint64_t nonce;
|
||||||
|
if (fread_ui64(&nonce, file_in) < 1U)
|
||||||
|
{
|
||||||
|
FPUTS(T("\n\nI/O error: Failed to read nonce value!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = slunkcrypt_alloc(nonce ^ MAGIC_NUMBER, (const uint8_t*)passphrase, strlen(passphrase), SLUNKCRYPT_DECRYPT);
|
||||||
|
if (!ctx)
|
||||||
|
{
|
||||||
|
FPUTS(g_slunkcrypt_abort_flag ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to initialize decryption!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned refresh_cycles = 0U;
|
||||||
|
clock_t clk_update = clock();
|
||||||
|
uint64_t bytes_read = sizeof(uint64_t);
|
||||||
|
uint8_t buffer[BUFFER_SIZE];
|
||||||
|
|
||||||
|
const uint64_t read_limit = round_down(file_size, sizeof(uint64_t)) - (2U * sizeof(uint64_t));
|
||||||
|
|
||||||
|
blake2s_t blake2s_state;
|
||||||
|
blake2s_init(&blake2s_state);
|
||||||
|
|
||||||
|
FPRINTF(stderr, T("%5.1f%% "), 0.0);
|
||||||
|
fflush(stderr);
|
||||||
|
|
||||||
|
while (bytes_read < read_limit)
|
||||||
|
{
|
||||||
|
const uint64_t bytes_remaining = read_limit - bytes_read;
|
||||||
|
const size_t request_len = (bytes_remaining < BUFFER_SIZE) ? ((size_t)bytes_remaining) : BUFFER_SIZE;
|
||||||
|
const size_t count = fread(buffer, sizeof(uint8_t), request_len, file_in);
|
||||||
|
if (count > 0U)
|
||||||
|
{
|
||||||
|
bytes_read += count;
|
||||||
|
if ((status = slunkcrypt_inplace(ctx, buffer, count)) != SLUNKCRYPT_SUCCESS)
|
||||||
|
{
|
||||||
|
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to decrypt data!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
blake2s_update(&blake2s_state, buffer, count);
|
||||||
|
if (fwrite(buffer, sizeof(uint8_t), count, file_out) < count)
|
||||||
|
{
|
||||||
|
FPUTS(T("failed!\n\nI/O error: Failed to write decrypted data!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count < request_len)
|
||||||
|
{
|
||||||
|
break; /*EOF*/
|
||||||
|
}
|
||||||
|
if (!(++refresh_cycles & 0x1F))
|
||||||
|
{
|
||||||
|
const clock_t clk_now = clock();
|
||||||
|
if ((clk_now < clk_update) || (clk_now - clk_update > UPDATE_INTERVAL))
|
||||||
|
{
|
||||||
|
FPRINTF(stderr, T("\b\b\b\b\b\b\b%5.1f%% "), (bytes_read / ((double)read_limit)) * 100.0);
|
||||||
|
fflush(stderr);
|
||||||
|
clk_update = clk_now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ferror(file_in))
|
||||||
|
{
|
||||||
|
FPUTS(T("\n\nI/O error: Failed to read input data!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes_read != read_limit)
|
||||||
|
{
|
||||||
|
FPUTS(T("\n\nI/O error: Input file could not be fully read!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fread(buffer, sizeof(uint8_t), sizeof(uint64_t), file_in) < sizeof(uint64_t))
|
||||||
|
{
|
||||||
|
FPUTS(T("\n\nI/O error: Failed to read final block!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((status = slunkcrypt_inplace(ctx, buffer, sizeof(uint64_t))) != SLUNKCRYPT_SUCCESS)
|
||||||
|
{
|
||||||
|
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to decrypt data!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t padding = GET_LOWBITS(buffer[sizeof(uint64_t) - 1U]) + 1U;
|
||||||
|
assert(padding && (padding <= sizeof(uint64_t)));
|
||||||
|
if (padding != sizeof(uint64_t))
|
||||||
|
{
|
||||||
|
const size_t count = sizeof(uint64_t) - padding;
|
||||||
|
if (fwrite(buffer, sizeof(uint8_t), count, file_out) < count)
|
||||||
|
{
|
||||||
|
FPUTS(T("failed!\n\nI/O error: Failed to write decrypted data!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
blake2s_update(&blake2s_state, buffer, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t checksum_actual = blake2s_final(&blake2s_state);
|
||||||
|
|
||||||
|
uint8_t checksum_buffer[sizeof(uint64_t)];
|
||||||
|
if (fread(checksum_buffer, sizeof(uint8_t), sizeof(uint64_t), file_in) < sizeof(uint64_t))
|
||||||
|
{
|
||||||
|
FPUTS(T("\n\nI/O error: Failed to read the checksum!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((status = slunkcrypt_inplace(ctx, checksum_buffer, sizeof(uint64_t))) != SLUNKCRYPT_SUCCESS)
|
||||||
|
{
|
||||||
|
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to decrypt checksum!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
FPRINTF(stderr, T("\b\b\b\b\b\b\b%5.1f%%\n\n"), 100.0);
|
||||||
|
|
||||||
|
const uint64_t checksum_stored = load_ui64(checksum_buffer);
|
||||||
|
if (checksum_actual != checksum_stored)
|
||||||
|
{
|
||||||
|
FPRINTF(stderr, T("Error: Checksum mismatch detected! [expected: 0x%016") T(PRIX64) T(", actual: 0x%016") T(PRIX64) T("]\n\n"), checksum_stored, checksum_actual);
|
||||||
|
FPUTS(T("Wrong passphrase or corrupted file?\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = EXIT_SUCCESS;
|
||||||
|
|
||||||
|
FPUTS(T("Checksum is correct.\n\n"), stderr);
|
||||||
|
fflush(stderr);
|
||||||
|
|
||||||
|
clean_up:
|
||||||
|
|
||||||
|
if (ctx)
|
||||||
|
{
|
||||||
|
slunkcrypt_free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_out)
|
||||||
|
{
|
||||||
|
fclose(file_out);
|
||||||
|
if ((result != EXIT_SUCCESS) && (!keep_incomplete))
|
||||||
|
{
|
||||||
|
if (REMOVE(output_path))
|
||||||
|
{
|
||||||
|
FPUTS(T("Warning: Failed to remove incomplete output file!\n\n"), stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_in)
|
||||||
|
{
|
||||||
|
fclose(file_in);
|
||||||
|
}
|
||||||
|
|
||||||
|
slunkcrypt_bzero(buffer, BUFFER_SIZE);
|
||||||
|
slunkcrypt_bzero(checksum_buffer, sizeof(uint64_t));
|
||||||
|
slunkcrypt_bzero(&blake2s_state, sizeof(blake2s_t));
|
||||||
|
slunkcrypt_bzero(&nonce, sizeof(uint64_t));
|
||||||
|
slunkcrypt_bzero((void*)&checksum_stored, sizeof(uint64_t));
|
||||||
|
slunkcrypt_bzero((void*)&checksum_actual, sizeof(uint64_t));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
15
frontend/src/crypt.h
Normal file
15
frontend/src/crypt.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/******************************************************************************/
|
||||||
|
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
|
||||||
|
/* This work has been released under the CC0 1.0 Universal license! */
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef INC_SLUNKAPP_CRYPT_H
|
||||||
|
#define INC_SLUNKAPP_CRYPT_H
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
int encrypt(const char *const passphrase, const CHR *const input_path, const CHR *const output_path, const int keep_incomplete);
|
||||||
|
int decrypt(const char *const passphrase, const CHR *const input_path, const CHR *const output_path, const int keep_incomplete);
|
||||||
|
|
||||||
|
#endif
|
@ -9,13 +9,11 @@
|
|||||||
# define _GNU_SOURCE 1
|
# define _GNU_SOURCE 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* API */
|
/* Internal */
|
||||||
#include <slunkcrypt.h>
|
#include <slunkcrypt.h>
|
||||||
|
|
||||||
/* CLI */
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "blake2.h"
|
#include "crypt.h"
|
||||||
#include "test.h"
|
#include "selftest.h"
|
||||||
|
|
||||||
/* CRT */
|
/* CRT */
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -23,14 +21,11 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Constants
|
// Constants
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
#define BUFFER_SIZE 4096U
|
|
||||||
|
|
||||||
#define MODE_HELP 0
|
#define MODE_HELP 0
|
||||||
#define MODE_VERS 1
|
#define MODE_VERS 1
|
||||||
#define MODE_ENCR 2
|
#define MODE_ENCR 2
|
||||||
@ -59,10 +54,6 @@ static const char PASSWD_SYMBOLS[] =
|
|||||||
static const size_t RCMD_PWDLEN_LENGTH = 12U;
|
static const size_t RCMD_PWDLEN_LENGTH = 12U;
|
||||||
static const size_t DFLT_PWDLEN_LENGTH = 20U;
|
static const size_t DFLT_PWDLEN_LENGTH = 20U;
|
||||||
|
|
||||||
static const clock_t UPDATE_INTERVAL = (clock_t)(1.5708 * CLOCKS_PER_SEC);
|
|
||||||
|
|
||||||
static const uint64_t MAGIC_NUMBER = 0x243F6A8885A308D3ull;
|
|
||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Auxiliary functions
|
// Auxiliary functions
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
@ -241,32 +232,23 @@ clean_up:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int open_files(FILE **const file_in, FILE **const file_out, const CHR *const input_path, const CHR *const output_path)
|
static int keep_incomplete_files(void)
|
||||||
{
|
|
||||||
if (!(*file_in = FOPEN(input_path, T("rb"))))
|
|
||||||
{
|
|
||||||
FPRINTF(stderr, T("Error: Failed to open input file \"%") T(PRISTR) T("\" for reading!\n\n"), input_path);
|
|
||||||
*file_out = NULL;
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(*file_out = FOPEN(output_path, T("wb"))))
|
|
||||||
{
|
|
||||||
FPRINTF(stderr, T("Error: Failed to open output file \"%") T(PRISTR) T("\" for writing!\n\n"), output_path);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int remove_incomplete_files(void)
|
|
||||||
{
|
{
|
||||||
const CHR *const keep_files = GETENV(ENV_KEEPFILE);
|
const CHR *const keep_files = GETENV(ENV_KEEPFILE);
|
||||||
if (keep_files)
|
if (keep_files)
|
||||||
{
|
{
|
||||||
return (!STRTOUL(keep_files));
|
return BOOLIFY(STRTOUL(keep_files));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_excess_arguments(const int argc, int maximum)
|
||||||
|
{
|
||||||
|
if (argc > maximum)
|
||||||
|
{
|
||||||
|
FPUTS(T("Warning: Excess command-line argument(s) will be ignored!\n\n"), stderr);
|
||||||
|
fflush(stderr);
|
||||||
}
|
}
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sigint_handler(const int sig)
|
static void sigint_handler(const int sig)
|
||||||
@ -277,525 +259,6 @@ static void sigint_handler(const int sig)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==========================================================================
|
|
||||||
// Encrypt
|
|
||||||
// ==========================================================================
|
|
||||||
|
|
||||||
static int encrypt(const char* const passphrase, const CHR* const input_path, const CHR* const output_path)
|
|
||||||
{
|
|
||||||
slunkcrypt_t ctx = SLUNKCRYPT_NULL;
|
|
||||||
FILE *file_in = NULL, *file_out = NULL;
|
|
||||||
int result = EXIT_FAILURE, status;
|
|
||||||
|
|
||||||
if (open_files(&file_in, &file_out, input_path, output_path) != EXIT_SUCCESS)
|
|
||||||
{
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint64_t file_size = get_file_size(file_in);
|
|
||||||
if (file_size == UINT64_MAX)
|
|
||||||
{
|
|
||||||
FPUTS(T("I/O error: Failed to determine size of input file!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
else if (file_size < 1U)
|
|
||||||
{
|
|
||||||
FPUTS(T("Error: Input file is empty or an unsupported type!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
FPUTS(T("Encrypting file contents, please be patient... "), stderr);
|
|
||||||
fflush(stderr);
|
|
||||||
|
|
||||||
uint64_t nonce;
|
|
||||||
if (slunkcrypt_generate_nonce(&nonce) != SLUNKCRYPT_SUCCESS)
|
|
||||||
{
|
|
||||||
FPUTS(T("\n\nSlunkCrypt error: Failed to generate nonce!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = slunkcrypt_alloc(nonce, (const uint8_t*)passphrase, strlen(passphrase), SLUNKCRYPT_ENCRYPT);
|
|
||||||
if (!ctx)
|
|
||||||
{
|
|
||||||
FPUTS(g_slunkcrypt_abort_flag ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to initialize encryption!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fwrite_ui64(nonce ^ MAGIC_NUMBER, file_out) < 1U)
|
|
||||||
{
|
|
||||||
FPUTS(T("\n\nI/O error: Failed to write nonce value!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned refresh_cycles = 0U;
|
|
||||||
clock_t clk_update = clock();
|
|
||||||
uint64_t bytes_read = 0U;
|
|
||||||
uint8_t buffer[BUFFER_SIZE];
|
|
||||||
|
|
||||||
blake2s_t blake2s_state;
|
|
||||||
blake2s_init(&blake2s_state);
|
|
||||||
|
|
||||||
FPRINTF(stderr, T("%5.1f%% "), 0.0);
|
|
||||||
fflush(stderr);
|
|
||||||
|
|
||||||
while (bytes_read < file_size)
|
|
||||||
{
|
|
||||||
const uint64_t bytes_remaining = file_size - bytes_read;
|
|
||||||
const size_t request_len = (bytes_remaining < BUFFER_SIZE) ? ((size_t)bytes_remaining) : BUFFER_SIZE;
|
|
||||||
const size_t count = fread(buffer, sizeof(uint8_t), request_len, file_in);
|
|
||||||
if (count > 0U)
|
|
||||||
{
|
|
||||||
blake2s_update(&blake2s_state, buffer, count);
|
|
||||||
bytes_read += count;
|
|
||||||
if ((status = slunkcrypt_inplace(ctx, buffer, count)) != SLUNKCRYPT_SUCCESS)
|
|
||||||
{
|
|
||||||
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to encrypt data!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
if (fwrite(buffer, sizeof(uint8_t), count, file_out) < count)
|
|
||||||
{
|
|
||||||
FPUTS(T("\n\nI/O error: Failed to write encrypted data!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (count < request_len)
|
|
||||||
{
|
|
||||||
break; /*EOF*/
|
|
||||||
}
|
|
||||||
if (!(++refresh_cycles & 0x1F))
|
|
||||||
{
|
|
||||||
const clock_t clk_now = clock();
|
|
||||||
if ((clk_now < clk_update) || (clk_now - clk_update > UPDATE_INTERVAL))
|
|
||||||
{
|
|
||||||
FPRINTF(stderr, T("\b\b\b\b\b\b\b%5.1f%% "), (bytes_read / ((double)file_size)) * 100.0);
|
|
||||||
fflush(stderr);
|
|
||||||
clk_update = clk_now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ferror(file_in))
|
|
||||||
{
|
|
||||||
FPUTS(T("\n\nI/O error: Failed to read input data!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bytes_read != file_size)
|
|
||||||
{
|
|
||||||
FPUTS(T("\n\nI/O error: Input file could not be fully read!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t padding = sizeof(uint64_t) - (file_size % sizeof(uint64_t));
|
|
||||||
assert(padding && (padding <= sizeof(uint64_t)));
|
|
||||||
if (slunkcrypt_random_bytes(buffer, padding) < padding)
|
|
||||||
{
|
|
||||||
FPUTS(T("\n\nSlunkCrypt error: Failed to generate random data!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
SET_LOWBITS(buffer[padding - 1U], padding - 1U);
|
|
||||||
if ((status = slunkcrypt_inplace(ctx, buffer, padding)) != SLUNKCRYPT_SUCCESS)
|
|
||||||
{
|
|
||||||
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to encrypt data!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fwrite(buffer, sizeof(uint8_t), padding, file_out) < padding)
|
|
||||||
{
|
|
||||||
FPUTS(T("\n\nI/O error: Failed to write padding data!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t checksum_buffer[sizeof(uint64_t)];
|
|
||||||
store_ui64(checksum_buffer, blake2s_final(&blake2s_state));
|
|
||||||
|
|
||||||
if ((status = slunkcrypt_inplace(ctx, checksum_buffer, sizeof(uint64_t))) != SLUNKCRYPT_SUCCESS)
|
|
||||||
{
|
|
||||||
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to encrypt checksum!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fwrite(checksum_buffer, sizeof(uint8_t), sizeof(uint64_t), file_out) < sizeof(uint64_t))
|
|
||||||
{
|
|
||||||
FPUTS(T("\n\nI/O error: Failed to write the checksum!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
FPRINTF(stderr, T("\b\b\b\b\b\b\b%5.1f%%\n\n"), 100.0);
|
|
||||||
|
|
||||||
result = EXIT_SUCCESS;
|
|
||||||
|
|
||||||
FPUTS(T("All is done.\n\n"), stderr);
|
|
||||||
fflush(stderr);
|
|
||||||
|
|
||||||
clean_up:
|
|
||||||
|
|
||||||
if (ctx)
|
|
||||||
{
|
|
||||||
slunkcrypt_free(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_out)
|
|
||||||
{
|
|
||||||
fclose(file_out);
|
|
||||||
if ((result != EXIT_SUCCESS) && remove_incomplete_files())
|
|
||||||
{
|
|
||||||
if (REMOVE(output_path))
|
|
||||||
{
|
|
||||||
FPUTS(T("Warning: Failed to remove incomplete output file!\n\n"), stderr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_in)
|
|
||||||
{
|
|
||||||
fclose(file_in);
|
|
||||||
}
|
|
||||||
|
|
||||||
slunkcrypt_bzero(buffer, BUFFER_SIZE);
|
|
||||||
slunkcrypt_bzero(checksum_buffer, sizeof(uint64_t));
|
|
||||||
slunkcrypt_bzero(&blake2s_state, sizeof(blake2s_t));
|
|
||||||
slunkcrypt_bzero(&nonce, sizeof(uint64_t));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==========================================================================
|
|
||||||
// Decrypt
|
|
||||||
// ==========================================================================
|
|
||||||
|
|
||||||
static int decrypt(const char* const passphrase, const CHR* const input_path, const CHR* const output_path)
|
|
||||||
{
|
|
||||||
slunkcrypt_t ctx = SLUNKCRYPT_NULL;
|
|
||||||
FILE *file_in = NULL, *file_out = NULL;
|
|
||||||
int result = EXIT_FAILURE, status;
|
|
||||||
|
|
||||||
if (open_files(&file_in, &file_out, input_path, output_path) != EXIT_SUCCESS)
|
|
||||||
{
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint64_t file_size = get_file_size(file_in);
|
|
||||||
if (file_size == UINT64_MAX)
|
|
||||||
{
|
|
||||||
FPUTS(T("I/O error: Failed to determine size of input file!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
else if (file_size < (3U * sizeof(uint64_t)))
|
|
||||||
{
|
|
||||||
FPUTS(T("Error: Input file is too small! Truncated?\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
else if ((file_size % sizeof(uint64_t)) != 0)
|
|
||||||
{
|
|
||||||
FPRINTF(stderr, T("Warning: File size is *not* an integer multiple of %u, ignoring excess bytes!\n\n"), (unsigned)sizeof(uint64_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
FPUTS(T("Decrypting file contents, please be patient... "), stderr);
|
|
||||||
fflush(stderr);
|
|
||||||
|
|
||||||
uint64_t nonce;
|
|
||||||
if (fread_ui64(&nonce, file_in) < 1U)
|
|
||||||
{
|
|
||||||
FPUTS(T("\n\nI/O error: Failed to read nonce value!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = slunkcrypt_alloc(nonce ^ MAGIC_NUMBER, (const uint8_t*)passphrase, strlen(passphrase), SLUNKCRYPT_DECRYPT);
|
|
||||||
if (!ctx)
|
|
||||||
{
|
|
||||||
FPUTS(g_slunkcrypt_abort_flag ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to initialize decryption!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned refresh_cycles = 0U;
|
|
||||||
clock_t clk_update = clock();
|
|
||||||
uint64_t bytes_read = sizeof(uint64_t);
|
|
||||||
uint8_t buffer[BUFFER_SIZE];
|
|
||||||
|
|
||||||
const uint64_t read_limit = round_down(file_size, sizeof(uint64_t)) - (2U * sizeof(uint64_t));
|
|
||||||
|
|
||||||
blake2s_t blake2s_state;
|
|
||||||
blake2s_init(&blake2s_state);
|
|
||||||
|
|
||||||
FPRINTF(stderr, T("%5.1f%% "), 0.0);
|
|
||||||
fflush(stderr);
|
|
||||||
|
|
||||||
while (bytes_read < read_limit)
|
|
||||||
{
|
|
||||||
const uint64_t bytes_remaining = read_limit - bytes_read;
|
|
||||||
const size_t request_len = (bytes_remaining < BUFFER_SIZE) ? ((size_t)bytes_remaining) : BUFFER_SIZE;
|
|
||||||
const size_t count = fread(buffer, sizeof(uint8_t), request_len, file_in);
|
|
||||||
if (count > 0U)
|
|
||||||
{
|
|
||||||
bytes_read += count;
|
|
||||||
if ((status = slunkcrypt_inplace(ctx, buffer, count)) != SLUNKCRYPT_SUCCESS)
|
|
||||||
{
|
|
||||||
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to decrypt data!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
blake2s_update(&blake2s_state, buffer, count);
|
|
||||||
if (fwrite(buffer, sizeof(uint8_t), count, file_out) < count)
|
|
||||||
{
|
|
||||||
FPUTS(T("failed!\n\nI/O error: Failed to write decrypted data!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (count < request_len)
|
|
||||||
{
|
|
||||||
break; /*EOF*/
|
|
||||||
}
|
|
||||||
if (!(++refresh_cycles & 0x1F))
|
|
||||||
{
|
|
||||||
const clock_t clk_now = clock();
|
|
||||||
if ((clk_now < clk_update) || (clk_now - clk_update > UPDATE_INTERVAL))
|
|
||||||
{
|
|
||||||
FPRINTF(stderr, T("\b\b\b\b\b\b\b%5.1f%% "), (bytes_read / ((double)read_limit)) * 100.0);
|
|
||||||
fflush(stderr);
|
|
||||||
clk_update = clk_now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ferror(file_in))
|
|
||||||
{
|
|
||||||
FPUTS(T("\n\nI/O error: Failed to read input data!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bytes_read != read_limit)
|
|
||||||
{
|
|
||||||
FPUTS(T("\n\nI/O error: Input file could not be fully read!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fread(buffer, sizeof(uint8_t), sizeof(uint64_t), file_in) < sizeof(uint64_t))
|
|
||||||
{
|
|
||||||
FPUTS(T("\n\nI/O error: Failed to read final block!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((status = slunkcrypt_inplace(ctx, buffer, sizeof(uint64_t))) != SLUNKCRYPT_SUCCESS)
|
|
||||||
{
|
|
||||||
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to decrypt data!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t padding = GET_LOWBITS(buffer[sizeof(uint64_t) - 1U]) + 1U;
|
|
||||||
assert(padding && (padding <= sizeof(uint64_t)));
|
|
||||||
if (padding != sizeof(uint64_t))
|
|
||||||
{
|
|
||||||
const size_t count = sizeof(uint64_t) - padding;
|
|
||||||
if (fwrite(buffer, sizeof(uint8_t), count, file_out) < count)
|
|
||||||
{
|
|
||||||
FPUTS(T("failed!\n\nI/O error: Failed to write decrypted data!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
blake2s_update(&blake2s_state, buffer, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint64_t checksum_actual = blake2s_final(&blake2s_state);
|
|
||||||
|
|
||||||
uint8_t checksum_buffer[sizeof(uint64_t)];
|
|
||||||
if (fread(checksum_buffer, sizeof(uint8_t), sizeof(uint64_t), file_in) < sizeof(uint64_t))
|
|
||||||
{
|
|
||||||
FPUTS(T("\n\nI/O error: Failed to read the checksum!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((status = slunkcrypt_inplace(ctx, checksum_buffer, sizeof(uint64_t))) != SLUNKCRYPT_SUCCESS)
|
|
||||||
{
|
|
||||||
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to decrypt checksum!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
FPRINTF(stderr, T("\b\b\b\b\b\b\b%5.1f%%\n\n"), 100.0);
|
|
||||||
|
|
||||||
const uint64_t checksum_stored = load_ui64(checksum_buffer);
|
|
||||||
if (checksum_actual != checksum_stored)
|
|
||||||
{
|
|
||||||
FPRINTF(stderr, T("Error: Checksum mismatch detected! [expected: 0x%016") T(PRIX64) T(", actual: 0x%016") T(PRIX64) T("]\n\n"), checksum_stored, checksum_actual);
|
|
||||||
FPUTS(T("Wrong passphrase or corrupted file?\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = EXIT_SUCCESS;
|
|
||||||
|
|
||||||
FPUTS(T("Checksum is correct.\n\n"), stderr);
|
|
||||||
fflush(stderr);
|
|
||||||
|
|
||||||
clean_up:
|
|
||||||
|
|
||||||
if (ctx)
|
|
||||||
{
|
|
||||||
slunkcrypt_free(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_out)
|
|
||||||
{
|
|
||||||
fclose(file_out);
|
|
||||||
if ((result != EXIT_SUCCESS) && remove_incomplete_files())
|
|
||||||
{
|
|
||||||
if (REMOVE(output_path))
|
|
||||||
{
|
|
||||||
FPUTS(T("Warning: Failed to remove incomplete output file!\n\n"), stderr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_in)
|
|
||||||
{
|
|
||||||
fclose(file_in);
|
|
||||||
}
|
|
||||||
|
|
||||||
slunkcrypt_bzero(buffer, BUFFER_SIZE);
|
|
||||||
slunkcrypt_bzero(checksum_buffer, sizeof(uint64_t));
|
|
||||||
slunkcrypt_bzero(&blake2s_state, sizeof(blake2s_t));
|
|
||||||
slunkcrypt_bzero(&nonce, sizeof(uint64_t));
|
|
||||||
slunkcrypt_bzero((void*)&checksum_stored, sizeof(uint64_t));
|
|
||||||
slunkcrypt_bzero((void*)&checksum_actual, sizeof(uint64_t));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==========================================================================
|
|
||||||
// Self-test
|
|
||||||
// ==========================================================================
|
|
||||||
|
|
||||||
static int run_test_case(const char *const message, const uint64_t nonce, const uint64_t checksum_message, const uint64_t checksum_expected)
|
|
||||||
{
|
|
||||||
static const char* const TEST_PASSPHRASE = "OrpheanBeh0lderScry!Doubt";
|
|
||||||
|
|
||||||
int status, result = EXIT_FAILURE;
|
|
||||||
const size_t length = strlen(message) + 1U;
|
|
||||||
slunkcrypt_t ctx = SLUNKCRYPT_NULL;
|
|
||||||
|
|
||||||
char* const text_temp = strdup(message);
|
|
||||||
if (!text_temp)
|
|
||||||
{
|
|
||||||
FPUTS(T("\n\nWhoops: Failed to allocate text buffer!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint64_t checksum_original = blake2s_compute((uint8_t*)text_temp, length);
|
|
||||||
if (checksum_original != checksum_message)
|
|
||||||
{
|
|
||||||
FPRINTF(stderr, T("\n\nWhoops: Checksum mismatch detected! [expected: 0x%016") T(PRIX64) T(", actual: 0x%016") T(PRIX64) T("]\n\n"), checksum_message, checksum_original);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = slunkcrypt_alloc(nonce, (const uint8_t*)TEST_PASSPHRASE, strlen(TEST_PASSPHRASE), SLUNKCRYPT_ENCRYPT);
|
|
||||||
if (!ctx)
|
|
||||||
{
|
|
||||||
FPUTS(g_slunkcrypt_abort_flag ? T("\n\nProcess interrupted!\n\n") : T("\n\nWhoops: Failed to initialize encoder!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = slunkcrypt_inplace(ctx, (uint8_t*)text_temp, length);
|
|
||||||
if (status != SLUNKCRYPT_SUCCESS)
|
|
||||||
{
|
|
||||||
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nWhoops: Failed to encrypt the message!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strncmp(message, text_temp, length) == 0)
|
|
||||||
{
|
|
||||||
FPUTS(T("\n\nWhoops: Encrypted message equals the original message!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint64_t checksum_encrypted = blake2s_compute((uint8_t*)text_temp, length);
|
|
||||||
if (checksum_encrypted != checksum_expected)
|
|
||||||
{
|
|
||||||
FPRINTF(stderr, T("\n\nWhoops: Checksum mismatch detected! [expected: 0x%016") T(PRIX64) T(", actual: 0x%016") T(PRIX64) T("]\n\n"), checksum_expected, checksum_encrypted);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = slunkcrypt_reset(ctx, nonce, (const uint8_t*)TEST_PASSPHRASE, strlen(TEST_PASSPHRASE), SLUNKCRYPT_DECRYPT);
|
|
||||||
if (status != SLUNKCRYPT_SUCCESS)
|
|
||||||
{
|
|
||||||
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nWhoops: Failed to initialize decoder!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = slunkcrypt_inplace(ctx, (uint8_t*)text_temp, length);
|
|
||||||
if (status != SLUNKCRYPT_SUCCESS)
|
|
||||||
{
|
|
||||||
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nWhoops: Failed to decrypt the message!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (memcmp(message, text_temp, length * sizeof(char)) != 0)
|
|
||||||
{
|
|
||||||
FPUTS(T("\n\nWhoops: Decrypted message does *not* match the original message!\n\n"), stderr);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint64_t checksum_decrypted = blake2s_compute((uint8_t*)text_temp, length);
|
|
||||||
if (checksum_decrypted != checksum_original)
|
|
||||||
{
|
|
||||||
FPRINTF(stderr, T("\n\nWhoops: Checksum mismatch detected! [expected: 0x%016") T(PRIX64) T(", actual: 0x%016") T(PRIX64) T("]\n\n"), checksum_original, checksum_decrypted);
|
|
||||||
goto clean_up;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = EXIT_SUCCESS;
|
|
||||||
|
|
||||||
clean_up:
|
|
||||||
|
|
||||||
if (ctx)
|
|
||||||
{
|
|
||||||
slunkcrypt_free(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (text_temp)
|
|
||||||
{
|
|
||||||
slunkcrypt_bzero(text_temp, strlen(text_temp));
|
|
||||||
free(text_temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int run_self_test(void)
|
|
||||||
{
|
|
||||||
static const uint64_t TEST_NONCE[] = { 0x243F6A8885A308D3, 0x13198A2E03707344 };
|
|
||||||
const struct
|
|
||||||
{
|
|
||||||
const char* text;
|
|
||||||
uint64_t check_orig, check_encr[2U];
|
|
||||||
}
|
|
||||||
TEST_STAGE[] =
|
|
||||||
{
|
|
||||||
{ TEST_DATA_0, TEST_CHCK_ORIG_0, { TEST_CHCK_ENCR_0[0U], TEST_CHCK_ENCR_0[1U] } },
|
|
||||||
{ TEST_DATA_1, TEST_CHCK_ORIG_1, { TEST_CHCK_ENCR_1[0U], TEST_CHCK_ENCR_1[1U] } },
|
|
||||||
{ TEST_DATA_2, TEST_CHCK_ORIG_2, { TEST_CHCK_ENCR_2[0U], TEST_CHCK_ENCR_2[1U] } },
|
|
||||||
{ TEST_DATA_3, TEST_CHCK_ORIG_3, { TEST_CHCK_ENCR_3[0U], TEST_CHCK_ENCR_3[1U] } },
|
|
||||||
};
|
|
||||||
|
|
||||||
const size_t total = ARRAY_SIZE(TEST_NONCE) * ARRAY_SIZE(TEST_STAGE);
|
|
||||||
FPRINTF(stderr, T("Self-test is in progress, please be patient... stage %u/%u "), 0U, (unsigned)total);
|
|
||||||
fflush(stderr);
|
|
||||||
|
|
||||||
for (size_t i = 0U, count = 0U; i < ARRAY_SIZE(TEST_STAGE); ++i)
|
|
||||||
{
|
|
||||||
for (size_t j = 0U; j < ARRAY_SIZE(TEST_NONCE); ++j)
|
|
||||||
{
|
|
||||||
FPRINTF(stderr, T("\b\b\b\b%u/%u "), (unsigned)++count, (unsigned)total);
|
|
||||||
fflush(stderr);
|
|
||||||
if (run_test_case(TEST_STAGE[i].text, TEST_NONCE[j], TEST_STAGE[i].check_orig, TEST_STAGE[i].check_encr[j]) != EXIT_SUCCESS)
|
|
||||||
{
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FPRINTF(stderr, T("\b\b\b\b%u/%u\n\nCompleted successfully.\n\n"), (unsigned)total, (unsigned)total);
|
|
||||||
fflush(stderr);
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Main function
|
// Main function
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
@ -834,10 +297,12 @@ int MAIN(const int argc, CHR *const argv[])
|
|||||||
case MODE_DECR:
|
case MODE_DECR:
|
||||||
break; /*fallthrough*/
|
break; /*fallthrough*/
|
||||||
case MODE_PASS:
|
case MODE_PASS:
|
||||||
|
check_excess_arguments(argc, 3);
|
||||||
result = generate_passphrase((argc > 2) ? STRTOUL(argv[2U]) : DFLT_PWDLEN_LENGTH);
|
result = generate_passphrase((argc > 2) ? STRTOUL(argv[2U]) : DFLT_PWDLEN_LENGTH);
|
||||||
goto clean_up;
|
goto clean_up;
|
||||||
case MODE_TEST:
|
case MODE_TEST:
|
||||||
result = run_self_test();
|
check_excess_arguments(argc, 2);
|
||||||
|
result = run_selftest_routine();
|
||||||
goto clean_up;
|
goto clean_up;
|
||||||
default:
|
default:
|
||||||
FPRINTF(stderr, T("Error: The specified command \"%") T(PRISTR) T("\" is unknown!\n\n"), argv[1U]);
|
FPRINTF(stderr, T("Error: The specified command \"%") T(PRISTR) T("\" is unknown!\n\n"), argv[1U]);
|
||||||
@ -850,10 +315,7 @@ int MAIN(const int argc, CHR *const argv[])
|
|||||||
goto clean_up;
|
goto clean_up;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc > 5)
|
check_excess_arguments(argc, 5);
|
||||||
{
|
|
||||||
FPUTS(T("Warning: Excess command-line argument(s) will be ignored!\n\n"), stderr);
|
|
||||||
}
|
|
||||||
|
|
||||||
const CHR *const passphrase = PW_FROM_ENV ? GETENV(ENV_PASSWORD) : argv[2U];
|
const CHR *const passphrase = PW_FROM_ENV ? GETENV(ENV_PASSWORD) : argv[2U];
|
||||||
const CHR *const input_file = argv[PW_FROM_ENV ? 2U : 3U], *const output_file = argv[PW_FROM_ENV ? 3U : 4U];
|
const CHR *const input_file = argv[PW_FROM_ENV ? 2U : 3U], *const output_file = argv[PW_FROM_ENV ? 3U : 4U];
|
||||||
@ -920,14 +382,15 @@ int MAIN(const int argc, CHR *const argv[])
|
|||||||
/* ----------------------------------------------------- */
|
/* ----------------------------------------------------- */
|
||||||
|
|
||||||
const clock_t clk_start = clock();
|
const clock_t clk_start = clock();
|
||||||
|
const int keep_incomplete = keep_incomplete_files();
|
||||||
|
|
||||||
switch (slunk_mode)
|
switch (slunk_mode)
|
||||||
{
|
{
|
||||||
case MODE_ENCR:
|
case MODE_ENCR:
|
||||||
result = encrypt(passphrase_buffer, input_file, output_file);
|
result = encrypt(passphrase_buffer, input_file, output_file, keep_incomplete);
|
||||||
break;
|
break;
|
||||||
case MODE_DECR:
|
case MODE_DECR:
|
||||||
result = decrypt(passphrase_buffer, input_file, output_file);
|
result = decrypt(passphrase_buffer, input_file, output_file, keep_incomplete);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
FPUTS(T("Unexpected mode encountered!\n\n"), stderr);
|
FPUTS(T("Unexpected mode encountered!\n\n"), stderr);
|
||||||
|
160
frontend/src/selftest.c
Normal file
160
frontend/src/selftest.c
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
/******************************************************************************/
|
||||||
|
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
|
||||||
|
/* This work has been released under the CC0 1.0 Universal license! */
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
# define _CRT_SECURE_NO_WARNINGS 1
|
||||||
|
#else
|
||||||
|
# define _GNU_SOURCE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Internal */
|
||||||
|
#include "crypt.h"
|
||||||
|
#include <slunkcrypt.h>
|
||||||
|
#include "utils.h"
|
||||||
|
#include "test_data.h"
|
||||||
|
#include "blake2.h"
|
||||||
|
|
||||||
|
/* CRT */
|
||||||
|
#include <time.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
// Self-test routines
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
|
static int run_testcase(const char* const message, const uint64_t nonce, const uint64_t checksum_message, const uint64_t checksum_expected)
|
||||||
|
{
|
||||||
|
static const char* const TEST_PASSPHRASE = "OrpheanBeh0lderScry!Doubt";
|
||||||
|
|
||||||
|
int status, result = EXIT_FAILURE;
|
||||||
|
const size_t length = strlen(message) + 1U;
|
||||||
|
slunkcrypt_t ctx = SLUNKCRYPT_NULL;
|
||||||
|
|
||||||
|
char* const text_temp = strdup(message);
|
||||||
|
if (!text_temp)
|
||||||
|
{
|
||||||
|
FPUTS(T("\n\nWhoops: Failed to allocate text buffer!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t checksum_original = blake2s_compute((uint8_t*)text_temp, length);
|
||||||
|
if (checksum_original != checksum_message)
|
||||||
|
{
|
||||||
|
FPRINTF(stderr, T("\n\nWhoops: Checksum mismatch detected! [expected: 0x%016") T(PRIX64) T(", actual: 0x%016") T(PRIX64) T("]\n\n"), checksum_message, checksum_original);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = slunkcrypt_alloc(nonce, (const uint8_t*)TEST_PASSPHRASE, strlen(TEST_PASSPHRASE), SLUNKCRYPT_ENCRYPT);
|
||||||
|
if (!ctx)
|
||||||
|
{
|
||||||
|
FPUTS(g_slunkcrypt_abort_flag ? T("\n\nProcess interrupted!\n\n") : T("\n\nWhoops: Failed to initialize encoder!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = slunkcrypt_inplace(ctx, (uint8_t*)text_temp, length);
|
||||||
|
if (status != SLUNKCRYPT_SUCCESS)
|
||||||
|
{
|
||||||
|
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nWhoops: Failed to encrypt the message!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(message, text_temp, length) == 0)
|
||||||
|
{
|
||||||
|
FPUTS(T("\n\nWhoops: Encrypted message equals the original message!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t checksum_encrypted = blake2s_compute((uint8_t*)text_temp, length);
|
||||||
|
if (checksum_encrypted != checksum_expected)
|
||||||
|
{
|
||||||
|
FPRINTF(stderr, T("\n\nWhoops: Checksum mismatch detected! [expected: 0x%016") T(PRIX64) T(", actual: 0x%016") T(PRIX64) T("]\n\n"), checksum_expected, checksum_encrypted);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = slunkcrypt_reset(ctx, nonce, (const uint8_t*)TEST_PASSPHRASE, strlen(TEST_PASSPHRASE), SLUNKCRYPT_DECRYPT);
|
||||||
|
if (status != SLUNKCRYPT_SUCCESS)
|
||||||
|
{
|
||||||
|
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nWhoops: Failed to initialize decoder!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = slunkcrypt_inplace(ctx, (uint8_t*)text_temp, length);
|
||||||
|
if (status != SLUNKCRYPT_SUCCESS)
|
||||||
|
{
|
||||||
|
FPUTS((status == SLUNKCRYPT_ABORTED) ? T("\n\nProcess interrupted!\n\n") : T("\n\nWhoops: Failed to decrypt the message!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(message, text_temp, length * sizeof(char)) != 0)
|
||||||
|
{
|
||||||
|
FPUTS(T("\n\nWhoops: Decrypted message does *not* match the original message!\n\n"), stderr);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t checksum_decrypted = blake2s_compute((uint8_t*)text_temp, length);
|
||||||
|
if (checksum_decrypted != checksum_original)
|
||||||
|
{
|
||||||
|
FPRINTF(stderr, T("\n\nWhoops: Checksum mismatch detected! [expected: 0x%016") T(PRIX64) T(", actual: 0x%016") T(PRIX64) T("]\n\n"), checksum_original, checksum_decrypted);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = EXIT_SUCCESS;
|
||||||
|
|
||||||
|
clean_up:
|
||||||
|
|
||||||
|
if (ctx)
|
||||||
|
{
|
||||||
|
slunkcrypt_free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text_temp)
|
||||||
|
{
|
||||||
|
slunkcrypt_bzero(text_temp, strlen(text_temp));
|
||||||
|
free(text_temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int run_selftest_routine(void)
|
||||||
|
{
|
||||||
|
static const uint64_t TEST_NONCE[] = { 0x243F6A8885A308D3, 0x13198A2E03707344 };
|
||||||
|
const struct
|
||||||
|
{
|
||||||
|
const char* text;
|
||||||
|
uint64_t check_orig, check_encr[2U];
|
||||||
|
}
|
||||||
|
TEST_STAGE[] =
|
||||||
|
{
|
||||||
|
{ TEST_DATA_0, TEST_CHCK_ORIG_0, { TEST_CHCK_ENCR_0[0U], TEST_CHCK_ENCR_0[1U] } },
|
||||||
|
{ TEST_DATA_1, TEST_CHCK_ORIG_1, { TEST_CHCK_ENCR_1[0U], TEST_CHCK_ENCR_1[1U] } },
|
||||||
|
{ TEST_DATA_2, TEST_CHCK_ORIG_2, { TEST_CHCK_ENCR_2[0U], TEST_CHCK_ENCR_2[1U] } },
|
||||||
|
{ TEST_DATA_3, TEST_CHCK_ORIG_3, { TEST_CHCK_ENCR_3[0U], TEST_CHCK_ENCR_3[1U] } },
|
||||||
|
};
|
||||||
|
|
||||||
|
const size_t total = ARRAY_SIZE(TEST_NONCE) * ARRAY_SIZE(TEST_STAGE);
|
||||||
|
FPRINTF(stderr, T("Self-test is in progress, please be patient... stage %u/%u "), 0U, (unsigned)total);
|
||||||
|
fflush(stderr);
|
||||||
|
|
||||||
|
for (size_t i = 0U, count = 0U; i < ARRAY_SIZE(TEST_STAGE); ++i)
|
||||||
|
{
|
||||||
|
for (size_t j = 0U; j < ARRAY_SIZE(TEST_NONCE); ++j)
|
||||||
|
{
|
||||||
|
FPRINTF(stderr, T("\b\b\b\b%u/%u "), (unsigned)++count, (unsigned)total);
|
||||||
|
fflush(stderr);
|
||||||
|
if (run_testcase(TEST_STAGE[i].text, TEST_NONCE[j], TEST_STAGE[i].check_orig, TEST_STAGE[i].check_encr[j]) != EXIT_SUCCESS)
|
||||||
|
{
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FPRINTF(stderr, T("\b\b\b\b%u/%u\n\nCompleted successfully.\n\n"), (unsigned)total, (unsigned)total);
|
||||||
|
fflush(stderr);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
14
frontend/src/selftest.h
Normal file
14
frontend/src/selftest.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/******************************************************************************/
|
||||||
|
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
|
||||||
|
/* This work has been released under the CC0 1.0 Universal license! */
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef INC_SLUNKAPP_SELFTEST_H
|
||||||
|
#define INC_SLUNKAPP_SELFTEST_H
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
int run_selftest_routine(void);
|
||||||
|
|
||||||
|
#endif
|
@ -3,7 +3,7 @@
|
|||||||
/* This work has been released under the CC0 1.0 Universal license! */
|
/* This work has been released under the CC0 1.0 Universal license! */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
#include "test.h"
|
#include "test_data.h"
|
||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Test #1
|
// Test #1
|
@ -3,6 +3,9 @@
|
|||||||
/* This work has been released under the CC0 1.0 Universal license! */
|
/* This work has been released under the CC0 1.0 Universal license! */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef INC_SLUNKAPP_TEST_DATA_H
|
||||||
|
#define INC_SLUNKAPP_TEST_DATA_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
extern const char* const TEST_DATA_0;
|
extern const char* const TEST_DATA_0;
|
||||||
@ -14,3 +17,5 @@ extern const uint64_t TEST_CHCK_ORIG_0, TEST_CHCK_ENCR_0[2U];
|
|||||||
extern const uint64_t TEST_CHCK_ORIG_1, TEST_CHCK_ENCR_1[2U];
|
extern const uint64_t TEST_CHCK_ORIG_1, TEST_CHCK_ENCR_1[2U];
|
||||||
extern const uint64_t TEST_CHCK_ORIG_2, TEST_CHCK_ENCR_2[2U];
|
extern const uint64_t TEST_CHCK_ORIG_2, TEST_CHCK_ENCR_2[2U];
|
||||||
extern const uint64_t TEST_CHCK_ORIG_3, TEST_CHCK_ENCR_3[2U];
|
extern const uint64_t TEST_CHCK_ORIG_3, TEST_CHCK_ENCR_3[2U];
|
||||||
|
|
||||||
|
#endif
|
@ -11,8 +11,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Internal */
|
/* Internal */
|
||||||
#include <slunkcrypt.h>
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include <slunkcrypt.h>
|
||||||
|
|
||||||
/* CRT */
|
/* CRT */
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
/* This work has been released under the CC0 1.0 Universal license! */
|
/* This work has been released under the CC0 1.0 Universal license! */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
#ifndef INC_UTILS_H
|
#ifndef INC_SLUNKAPP_UTILS_H
|
||||||
#define INC_UTILS_H
|
#define INC_SLUNKAPP_UTILS_H
|
||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -26,8 +26,10 @@ const CHR *get_file_name(const CHR *path);
|
|||||||
uint64_t round_down(const uint64_t value, const uint64_t base);
|
uint64_t round_down(const uint64_t value, const uint64_t base);
|
||||||
|
|
||||||
#define ARRAY_SIZE(X) (sizeof((X)) / sizeof(*(X)))
|
#define ARRAY_SIZE(X) (sizeof((X)) / sizeof(*(X)))
|
||||||
|
#define BOOLIFY(X) (!!(X))
|
||||||
#define BOUND(MIN,VAL,MAX) (((VAL) < (MIN)) ? (MIN) : (((VAL) > (MAX)) ? (MAX) : (VAL)))
|
#define BOUND(MIN,VAL,MAX) (((VAL) < (MIN)) ? (MIN) : (((VAL) > (MAX)) ? (MAX) : (VAL)))
|
||||||
#define STARTS_WITH(X,Y) (!STRNICMP((X), (Y), STRLEN((Y))))
|
#define STARTS_WITH(X,Y) (!STRNICMP((X), (Y), STRLEN((Y))))
|
||||||
#define GET_LOWBITS(X) ((X) & 0x07)
|
#define GET_LOWBITS(X) ((X) & 0x07)
|
||||||
#define SET_LOWBITS(X,Y) do { X = ((X) & 0xF8) | ((Y) & 0x07); } while(0)
|
#define SET_LOWBITS(X,Y) do { X = ((X) & 0xF8) | ((Y) & 0x07); } while(0)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user