@@ -13,7 +13,6 @@
# include <termios.h>
# include <fcntl.h>
# include <math.h>
# include "src/version.h"
# include "nostr_chacha20.h"
// Custom base64 character set
@@ -125,6 +124,11 @@ int add_entropy_to_pad(const char* pad_chksum, const unsigned char* entropy_data
size_t entropy_size , int show_progress ) ;
int handle_add_entropy_to_pad ( const char * pad_chksum ) ;
// Enhanced entropy system helper functions
int update_pad_checksum_after_entropy ( const char * old_chksum , char * new_chksum ) ;
int rename_pad_files_safely ( const char * old_chksum , const char * new_chksum ) ;
int is_pad_unused ( const char * pad_chksum ) ;
// Directory management
int ensure_pads_directory ( void ) ;
void get_pad_path ( const char * chksum , char * pad_path , char * state_path ) ;
@@ -134,7 +138,6 @@ void get_default_file_path(const char* filename, char* result_path, size_t resul
// Utility functions
uint64_t parse_size_string ( const char * size_str ) ;
char * find_pad_by_prefix ( const char * prefix ) ;
int list_available_pads ( void ) ;
int show_pad_info ( const char * chksum ) ;
void show_progress ( uint64_t current , uint64_t total , time_t start_time ) ;
@@ -172,6 +175,14 @@ int get_filename_with_default(const char* prompt, const char* default_path, char
// Directory display functions
void get_directory_display ( const char * file_path , char * result , size_t result_size ) ;
// Unified pad selection function
typedef enum {
PAD_FILTER_ALL , // Show all pads
PAD_FILTER_UNUSED_ONLY // Show only unused pads (0% usage)
} pad_filter_type_t ;
char * select_pad_interactive ( const char * title , const char * prompt , pad_filter_type_t filter_type , int allow_cancel ) ;
void print_usage ( const char * program_name ) ;
@@ -392,7 +403,12 @@ int command_line_mode(int argc, char* argv[]) {
return encrypt_file ( pad_prefix , input_file , output_file , ascii_armor ) ;
}
else if ( strcmp ( argv [ 1 ] , " list " ) = = 0 | | strcmp ( argv [ 1 ] , " -l " ) = = 0 ) {
return list_available_pads ( ) ;
printf ( " Available pads: \n " ) ;
char * selected = select_pad_interactive ( " Available pads: " , " Select pad (or press Enter to exit) " , PAD_FILTER_ALL , 0 ) ;
if ( selected ) {
free ( selected ) ;
}
return 0 ;
}
else {
print_usage ( argv [ 0 ] ) ;
@@ -410,7 +426,7 @@ int command_line_mode(int argc, char* argv[]) {
int interactive_mode ( void ) {
char input [ 10 ] ;
printf ( " \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n " ) ;
while ( 1 ) {
show_main_menu ( ) ;
@@ -450,7 +466,8 @@ int interactive_mode(void) {
void show_main_menu ( void ) {
printf ( " \n \n \n \n =========================== Main Menu - OTP %s =========================== \n \n " , get_version ( ) ) ;
printf ( " \n =========================== Main Menu - OTP v1.0.0 =========================== \n \n " ) ;
printf ( " \033 [4mT \033 [0mext encrypt \n " ) ; //TEXT ENCRYPT
printf ( " \033 [4mF \033 [0mile encrypt \n " ) ; //FILE ENCRYPT
@@ -488,7 +505,14 @@ int handle_generate_menu(void) {
int handle_encrypt_menu ( void ) {
printf ( " \n === Encrypt Data === \n " ) ;
int pad_count = list_available_pads ( ) ;
printf ( " Available pads: \n " ) ;
char * selected = select_pad_interactive ( " Available pads: " , " Select pad (or press Enter to continue) " , PAD_FILTER_ALL , 0 ) ;
int pad_count = 1 ; // Assume at least 1 pad if function returned
if ( selected ) {
free ( selected ) ;
} else {
pad_count = 0 ;
}
if ( pad_count = = 0 ) {
printf ( " No pads available. Generate a pad first. \n " ) ;
return 1 ;
@@ -509,57 +533,18 @@ int handle_encrypt_menu(void) {
int choice = atoi ( choice_input ) ;
if ( choice = = 1 ) {
// Text encryption
printf ( " \n Pad selection options: \n " ) ;
printf ( " 1. Select from numbered list \n " ) ;
printf ( " 2. Enter checksum/prefix manually \n " ) ;
printf ( " 3. Browse pad files \n " ) ;
printf ( " Enter choice (1-3): " ) ;
char pad_choice [ 10 ] ;
if ( ! fgets ( pad_choice , sizeof ( pad_choice ) , stdin ) ) {
printf ( " Error: Failed to read input \n " ) ;
// Text encryption - use unified pad selection
char * selected_pad = select_pad_interactive ( " === Select Pad for Text Encryption === " ,
" Select pad (by prefix or number) " ,
PAD_FILTER_ALL , 1 ) ;
if ( ! selected_pad ) {
printf ( " Text encryption cancelled. \n " ) ;
return 1 ;
}
char input [ MAX_HASH_LENGTH ] ;
if ( atoi ( pad_choice ) = = 3 ) {
// Use file manager to browse pads directory
char selected_pad [ 512 ] ;
if ( launch_file_manager ( " pads " , selected_pad , sizeof ( selected_pad ) ) = = 0 ) {
// Extract checksum from selected .pad file
char * filename = strrchr ( selected_pad , ' / ' ) ;
if ( ! filename ) filename = selected_pad ;
else filename + + ; // Skip the '/'
// Remove .pad extension to get checksum
if ( strlen ( filename ) = = 68 & & strstr ( filename , " .pad " ) ) {
strncpy ( input , filename , 64 ) ;
input [ 64 ] = ' \0 ' ;
} else {
printf ( " Invalid pad file selected. \n " ) ;
return 1 ;
}
} else {
printf ( " Falling back to manual pad selection. \n " ) ;
printf ( " Enter pad selection (number, chksum, or prefix): " ) ;
if ( ! fgets ( input , sizeof ( input ) , stdin ) ) {
printf ( " Error: Failed to read input \n " ) ;
return 1 ;
}
input [ strcspn ( input , " \n " ) ] = 0 ;
}
} else {
// Manual pad selection
printf ( " Enter pad selection (number, chksum, or prefix): " ) ;
if ( ! fgets ( input , sizeof ( input ) , stdin ) ) {
printf ( " Error: Failed to read input \n " ) ;
return 1 ;
}
input [ strcspn ( input , " \n " ) ] = 0 ;
}
return encrypt_text ( input , NULL ) ; // NULL for interactive mode
int result = encrypt_text ( selected_pad , NULL ) ; // NULL for interactive mode
free ( selected_pad ) ;
return result ;
}
else if ( choice = = 2 ) {
// File encryption
@@ -603,13 +588,14 @@ int handle_encrypt_menu(void) {
return 1 ;
}
printf ( " \n Enter pad selection (number, chksum, or prefix): " ) ;
char pad_input [ MAX_HASH_LENGTH ] ;
if ( ! fgets ( pad_input , sizeof ( pad_input ) , stdin ) ) {
printf ( " Error: Failed to read input \n " ) ;
// Use unified pad selection
char * selected_pad = select_pad_interactive ( " === Select Pad for File Encryption === " ,
" Select pad (by prefix) " ,
PAD_FILTER_ALL , 1 ) ;
if ( ! selected_pad ) {
printf ( " File encryption cancelled. \n " ) ;
return 1 ;
}
pad_input [ strcspn ( pad_input , " \n " ) ] = 0 ;
// Ask for output format
printf ( " \n Select output format: \n " ) ;
@@ -647,7 +633,9 @@ int handle_encrypt_menu(void) {
const char * output_filename = output_file ;
return encrypt_file ( pad_input , input_file , output_filename , ascii_armor ) ;
int result = encrypt_file ( selected_pad , input_file , output_filename , ascii_armor ) ;
free ( selected_pad ) ;
return result ;
}
else {
printf ( " Invalid choice. Please enter 1 or 2. \n " ) ;
@@ -865,7 +853,10 @@ char* find_pad_by_prefix(const char* prefix) {
if ( match_count = = 0 ) {
printf ( " No pads found matching '%s' \n " , prefix ) ;
printf ( " Available pads: \n " ) ;
list_available_pads ( ) ;
char * selected = select_pad_interactive ( " Available pads: " , " Available pads (press Enter to continue) " , PAD_FILTER_ALL , 0 ) ;
if ( selected ) {
free ( selected ) ;
}
return NULL ;
} else if ( match_count = = 1 ) {
char * result = matches [ 0 ] ;
@@ -906,99 +897,14 @@ char* find_pad_by_prefix(const char* prefix) {
}
}
int list_available_pads ( void ) {
DIR * dir = opendir ( current_pads_dir ) ;
if ( ! dir ) {
printf ( " Error: Cannot open pads directory %s \n " , current_pads_dir ) ;
return 0 ;
}
struct dirent * entry ;
int count = 0 ;
// Get current default pad path for comparison
char * current_default = get_default_pad_path ( ) ;
char default_pad_checksum [ 65 ] = " " ;
if ( current_default ) {
// Extract checksum from default pad path
char * filename = strrchr ( current_default , ' / ' ) ;
if ( ! filename ) filename = current_default ;
else filename + + ; // Skip the '/'
// Extract checksum (remove .pad extension)
if ( strlen ( filename ) > = 68 & & strstr ( filename , " .pad " ) ) {
strncpy ( default_pad_checksum , filename , 64 ) ;
default_pad_checksum [ 64 ] = ' \0 ' ;
}
free ( current_default ) ;
}
printf ( " \n Available pads: \n " ) ;
printf ( " %-4s %-7s %-20s %-12s %-12s %-8s \n " , " No. " , " Default " , " ChkSum " , " Size " , " Used " , " % Used " ) ;
printf ( " %-4s %-7s %-20s %-12s %-12s %-8s \n " , " --- " , " ------- " , " ------------------- " , " ---------- " , " ---------- " , " ------ " ) ;
while ( ( entry = readdir ( dir ) ) ! = NULL ) {
if ( strstr ( entry - > d_name , " .pad " ) & & strlen ( entry - > d_name ) = = 68 ) {
count + + ;
char chksum [ 65 ] ;
strncpy ( chksum , entry - > d_name , 64 ) ;
chksum [ 64 ] = ' \0 ' ;
// Check if this is the default pad
int is_default = ( strlen ( default_pad_checksum ) > 0 & &
strncmp ( chksum , default_pad_checksum , 64 ) = = 0 ) ;
// Get pad file size
char full_path [ 1024 ] ; // Increased buffer size to accommodate longer paths
snprintf ( full_path , sizeof ( full_path ) , " %s/%s " , current_pads_dir , entry - > d_name ) ;
struct stat st ;
if ( stat ( full_path , & st ) = = 0 ) {
// Get used bytes from state
uint64_t used_bytes ;
read_state_offset ( chksum , & used_bytes ) ;
// Format sizes
char size_str [ 32 ] , used_str [ 32 ] ;
// Format total size
if ( st . st_size < 1024 ) {
snprintf ( size_str , sizeof ( size_str ) , " %luB " , st . st_size ) ;
} else if ( st . st_size < 1024 * 1024 ) {
snprintf ( size_str , sizeof ( size_str ) , " %.1fKB " , ( double ) st . st_size / 1024.0 ) ;
} else if ( st . st_size < 1024 * 1024 * 1024 ) {
snprintf ( size_str , sizeof ( size_str ) , " %.1fMB " , ( double ) st . st_size / ( 1024.0 * 1024.0 ) ) ;
} else {
snprintf ( size_str , sizeof ( size_str ) , " %.2fGB " , ( double ) st . st_size / ( 1024.0 * 1024.0 * 1024.0 ) ) ;
}
// Format used size
if ( used_bytes < 1024 ) {
snprintf ( used_str , sizeof ( used_str ) , " %luB " , used_bytes ) ;
} else if ( used_bytes < 1024 * 1024 ) {
snprintf ( used_str , sizeof ( used_str ) , " %.1fKB " , ( double ) used_bytes / 1024.0 ) ;
} else if ( used_bytes < 1024 * 1024 * 1024 ) {
snprintf ( used_str , sizeof ( used_str ) , " %.1fMB " , ( double ) used_bytes / ( 1024.0 * 1024.0 ) ) ;
} else {
snprintf ( used_str , sizeof ( used_str ) , " %.2fGB " , ( double ) used_bytes / ( 1024.0 * 1024.0 * 1024.0 ) ) ;
}
// Calculate percentage
double percentage = ( double ) used_bytes / st . st_size * 100.0 ;
printf ( " %-4d %-7s %-20.16s %-12s %-12s %.1f%% \n " , count , is_default ? " * " : " " , chksum , size_str , used_str , percentage ) ;
}
}
}
closedir ( dir ) ;
if ( count = = 0 ) {
printf ( " No pads found. \n " ) ;
}
return count ;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// PADS MENU
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
int show_pad_info ( const char * chksum ) {
char pad_filename [ MAX_HASH_LENGTH + 10 ] ;
@@ -1320,6 +1226,24 @@ int add_entropy_to_pad(const char* pad_chksum, const unsigned char* entropy_data
printf ( " ✓ Pad integrity maintained \n " ) ;
printf ( " ✓ %zu bytes of entropy distributed across entire pad \n " , entropy_size ) ;
printf ( " ✓ Pad restored to read-only mode \n " ) ;
// Update checksum after entropy addition
printf ( " \n 🔄 Updating pad checksum... \n " ) ;
char new_chksum [ 65 ] ;
int checksum_result = update_pad_checksum_after_entropy ( pad_chksum , new_chksum ) ;
if ( checksum_result = = 0 ) {
printf ( " ✓ Pad checksum updated successfully \n " ) ;
printf ( " Old checksum: %.16s... \n " , pad_chksum ) ;
printf ( " New checksum: %.16s... \n " , new_chksum ) ;
printf ( " ✓ Pad files renamed to new checksum \n " ) ;
} else if ( checksum_result = = 2 ) {
printf ( " ℹ Checksum unchanged (unusual but not an error)\n " ) ;
} else {
printf ( " ⚠ Warning: Checksum update failed (entropy was added successfully) \n " ) ;
printf ( " You may need to manually handle the checksum update \n " ) ;
return 1 ; // Report error despite successful entropy addition
}
}
return 0 ;
@@ -1503,7 +1427,7 @@ int encrypt_text(const char* pad_identifier, const char* input_text) {
int is_interactive = ( input_text = = NULL ) ; // Interactive if no input_text provided
if ( is_interactive ) {
printf ( " \n \n %s \n \n " , ascii_output ) ;
printf ( " \n \n \n %s \n \n " , ascii_output ) ;
} else {
printf ( " %s \n " , ascii_output ) ; // Add newline for proper piping with tee
}
@@ -1868,7 +1792,10 @@ int decrypt_binary_file(FILE* input_fp, const char* output_file) {
if ( access ( pad_path , R_OK ) ! = 0 ) {
printf ( " Error: Required pad not found: %s \n " , pad_chksum_hex ) ;
printf ( " Available pads: \n " ) ;
list_available_pads ( ) ;
char * selected = select_pad_interactive ( " Available pads: " , " Available pads (press Enter to continue) " , PAD_FILTER_ALL , 0 ) ;
if ( selected ) {
free ( selected ) ;
}
fclose ( input_fp ) ;
return 1 ;
}
@@ -2156,13 +2083,8 @@ int collect_entropy_with_feedback(unsigned char* entropy_buffer, size_t target_b
state . unique_keys + + ;
}
} else {
// No key available, add timing entropy
clock_gettime ( CLOCK_MONOTONIC , & timestamp ) ;
if ( state . collected_bytes + 12 < MAX_ENTROPY_BUFFER ) {
memcpy ( entropy_buffer + state . collected_bytes , & timestamp , 12 ) ;
state . collected_bytes + = 12 ;
}
usleep ( 1000 ) ; // 1ms delay
// No key available, just sleep and wait for keystrokes
usleep ( 10000 ) ; // 10ms delay - wait for keystrokes, don't add timing entropy
}
// Auto-complete at target if enabled
@@ -2875,6 +2797,97 @@ int derive_chacha20_params(const unsigned char* entropy_data, size_t entropy_siz
return 0 ; // Success
}
// Enhanced entropy system helper functions
// Check if a pad is unused (0% usage)
int is_pad_unused ( const char * pad_chksum ) {
uint64_t used_bytes ;
if ( read_state_offset ( pad_chksum , & used_bytes ) ! = 0 ) {
return 0 ; // Error reading state, assume used
}
return ( used_bytes < = 32 ) ; // Only reserved bytes used (32 bytes for checksum encryption)
}
// Safely rename pad files (pad and state) from old to new checksum
int rename_pad_files_safely ( const char * old_chksum , const char * new_chksum ) {
char old_pad_path [ 1024 ] , new_pad_path [ 1024 ] ;
char old_state_path [ 1024 ] , new_state_path [ 1024 ] ;
// Construct file paths
snprintf ( old_pad_path , sizeof ( old_pad_path ) , " %s/%s.pad " , current_pads_dir , old_chksum ) ;
snprintf ( new_pad_path , sizeof ( new_pad_path ) , " %s/%s.pad " , current_pads_dir , new_chksum ) ;
snprintf ( old_state_path , sizeof ( old_state_path ) , " %s/%s.state " , current_pads_dir , old_chksum ) ;
snprintf ( new_state_path , sizeof ( new_state_path ) , " %s/%s.state " , current_pads_dir , new_chksum ) ;
// Check if new files would conflict with existing files
if ( access ( new_pad_path , F_OK ) = = 0 ) {
printf ( " Error: New pad file already exists: %s \n " , new_pad_path ) ;
return 1 ; // Conflict
}
// Rename pad file
if ( rename ( old_pad_path , new_pad_path ) ! = 0 ) {
printf ( " Error: Failed to rename pad file from %s to %s \n " , old_pad_path , new_pad_path ) ;
return 2 ; // Pad rename failed
}
// Rename state file (if it exists)
if ( access ( old_state_path , F_OK ) = = 0 ) {
if ( rename ( old_state_path , new_state_path ) ! = 0 ) {
printf ( " Warning: Failed to rename state file, but pad file was renamed successfully \n " ) ;
// Try to rollback pad file rename
rename ( new_pad_path , old_pad_path ) ;
return 3 ; // State rename failed
}
}
return 0 ; // Success
}
// Update pad checksum after entropy addition
int update_pad_checksum_after_entropy ( const char * old_chksum , char * new_chksum ) {
char pad_path [ 1024 ] ;
snprintf ( pad_path , sizeof ( pad_path ) , " %s/%s.pad " , current_pads_dir , old_chksum ) ;
// Calculate new checksum of the modified pad
if ( calculate_checksum ( pad_path , new_chksum ) ! = 0 ) {
printf ( " Error: Cannot calculate new pad checksum \n " ) ;
return 1 ;
}
// Check if checksum actually changed
if ( strcmp ( old_chksum , new_chksum ) = = 0 ) {
printf ( " Warning: Pad checksum unchanged after entropy addition \n " ) ;
return 2 ; // Checksum didn't change (unusual but not fatal)
}
// Rename pad files to use new checksum
if ( rename_pad_files_safely ( old_chksum , new_chksum ) ! = 0 ) {
return 3 ; // Rename failed
}
// Update default pad preference if this was the default pad
char * current_default = get_default_pad_path ( ) ;
if ( current_default ) {
// Check if the old pad was the default
if ( strstr ( current_default , old_chksum ) ) {
// Update to new checksum
char new_default_path [ 1024 ] ;
snprintf ( new_default_path , sizeof ( new_default_path ) , " %s/%s.pad " , current_pads_dir , new_chksum ) ;
if ( set_default_pad_path ( new_default_path ) ! = 0 ) {
printf ( " Warning: Failed to update default pad preference \n " ) ;
} else {
printf ( " Updated default pad to new checksum: %.16s... \n " , new_chksum ) ;
}
}
free ( current_default ) ;
}
return 0 ; // Success
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// UNIVERSAL CORE FUNCTIONS FOR CODE CONSOLIDATION
@@ -3045,7 +3058,7 @@ int generate_ascii_armor(const char* chksum, uint64_t offset, const unsigned cha
strcpy ( * ascii_output , " -----BEGIN OTP MESSAGE----- \n " ) ;
char temp_line [ 256 ] ;
snprintf ( temp_line , sizeof ( temp_line ) , " Version: %s \n " , get_version ( ) ) ;
snprintf ( temp_line , sizeof ( temp_line ) , " Version: v1.0.0 \n " ) ;
strcat ( * ascii_output , temp_line ) ;
snprintf ( temp_line , sizeof ( temp_line ) , " Pad-ChkSum: %s \n " , chksum ) ;
@@ -3182,7 +3195,10 @@ int universal_decrypt(const char* input_data, const char* output_target, decrypt
printf ( " Error: Required pad not found: %s \n " , stored_chksum ) ;
if ( mode = = DECRYPT_MODE_INTERACTIVE | | mode = = DECRYPT_MODE_FILE_TO_TEXT ) {
printf ( " Available pads: \n " ) ;
list_available_pads ( ) ;
char * selected = select_pad_interactive ( " Available pads: " , " Available pads (press Enter to continue) " , PAD_FILTER_ALL , 0 ) ;
if ( selected ) {
free ( selected ) ;
}
}
}
return 1 ;
@@ -3705,22 +3721,18 @@ int handle_text_encrypt(void) {
return 1 ;
}
// List available pads and get selection
int pad_count = list_available_pads ( ) ;
if ( pad_count = = 0 ) {
printf ( " No pads available. Generate a pad first. \n " ) ;
// Use unified pad selection
char * selected_pad = select_pad_interactive ( " === Select Pad for Text Encryption === " ,
" Select pad (by prefix) " ,
PAD_FILTER_ALL , 1 ) ;
if ( ! selected_pad ) {
printf ( " Text encryption cancelled. \n " ) ;
return 1 ;
}
printf ( " \n Enter pad selection (number, checksum, or prefix): " ) ;
char pad_input [ MAX_HASH_LENGTH ] ;
if ( ! fgets ( pad_input , sizeof ( pad_input ) , stdin ) ) {
printf ( " Error: Failed to read pad selection \n " ) ;
return 1 ;
}
pad_input [ strcspn ( pad_input , " \n " ) ] = 0 ;
return encrypt_text ( pad_input , text_buffer ) ;
int result = encrypt_text ( selected_pad , text_buffer ) ;
free ( selected_pad ) ;
return result ;
}
int handle_file_encrypt ( void ) {
@@ -3739,21 +3751,15 @@ int handle_file_encrypt(void) {
return 1 ;
}
// List available pads
int pad_count = list_available_pads ( ) ;
if ( pad_count = = 0 ) {
printf ( " No pads available. Generate a pad first. \n " ) ;
// Use unified pad selection
char * selected_pad = select_pad_interactive ( " === Select Pad for File Encryption === " ,
" Select pad (by prefix) " ,
PAD_FILTER_ALL , 1 ) ;
if ( ! selected_pad ) {
printf ( " File encryption cancelled. \n " ) ;
return 1 ;
}
printf ( " \n Enter pad selection (number, checksum, or prefix): " ) ;
char pad_input [ MAX_HASH_LENGTH ] ;
if ( ! fgets ( pad_input , sizeof ( pad_input ) , stdin ) ) {
printf ( " Error: Failed to read pad selection \n " ) ;
return 1 ;
}
pad_input [ strcspn ( pad_input , " \n " ) ] = 0 ;
// Ask for output format
printf ( " \n Select output format: \n " ) ;
printf ( " 1. Binary (.otp) - preserves file permissions \n " ) ;
@@ -3785,10 +3791,258 @@ int handle_file_encrypt(void) {
const char * output_filename = output_file ;
return encrypt_file ( pad_input , input_file , output_filename , ascii_armor ) ;
int result = encrypt_file ( selected_pad , input_file , output_filename , ascii_armor ) ;
free ( selected_pad ) ;
return result ;
}
// Unified pad selection function - extracts the best UI from handle_pads_menu()
char * select_pad_interactive ( const char * title , const char * prompt , pad_filter_type_t filter_type , int allow_cancel ) {
// Get list of pads from current directory
DIR * dir = opendir ( current_pads_dir ) ;
if ( ! dir ) {
printf ( " Error: Cannot open pads directory %s \n " , current_pads_dir ) ;
return NULL ;
}
// Structure to store pad information
struct PadInfo {
char chksum [ 65 ] ;
char size_str [ 32 ] ;
char used_str [ 32 ] ;
double percentage ;
char location [ 256 ] ;
} ;
struct PadInfo pads [ 100 ] ; // Support up to 100 pads
int pad_count = 0 ;
// Collect all pad information
struct dirent * entry ;
while ( ( entry = readdir ( dir ) ) ! = NULL & & pad_count < 100 ) {
if ( strstr ( entry - > d_name , " .pad " ) & & strlen ( entry - > d_name ) = = 68 ) {
strncpy ( pads [ pad_count ] . chksum , entry - > d_name , 64 ) ;
pads [ pad_count ] . chksum [ 64 ] = ' \0 ' ;
// Get pad file size and usage info
char full_path [ 1024 ] ;
snprintf ( full_path , sizeof ( full_path ) , " %s/%s " , current_pads_dir , entry - > d_name ) ;
struct stat st ;
if ( stat ( full_path , & st ) = = 0 ) {
// Get used bytes from state
uint64_t used_bytes ;
read_state_offset ( pads [ pad_count ] . chksum , & used_bytes ) ;
// Apply filter
if ( filter_type = = PAD_FILTER_UNUSED_ONLY & & used_bytes > 32 ) {
continue ; // Skip used pads when filtering for unused only
}
// Format total size
if ( st . st_size < 1024 ) {
snprintf ( pads [ pad_count ] . size_str , sizeof ( pads [ pad_count ] . size_str ) , " %luB " , st . st_size ) ;
} else if ( st . st_size < 1024 * 1024 ) {
snprintf ( pads [ pad_count ] . size_str , sizeof ( pads [ pad_count ] . size_str ) , " %.1fKB " , ( double ) st . st_size / 1024.0 ) ;
} else if ( st . st_size < 1024 * 1024 * 1024 ) {
snprintf ( pads [ pad_count ] . size_str , sizeof ( pads [ pad_count ] . size_str ) , " %.1fMB " , ( double ) st . st_size / ( 1024.0 * 1024.0 ) ) ;
} else {
snprintf ( pads [ pad_count ] . size_str , sizeof ( pads [ pad_count ] . size_str ) , " %.2fGB " , ( double ) st . st_size / ( 1024.0 * 1024.0 * 1024.0 ) ) ;
}
// Format used size
if ( used_bytes < 1024 ) {
snprintf ( pads [ pad_count ] . used_str , sizeof ( pads [ pad_count ] . used_str ) , " %luB " , used_bytes ) ;
} else if ( used_bytes < 1024 * 1024 ) {
snprintf ( pads [ pad_count ] . used_str , sizeof ( pads [ pad_count ] . used_str ) , " %.1fKB " , ( double ) used_bytes / 1024.0 ) ;
} else if ( used_bytes < 1024 * 1024 * 1024 ) {
snprintf ( pads [ pad_count ] . used_str , sizeof ( pads [ pad_count ] . used_str ) , " %.1fMB " , ( double ) used_bytes / ( 1024.0 * 1024.0 ) ) ;
} else {
snprintf ( pads [ pad_count ] . used_str , sizeof ( pads [ pad_count ] . used_str ) , " %.2fGB " , ( double ) used_bytes / ( 1024.0 * 1024.0 * 1024.0 ) ) ;
}
// Calculate percentage
pads [ pad_count ] . percentage = ( double ) used_bytes / st . st_size * 100.0 ;
// Set location info using directory display
get_directory_display ( full_path , pads [ pad_count ] . location , sizeof ( pads [ pad_count ] . location ) ) ;
pad_count + + ;
}
}
}
closedir ( dir ) ;
if ( pad_count = = 0 ) {
printf ( " \n %s \n " , title ) ;
if ( filter_type = = PAD_FILTER_UNUSED_ONLY ) {
printf ( " No unused pads found. \n " ) ;
printf ( " Entropy can only be added to pads with 0%% usage (only reserved bytes used). \n " ) ;
} else {
printf ( " No pads found. \n " ) ;
}
return NULL ;
}
// Calculate minimal unique prefixes for each pad
char prefixes [ 100 ] [ 65 ] ;
int prefix_lengths [ 100 ] ;
for ( int i = 0 ; i < pad_count ; i + + ) {
prefix_lengths [ i ] = 1 ;
// Find minimal unique prefix
while ( prefix_lengths [ i ] < = 64 ) {
int unique = 1 ;
// Check if current prefix is unique among all other pads
for ( int j = 0 ; j < pad_count ; j + + ) {
if ( i ! = j & & strncmp ( pads [ i ] . chksum , pads [ j ] . chksum , prefix_lengths [ i ] ) = = 0 ) {
unique = 0 ;
break ;
}
}
if ( unique ) {
break ;
}
prefix_lengths [ i ] + + ;
}
// Store the minimal prefix
strncpy ( prefixes [ i ] , pads [ i ] . chksum , prefix_lengths [ i ] ) ;
prefixes [ i ] [ prefix_lengths [ i ] ] = ' \0 ' ;
}
// Display title and pads table
printf ( " \n %s \n " , title ) ;
printf ( " %-8s %-2s %-12s %-12s %-12s %-8s \n " , " ChkSum " , " D " , " Dir " , " Size " , " Used " , " % Used " ) ;
printf ( " %-8s %-2s %-12s %-12s %-12s %-8s \n " , " -------- " , " -- " , " ------------ " , " ---------- " , " ---------- " , " ------ " ) ;
// Get current default pad path for comparison
char * current_default = get_default_pad_path ( ) ;
char default_pad_checksum [ 65 ] = " " ;
if ( current_default ) {
// Extract checksum from default pad path
char * filename = strrchr ( current_default , ' / ' ) ;
if ( ! filename ) filename = current_default ;
else filename + + ; // Skip the '/'
// Extract checksum (remove .pad extension)
if ( strlen ( filename ) > = 68 & & strstr ( filename , " .pad " ) ) {
strncpy ( default_pad_checksum , filename , 64 ) ;
default_pad_checksum [ 64 ] = ' \0 ' ;
}
free ( current_default ) ;
}
for ( int i = 0 ; i < pad_count ; i + + ) {
// Check if this is the default pad
int is_default = ( strlen ( default_pad_checksum ) > 0 & &
strncmp ( pads [ i ] . chksum , default_pad_checksum , 64 ) = = 0 ) ;
// Display first 8 characters of checksum with prefix underlined
char checksum_8char [ 9 ] ;
strncpy ( checksum_8char , pads [ i ] . chksum , 8 ) ;
checksum_8char [ 8 ] = ' \0 ' ;
printf ( " \033 [4m%.*s \033 [0m%s %-2s %-12s %-12s %-12s %.1f%% \n " ,
prefix_lengths [ i ] , checksum_8char , // Underlined prefix
checksum_8char + prefix_lengths [ i ] , // Rest of 8-char checksum
is_default ? " * " : " " , // Default indicator
pads [ i ] . location ,
pads [ i ] . size_str ,
pads [ i ] . used_str ,
pads [ i ] . percentage ) ;
}
// Display prompt
printf ( " \n %s " , prompt ) ;
if ( allow_cancel ) {
printf ( " (or 'x' to cancel) " ) ;
}
printf ( " : " ) ;
char input [ MAX_HASH_LENGTH ] ;
if ( ! fgets ( input , sizeof ( input ) , stdin ) ) {
printf ( " Error: Failed to read input \n " ) ;
return NULL ;
}
input [ strcspn ( input , " \n " ) ] = 0 ;
// Handle empty input - select default pad if available
if ( strlen ( input ) = = 0 ) {
// Get current default pad path
char * current_default = get_default_pad_path ( ) ;
if ( current_default ) {
// Extract checksum from default pad path
char * filename = strrchr ( current_default , ' / ' ) ;
if ( ! filename ) filename = current_default ;
else filename + + ; // Skip the '/'
// Extract checksum (remove .pad extension)
if ( strlen ( filename ) > = 68 & & strstr ( filename , " .pad " ) ) {
char default_checksum [ 65 ] ;
strncpy ( default_checksum , filename , 64 ) ;
default_checksum [ 64 ] = ' \0 ' ;
// Verify this default pad is in our current list
for ( int i = 0 ; i < pad_count ; i + + ) {
if ( strncmp ( pads [ i ] . chksum , default_checksum , 64 ) = = 0 ) {
free ( current_default ) ;
printf ( " Selected default pad: %.16s... \n " , default_checksum ) ;
return strdup ( default_checksum ) ;
}
}
}
free ( current_default ) ;
}
// No default pad or default pad not in current list
printf ( " No default pad available or default pad not in current list \n " ) ;
return NULL ;
}
// Handle cancel
if ( allow_cancel & & ( toupper ( input [ 0 ] ) = = ' X ' & & strlen ( input ) = = 1 ) ) {
return NULL ;
}
// Find matching pad by prefix or number
int selected_pad = - 1 ;
int match_count = 0 ;
// Check if input is a number first
char * endptr ;
int selection = strtol ( input , & endptr , 10 ) ;
if ( * endptr = = ' \0 ' & & selection > = 1 & & selection < = pad_count ) {
// Valid number selection
selected_pad = selection - 1 ;
match_count = 1 ;
} else {
// Try prefix matching
for ( int i = 0 ; i < pad_count ; i + + ) {
if ( strncmp ( input , pads [ i ] . chksum , strlen ( input ) ) = = 0 ) {
if ( match_count = = 0 ) {
selected_pad = i ;
}
match_count + + ;
}
}
}
if ( match_count = = 0 ) {
printf ( " No pad found matching '%s' \n " , input ) ;
return NULL ;
} else if ( match_count > 1 ) {
printf ( " Ambiguous prefix. Multiple matches found. \n " ) ;
return NULL ;
}
// Return selected pad checksum (caller must free)
return strdup ( pads [ selected_pad ] . chksum ) ;
}
int handle_pads_menu ( void ) {
printf ( " \n === Pad Management === \n " ) ;
@@ -3915,8 +4169,8 @@ int handle_pads_menu(void) {
// Display pads with minimal prefixes underlined and default indicator
printf ( " \n Available pads: \n " ) ;
printf ( " %-7 s %-8 s %-12s %-12s %-12s %-8s \n " , " Default " , " ChkSum " , " Dir " , " Size " , " Used " , " % Used " ) ;
printf ( " %-7 s %-8 s %-12s %-12s %-12s %-8s \n " , " ------- " , " -------- " , " ------------ " , " ---------- " , " ---------- " , " ------ " ) ;
printf ( " %-8 s %-2 s %-12s %-12s %-12s %-8s \n " , " ChkSum " , " D " , " Dir " , " Size " , " Used " , " % Used " ) ;
printf ( " %-8 s %-2 s %-12s %-12s %-12s %-8s \n " , " -------- " , " -- " , " ------------ " , " ---------- " , " ---------- " , " ------ " ) ;
// Get current default pad path for comparison
char * current_default = get_default_pad_path ( ) ;
@@ -3946,10 +4200,10 @@ int handle_pads_menu(void) {
strncpy ( checksum_8char , pads [ i ] . chksum , 8 ) ;
checksum_8char [ 8 ] = ' \0 ' ;
printf ( " %-7s \033 [4m%.*s \033 [0m%s %-12s %-12s %-12s %.1f%% \n " ,
is_default ? " * " : " " , // Default indicator
printf ( " \033 [4m%.*s \033 [0m%s %-2s %-12s %-12s %-12s %.1f%% \n " ,
prefix_lengths [ i ] , checksum_8char , // Underlined prefix
checksum_8char + prefix_lengths [ i ] , // Rest of 8-char checksum
is_default ? " * " : " " , // Default indicator
pads [ i ] . location , // Use the stored location info
pads [ i ] . size_str ,
pads [ i ] . used_str ,
@@ -3958,9 +4212,10 @@ int handle_pads_menu(void) {
printf ( " \n Actions: \n " ) ;
printf ( " \033 [4mG \033 [0menerate new pad \n " ) ;
printf ( " \033 [4mA \033 [0mdd entropy to pad \n " ) ;
printf ( " \033 [4mS \033 [0met default pad \n " ) ;
printf ( " E \033 [4mx \033 [0mit \n " ) ;
printf ( " \n Select pad (by prefix) or action : " ) ;
printf ( " \n Select pad (by prefix): " ) ;
char input [ MAX_HASH_LENGTH ] ;
if ( ! fgets ( input , sizeof ( input ) , stdin ) ) {
@@ -3977,32 +4232,31 @@ int handle_pads_menu(void) {
return handle_pads_menu ( ) ;
}
return result ;
} else if ( toupper ( input [ 0 ] ) = = ' S ' ) {
// Set default pad
printf ( " \n Select pad to set as default (by prefix): " ) ;
char pad_input [ MAX_HASH_LENGTH ] ;
if ( ! fgets ( pad_input , sizeof ( pad_input ) , stdin ) ) {
printf ( " Error: Failed to read input \n " ) ;
return 1 ;
}
pad_input [ strcspn ( pad_input , " \n " ) ] = 0 ;
// Find matching pad by prefix using the same logic as pad selection
int matched_pad = - 1 ;
int match_count = 0 ;
for ( int i = 0 ; i < pad_count ; i + + ) {
if ( strncmp ( pad_input , pads [ i ] . chksum , strlen ( pad_input ) ) = = 0 ) {
matched_pad = i ;
match_count + + ;
}
}
if ( match_count = = 0 ) {
printf ( " No pad found matching prefix '%s' \n " , pad_input ) ;
} else if ( toupper ( input [ 0 ] ) = = ' A ' ) {
// Add entropy to pad - use unified function with unused pads filter
char * selected_pad = select_pad_interactive ( " === Select Unused Pad for Entropy Addition === " ,
" Select unused pad (by prefix or number) " ,
PAD_FILTER_UNUSED_ONLY , 1 ) ;
if ( ! selected_pad ) {
printf ( " Entropy addition cancelled. \n " ) ;
return handle_pads_menu ( ) ;
} else if ( match_count > 1 ) {
printf ( " Ambiguous prefix. Multiple matches found. \n " ) ;
}
// Add entropy to the selected unused pad
int result = handle_add_entropy_to_pad ( selected_pad ) ;
free ( selected_pad ) ;
if ( result = = 0 ) {
// Return to pads menu after successful entropy addition
return handle_pads_menu ( ) ;
}
return result ;
} else if ( toupper ( input [ 0 ] ) = = ' S ' ) {
// Set default pad - use unified function
char * selected_pad = select_pad_interactive ( " === Select Default Pad === " ,
" Select pad to set as default (by prefix) " ,
PAD_FILTER_ALL , 1 ) ;
if ( ! selected_pad ) {
printf ( " Default pad selection cancelled. \n " ) ;
return handle_pads_menu ( ) ;
}
@@ -4010,41 +4264,45 @@ int handle_pads_menu(void) {
char new_default_path [ 1024 ] ;
if ( current_pads_dir [ 0 ] = = ' / ' ) {
// Already absolute path
int ret = snprintf ( new_default_path , sizeof ( new_default_path ) , " %s/%s.pad " , current_pads_dir , pads [ matched_pad ] . chksum ) ;
int ret = snprintf ( new_default_path , sizeof ( new_default_path ) , " %s/%s.pad " , current_pads_dir , selected_pad ) ;
if ( ret > = ( int ) sizeof ( new_default_path ) ) {
printf ( " Error: Path too long for default pad setting \n " ) ;
free ( selected_pad ) ;
return handle_pads_menu ( ) ;
}
} else {
// Relative path - make it absolute
char current_dir [ 512 ] ;
if ( getcwd ( current_dir , sizeof ( current_dir ) ) ) {
int ret = snprintf ( new_default_path , sizeof ( new_default_path ) , " %s/%s/%s.pad " , current_dir , current_pads_dir , pads [ matched_pad ] . chksum ) ;
int ret = snprintf ( new_default_path , sizeof ( new_default_path ) , " %s/%s/%s.pad " , current_dir , current_pads_dir , selected_pad ) ;
if ( ret > = ( int ) sizeof ( new_default_path ) ) {
// Path was truncated, fall back to relative path
int ret2 = snprintf ( new_default_path , sizeof ( new_default_path ) , " %s/%s.pad " , current_pads_dir , pads [ matched_pad ] . chksum ) ;
int ret2 = snprintf ( new_default_path , sizeof ( new_default_path ) , " %s/%s.pad " , current_pads_dir , selected_pad ) ;
if ( ret2 > = ( int ) sizeof ( new_default_path ) ) {
printf ( " Error: Path too long for default pad setting \n " ) ;
free ( selected_pad ) ;
return handle_pads_menu ( ) ;
}
}
} else {
// Fallback to relative path
int ret = snprintf ( new_default_path , sizeof ( new_default_path ) , " %s/%s.pad " , current_pads_dir , pads [ matched_pad ] . chksum ) ;
int ret = snprintf ( new_default_path , sizeof ( new_default_path ) , " %s/%s.pad " , current_pads_dir , selected_pad ) ;
if ( ret > = ( int ) sizeof ( new_default_path ) ) {
printf ( " Error: Path too long for default pad setting \n " ) ;
free ( selected_pad ) ;
return handle_pads_menu ( ) ;
}
}
}
if ( set_default_pad_path ( new_default_path ) = = 0 ) {
printf ( " Default pad set to: %.16s... \n " , pads [ matched_pad ] . chksum ) ;
printf ( " Default pad set to: %.16s... \n " , selected_pad ) ;
printf ( " Full path: %s \n " , new_default_path ) ;
} else {
printf ( " Error: Failed to update default pad preference \n " ) ;
}
free ( selected_pad ) ;
return handle_pads_menu ( ) ;
} else if ( toupper ( input [ 0 ] ) = = ' X ' ) {
return 0 ; // Exit to main menu
@@ -4326,8 +4584,8 @@ int handle_add_entropy_to_pad(const char* pad_chksum) {
}
void print_usage ( const char * program_name ) {
printf ( " OTP Cipher - One Time Pad Implementation %s \n " , get_version ( ) ) ;
printf ( " %s \n " , get_build_info ( ) ) ;
printf ( " OTP Cipher - One Time Pad Implementation v1.0.0 \n " ) ;
printf ( " Built for testing entropy system \n " ) ;
printf ( " Usage: \n " ) ;
printf ( " %s - Interactive mode \n " , program_name ) ;
printf ( " %s generate|-g <size> - Generate new pad \n " , program_name ) ;