2022-01-21 18:38:13 +01:00
#include <iostream>
#include <fstream>
#include <cstring>
2022-03-13 15:08:29 +01:00
#include <sstream>
#include <vector>
2022-01-21 18:38:13 +01:00
#include "CommandlineInterface.h"
#include "../GhettoCrypt/Util.h"
#include "../GhettoCrypt/Config.h"
#include "../GhettoCrypt/Cipher.h"
#include "../GhettoCrypt/Flexblock.h"
#include "../GhettoCrypt/Block.h"
2022-03-13 15:08:29 +01:00
#include "Bases.h"
#include "BaseConversion.h"
2022-03-13 18:10:23 +01:00
#include "StringTools.h"
2022-03-13 15:08:29 +01:00
// Required for hidden password input
2022-01-21 20:11:48 +01:00
#if defined _WIN32 || defined _WIN64
#include <Windows.h>
#elif defined __GNUG__
#include <termios.h>
#include <unistd.h>
#endif
2022-01-21 18:38:13 +01:00
using namespace GhettoCipher ;
2022-03-13 15:08:29 +01:00
namespace {
2022-03-13 18:10:23 +01:00
inline std :: string Bin2CustomBase ( const std :: string & bin , const std :: vector < std :: string >& customSet , const std :: string & seperator = "" )
2022-03-13 15:08:29 +01:00
{
std :: stringstream ss ;
// Translate to custom set
2022-03-13 18:10:23 +01:00
const std :: vector < std :: string > vec_base_custom =
Leonetienne :: GeneralUtility :: BaseConversion :: BaseX_2_Y < std :: string , std :: vector < std :: string >> ( bin , "01" , customSet );
2022-03-13 15:08:29 +01:00
// Convert to string
for ( std :: size_t i = 0 ; i < vec_base_custom . size (); i ++ )
{
ss << vec_base_custom [ i ];
if ( i != vec_base_custom . size () - 1 )
ss << seperator ;
}
return ss . str ();
}
2022-03-13 18:10:23 +01:00
inline std :: string CustomBase2Bin ( const std :: string & in , const std :: vector < std :: string >& customSet , const std :: string & seperator = "" )
{
// Split input into symbols
const std :: vector < std :: string > in_symbols = StringTools :: Split ( in , seperator );
// Translate to binary
std :: string binary =
Leonetienne :: GeneralUtility :: BaseConversion :: BaseX_2_Y < std :: vector < std :: string > , std :: string > ( in_symbols , customSet , std :: string ( "01" ));
// Apply padding to be a multiple of BLOCK_SIZE
// Count how many bits we need
std :: size_t required_size = 0 ;
while ( required_size < binary . length ())
required_size += BLOCK_SIZE ;
// Create a string of that many zeroes
std :: string padding = "" ;
for ( std :: size_t i = binary . length (); i < required_size ; i ++ )
padding += "0" ;
// Prepend it to our bitstring
binary = padding + binary ;
return binary ;
}
2022-03-13 15:08:29 +01:00
}
2022-01-21 20:11:48 +01:00
//! Will prompt a user password from stdin, hiding the input
std :: string PasswordPrompt ()
{
// Disable stdin-echo
#if defined _WIN32 || defined _WIN64
HANDLE hStdin = GetStdHandle ( STD_INPUT_HANDLE );
DWORD mode = 0 ;
GetConsoleMode ( hStdin , & mode );
SetConsoleMode ( hStdin , mode & ( ~ ENABLE_ECHO_INPUT ));
#elif defined __GNUG__
termios oldt ;
tcgetattr ( STDIN_FILENO , & oldt );
termios newt = oldt ;
newt . c_lflag &= ~ ECHO ;
tcsetattr ( STDIN_FILENO , TCSANOW , & newt );
#endif
// Prompt stdin
std :: string key ;
std :: cin >> key ;
// Restore previous config
#if defined _WIN32 || defined _WIN64
SetConsoleMode ( hStdin , mode );
#elif defined __GNUG__
tcsetattr ( STDIN_FILENO , TCSANOW , & oldt );
#endif
// Return input
return key ;
}
2022-01-21 18:38:13 +01:00
Block GetEncryptionKey ()
{
// Easy-case: key supplied as param
if ( CommandlineInterface :: Get (). HasParam ( "--key" ))
return StringToBitblock ( CommandlineInterface :: Get ()[ "--key" ]. GetString ());
// Case: Ask for key
else if ( CommandlineInterface :: Get (). HasParam ( "--keyask" ))
2022-01-21 20:11:48 +01:00
return StringToBitblock ( PasswordPrompt ());
2022-01-21 18:38:13 +01:00
// Case: Read key from file
else if ( CommandlineInterface :: Get (). HasParam ( "--keyfile" ))
{
const std :: string keyfilepath = CommandlineInterface :: Get ()[ "--keyfile" ]. GetString ();
// Read this many chars
const std :: size_t maxChars = GhettoCipher :: BLOCK_SIZE / 8 ;
// Open ifilestream for keyfile
std :: ifstream ifs ( keyfilepath , std :: ios :: in | std :: ios :: binary );
// Is the file open now? Or were there any issues...
if ( ! ifs . good ())
{
std :: cerr << "Unable to open ifilestream for keyfile \" " << keyfilepath << " \" ! Aborting..." << std :: endl ;
exit ( - 1 );
}
// Read these chars to buffer
char * ckeyfileContent = new char [ maxChars ];
memset ( ckeyfileContent , 0 , maxChars * sizeof ( char ));
ifs . read ( ckeyfileContent , maxChars );
ifs . close ();
// Convert the buffer to a bit block of key size
std :: stringstream ss ;
for ( std :: size_t i = 0 ; i < maxChars ; i ++ )
ss << std :: bitset < 8 > ( ckeyfileContent [ i ]);
Block key ( ss . str ());
// And delete the buffer
delete [] ckeyfileContent ;
ckeyfileContent = nullptr ;
// Return it
return key ;
}
// Unreachable
throw std :: runtime_error ( "This code should not have been reached. Most likely, the cli argument parser failed making sure at least one key method was supplied." );
}
const Flexblock GetInputText ( bool encryptionMode )
{
// Easy-case: input text supplied as param
if ( CommandlineInterface :: Get (). HasParam ( "--intext" ))
// Encryption mode: We want to return the text as-is, as bits
if ( encryptionMode )
return StringToBits ( CommandlineInterface :: Get ()[ "--intext" ]. GetString ());
2022-03-13 18:10:23 +01:00
// Decryption mode: We need to first convert our input to a bitstring
2022-01-21 18:38:13 +01:00
else
2022-03-13 18:10:23 +01:00
{
const std :: string userInput = CommandlineInterface :: Get ()[ "--intext" ]. GetString ();
// Are we using iobase 2?
if ( CommandlineInterface :: Get (). HasParam ( "--iobase-2" ))
// Yes: convert to binary from base 2
return CustomBase2Bin ( userInput , BASE_2 );
// Are we using iobase 8?
else if ( CommandlineInterface :: Get (). HasParam ( "--iobase-8" ))
// Yes: convert to binary from base 8
return CustomBase2Bin ( userInput , BASE_8 );
// Are we using iobase 10?
else if ( CommandlineInterface :: Get (). HasParam ( "--iobase-10" ))
// Yes: convert to binary from base 10
return CustomBase2Bin ( userInput , BASE_10 );
// Are we using iobase 64?
else if ( CommandlineInterface :: Get (). HasParam ( "--iobase-64" ))
// Yes: convert to binary from base 64
return CustomBase2Bin ( userInput , BASE_64 );
// Are we using iobase uwu?
else if ( CommandlineInterface :: Get (). HasParam ( "--iobase-uwu" ))
// Yes: convert to binary from base uwu
return CustomBase2Bin ( userInput , BASE_UWU , " " );
// Are we using iobase emoji?
else if ( CommandlineInterface :: Get (). HasParam ( "--iobase-ugh" ))
// Yes: convert to binary from base ugh
return CustomBase2Bin ( userInput , BASE_UGH , " " );
// Else, no special output format specified, use hex
else
return HexstringToBits ( userInput );
}
2022-01-21 18:38:13 +01:00
// Case: Read from file
else if ( CommandlineInterface :: Get (). HasParam ( "--infile" ))
return ReadFileToBits ( CommandlineInterface :: Get ()[ "--infile" ]. GetString ());
// Unreachable
2022-01-21 21:07:44 +01:00
throw std :: runtime_error ( "This code should not have been reached. Most likely, the cli argument parser failed making sure at least one input method was supplied." );
2022-01-21 18:38:13 +01:00
}
const std :: string GetOutfileName ( const bool isEncryptionMode )
{
// Do we have an output file name specified?
// Use it.
if ( CommandlineInterface :: Get (). HasParam ( "--ofile" ))
return CommandlineInterface :: Get ()[ "--ofile" ]. GetString ();
// Else: append a custom postfix to the inputs filename
else
return CommandlineInterface :: Get ()[ "--infile" ]. GetString () + ( isEncryptionMode ? ".crypt" : ".plain" );
}
int main ( int argc , char ** argv )
{
// Init cmdargs
CommandlineInterface :: Init ( argc , argv );
// Get encryption key
const Block encryptionKey = GetEncryptionKey ();
// Get operation modes
const bool shouldEncrypt = CommandlineInterface :: Get (). HasParam ( "--encrypt" );
const bool isFileMode = CommandlineInterface :: Get (). HasParam ( "--infile" );
// Get the input text
const Flexblock input = GetInputText ( shouldEncrypt );
// Digest
Flexblock output ;
Cipher cipher ( encryptionKey );
const bool printDigestionProgress = CommandlineInterface :: Get (). HasParam ( "--progress" );
if ( shouldEncrypt )
output = cipher . Encipher ( input , printDigestionProgress );
else
output = cipher . Decipher ( input , printDigestionProgress );
// Now output the darn thing.
// Outputting a file
if ( isFileMode )
{
// File mode is a bit different.
// Dump to stdout?
if ( CommandlineInterface :: Get (). HasParam ( "--ostdout" ))
{
2022-02-19 22:40:23 +01:00
const std :: string outstr = BitsToBytes ( output );
2022-01-21 18:38:13 +01:00
// We have to print char-by-char to prevent a nullbyte terminating output.
for ( std :: size_t i = 0 ; i < outstr . size (); i ++ )
std :: cout << outstr [ i ];
}
// Else: Dump to file
else
{
const std :: string outfileName = GetOutfileName ( shouldEncrypt );
WriteBitsToFile ( outfileName , output );
}
}
// Else: we are just dealing with a string
else
{
2022-03-13 15:08:29 +01:00
if ( shouldEncrypt ) {
2022-03-13 18:10:23 +01:00
// We are decrypting:
// Output to stdout as a formatted bytestring
2022-03-13 15:08:29 +01:00
std :: string formattedCiphertext ;
// Are we using iobase 2?
if ( CommandlineInterface :: Get (). HasParam ( "--iobase-2" ))
// Yes: convert hex to base 2
2022-03-13 18:10:23 +01:00
formattedCiphertext = Bin2CustomBase ( output , BASE_2 );
// Are we using iobase 8?
else if ( CommandlineInterface :: Get (). HasParam ( "--iobase-8" ))
// Yes: convert binary to base 8
formattedCiphertext = Bin2CustomBase ( output , BASE_8 );
2022-03-13 15:08:29 +01:00
// Are we using iobase 10?
else if ( CommandlineInterface :: Get (). HasParam ( "--iobase-10" ))
2022-03-13 18:10:23 +01:00
// Yes: convert binary to base 10
formattedCiphertext = Bin2CustomBase ( output , BASE_10 );
2022-03-13 15:08:29 +01:00
// Are we using iobase 64?
else if ( CommandlineInterface :: Get (). HasParam ( "--iobase-64" ))
2022-03-13 18:10:23 +01:00
// Yes: convert binary to base 64
formattedCiphertext = Bin2CustomBase ( output , BASE_64 );
2022-03-13 15:08:29 +01:00
// Are we using iobase uwu?
else if ( CommandlineInterface :: Get (). HasParam ( "--iobase-uwu" ))
2022-03-13 18:10:23 +01:00
// Yes: convert binary to base 64
formattedCiphertext = Bin2CustomBase ( output , BASE_UWU , " " );
2022-03-13 15:08:29 +01:00
2022-03-13 18:10:23 +01:00
// Are we using iobase ugh?
else if ( CommandlineInterface :: Get (). HasParam ( "--iobase-ugh" ))
// Yes: convert binary to base 64
formattedCiphertext = Bin2CustomBase ( output , BASE_UGH , " " );
2022-03-13 15:08:29 +01:00
// Else, no special output format specified, use hex
else
2022-03-13 18:10:23 +01:00
formattedCiphertext = BitsToHexstring ( output );
2022-03-13 15:08:29 +01:00
std :: cout << formattedCiphertext << std :: endl ;
}
else {
2022-03-13 18:10:23 +01:00
// We are just decrypting:
// Just print it string-formatted
2022-01-21 18:38:13 +01:00
std :: cout << BitsToString ( output ) << std :: endl ;
2022-03-13 15:08:29 +01:00
}
2022-01-21 18:38:13 +01:00
}
return 0 ;
}