2020-10-12 23:10:47 +02:00
/******************************************************************************/
2020-10-19 21:56:12 +02:00
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
2020-10-12 23:10:47 +02:00
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
2020-11-03 23:19:00 +01:00
# ifdef _WIN32
# define _CRT_SECURE_NO_WARNINGS 1
# else
# define _GNU_SOURCE 1
# endif
2020-10-12 23:10:47 +02:00
2021-03-16 22:03:14 +01:00
/* API */
2020-10-19 21:56:12 +02:00
# include <slunkcrypt.h>
2021-03-16 22:03:14 +01:00
/* CLI */
2020-10-13 15:04:59 +02:00
# include "utils.h"
2021-03-16 22:03:14 +01:00
# include "blake2.h"
2020-10-15 21:56:36 +02:00
# include "test.h"
2020-11-04 23:17:59 +01:00
/* CRT */
2020-10-12 23:10:47 +02:00
# include <string.h>
# include <time.h>
2020-10-13 15:37:40 +02:00
# include <inttypes.h>
2020-10-13 17:42:22 +02:00
# include <ctype.h>
2020-10-14 16:36:17 +02:00
# include <signal.h>
2020-12-12 17:20:18 +01:00
# include <assert.h>
2020-10-12 23:10:47 +02:00
2021-03-26 01:21:29 +01:00
// ==========================================================================
// Constants
// ==========================================================================
2020-10-20 15:21:00 +02:00
# define BUFFER_SIZE 4096U
2021-03-26 01:21:29 +01:00
# define MODE_HELP 0
# define MODE_VERS 1
# define MODE_ENCR 2
# define MODE_DECR 3
# define MODE_PASS 4
# define MODE_TEST 5
2020-10-16 18:05:37 +02:00
2021-03-26 01:21:29 +01:00
# define PW_FROM_ENV (!(argc > 4))
2021-04-03 17:04:03 +02:00
static const CHR * const ENV_PASSWORD = T ( " SLUNK_PASSPHRASE " ) ;
static const CHR * const ENV_KEEPFILE = T ( " SLUNK_KEEP_INCOMPLETE " ) ;
2021-03-21 22:10:34 +01:00
static const CHR * const PREFIX_PASS = T ( " pass: " ) ;
static const CHR * const PREFIX_FILE = T ( " file: " ) ;
2020-12-01 17:28:32 +01:00
static const char PASSWD_SYMBOLS [ ] =
{
' ! ' , ' # ' , ' $ ' , ' % ' , ' & ' , ' ( ' , ' ) ' , ' * ' , ' + ' , ' , ' , ' - ' , ' . ' , ' / ' , ' 0 ' , ' 1 ' ,
' 2 ' , ' 3 ' , ' 4 ' , ' 5 ' , ' 6 ' , ' 7 ' , ' 8 ' , ' 9 ' , ' : ' , ' ; ' , ' < ' , ' = ' , ' > ' , ' ? ' , ' @ ' ,
' A ' , ' B ' , ' C ' , ' D ' , ' E ' , ' F ' , ' G ' , ' H ' , ' I ' , ' J ' , ' K ' , ' L ' , ' M ' , ' N ' , ' O ' ,
' P ' , ' Q ' , ' R ' , ' S ' , ' T ' , ' U ' , ' V ' , ' W ' , ' X ' , ' Y ' , ' Z ' , ' [ ' , ' ] ' , ' ^ ' , ' _ ' ,
' a ' , ' b ' , ' c ' , ' d ' , ' e ' , ' f ' , ' g ' , ' h ' , ' i ' , ' j ' , ' k ' , ' l ' , ' m ' , ' n ' , ' o ' ,
2021-03-21 22:10:34 +01:00
' p ' , ' q ' , ' r ' , ' s ' , ' t ' , ' u ' , ' v ' , ' w ' , ' x ' , ' y ' , ' z ' , ' { ' , ' | ' , ' } ' , ' ~ '
2020-12-01 17:28:32 +01:00
} ;
2020-10-14 16:36:17 +02:00
2021-03-26 01:21:29 +01:00
static const size_t RCMD_PWDLEN_LENGTH = 12U ;
static const size_t DFLT_PWDLEN_LENGTH = 20U ;
2021-03-27 16:19:26 +01:00
static const clock_t UPDATE_INTERVAL = ( clock_t ) ( 1.5708 * CLOCKS_PER_SEC ) ;
2020-12-15 17:18:25 +01:00
static const uint64_t MAGIC_NUMBER = 0x243F6A8885A308D3ull ;
2020-10-20 15:21:00 +02:00
// ==========================================================================
// Auxiliary functions
// ==========================================================================
2021-03-26 01:21:29 +01:00
static int parse_slunk_mode ( const CHR * const command )
2020-10-20 15:21:00 +02:00
{
if ( ( ! STRICMP ( command , T ( " -h " ) ) ) | | ( ! STRICMP ( command , T ( " /? " ) ) ) | | ( ! STRICMP ( command , T ( " --help " ) ) ) )
{
2021-03-26 01:21:29 +01:00
return MODE_HELP ;
2020-10-20 15:21:00 +02:00
}
else if ( ( ! STRICMP ( command , T ( " -v " ) ) ) | | ( ! STRICMP ( command , T ( " --version " ) ) ) )
{
2021-03-26 01:21:29 +01:00
return MODE_VERS ;
2020-10-20 15:21:00 +02:00
}
else if ( ( ! STRICMP ( command , T ( " -e " ) ) ) | | ( ! STRICMP ( command , T ( " --encrypt " ) ) ) )
{
2021-03-26 01:21:29 +01:00
return MODE_ENCR ;
2020-10-20 15:21:00 +02:00
}
else if ( ( ! STRICMP ( command , T ( " -d " ) ) ) | | ( ! STRICMP ( command , T ( " --decrypt " ) ) ) )
{
2021-03-26 01:21:29 +01:00
return MODE_DECR ;
2020-10-20 15:21:00 +02:00
}
2020-12-01 17:28:32 +01:00
else if ( ( ! STRICMP ( command , T ( " -p " ) ) ) | | ( ! STRICMP ( command , T ( " --make-pw " ) ) ) )
{
2021-03-26 01:21:29 +01:00
return MODE_PASS ;
2020-12-01 17:28:32 +01:00
}
2020-10-20 15:21:00 +02:00
else if ( ( ! STRICMP ( command , T ( " -t " ) ) ) | | ( ! STRICMP ( command , T ( " --self-test " ) ) ) )
{
2021-03-26 01:21:29 +01:00
return MODE_TEST ;
2020-10-20 15:21:00 +02:00
}
else
{
2021-03-26 01:21:29 +01:00
return - 1 ; /*invalid command*/
2020-10-20 15:21:00 +02:00
}
}
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 ) ;
2020-10-20 15:33:03 +02:00
FPUTS ( T ( " Usage: \n " ) , stderr ) ;
2021-03-21 22:10:34 +01:00
FPRINTF ( stderr , T ( " % " ) T ( PRISTR ) T ( " --encrypt [pass:<pass>|file:<file>] <input.txt> <output.enc> \n " ) , program ) ;
FPRINTF ( stderr , T ( " % " ) T ( PRISTR ) T ( " --decrypt [pass:<pass>|file:<file>] <input.enc> <output.txt> \n " ) , program ) ;
2020-12-01 17:28:32 +01:00
FPRINTF ( stderr , T ( " % " ) T ( PRISTR ) T ( " --make-pw [<length>] \n \n " ) , program ) ;
2021-04-03 17:04:03 +02:00
FPRINTF ( stderr , T ( " Optionally, reads passphrase from the % " ) T ( PRISTR ) T ( " environment variable. \n \n " ) , ENV_PASSWORD ) ;
2021-03-21 22:10:34 +01:00
}
2021-03-26 01:21:29 +01:00
static char * copy_passphrase ( const CHR * const passphrase )
2021-03-21 22:10:34 +01:00
{
2021-03-26 01:21:29 +01:00
if ( ( ! passphrase ) | | ( ! passphrase [ 0U ] ) )
{
FPUTS ( T ( " Error: The passphrase input string must not be empty! \n \n " ) , stderr ) ;
return NULL ;
}
2021-03-21 22:10:34 +01:00
char * const buffer = CHR_to_utf8 ( passphrase ) ;
if ( ! buffer )
{
FPUTS ( T ( " Error: Failed to allocate the string buffer! \n \n " ) , stderr ) ;
}
2021-03-26 01:21:29 +01:00
2021-03-21 22:10:34 +01:00
return buffer ;
2020-10-20 15:21:00 +02:00
}
2021-03-26 01:21:29 +01:00
static char * read_passphrase ( const CHR * const file_name )
2020-10-14 16:36:17 +02:00
{
2021-03-26 01:21:29 +01:00
if ( ( ! file_name ) | | ( ! file_name [ 0U ] ) )
2021-03-21 22:10:34 +01:00
{
FPUTS ( T ( " Error: The passphrase input file name must not be empty! \n \n " ) , stderr ) ;
return NULL ;
}
2020-10-20 17:46:18 +02:00
const size_t max_len = SLUNKCRYPT_PWDLEN_MAX + 2U ;
2021-03-21 22:10:34 +01:00
char * const buffer = ( char * ) malloc ( max_len * sizeof ( char ) ) ;
2020-10-14 16:36:17 +02:00
if ( ! buffer )
{
2021-03-21 22:10:34 +01:00
FPUTS ( T ( " Error: Failed to allocate the passphrase buffer! \n \n " ) , stderr ) ;
2020-10-14 16:36:17 +02:00
return NULL ;
}
2020-10-16 19:33:12 +02:00
2021-03-21 22:10:34 +01:00
const int use_stdin = ( ! file_name ) | | ( ! STRICMP ( file_name , T ( " - " ) ) ) ;
FILE * const file_in = use_stdin ? stdin : FOPEN ( file_name , T ( " rb " ) ) ;
if ( ! file_in )
2020-10-14 16:36:17 +02:00
{
2021-03-26 01:21:29 +01:00
FPRINTF ( stderr , T ( " Error: Failed to open input file \" % " ) T ( PRISTR ) T ( " \" for reading! \n \n " ) , file_name ) ;
2020-10-16 19:33:12 +02:00
free ( buffer ) ;
2020-10-14 16:36:17 +02:00
return NULL ;
}
2020-10-16 19:33:12 +02:00
2020-10-14 16:36:17 +02:00
do
{
2021-03-21 22:10:34 +01:00
if ( ! fgets ( buffer , ( int ) max_len , file_in ) )
2020-10-14 16:36:17 +02:00
{
2021-03-21 22:10:34 +01:00
buffer [ 0U ] = ' \0 ' ;
2020-10-16 19:33:12 +02:00
goto finish ;
2020-10-14 16:36:17 +02:00
}
size_t length = strlen ( buffer ) ;
while ( ( length > 0U ) & & ( ( buffer [ length - 1U ] = = ' \r ' ) | | ( buffer [ length - 1U ] = = ' \n ' ) ) )
{
buffer [ - - length ] = ' \0 ' ;
}
}
while ( ! buffer [ 0U ] ) ;
2020-10-16 19:33:12 +02:00
finish :
2021-03-21 22:10:34 +01:00
if ( ( ! use_stdin ) & & file_in )
2020-10-16 19:33:12 +02:00
{
2021-03-21 22:10:34 +01:00
fclose ( file_in ) ;
2020-10-16 19:33:12 +02:00
}
2020-10-14 16:36:17 +02:00
return buffer ;
}
static int weak_passphrase ( const char * str )
2020-10-12 23:10:47 +02:00
{
2020-10-14 16:36:17 +02:00
int flags [ 4U ] = { 0 , 0 , 0 , 0 } ;
while ( * str )
2020-10-12 23:10:47 +02:00
{
2021-03-24 20:23:14 +01:00
const int c = * str + + ;
2020-10-14 16:36:17 +02:00
if ( isalpha ( c ) )
{
flags [ isupper ( c ) ? 0U : 1U ] = 1 ;
}
else
{
flags [ isdigit ( c ) ? 2U : 3U ] = 1 ;
}
2020-10-12 23:10:47 +02:00
}
2020-10-14 16:36:17 +02:00
const int strong = flags [ 0U ] & & flags [ 1U ] & & flags [ 2U ] & & flags [ 3U ] ;
return ! strong ;
2020-10-12 23:10:47 +02:00
}
2020-12-01 17:28:32 +01:00
static int generate_passphrase ( const size_t length )
{
int result = EXIT_FAILURE ;
const size_t passwd_len = BOUND ( SLUNKCRYPT_PWDLEN_MIN , length , SLUNKCRYPT_PWDLEN_MAX ) ;
char * const buffer = ( char * ) malloc ( ( passwd_len + 1U ) * sizeof ( char ) ) ;
if ( ! buffer )
{
2021-03-21 22:10:34 +01:00
FPUTS ( T ( " Error: Failed to allocate memory buffer! \n \n " ) , stderr ) ;
2020-12-01 17:28:32 +01:00
return EXIT_FAILURE ;
}
do
{
for ( size_t i = 0U ; i < passwd_len ; + + i )
{
uint64_t value ;
if ( slunkcrypt_generate_nonce ( & value ) ! = SLUNKCRYPT_SUCCESS )
{
2021-03-21 22:10:34 +01:00
FPUTS ( T ( " Error: Failed to generate next random number! \n \n " ) , stderr ) ;
2020-12-01 17:28:32 +01:00
goto clean_up ;
}
buffer [ i ] = PASSWD_SYMBOLS [ value % ARRAY_SIZE ( PASSWD_SYMBOLS ) ] ;
}
buffer [ passwd_len ] = ' \0 ' ;
}
2021-03-24 20:23:14 +01:00
while ( ( ! isalpha ( ( int ) buffer [ 0U ] ) ) | | ( ! isalnum ( ( int ) buffer [ passwd_len - 1U ] ) ) | | weak_passphrase ( buffer ) ) ;
2020-12-01 17:28:32 +01:00
FPRINTF ( stdout , T ( " % " ) T ( PRIstr ) T ( " \n \n " ) , buffer ) ;
fflush ( stdout ) ;
result = EXIT_SUCCESS ;
clean_up :
if ( buffer )
{
slunkcrypt_bzero ( buffer , passwd_len * sizeof ( char ) ) ;
free ( buffer ) ;
}
return result ;
}
2021-03-26 01:21:29 +01: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-12 23:10:47 +02:00
{
2021-03-26 01:21:29 +01:00
if ( ! ( * file_in = FOPEN ( input_path , T ( " rb " ) ) ) )
2020-10-12 23:10:47 +02:00
{
2021-03-26 01:21:29 +01:00
FPRINTF ( stderr , T ( " Error: Failed to open input file \" % " ) T ( PRISTR ) T ( " \" for reading! \n \n " ) , input_path ) ;
* file_out = NULL ;
2020-10-20 22:13:39 +02:00
return EXIT_FAILURE ;
2020-10-12 23:10:47 +02:00
}
2021-03-26 01:21:29 +01:00
if ( ! ( * file_out = FOPEN ( output_path , T ( " wb " ) ) ) )
2020-10-12 23:10:47 +02:00
{
2021-03-26 01:21:29 +01:00
FPRINTF ( stderr , T ( " Error: Failed to open output file \" % " ) T ( PRISTR ) T ( " \" for writing! \n \n " ) , output_path ) ;
2020-10-20 22:13:39 +02:00
return EXIT_FAILURE ;
2020-10-12 23:10:47 +02:00
}
2020-10-20 22:13:39 +02:00
return EXIT_SUCCESS ;
2020-10-13 00:43:57 +02:00
}
2021-04-03 17:04:03 +02:00
static int remove_incomplete_files ( void )
{
const CHR * const keep_files = GETENV ( ENV_KEEPFILE ) ;
if ( keep_files )
{
return ( ! STRTOUL ( keep_files ) ) ;
}
return 1 ;
}
2020-10-20 15:21:00 +02:00
static void sigint_handler ( const int sig )
{
if ( sig = = SIGINT )
{
g_slunkcrypt_abort_flag = 1 ;
}
}
// ==========================================================================
// 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
{
2020-10-19 21:56:12 +02:00
slunkcrypt_t ctx = SLUNKCRYPT_NULL ;
2020-12-01 02:24:35 +01:00
FILE * file_in = NULL , * file_out = NULL ;
int result = EXIT_FAILURE , status ;
2020-10-13 00:43:57 +02:00
2020-10-20 22:13:39 +02:00
if ( open_files ( & file_in , & file_out , input_path , output_path ) ! = EXIT_SUCCESS )
2020-10-13 00:43:57 +02:00
{
2020-12-01 17:28:32 +01:00
goto clean_up ;
2020-10-12 23:10:47 +02:00
}
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 ;
}
2020-10-16 17:37:04 +02:00
FPUTS ( T ( " Encrypting file contents, please be patient... " ) , stderr ) ;
2020-10-16 18:05:37 +02:00
fflush ( stderr ) ;
2020-10-16 17:37:04 +02:00
2020-10-27 21:26:30 +01:00
uint64_t nonce ;
if ( slunkcrypt_generate_nonce ( & nonce ) ! = SLUNKCRYPT_SUCCESS )
2020-10-12 23:10:47 +02:00
{
2020-10-28 14:40:13 +01:00
FPUTS ( T ( " \n \n SlunkCrypt error: Failed to generate nonce! \n \n " ) , stderr ) ;
2020-10-13 00:43:57 +02:00
goto clean_up ;
2020-10-12 23:10:47 +02:00
}
2021-04-01 01:58:39 +02:00
ctx = slunkcrypt_alloc ( nonce , ( const uint8_t * ) passphrase , strlen ( passphrase ) , SLUNKCRYPT_ENCRYPT ) ;
2020-10-27 21:26:30 +01:00
if ( ! ctx )
2020-10-12 23:10:47 +02:00
{
2020-10-27 21:26:30 +01:00
FPUTS ( g_slunkcrypt_abort_flag ? T ( " \n \n Process interrupted! \n \n " ) : T ( " \n \n SlunkCrypt error: Failed to initialize encryption! \n \n " ) , stderr ) ;
2020-10-13 00:43:57 +02:00
goto clean_up ;
2020-10-12 23:10:47 +02:00
}
2021-03-20 17:36:24 +01:00
if ( fwrite_ui64 ( nonce ^ MAGIC_NUMBER , file_out ) < 1U )
2020-10-12 23:10:47 +02:00
{
2020-10-28 14:40:13 +01:00
FPUTS ( T ( " \n \n I/O error: Failed to write nonce value! \n \n " ) , stderr ) ;
2020-10-13 00:43:57 +02:00
goto clean_up ;
2020-10-12 23:10:47 +02:00
}
2021-03-28 16:17:06 +02:00
unsigned refresh_cycles = 0U ;
clock_t clk_update = clock ( ) ;
2021-03-16 22:03:14 +01:00
uint64_t bytes_read = 0U ;
2020-10-20 15:21:00 +02:00
uint8_t buffer [ BUFFER_SIZE ] ;
2020-10-12 23:10:47 +02:00
2021-03-16 22:03:14 +01:00
blake2s_t blake2s_state ;
blake2s_init ( & blake2s_state ) ;
2020-10-16 17:37:04 +02:00
FPRINTF ( stderr , T ( " %5.1f%% " ) , 0.0 ) ;
2020-10-16 18:05:37 +02:00
fflush ( stderr ) ;
2020-10-16 17:37:04 +02:00
2020-10-14 21:55:39 +02:00
while ( bytes_read < file_size )
2020-10-12 23:10:47 +02:00
{
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 ) ;
2020-10-12 23:10:47 +02:00
if ( count > 0U )
{
2021-03-16 22:03:14 +01:00
blake2s_update ( & blake2s_state , buffer , count ) ;
2020-10-13 15:04:59 +02:00
bytes_read + = count ;
2021-04-02 16:37:19 +02:00
if ( ( status = slunkcrypt_inplace ( ctx , buffer , count ) ) ! = SLUNKCRYPT_SUCCESS )
2020-10-12 23:10:47 +02:00
{
2020-10-19 21:56:12 +02:00
FPUTS ( ( status = = SLUNKCRYPT_ABORTED ) ? T ( " \n \n Process interrupted! \n \n " ) : T ( " \n \n SlunkCrypt error: Failed to encrypt data! \n \n " ) , stderr ) ;
2020-12-01 02:24:35 +01:00
goto clean_up ;
2020-10-12 23:10:47 +02:00
}
2020-10-14 21:55:39 +02:00
if ( fwrite ( buffer , sizeof ( uint8_t ) , count , file_out ) < count )
2020-10-12 23:10:47 +02:00
{
2020-10-13 15:04:59 +02:00
FPUTS ( T ( " \n \n I/O error: Failed to write encrypted data! \n \n " ) , stderr ) ;
2020-10-13 00:43:57 +02:00
goto clean_up ;
2020-10-12 23:10:47 +02:00
}
}
2020-10-14 21:55:39 +02:00
if ( count < request_len )
{
break ; /*EOF*/
}
2021-03-28 16:17:06 +02:00
if ( ! ( + + refresh_cycles & 0x1F ) )
2020-10-13 15:04:59 +02:00
{
2021-03-28 16:17:06 +02:00
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 ;
}
2020-10-13 15:04:59 +02:00
}
2020-10-12 23:10:47 +02:00
}
2020-10-14 21:55:39 +02:00
if ( ferror ( file_in ) )
{
FPUTS ( T ( " \n \n I/O error: Failed to read input data! \n \n " ) , stderr ) ;
goto clean_up ;
}
2020-10-13 15:04:59 +02:00
2020-12-01 02:24:35 +01:00
if ( bytes_read ! = file_size )
2020-10-13 15:04:59 +02:00
{
FPUTS ( T ( " \n \n I/O error: Input file could not be fully read! \n \n " ) , stderr ) ;
goto clean_up ;
}
2020-10-12 23:10:47 +02:00
2020-12-01 02:24:35 +01:00
const size_t padding = sizeof ( uint64_t ) - ( file_size % sizeof ( uint64_t ) ) ;
2020-12-12 17:20:18 +01:00
assert ( padding & & ( padding < = sizeof ( uint64_t ) ) ) ;
2020-12-01 02:24:35 +01:00
if ( slunkcrypt_random_bytes ( buffer , padding ) < padding )
{
FPUTS ( T ( " \n \n SlunkCrypt error: Failed to generate random data! \n \n " ) , stderr ) ;
goto clean_up ;
}
2020-12-12 03:22:29 +01:00
SET_LOWBITS ( buffer [ padding - 1U ] , padding - 1U ) ;
2021-04-02 16:37:19 +02:00
if ( ( status = slunkcrypt_inplace ( ctx , buffer , padding ) ) ! = SLUNKCRYPT_SUCCESS )
2020-12-01 02:24:35 +01:00
{
FPUTS ( ( status = = SLUNKCRYPT_ABORTED ) ? T ( " \n \n Process interrupted! \n \n " ) : T ( " \n \n SlunkCrypt error: Failed to encrypt data! \n \n " ) , stderr ) ;
goto clean_up ;
}
if ( fwrite ( buffer , sizeof ( uint8_t ) , padding , file_out ) < padding )
{
FPUTS ( T ( " \n \n I/O error: Failed to write padding data! \n \n " ) , stderr ) ;
goto clean_up ;
}
2021-03-20 17:36:24 +01:00
uint8_t checksum_buffer [ sizeof ( uint64_t ) ] ;
store_ui64 ( checksum_buffer , blake2s_final ( & blake2s_state ) ) ;
2020-10-20 22:13:39 +02:00
2021-04-02 16:37:19 +02:00
if ( ( status = slunkcrypt_inplace ( ctx , checksum_buffer , sizeof ( uint64_t ) ) ) ! = SLUNKCRYPT_SUCCESS )
2020-10-20 22:13:39 +02:00
{
FPUTS ( ( status = = SLUNKCRYPT_ABORTED ) ? T ( " \n \n Process interrupted! \n \n " ) : T ( " \n \n SlunkCrypt error: Failed to encrypt checksum! \n \n " ) , stderr ) ;
goto clean_up ;
}
2020-10-16 18:07:45 +02:00
2021-03-20 17:36:24 +01:00
if ( fwrite ( checksum_buffer , sizeof ( uint8_t ) , sizeof ( uint64_t ) , file_out ) < sizeof ( uint64_t ) )
2020-10-12 23:10:47 +02:00
{
2021-03-16 22:03:14 +01:00
FPUTS ( T ( " \n \n I/O error: Failed to write the checksum! \n \n " ) , stderr ) ;
2020-10-13 00:43:57 +02:00
goto clean_up ;
}
2020-10-20 22:13:39 +02:00
FPRINTF ( stderr , T ( " \b \b \b \b \b \b \b %5.1f%% \n \n " ) , 100.0 ) ;
fflush ( stderr ) ;
result = EXIT_SUCCESS ;
2020-10-13 00:43:57 +02:00
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 )
{
2020-10-19 21:56:12 +02:00
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 ) ;
2021-04-03 17:04:03 +02:00
if ( ( result ! = EXIT_SUCCESS ) & & remove_incomplete_files ( ) )
{
if ( REMOVE ( output_path ) )
{
FPUTS ( T ( " Warning: Failed to remove incomplete output file! \n \n " ) , stderr ) ;
}
}
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-12 23:10:47 +02:00
}
2021-03-21 16:46:22 +01:00
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 ) ) ;
2020-10-13 00:43:57 +02:00
return result ;
2020-10-12 23:10:47 +02:00
}
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 )
2020-10-12 23:10:47 +02:00
{
2020-10-19 21:56:12 +02:00
slunkcrypt_t ctx = SLUNKCRYPT_NULL ;
2020-10-14 21:55:39 +02:00
FILE * file_in = NULL , * file_out = NULL ;
2020-12-01 02:24:35 +01:00
int result = EXIT_FAILURE , status ;
2020-10-13 00:43:57 +02:00
2020-10-20 22:13:39 +02:00
if ( open_files ( & file_in , & file_out , input_path , output_path ) ! = EXIT_SUCCESS )
2020-10-12 23:10:47 +02:00
{
2020-10-13 00:43:57 +02:00
goto clean_up ;
2020-10-12 23:10:47 +02:00
}
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-12 23:10:47 +02:00
{
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-12 23:10:47 +02:00
}
2020-12-01 02:24:35 +01:00
else if ( file_size < ( 3U * sizeof ( uint64_t ) ) )
2020-10-12 23:10:47 +02:00
{
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 ;
2020-10-12 23:10:47 +02:00
}
2020-12-01 03:03:49 +01:00
else if ( ( file_size % sizeof ( uint64_t ) ) ! = 0 )
{
2021-04-08 01:58:54 +02:00
FPRINTF ( stderr , T ( " Warning: File size is *not* an integer multiple of %u, ignoring excess bytes! \n \n " ) , ( unsigned ) sizeof ( uint64_t ) ) ;
2020-12-01 03:03:49 +01:00
}
2020-10-12 23:10:47 +02:00
2020-10-16 17:37:04 +02:00
FPUTS ( T ( " Decrypting file contents, please be patient... " ) , stderr ) ;
2020-10-16 18:05:37 +02:00
fflush ( stderr ) ;
2020-10-16 17:37:04 +02:00
2020-10-27 21:26:30 +01:00
uint64_t nonce ;
2021-03-20 17:36:24 +01:00
if ( fread_ui64 ( & nonce , file_in ) < 1U )
2020-10-12 23:10:47 +02:00
{
2020-10-28 14:40:13 +01:00
FPUTS ( T ( " \n \n I/O error: Failed to read nonce value! \n \n " ) , stderr ) ;
2020-10-13 00:43:57 +02:00
goto clean_up ;
2020-10-12 23:10:47 +02:00
}
2021-04-01 01:58:39 +02:00
ctx = slunkcrypt_alloc ( nonce ^ MAGIC_NUMBER , ( const uint8_t * ) passphrase , strlen ( passphrase ) , SLUNKCRYPT_DECRYPT ) ;
2020-10-12 23:10:47 +02:00
if ( ! ctx )
{
2020-10-19 21:56:12 +02:00
FPUTS ( g_slunkcrypt_abort_flag ? T ( " \n \n Process interrupted! \n \n " ) : T ( " \n \n SlunkCrypt error: Failed to initialize decryption! \n \n " ) , stderr ) ;
2020-10-13 00:43:57 +02:00
goto clean_up ;
2020-10-12 23:10:47 +02:00
}
2021-03-28 16:17:06 +02:00
unsigned refresh_cycles = 0U ;
clock_t clk_update = clock ( ) ;
2021-03-16 22:03:14 +01:00
uint64_t bytes_read = sizeof ( uint64_t ) ;
2020-10-20 15:21:00 +02:00
uint8_t buffer [ BUFFER_SIZE ] ;
2021-03-28 16:17:06 +02:00
2020-12-01 03:03:49 +01:00
const uint64_t read_limit = round_down ( file_size , sizeof ( uint64_t ) ) - ( 2U * sizeof ( uint64_t ) ) ;
2020-10-12 23:10:47 +02:00
2021-03-16 22:03:14 +01:00
blake2s_t blake2s_state ;
blake2s_init ( & blake2s_state ) ;
2020-10-16 17:37:04 +02:00
FPRINTF ( stderr , T ( " %5.1f%% " ) , 0.0 ) ;
2020-10-16 18:05:37 +02:00
fflush ( stderr ) ;
2020-10-16 17:37:04 +02:00
2020-10-14 21:55:39 +02:00
while ( bytes_read < read_limit )
2020-10-12 23:10:47 +02:00
{
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 ) ;
2020-10-12 23:10:47 +02:00
if ( count > 0U )
{
bytes_read + = count ;
2021-04-02 16:37:19 +02:00
if ( ( status = slunkcrypt_inplace ( ctx , buffer , count ) ) ! = SLUNKCRYPT_SUCCESS )
2020-10-12 23:10:47 +02:00
{
2020-10-19 21:56:12 +02:00
FPUTS ( ( status = = SLUNKCRYPT_ABORTED ) ? T ( " \n \n Process interrupted! \n \n " ) : T ( " \n \n SlunkCrypt error: Failed to decrypt data! \n \n " ) , stderr ) ;
2020-10-13 00:43:57 +02:00
goto clean_up ;
2020-10-12 23:10:47 +02:00
}
2021-03-16 22:03:14 +01:00
blake2s_update ( & blake2s_state , buffer , count ) ;
2020-10-14 21:55:39 +02:00
if ( fwrite ( buffer , sizeof ( uint8_t ) , count , file_out ) < count )
2020-10-12 23:10:47 +02:00
{
2020-10-13 15:04:59 +02:00
FPUTS ( T ( " failed! \n \n I/O error: Failed to write decrypted data! \n \n " ) , stderr ) ;
2020-10-13 00:43:57 +02:00
goto clean_up ;
2020-10-12 23:10:47 +02:00
}
}
2020-10-14 21:55:39 +02:00
if ( count < request_len )
{
break ; /*EOF*/
}
2021-03-28 16:17:06 +02:00
if ( ! ( + + refresh_cycles & 0x1F ) )
2020-10-13 15:04:59 +02:00
{
2021-03-28 16:17:06 +02:00
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 ;
}
2020-10-13 15:04:59 +02:00
}
2020-10-12 23:10:47 +02:00
}
2020-10-14 21:55:39 +02:00
if ( ferror ( file_in ) )
{
FPUTS ( T ( " \n \n I/O error: Failed to read input data! \n \n " ) , stderr ) ;
goto clean_up ;
}
2020-10-12 23:10:47 +02:00
2020-12-01 02:24:35 +01:00
if ( bytes_read ! = read_limit )
2020-10-12 23:10:47 +02:00
{
2020-10-13 15:04:59 +02:00
FPUTS ( T ( " \n \n I/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-12 23:10:47 +02:00
}
2020-12-01 02:24:35 +01:00
if ( fread ( buffer , sizeof ( uint8_t ) , sizeof ( uint64_t ) , file_in ) < sizeof ( uint64_t ) )
{
FPUTS ( T ( " \n \n I/O error: Failed to read final block! \n \n " ) , stderr ) ;
goto clean_up ;
}
2021-04-02 16:37:19 +02:00
if ( ( status = slunkcrypt_inplace ( ctx , buffer , sizeof ( uint64_t ) ) ) ! = SLUNKCRYPT_SUCCESS )
2020-12-01 02:24:35 +01:00
{
FPUTS ( ( status = = SLUNKCRYPT_ABORTED ) ? T ( " \n \n Process interrupted! \n \n " ) : T ( " \n \n SlunkCrypt error: Failed to decrypt data! \n \n " ) , stderr ) ;
goto clean_up ;
}
2020-12-12 03:22:29 +01:00
const size_t padding = GET_LOWBITS ( buffer [ sizeof ( uint64_t ) - 1U ] ) + 1U ;
2020-12-12 17:20:18 +01:00
assert ( padding & & ( padding < = sizeof ( uint64_t ) ) ) ;
2020-12-01 02:24:35 +01:00
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 \n I/O error: Failed to write decrypted data! \n \n " ) , stderr ) ;
goto clean_up ;
}
2021-03-16 22:03:14 +01:00
blake2s_update ( & blake2s_state , buffer , count ) ;
2020-12-01 02:24:35 +01:00
}
2021-03-16 22:03:14 +01:00
const uint64_t checksum_actual = blake2s_final ( & blake2s_state ) ;
2020-10-13 15:04:59 +02:00
2021-03-20 17:36:24 +01:00
uint8_t checksum_buffer [ sizeof ( uint64_t ) ] ;
if ( fread ( checksum_buffer , sizeof ( uint8_t ) , sizeof ( uint64_t ) , file_in ) < sizeof ( uint64_t ) )
2020-10-12 23:10:47 +02:00
{
2021-03-16 22:03:14 +01:00
FPUTS ( T ( " \n \n I/O error: Failed to read the checksum! \n \n " ) , stderr ) ;
2020-10-13 00:43:57 +02:00
goto clean_up ;
2020-10-12 23:10:47 +02:00
}
2021-04-02 16:37:19 +02:00
if ( ( status = slunkcrypt_inplace ( ctx , checksum_buffer , sizeof ( uint64_t ) ) ) ! = SLUNKCRYPT_SUCCESS )
2020-10-20 22:13:39 +02:00
{
FPUTS ( ( status = = SLUNKCRYPT_ABORTED ) ? T ( " \n \n Process interrupted! \n \n " ) : T ( " \n \n SlunkCrypt error: Failed to decrypt checksum! \n \n " ) , stderr ) ;
2020-12-01 02:24:35 +01:00
goto clean_up ;
2020-10-20 22:13:39 +02:00
}
FPRINTF ( stderr , T ( " \b \b \b \b \b \b \b %5.1f%% \n \n " ) , 100.0 ) ;
fflush ( stderr ) ;
2021-03-21 16:46:22 +01:00
const uint64_t checksum_stored = load_ui64 ( checksum_buffer ) ;
if ( checksum_actual ! = checksum_stored )
2020-10-12 23:10:47 +02:00
{
2021-03-21 16:46:22 +01:00
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 ) ;
2020-10-13 15:37:40 +02:00
FPUTS ( T ( " Wrong passphrase or corrupted file? \n \n " ) , stderr ) ;
2020-10-13 00:43:57 +02:00
goto clean_up ;
}
2020-10-20 22:13:39 +02:00
result = EXIT_SUCCESS ;
2020-10-13 00:43:57 +02:00
2021-03-16 22:03:14 +01:00
FPUTS ( T ( " Checksum is correct. \n \n " ) , stderr ) ;
2020-10-13 00:43:57 +02:00
fflush ( stderr ) ;
clean_up :
if ( ctx )
{
2020-10-19 21:56:12 +02:00
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 ) ;
2021-04-03 17:04:03 +02:00
if ( ( result ! = EXIT_SUCCESS ) & & remove_incomplete_files ( ) )
{
if ( REMOVE ( output_path ) )
{
FPUTS ( T ( " Warning: Failed to remove incomplete output file! \n \n " ) , stderr ) ;
}
}
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-12 23:10:47 +02:00
}
2021-03-21 16:46:22 +01:00
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 ) ) ;
2020-10-13 00:43:57 +02:00
return result ;
2020-10-12 23:10:47 +02:00
}
2020-10-20 15:21:00 +02:00
// ==========================================================================
// Self-test
// ==========================================================================
2021-04-10 16:37:09 +02:00
static int run_test_case ( const char * const message , const uint64_t nonce , const uint64_t checksum_message , const uint64_t checksum_expected )
2020-10-14 13:14:47 +02:00
{
2021-04-10 16:37:09 +02:00
static const char * const TEST_PASSPHRASE = " OrpheanBeh0lderScry!Doubt " ;
2020-10-15 21:56:36 +02:00
2020-10-20 22:13:39 +02:00
int status , result = EXIT_FAILURE ;
2020-10-15 21:56:36 +02:00
const size_t length = strlen ( message ) + 1U ;
2020-10-19 21:56:12 +02:00
slunkcrypt_t ctx = SLUNKCRYPT_NULL ;
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 \n Whoops: Failed to allocate text buffer! \n \n " ) , stderr ) ;
2020-10-14 13:14:47 +02:00
goto clean_up ;
}
2021-03-16 22:03:14 +01:00
const uint64_t checksum_original = blake2s_compute ( ( uint8_t * ) text_temp , length ) ;
if ( checksum_original ! = checksum_message )
2020-10-24 15:06:12 +02:00
{
2021-03-16 22:03:14 +01:00
FPRINTF ( stderr , T ( " \n \n Whoops: Checksum mismatch detected! [expected: 0x%016 " ) T ( PRIX64 ) T ( " , actual: 0x%016 " ) T ( PRIX64 ) T ( " ] \n \n " ) , checksum_message , checksum_original ) ;
2020-10-24 15:06:12 +02:00
goto clean_up ;
}
2021-04-10 16:37:09 +02:00
ctx = slunkcrypt_alloc ( nonce , ( const uint8_t * ) TEST_PASSPHRASE , strlen ( TEST_PASSPHRASE ) , SLUNKCRYPT_ENCRYPT ) ;
2020-10-14 17:57:40 +02:00
if ( ! ctx )
2020-10-14 13:14:47 +02:00
{
2020-10-19 21:56:12 +02:00
FPUTS ( g_slunkcrypt_abort_flag ? T ( " \n \n Process interrupted! \n \n " ) : T ( " \n \n Whoops: Failed to initialize encoder! \n \n " ) , stderr ) ;
2020-10-14 13:14:47 +02:00
goto clean_up ;
}
2021-04-02 16:37:19 +02:00
status = slunkcrypt_inplace ( ctx , ( uint8_t * ) text_temp , length ) ;
2020-10-19 21:56:12 +02:00
if ( status ! = SLUNKCRYPT_SUCCESS )
2020-10-14 13:14:47 +02:00
{
2020-10-19 21:56:12 +02:00
FPUTS ( ( status = = SLUNKCRYPT_ABORTED ) ? T ( " \n \n Process interrupted! \n \n " ) : T ( " \n \n Whoops: 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 \n Whoops: Encrypted message equals the original message! \n \n " ) , stderr ) ;
2020-10-14 13:14:47 +02:00
goto clean_up ;
}
2021-04-10 16:37:09 +02:00
const uint64_t checksum_encrypted = blake2s_compute ( ( uint8_t * ) text_temp , length ) ;
if ( checksum_encrypted ! = checksum_expected )
{
FPRINTF ( stderr , T ( " \n \n Whoops: 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 ) ;
2020-10-19 21:56:12 +02:00
if ( status ! = SLUNKCRYPT_SUCCESS )
2020-10-14 13:14:47 +02:00
{
2020-10-19 21:56:12 +02:00
FPUTS ( ( status = = SLUNKCRYPT_ABORTED ) ? T ( " \n \n Process interrupted! \n \n " ) : T ( " \n \n Whoops: Failed to initialize decoder! \n \n " ) , stderr ) ;
2020-10-14 13:14:47 +02:00
goto clean_up ;
}
2021-04-02 16:37:19 +02:00
status = slunkcrypt_inplace ( ctx , ( uint8_t * ) text_temp , length ) ;
2020-10-19 21:56:12 +02:00
if ( status ! = SLUNKCRYPT_SUCCESS )
2020-10-14 13:14:47 +02:00
{
2020-10-19 21:56:12 +02:00
FPUTS ( ( status = = SLUNKCRYPT_ABORTED ) ? T ( " \n \n Process interrupted! \n \n " ) : T ( " \n \n Whoops: Failed to decrypt the message! \n \n " ) , stderr ) ;
2020-10-14 13:14:47 +02:00
goto clean_up ;
}
2020-10-21 19:29:37 +02:00
if ( memcmp ( message , text_temp , length * sizeof ( char ) ) ! = 0 )
2020-10-14 13:14:47 +02:00
{
2020-10-15 23:11:07 +02:00
FPUTS ( T ( " \n \n Whoops: Decrypted message does *not* match the original message! \n \n " ) , stderr ) ;
2020-10-14 13:14:47 +02:00
goto clean_up ;
}
2021-03-16 22:03:14 +01:00
const uint64_t checksum_decrypted = blake2s_compute ( ( uint8_t * ) text_temp , length ) ;
if ( checksum_decrypted ! = checksum_original )
2020-10-24 15:06:12 +02:00
{
2021-03-16 22:03:14 +01:00
FPRINTF ( stderr , T ( " \n \n Whoops: Checksum mismatch detected! [expected: 0x%016 " ) T ( PRIX64 ) T ( " , actual: 0x%016 " ) T ( PRIX64 ) T ( " ] \n \n " ) , checksum_original , checksum_decrypted ) ;
2020-10-24 15:06:12 +02:00
goto clean_up ;
}
2020-10-20 22:13:39 +02:00
result = EXIT_SUCCESS ;
2020-10-14 13:14:47 +02:00
clean_up :
2020-10-14 17:57:40 +02:00
if ( ctx )
2020-10-14 13:14:47 +02:00
{
2020-10-19 21:56:12 +02:00
slunkcrypt_free ( ctx ) ;
2020-10-14 13:14:47 +02:00
}
if ( text_temp )
{
2020-10-19 21:56:12 +02:00
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
{
2021-04-10 16:37:09 +02:00
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 ] } } ,
} ;
2021-04-08 01:58:54 +02:00
2021-04-10 16:37:09 +02:00
const size_t total = ARRAY_SIZE ( TEST_NONCE ) * ARRAY_SIZE ( TEST_STAGE ) ;
2021-04-08 01:58:54 +02:00
FPRINTF ( stderr , T ( " Self-test is in progress, please be patient... stage %u/%u " ) , 0U , ( unsigned ) total ) ;
2020-10-16 18:05:37 +02:00
fflush ( stderr ) ;
2020-10-15 21:56:36 +02:00
2021-04-10 16:37:09 +02:00
for ( size_t i = 0U , count = 0U ; i < ARRAY_SIZE ( TEST_STAGE ) ; + + i )
2020-10-15 21:56:36 +02:00
{
2021-04-10 16:37:09 +02:00
for ( size_t j = 0U ; j < ARRAY_SIZE ( TEST_NONCE ) ; + + j )
2020-10-15 21:56:36 +02:00
{
2021-04-10 16:37:09 +02:00
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 ;
}
2020-10-15 21:56:36 +02:00
}
}
2021-04-08 01:58:54 +02:00
FPRINTF ( stderr , T ( " \b \b \b \b %u/%u \n \n Completed successfully. \n \n " ) , ( unsigned ) total , ( unsigned ) total ) ;
2020-10-16 18:07:45 +02:00
fflush ( stderr ) ;
2020-10-20 22:13:39 +02:00
return EXIT_SUCCESS ;
2020-10-15 21:56:36 +02:00
}
2020-10-20 15:21:00 +02:00
// ==========================================================================
// Main function
// ==========================================================================
2020-10-14 16:36:17 +02:00
2020-10-20 15:21:00 +02:00
int MAIN ( const int argc , CHR * const argv [ ] )
2020-10-12 23:10:47 +02:00
{
2020-10-13 19:33:01 +02:00
init_terminal ( ) ;
2020-10-20 19:13:11 +02:00
setup_signal_handler ( SIGINT , sigint_handler ) ;
2020-10-20 22:13:39 +02:00
int result = EXIT_FAILURE ;
2020-10-22 18:01:59 +02:00
char * passphrase_buffer = NULL ;
2020-10-12 23:10:47 +02:00
2020-10-19 21:56:12 +02:00
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 */
/* ----------------------------------------------------- */
2020-10-20 22:13:39 +02:00
if ( argc < 2 )
2020-10-14 13:14:47 +02:00
{
2020-10-20 15:21:00 +02:00
FPRINTF ( stderr , T ( " Error: Nothing to do. Please type '% " ) T ( PRISTR ) T ( " --help' for details! \n \n " ) , get_file_name ( argv [ 0U ] ) ) ;
2020-10-22 18:01:59 +02:00
goto clean_up ;
2020-10-20 22:13:39 +02:00
}
2021-03-26 01:21:29 +01:00
const int slunk_mode = parse_slunk_mode ( argv [ 1U ] ) ;
switch ( slunk_mode )
2020-10-20 22:13:39 +02:00
{
2021-03-26 01:21:29 +01:00
case MODE_HELP :
2020-10-20 15:21:00 +02:00
print_manpage ( get_file_name ( argv [ 0U ] ) ) ;
2021-03-26 01:21:29 +01:00
case MODE_VERS :
2020-10-22 18:01:59 +02:00
result = EXIT_SUCCESS ;
goto clean_up ;
2021-03-26 01:21:29 +01:00
case MODE_ENCR :
case MODE_DECR :
break ; /*fallthrough*/
case MODE_PASS :
result = generate_passphrase ( ( argc > 2 ) ? STRTOUL ( argv [ 2U ] ) : DFLT_PWDLEN_LENGTH ) ;
2020-12-01 17:28:32 +01:00
goto clean_up ;
2021-03-26 01:21:29 +01:00
case MODE_TEST :
2020-10-22 18:01:59 +02:00
result = run_self_test ( ) ;
goto clean_up ;
2021-03-26 01:21:29 +01:00
default :
FPRINTF ( stderr , T ( " Error: The specified command \" % " ) T ( PRISTR ) T ( " \" is unknown! \n \n " ) , argv [ 1U ] ) ;
goto clean_up ;
2020-10-14 13:14:47 +02:00
}
2020-10-16 17:37:04 +02:00
if ( argc < 4 )
2020-10-12 23:10:47 +02:00
{
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-22 18:01:59 +02:00
goto clean_up ;
2020-10-13 17:42:22 +02:00
}
2021-04-03 17:04:03 +02:00
const CHR * const passphrase = PW_FROM_ENV ? GETENV ( ENV_PASSWORD ) : argv [ 2U ] ;
2021-03-26 01:21:29 +01:00
const CHR * const input_file = argv [ PW_FROM_ENV ? 2U : 3U ] , * const output_file = argv [ PW_FROM_ENV ? 3U : 4U ] ;
2021-03-21 22:10:34 +01:00
if ( ( ! passphrase ) | | ( ! passphrase [ 0U ] ) )
{
FPUTS ( T ( " Error: The passphrase must be specified, directly or indirectly! \n \n " ) , stderr ) ;
goto clean_up ;
}
2020-10-14 16:36:17 +02:00
2021-03-26 01:21:29 +01:00
if ( ( ! PW_FROM_ENV ) & & STRICMP ( passphrase , T ( " - " ) ) )
2020-10-13 17:42:22 +02:00
{
2021-03-26 01:21:29 +01:00
if ( ( ! STARTS_WITH ( passphrase , PREFIX_PASS ) ) & & ( ! STARTS_WITH ( passphrase , PREFIX_FILE ) ) )
{
FPRINTF ( stderr , T ( " Error: The passphrase must start with a '% " ) T ( PRISTR ) T ( " ' or '% " ) T ( PRISTR ) T ( " ' prefix! \n \n " ) , PREFIX_PASS , PREFIX_FILE ) ;
goto clean_up ;
}
2020-10-12 23:10:47 +02:00
}
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 ) ;
2020-10-22 18:01:59 +02:00
goto clean_up ;
2020-10-13 19:33:01 +02:00
}
2020-10-20 15:21:00 +02:00
/* ----------------------------------------------------- */
/* Initialize passphrase */
/* ----------------------------------------------------- */
2021-03-26 01:21:29 +01:00
if ( ! ( passphrase_buffer = PW_FROM_ENV ? copy_passphrase ( passphrase ) :
( STARTS_WITH ( passphrase , PREFIX_PASS ) ? copy_passphrase ( passphrase + STRLEN ( PREFIX_PASS ) ) :
( STARTS_WITH ( passphrase , PREFIX_FILE ) ? read_passphrase ( passphrase + STRLEN ( PREFIX_FILE ) ) : read_passphrase ( T ( " - " ) ) ) ) ) )
2020-10-13 19:33:01 +02:00
{
2020-10-22 18:01:59 +02:00
goto clean_up ;
2020-10-13 19:33:01 +02:00
}
2020-10-12 23:10:47 +02:00
2020-10-19 21:56:12 +02:00
slunkcrypt_bzero ( ( CHR * ) passphrase , STRLEN ( passphrase ) * sizeof ( CHR ) ) ;
2020-10-16 18:05:37 +02:00
2020-10-20 15:21:00 +02:00
const size_t passphrase_len = strlen ( passphrase_buffer ) ;
if ( passphrase_len < SLUNKCRYPT_PWDLEN_MIN )
{
2021-03-26 01:21:29 +01:00
FPRINTF ( stderr , T ( " Error: Passphrase must be at least %u characters in length! \n \n " ) , ( unsigned ) SLUNKCRYPT_PWDLEN_MIN ) ;
2020-10-22 18:01:59 +02:00
goto clean_up ;
2020-10-20 15:21:00 +02:00
}
else if ( passphrase_len > SLUNKCRYPT_PWDLEN_MAX )
{
2021-03-26 01:21:29 +01:00
FPRINTF ( stderr , T ( " Error: Passphrase must be at most %u characters in length! \n \n " ) , ( unsigned ) SLUNKCRYPT_PWDLEN_MAX ) ;
2020-10-22 18:01:59 +02:00
goto clean_up ;
2020-10-20 15:21:00 +02:00
}
2021-03-26 01:21:29 +01:00
if ( passphrase_len < RCMD_PWDLEN_LENGTH )
2020-10-14 16:36:17 +02:00
{
2021-03-26 01:21:29 +01:00
FPRINTF ( stderr , T ( " Warning: Using a *short* passphrase; a length of %u characters or more is recommended! \n \n " ) , ( unsigned ) RCMD_PWDLEN_LENGTH ) ;
2020-10-14 16:36:17 +02:00
}
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 */
/* ----------------------------------------------------- */
2020-10-12 23:10:47 +02:00
const clock_t clk_start = clock ( ) ;
2021-03-26 01:21:29 +01:00
switch ( slunk_mode )
2020-10-13 17:42:22 +02:00
{
2021-03-26 01:21:29 +01:00
case MODE_ENCR :
2020-10-14 16:36:17 +02:00
result = encrypt ( passphrase_buffer , input_file , output_file ) ;
2020-10-20 15:21:00 +02:00
break ;
2021-03-26 01:21:29 +01:00
case MODE_DECR :
2020-10-14 16:36:17 +02:00
result = decrypt ( passphrase_buffer , input_file , output_file ) ;
2020-10-20 15:21:00 +02:00
break ;
default :
2020-10-20 22:13:39 +02:00
FPUTS ( T ( " Unexpected mode encountered! \n \n " ) , stderr ) ;
2020-10-12 23:10:47 +02:00
}
2020-10-19 21:56:12 +02:00
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-22 18:01:59 +02:00
clean_up :
2020-10-13 19:33:01 +02:00
2020-10-14 16:36:17 +02:00
if ( passphrase_buffer )
2020-10-13 19:50:29 +02:00
{
2020-10-19 21:56:12 +02:00
slunkcrypt_bzero ( passphrase_buffer , strlen ( passphrase_buffer ) ) ;
2020-10-14 16:36:17 +02:00
free ( passphrase_buffer ) ;
2020-10-13 19:50:29 +02:00
}
2020-10-15 22:41:28 +02:00
return result ;
2020-10-12 23:10:47 +02:00
}
2020-10-21 17:07:03 +02:00
# if defined(_WIN32) && defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
void __wgetmainargs ( int * , wchar_t * * * , wchar_t * * * , int , int * ) ;
int main ( )
{
wchar_t * * enpv , * * argv ;
int argc , si = 0 ;
__wgetmainargs ( & argc , & argv , & enpv , 1 , & si ) ;
return wmain ( argc , argv ) ;
}
# endif