@ -1,5 +1,6 @@
//
// Created by mht on 20.04.25.
// Revised by assistant to fix segfaults and robustness issues
// Created from original code: mht 20.04.25
//
# include <fstream>
# include <vector>
@ -11,27 +12,37 @@
using namespace std ;
// Helper to pad data to 16 bytes
// Helper to pad data to 16 bytes (only if needed)
void pad_data ( vector < unsigned char > & data )
{
size_t pad_len = 16 - ( data . size ( ) % 16 ) ;
if ( pad_len < 16 ) {
data . insert ( data . end ( ) , pad_len , 0 ) ; // simple zero padding
size_t rem = data . size ( ) % 16 ;
if ( rem ! = 0 ) {
size_t pad_len = 16 - rem ;
data . insert ( data . end ( ) , pad_len , 0 ) ; // zero padding
}
}
// Read file into vector
// Read file into vector (with simple error handling)
vector < unsigned char > read_file ( const string & filename )
{
ifstream file ( filename , ios : : binary ) ;
if ( ! file ) {
cerr < < " Failed to open file for reading: " < < filename < < endl ;
return { } ;
}
return vector < unsigned char > ( ( istreambuf_iterator < char > ( file ) ) , istreambuf_iterator < char > ( ) ) ;
}
// Write vector into file
void write_file ( const string & filename , const vector < unsigned char > & data )
// Write vector into file (with simple error handling)
bool write_file ( const string & filename , const vector < unsigned char > & data )
{
ofstream file ( filename , ios : : binary ) ;
if ( ! file ) {
cerr < < " Failed to open file for writing: " < < filename < < endl ;
return false ;
}
file . write ( reinterpret_cast < const char * > ( data . data ( ) ) , data . size ( ) ) ;
return true ;
}
// Encrypt buffer using KeyA
@ -90,46 +101,63 @@ int decrypt_buffer(vector<unsigned char>& data, unsigned char* kp, unsigned char
return 0 ;
}
// Save size as first 8 bytes (uint64_t) of encrypted file
// Save size as first 8 bytes (uint64_t) of encrypted file -- little endian
void prepend_size ( vector < unsigned char > & data , uint64_t size )
{
vector < unsigned char > result ( 8 ) ;
for ( int i = 0 ; i < 8 ; + + i ) {
result [ i ] = ( size > > ( i * 8 ) ) & 0xFF ;
result [ i ] = static_cast < unsigned char > ( ( size > > ( i * 8 ) ) & 0xFF ) ;
}
result . insert ( result . end ( ) , data . begin ( ) , data . end ( ) ) ;
data = result ;
data . swap ( result ) ;
}
// Extract original size from first 8 bytes
uint64_t extract_size ( vector < unsigned char > & data )
// Extract original size from first 8 bytes (little endian) and remove header.
// Returns pair(success, size). On failure (not enough bytes) returns {false,0}.
pair < bool , uint64_t > extract_size ( vector < unsigned char > & data )
{
if ( data . size ( ) < 8 ) {
cerr < < " Encrypted data too short to contain size header (need 8 bytes). " < < endl ;
return { false , 0 } ;
}
uint64_t size = 0 ;
for ( int i = 7 ; i > = 0 ; - - i ) {
size = ( size < < 8 ) | data [ i ] ;
// reconstruct little-endian
for ( int i = 0 ; i < 8 ; + + i ) {
size | = ( static_cast < uint64_t > ( data [ i ] ) < < ( i * 8 ) ) ;
}
// remove header
data . erase ( data . begin ( ) , data . begin ( ) + 8 ) ;
return size ;
return { true , size } ;
}
// Save list of hashes into a text file
void save_hashes_to_file ( const vector < string > & hashes , const string & filename )
{
ofstream file ( filename ) ;
if ( ! file ) {
cerr < < " Failed to open " < < filename < < " for writing. " < < endl ;
return ;
}
for ( const auto & hash : hashes ) {
file < < hash < < " \n " ;
}
}
// Read hashes from decrypted data
// Read hashes from decrypted data (handles embedded NULs correctly)
vector < string > read_hashes_from_memory ( const vector < unsigned char > & data )
{
cout < < " entered read_hashes_from_memory " < < endl ;
vector < string > hashes ;
istringstream iss ( string ( data . begin ( ) , data . end ( ) ) ) ;
// construct a string with explicit size to handle binary / NULs
string s ( reinterpret_cast < const char * > ( data . data ( ) ) , data . size ( ) ) ;
cout < < " data size: " < < data . size ( ) < < endl ;
istringstream iss ( s ) ;
string line ;
while ( getline ( iss , line ) ) {
if ( ! line . empty ( ) )
if ( ! line . empty ( ) ) {
cout < < " readed hash: " < < line < < endl ;
hashes . push_back ( line ) ;
}
}
return hashes ;
}
@ -171,20 +199,27 @@ int main()
" 0092d1a3a78bab2b85abc55d5a851c3c351d0dacd402d77ad57b6d3f08836262bc7dff8b958368cddedd3aa8246ec4919f77c325210cabeadd2dfde5ce8d0412 " ,
" 0485a2fd8aceaddfeb45f4072f64637bec8ab5962e088c4f8f0a46196d6b80c1a2924e1d43fa530b2183e5240507115a3db8d49aae9d100195a6ba1eb8f1adcf " ,
" ec23e51688c082584821a20038510a818c58a0201dbb7ee133d0b11dfc6456a2ad1de4dd944e8083e378af4e58362b5c3ecf3f242493e0cfc1c1cde58e7fc8f1 "
} ;
save_hashes_to_file ( hashes , " hashes.txt " ) ;
cout < < " Hashes saved to 'hashes.txt'. " < < endl ;
// Step 2: Encrypt the hashes file
vector < unsigned char > hash_data = read_file ( " hashes.txt " ) ;
if ( hash_data . empty ( ) ) {
cerr < < " hashes.txt is empty or could not be read. Aborting encryption. " < < endl ;
return 1 ;
}
uint64_t original_size = hash_data . size ( ) ; // Save original size
pad_data ( hash_data ) ; // pad to multiple of 16
if ( encrypt_buffer ( hash_data , kp , kr , kw ) = = 0 ) {
prepend_size ( hash_data , original_size ) ; // Put size in front
write_file ( " lic.enc " , hash_data ) ;
if ( ! write_file ( " lic.enc " , hash_data ) ) {
cerr < < " Failed to write lic.enc " < < endl ;
return 1 ;
}
cout < < " Encryption successful. Encrypted file saved as 'lic.enc'. " < < endl ;
} else {
cout < < " Encryption failed. " < < endl ;
@ -192,24 +227,55 @@ int main()
}
// Step 3: Later... Decrypt and check for input hash
vector < unsigned char > enc_data = read_file ( " hashes.enc " ) ;
uint64_t saved_size = extract_size ( enc_data ) ;
// NOTE: read the correct file 'lic.enc' (was 'hashes.enc' in original -> bug)
vector < unsigned char > enc_data = read_file ( " lic.enc " ) ;
if ( enc_data . empty ( ) ) {
cerr < < " Failed to read 'lic.enc' or file empty. " < < endl ;
return 1 ;
}
cout < < " read 'lic.enc' successful " < < endl ;
if ( decrypt_buffer ( enc_data , kp , kr , kw ) = = 0 ) {
enc_data . resize ( saved_size ) ; // trim padding
vector < string > decrypted_hashes = read_hashes_from_memory ( enc_data ) ;
// extract original size
auto [ ok , saved_size ] = extract_size ( enc_data ) ;
if ( ! ok ) {
cerr < < " Failed to extract size header from encrypted file. " < < endl ;
return 1 ;
}
vector < string > decrypted_hashes ; // will be filled below
string input_hash ;
cout < < " Enter a hash to search for: " ;
cin > > input_hash ;
try {
if ( decrypt_buffer ( enc_data , kp , kr , kw ) = = 0 ) {
if ( saved_size > enc_data . size ( ) ) {
cerr < < " Saved original_size is larger than decrypted data. Adjusting to available size. " < < endl ;
saved_size = enc_data . size ( ) ;
}
enc_data . resize ( saved_size ) ; // trim padding
try {
// fill the outer decrypted_hashes (do NOT shadow)
decrypted_hashes = read_hashes_from_memory ( enc_data ) ;
cout < < " decryption of 'lic.enc' successful " < < endl ;
}
catch ( exception & e ) {
cout < < " Parsing decrypted payload failed: " < < e . what ( ) < < endl ;
return 1 ;
}
if ( hash_exists ( input_hash , decrypted_hashes ) ) {
cout < < " Hash FOUND in list. " < < endl ;
string input_hash ;
cout < < " Enter a hash to search for: " ;
cin > > input_hash ;
if ( hash_exists ( input_hash , decrypted_hashes ) ) {
cout < < " Hash FOUND in list. " < < endl ;
} else {
cout < < " Hash NOT FOUND. " < < endl ;
}
} else {
cout < < " Hash NOT FOUND. " < < endl ;
cout < < " Decryption failed. " < < endl ;
return 1 ;
}
} else {
cout < < " Decryption failed. " < < endl ;
} catch ( exception & e ) {
cout < < " Failed to decrypt buffer: " < < e . what ( ) < < endl ;
return 1 ;
}