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! */
/******************************************************************************/
# define _CRT_SECURE_NO_WARNINGS 1
2020-10-19 21:56:12 +02:00
# include <slunkcrypt.h>
2020-10-13 15:04:59 +02:00
# include "utils.h"
# include "crc.h"
2020-10-15 21:56:36 +02:00
# include "test.h"
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-10-12 23:10:47 +02:00
2020-10-14 21:55:39 +02:00
# define BUFF_SIZE 4096U
2020-10-16 18:05:37 +02:00
2020-10-19 21:56:12 +02:00
static const CHR * const ENVV_PASSWD_NAME = T ( " SLUNK_PASSPHRASE " ) ;
2020-10-14 16:36:17 +02:00
static char * read_passphrase ( const CHR * const file_name )
{
2020-10-16 19:33:12 +02:00
static const size_t buff_size = 512U ;
char * buffer = ( char * ) malloc ( buff_size * sizeof ( char ) ) ;
2020-10-14 16:36:17 +02:00
if ( ! buffer )
{
return NULL ;
}
2020-10-16 19:33:12 +02:00
const int use_stdin = ( STRICMP ( file_name , T ( " - " ) ) = = 0 ) ;
FILE * const file = use_stdin ? stdin : FOPEN ( file_name , T ( " rb " ) ) ;
2020-10-14 21:55:39 +02:00
if ( ! file )
2020-10-14 16:36:17 +02:00
{
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
{
2020-10-14 21:55:39 +02:00
if ( ! fgets ( buffer , ( int ) buff_size , file ) )
2020-10-14 16:36:17 +02:00
{
free ( buffer ) ;
2020-10-16 19:33:12 +02:00
buffer = NULL ;
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 :
if ( ( ! use_stdin ) & & file )
{
fclose ( file ) ;
}
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
{
2020-10-14 16:36:17 +02:00
const CHR c = * str + + ;
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-10-14 21:55:39 +02:00
static int open_files ( FILE * * const file_in , FILE * * const file_out , const CHR * const input_path , const CHR * const output_path )
2020-10-12 23:10:47 +02:00
{
2020-10-14 21:55:39 +02:00
* file_in = FOPEN ( input_path , T ( " rb " ) ) ;
if ( ! ( * file_in ) )
2020-10-12 23:10:47 +02:00
{
2020-10-13 15:04:59 +02:00
FPUTS ( T ( " Error: Failed to open input file for reading! \n \n " ) , stderr ) ;
2020-10-12 23:10:47 +02:00
return 1 ;
}
2020-10-14 21:55:39 +02:00
* file_out = FOPEN ( output_path , T ( " wb " ) ) ;
if ( ! ( * file_out ) )
2020-10-12 23:10:47 +02:00
{
2020-10-13 15:04:59 +02:00
FPUTS ( T ( " Error: Failed to open output file for writing! \n \n " ) , stderr ) ;
2020-10-14 21:55:39 +02:00
fclose ( * file_out ) ;
2020-10-12 23:10:47 +02:00
return 1 ;
}
2020-10-13 00:43:57 +02:00
return 0 ;
}
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-10-14 21:55:39 +02:00
FILE * file_in = NULL , * file_out = NULL ;
2020-10-14 13:14:47 +02:00
int result = 1 ;
2020-10-13 00:43:57 +02:00
2020-10-14 21:55:39 +02:00
if ( open_files ( & file_in , & file_out , input_path , output_path ) ! = 0 )
2020-10-13 00:43:57 +02:00
{
goto clean_up ; ;
2020-10-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-12 23:10:47 +02:00
uint64_t seed ;
2020-10-19 21:56:12 +02:00
if ( slunkcrypt_generate_seed ( & seed ) ! = SLUNKCRYPT_SUCCESS )
2020-10-12 23:10:47 +02:00
{
2020-10-19 21:56:12 +02:00
FPUTS ( T ( " \n \n SlunkCrypt error: Failed to generate seed! \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 ( fwrite ( & seed , sizeof ( uint64_t ) , 1U , file_out ) < 1U )
2020-10-12 23:10:47 +02:00
{
2020-10-16 17:37:04 +02:00
FPUTS ( T ( " \n \n I/O error: Failed to write seed value! \n \n " ) , stderr ) ;
2020-10-13 00:43:57 +02:00
goto clean_up ;
2020-10-12 23:10:47 +02:00
}
2020-10-19 21:56:12 +02:00
ctx = slunkcrypt_alloc ( seed , ( const uint8_t * ) passphrase , strlen ( passphrase ) ) ;
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 encryption! \n \n " ) , stderr ) ;
2020-10-13 00:43:57 +02:00
goto clean_up ;
2020-10-12 23:10:47 +02:00
}
2020-10-13 15:04:59 +02:00
clock_t clk_now , clk_update = clock ( ) ;
2020-10-19 00:32:33 +02:00
uint64_t crc_actual = CRC_INITIALIZER , bytes_read = 0U ;
2020-10-14 21:55:39 +02:00
uint8_t buffer [ BUFF_SIZE ] ;
2020-10-12 23:10:47 +02:00
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 ;
const size_t request_len = ( bytes_remaining < BUFF_SIZE ) ? ( ( size_t ) bytes_remaining ) : BUFF_SIZE ;
const size_t count = fread ( buffer , sizeof ( uint8_t ) , request_len , file_in ) ;
2020-10-12 23:10:47 +02:00
if ( count > 0U )
{
2020-10-13 15:04:59 +02:00
crc_actual = crc64_update ( crc_actual , buffer , count ) ;
bytes_read + = count ;
2020-10-19 21:56:12 +02:00
const int status = slunkcrypt_encrypt_inplace ( ctx , buffer , count ) ;
if ( status ! = 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-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 ( 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*/
}
2020-10-13 15:04:59 +02:00
if ( ( clk_now = clock ( ) ) - clk_update > CLOCKS_PER_SEC )
{
2020-10-16 17:37:04 +02:00
FPRINTF ( stderr , T ( " \b \b \b \b \b \b \b %5.1f%% " ) , ( bytes_read / ( ( double ) file_size ) ) * 100.0 ) ;
2020-10-13 15:04:59 +02:00
fflush ( stderr ) ;
clk_update = clk_now ;
}
2020-10-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
if ( bytes_read < file_size )
{
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-10-14 21:55:39 +02:00
crc_actual = crc64_finish ( crc_actual ) ;
2020-10-13 15:04:59 +02:00
FPRINTF ( stderr , T ( " \b \b \b \b \b \b %5.1f%% \n \n " ) , 100.0 ) ;
2020-10-16 18:07:45 +02:00
fflush ( stderr ) ;
2020-10-14 21:55:39 +02:00
if ( fwrite ( & crc_actual , sizeof ( uint64_t ) , 1U , file_out ) < 1U )
2020-10-12 23:10:47 +02:00
{
2020-10-13 15:04:59 +02:00
FPUTS ( T ( " I/O error: Failed to write CRC checksum! \n \n " ) , stderr ) ;
2020-10-13 00:43:57 +02:00
goto clean_up ;
}
result = 0 ;
2020-10-13 15:04:59 +02:00
FPUTS ( T ( " All is done. \n \n " ) , stderr ) ;
2020-10-13 00:43:57 +02:00
fflush ( stderr ) ;
clean_up :
if ( ctx )
{
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 ) ;
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
}
2020-10-13 00:43:57 +02:00
return result ;
2020-10-12 23:10:47 +02:00
}
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-10-14 13:14:47 +02:00
int result = 1 ;
2020-10-13 00:43:57 +02:00
2020-10-14 21:55:39 +02:00
if ( open_files ( & file_in , & file_out , input_path , output_path ) ! = 0 )
2020-10-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-10-14 21:55:39 +02:00
else if ( file_size < 16U )
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-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-12 23:10:47 +02:00
uint64_t seed ;
2020-10-14 21:55:39 +02:00
if ( fread ( & seed , sizeof ( uint64_t ) , 1U , file_in ) < 1U )
2020-10-12 23:10:47 +02:00
{
2020-10-16 17:37:04 +02:00
FPUTS ( T ( " \n \n I/O error: Failed to read seed value! \n \n " ) , stderr ) ;
2020-10-13 00:43:57 +02:00
goto clean_up ;
2020-10-12 23:10:47 +02:00
}
2020-10-19 21:56:12 +02:00
ctx = slunkcrypt_alloc ( seed , ( const uint8_t * ) passphrase , strlen ( passphrase ) ) ;
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
}
2020-10-13 15:04:59 +02:00
clock_t clk_now , clk_update = clock ( ) ;
uint64_t crc_actual = CRC_INITIALIZER , bytes_read = sizeof ( uint64_t ) ;
2020-10-14 21:55:39 +02:00
uint8_t buffer [ BUFF_SIZE ] ;
2020-10-13 15:04:59 +02:00
const uint64_t read_limit = file_size - sizeof ( uint64_t ) ;
2020-10-12 23:10:47 +02:00
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-14 21:55:39 +02:00
const size_t request_len = ( bytes_remaining < BUFF_SIZE ) ? ( ( size_t ) bytes_remaining ) : BUFF_SIZE ;
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 ;
2020-10-19 21:56:12 +02:00
const int status = slunkcrypt_decrypt_inplace ( ctx , buffer , count ) ;
if ( status ! = 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
}
2020-10-13 15:04:59 +02:00
crc_actual = crc64_update ( crc_actual , buffer , count ) ;
2020-10-14 21:55:39 +02:00
if ( fwrite ( buffer , sizeof ( uint8_t ) , count , file_out ) < count )
2020-10-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*/
}
2020-10-13 15:04:59 +02:00
if ( ( clk_now = clock ( ) ) - clk_update > CLOCKS_PER_SEC )
{
2020-10-16 17:37:04 +02:00
FPRINTF ( stderr , T ( " \b \b \b \b \b \b \b %5.1f%% " ) , ( bytes_read / ( ( double ) read_limit ) ) * 100.0 ) ;
2020-10-13 15:04:59 +02:00
fflush ( stderr ) ;
clk_update = clk_now ;
}
2020-10-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-10-13 00:43:57 +02: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-10-14 21:55:39 +02:00
crc_actual = crc64_finish ( crc_actual ) ;
2020-10-13 15:04:59 +02:00
FPRINTF ( stderr , T ( " \b \b \b \b \b \b %5.1f%% \n \n " ) , 100.0 ) ;
2020-10-16 18:07:45 +02:00
fflush ( stderr ) ;
2020-10-13 15:04:59 +02:00
2020-10-12 23:10:47 +02:00
uint64_t crc_expected ;
2020-10-14 21:55:39 +02:00
if ( fread ( & crc_expected , sizeof ( uint64_t ) , 1U , file_in ) < 1U )
2020-10-12 23:10:47 +02:00
{
2020-10-13 15:04:59 +02:00
FPUTS ( T ( " I/O error: Failed to read CRC checksum! \n \n " ) , stderr ) ;
2020-10-13 00:43:57 +02:00
goto clean_up ;
2020-10-12 23:10:47 +02:00
}
if ( crc_actual ! = crc_expected )
{
2020-10-13 15:37:40 +02:00
FPRINTF ( stderr , T ( " CRC error: Checksum mismatch detected! [expected: 0x%016 " ) T ( PRIX64 ) T ( " , actual: 0x%016 " ) T ( PRIX64 ) T ( " ] \n \n " ) , crc_actual , crc_expected ) ;
FPUTS ( T ( " Wrong passphrase or corrupted file? \n \n " ) , stderr ) ;
2020-10-13 00:43:57 +02:00
goto clean_up ;
}
result = 0 ;
2020-10-13 15:37:40 +02:00
FPUTS ( T ( " CRC checksum is correct. \n \n " ) , stderr ) ;
2020-10-13 00:43:57 +02:00
fflush ( stderr ) ;
clean_up :
if ( ctx )
{
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 ) ;
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
}
2020-10-13 00:43:57 +02:00
return result ;
2020-10-12 23:10:47 +02:00
}
2020-10-15 21:56:36 +02:00
static int run_test ( const char * const message )
2020-10-14 13:14:47 +02:00
{
2020-10-16 17:37:04 +02:00
static const char * const passphrase = " OrpheanBeh0lderScry!Doubt " ;
2020-10-15 21:56:36 +02:00
const size_t length = strlen ( message ) + 1U ;
2020-10-18 20:41:02 +02:00
int status , result = 1 ;
2020-10-19 21:56:12 +02:00
slunkcrypt_t ctx = SLUNKCRYPT_NULL ;
2020-10-14 13:14:47 +02:00
uint64_t seed ;
2020-10-19 21:56:12 +02:00
if ( slunkcrypt_generate_seed ( & seed ) ! = SLUNKCRYPT_SUCCESS )
2020-10-14 13:14:47 +02:00
{
2020-10-15 23:11:07 +02:00
FPUTS ( T ( " \n \n Whoops: Failed to generate seed! \n \n " ) , stderr ) ;
2020-10-15 22:41:28 +02:00
return 1 ;
2020-10-14 13:14:47 +02:00
}
2020-10-15 21:56:36 +02:00
char * const text_temp = strdup ( message ) ;
2020-10-14 13:14:47 +02:00
if ( ! text_temp )
{
2020-10-15 23:11:07 +02:00
FPUTS ( T ( " \n \n Whoops: Failed to allocate text buffer! \n \n " ) , stderr ) ;
2020-10-14 13:14:47 +02:00
goto clean_up ;
}
2020-10-19 21:56:12 +02:00
ctx = slunkcrypt_alloc ( seed , ( const uint8_t * ) passphrase , strlen ( passphrase ) ) ;
2020-10-14 17:57:40 +02:00
if ( ! ctx )
2020-10-14 13:14:47 +02:00
{
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 ;
}
2020-10-19 21:56:12 +02:00
status = slunkcrypt_encrypt_inplace ( ctx , ( uint8_t * ) text_temp , length ) ;
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 ;
}
2020-10-19 21:56:12 +02:00
status = slunkcrypt_reset ( ctx , seed , ( const uint8_t * ) passphrase , strlen ( passphrase ) ) ;
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 ;
}
2020-10-19 21:56:12 +02:00
status = slunkcrypt_decrypt_inplace ( ctx , ( uint8_t * ) text_temp , length ) ;
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-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: Decrypted message does *not* match the original message! \n \n " ) , stderr ) ;
2020-10-14 13:14:47 +02:00
goto clean_up ;
}
result = 0 ;
clean_up :
2020-10-14 17:57:40 +02:00
if ( ctx )
2020-10-14 13:14:47 +02:00
{
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-15 21:56:36 +02:00
static int self_test ( void )
{
2020-10-15 23:11:07 +02:00
static const size_t total = 32U ;
const char * const test_data [ ] = { TEST_DATA_0 , TEST_DATA_1 , TEST_DATA_2 , TEST_DATA_3 , NULL } ;
size_t completed = 0U ;
2020-10-16 18:05:37 +02:00
FPRINTF ( stderr , T ( " Self-test is running, please be patient... %2u/%2u " ) , ( unsigned int ) completed , ( unsigned int ) total ) ;
fflush ( stderr ) ;
2020-10-15 21:56:36 +02:00
for ( size_t i = 0U ; i < 8U ; + + i )
{
for ( size_t j = 0U ; test_data [ j ] ; + + j )
{
2020-10-16 18:05:37 +02:00
FPRINTF ( stderr , T ( " \b \b \b \b \b \b %2u/%2u " ) , ( unsigned int ) + + completed , ( unsigned int ) total ) ;
fflush ( stderr ) ;
2020-10-15 21:56:36 +02:00
if ( run_test ( test_data [ j ] ) )
{
return 1 ;
}
}
}
2020-10-16 18:07:45 +02:00
FPRINTF ( stderr , T ( " \b \b \b \b \b \b %2u/%2u \n \n Completed successfully. \n \n " ) , ( unsigned int ) total , ( unsigned int ) total ) ;
fflush ( stderr ) ;
2020-10-15 21:56:36 +02:00
return 0 ;
}
2020-10-14 16:36:17 +02:00
static void sigint_handler ( const int sig )
{
2020-10-18 19:48:17 +02:00
if ( sig = = SIGINT )
{
2020-10-19 21:56:12 +02:00
g_slunkcrypt_abort_flag = 1 ;
2020-10-18 19:48:17 +02:00
signal ( SIGINT , sigint_handler ) ;
}
2020-10-14 16:36:17 +02:00
}
2020-10-13 15:04:59 +02:00
int MAIN ( int argc , CHR * argv [ ] )
2020-10-12 23:10:47 +02:00
{
2020-10-13 19:33:01 +02:00
init_terminal ( ) ;
2020-10-14 16:36:17 +02:00
signal ( SIGINT , sigint_handler ) ;
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 ) ;
FPRINTF ( stderr , T ( " Using libSlunkCrypt v% " ) T ( PRIstr ) T ( " [% " ) T ( PRIstr ) T ( " ] \n \n " ) , SLUNKCRYPT_VERSION , SLUNKCRYPT_BUILD ) ;
2020-10-13 19:33:01 +02:00
2020-10-15 21:56:36 +02:00
if ( argc > 1 )
2020-10-14 13:14:47 +02:00
{
2020-10-15 21:56:36 +02:00
if ( ( ! STRICMP ( argv [ 1U ] , T ( " -v " ) ) ) | | ( ! STRICMP ( argv [ 1U ] , T ( " --version " ) ) ) )
{
return 0 ; /*exit right now*/
}
if ( ( ! STRICMP ( argv [ 1U ] , T ( " -h " ) ) ) | | ( ! STRICMP ( argv [ 1U ] , T ( " /? " ) ) ) | | ( ! STRICMP ( argv [ 1U ] , T ( " --help " ) ) ) )
{
const CHR * const program = get_file_name ( argv [ 0U ] ) ;
2020-10-16 17:37:04 +02:00
FPUTS ( T ( " ==================================================================== \n " ) , stderr ) ;
2020-10-15 21:56:36 +02:00
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 ) ;
2020-10-16 17:37:04 +02:00
FPUTS ( T ( " ==================================================================== \n \n " ) , stderr ) ;
2020-10-16 19:33:12 +02:00
FPUTS ( T ( " Synopsis: \n " ) , stderr ) ;
2020-10-16 17:37:04 +02:00
FPRINTF ( stderr , T ( " % " ) T ( PRISTR ) T ( " --encrypt [[@][:]<passphrase>] <input.txt> <output.enc> \n " ) , program ) ;
FPRINTF ( stderr , T ( " % " ) T ( PRISTR ) T ( " --decrypt [[@][:]<passphrase>] <input.enc> <output.txt> \n \n " ) , program ) ;
2020-10-19 21:56:12 +02:00
FPUTS ( T ( " Options: \n " ) , stderr ) ;
2020-10-16 17:37:04 +02:00
FPUTS ( T ( " - If <passphrase> is prefixed with a '@' character, then it specifies the file \n " ) , stderr ) ;
FPUTS ( T ( " to read the passphrase from; only the first line in that file is used! \n " ) , stderr ) ;
FPUTS ( T ( " - If <passphrase> is prefixed with a ':' character, then the leading character \n " ) , stderr ) ;
FPUTS ( T ( " is skipped and the remainder of the argument is used as passphrase. \n " ) , stderr ) ;
2020-10-19 21:56:12 +02:00
FPUTS ( T ( " - If argument <passphrase> is omitted, then the passphrase is read from the \n " ) , stderr ) ;
FPRINTF ( stderr , T ( " environment variable \" % " ) T ( PRISTR ) T ( " \" instead. \n " ) , ENVV_PASSWD_NAME ) ;
2020-10-16 19:33:12 +02:00
FPUTS ( T ( " - Specify \" @- \" in order to read the passphrase from the standard input stream! \n \n " ) , stderr ) ;
2020-10-15 21:56:36 +02:00
return 0 ;
}
if ( ( ! STRICMP ( argv [ 1U ] , T ( " -t " ) ) ) | | ( ! STRICMP ( argv [ 1U ] , T ( " --self-test " ) ) ) )
{
return self_test ( ) ; /*only self-test!*/
}
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-14 16:36:17 +02:00
const CHR * const program = get_file_name ( argv [ 0U ] ) ;
2020-10-15 21:56:36 +02:00
FPRINTF ( stderr , T ( " Error: Nothing to do. Please type '% " ) T ( PRISTR ) T ( " --help' for details! \n \n " ) , program ) ;
return 1 ;
2020-10-13 17:42:22 +02:00
}
2020-10-16 17:37:04 +02:00
else if ( argc > 5 )
{
FPUTS ( T ( " Warning: Excess command-line argument is ignored! \n \n " ) , stderr ) ;
}
2020-10-13 17:42:22 +02:00
2020-10-16 17:37:04 +02:00
const CHR * const command = argv [ 1U ] , * const passphrase = ( argc > 4 ) ? argv [ 2U ] : GETENV ( ENVV_PASSWD_NAME ) ;
const CHR * const input_file = argv [ ( argc > 4 ) ? 3U : 2U ] , * const output_file = argv [ ( argc > 4 ) ? 4U : 3U ] ;
2020-10-14 16:36:17 +02:00
2020-10-16 17:37:04 +02:00
if ( ( ! passphrase ) | | ( ! passphrase [ 0U ] ) | | ( ( ( passphrase [ 0U ] = = T ( ' @ ' ) ) | | ( passphrase [ 0U ] = = T ( ' : ' ) ) ) & & ( ! passphrase [ 1U ] ) ) )
2020-10-13 17:42:22 +02:00
{
2020-10-16 17:37:04 +02:00
FPUTS ( T ( " Error: The passphrase (file name) must not be empty! \n \n " ) , stderr ) ;
2020-10-12 23:10:47 +02:00
return 1 ;
}
2020-10-13 19:33:01 +02:00
if ( ( ! input_file [ 0U ] ) | | ( ! output_file [ 0U ] ) )
{
FPUTS ( T ( " Error: The input file and/or output file must not be empty! \n \n " ) , stderr ) ;
return 1 ;
}
2020-10-16 17:37:04 +02:00
char * const passphrase_buffer = ( passphrase [ 0U ] = = T ( ' @ ' ) ) ? read_passphrase ( passphrase + 1U ) : CHR_to_utf8 ( ( passphrase [ 0U ] = = T ( ' : ' ) ) ? ( passphrase + 1U ) : passphrase ) ;
2020-10-14 16:36:17 +02:00
if ( ! passphrase_buffer )
2020-10-13 19:33:01 +02:00
{
2020-10-14 16:36:17 +02:00
FPUTS ( T ( " Error: Failed to read the passphrase file! \n \n " ) , stderr ) ;
2020-10-13 19:33:01 +02:00
return 1 ;
}
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-14 16:36:17 +02:00
if ( strlen ( passphrase_buffer ) < 12U )
{
FPUTS ( T ( " Warning: Using a *short* passphrase; a length of 12 characters or more is recommended! \n \n " ) , stderr ) ;
}
else if ( weak_passphrase ( passphrase_buffer ) )
{
FPUTS ( T ( " Warning: Using a *weak* passphrase; a mix of upper-case letters, lower-case letters, digits and 'special' characters is recommended! \n \n " ) , stderr ) ;
}
2020-10-12 23:10:47 +02:00
const clock_t clk_start = clock ( ) ;
2020-10-13 17:42:22 +02:00
int result = - 1 ;
2020-10-12 23:10:47 +02:00
2020-10-14 21:55:39 +02:00
if ( ( ! STRICMP ( command , T ( " -e " ) ) ) | | ( ! STRICMP ( command , T ( " --encrypt " ) ) ) )
2020-10-13 17:42:22 +02:00
{
2020-10-14 16:36:17 +02:00
result = encrypt ( passphrase_buffer , input_file , output_file ) ;
2020-10-13 17:42:22 +02:00
}
2020-10-14 21:55:39 +02:00
else if ( ( ! STRICMP ( command , T ( " -d " ) ) ) | | ( ! STRICMP ( command , T ( " --decrypt " ) ) ) )
2020-10-12 23:10:47 +02:00
{
2020-10-14 16:36:17 +02:00
result = decrypt ( passphrase_buffer , input_file , output_file ) ;
2020-10-12 23:10:47 +02:00
}
else
{
2020-10-13 19:33:01 +02:00
FPRINTF ( stderr , T ( " Error: Command \" % " ) T ( PRISTR ) T ( " \" is unknown! \n \n " ) , command ) ;
goto exiting ;
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
exiting :
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
}