diff --git a/otp-arm64 b/otp-arm64 index 13dde59..9458558 100755 Binary files a/otp-arm64 and b/otp-arm64 differ diff --git a/otp-x86_64 b/otp-x86_64 index 3209a90..9204611 100755 Binary files a/otp-x86_64 and b/otp-x86_64 differ diff --git a/otp.c b/otp.c index ba57073..e5953a6 100644 --- a/otp.c +++ b/otp.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -44,7 +45,6 @@ static const int base64_decode_table[256] = { #define PROGRESS_UPDATE_INTERVAL (64 * 1024 * 1024) // 64MB intervals #define DEFAULT_PADS_DIR "pads" #define FILES_DIR "files" -#define MAX_ENTROPY_BUFFER (4 * 1024 * 1024) // 4MB entropy buffer for large operations //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -56,6 +56,60 @@ static char current_pads_dir[512] = DEFAULT_PADS_DIR; static char default_pad_path[1024] = ""; static int is_interactive_mode = 0; +// Terminal dimensions +static int terminal_width = 80; // Default fallback width +static int terminal_height = 24; // Default fallback height + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// TERMINAL UI FUNCTIONS +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// Initialize terminal dimensions +void init_terminal_dimensions(void) { + struct winsize ws; + + // Try to get actual terminal size + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 && ws.ws_col > 0 && ws.ws_row > 0) { + terminal_width = ws.ws_col; + terminal_height = ws.ws_row; + } + // If ioctl fails, keep the default values (80x24) +} + +// Print centered header with = padding +void print_centered_header(const char* text) { + if (!text) return; + + int text_len = strlen(text); + int available_width = terminal_width; + + // Ensure minimum spacing: at least 1 space on each side + int min_required = text_len + 4; // text + " " + text + " " (spaces around text) + + if (available_width < min_required) { + // Terminal too narrow - just print the text with minimal formatting + printf("=== %s ===\n", text); + return; + } + + // Calculate padding + int total_padding = available_width - text_len - 2; // -2 for spaces around text + int left_padding = total_padding / 2; + int right_padding = total_padding - left_padding; + + // Print the header + for (int i = 0; i < left_padding; i++) { + printf("="); + } + printf(" %s ", text); + for (int i = 0; i < right_padding; i++) { + printf("="); + } + printf("\n"); +} + //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // MAIN @@ -63,7 +117,10 @@ static int is_interactive_mode = 0; //////////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { - // Load preferences first + // Initialize terminal dimensions first + init_terminal_dimensions(); + + // Load preferences load_preferences(); // Detect interactive mode: only true when running with no arguments @@ -329,9 +386,9 @@ int interactive_mode(void) { void show_main_menu(void) { - - - printf("\n=========================== Main Menu - OTP v0.3.9 ===========================\n\n"); + printf("\n"); + print_centered_header("Main Menu - OTP v0.3.10"); + printf("\n"); printf(" \033[4mT\033[0mext encrypt\n"); //TEXT ENCRYPT printf(" \033[4mF\033[0mile encrypt\n"); //FILE ENCRYPT @@ -342,7 +399,8 @@ void show_main_menu(void) { } int handle_generate_menu(void) { - printf("\n=== Generate New Pad ===\n"); + printf("\n"); + print_centered_header("Generate New Pad"); printf("Enter pad size (examples: 1GB, 5TB, 512MB, 2048): "); char size_input[64]; @@ -367,7 +425,8 @@ int handle_generate_menu(void) { } int handle_encrypt_menu(void) { - printf("\n=== Encrypt Data ===\n"); + printf("\n"); + print_centered_header("Encrypt Data"); printf("Available pads:\n"); char* selected = select_pad_interactive("Available pads:", "Select pad (or press Enter to continue)", PAD_FILTER_ALL, 0); @@ -398,7 +457,7 @@ int handle_encrypt_menu(void) { if (choice == 1) { // Text encryption - use unified pad selection - char* selected_pad = select_pad_interactive("=== Select Pad for Text Encryption ===", + char* selected_pad = select_pad_interactive("Select Pad for Text Encryption", "Select pad (by prefix)", PAD_FILTER_ALL, 1); if (!selected_pad) { @@ -453,7 +512,7 @@ int handle_encrypt_menu(void) { } // Use unified pad selection - char* selected_pad = select_pad_interactive("=== Select Pad for File Encryption ===", + char* selected_pad = select_pad_interactive("Select Pad for File Encryption", "Select pad (by prefix)", PAD_FILTER_ALL, 1); if (!selected_pad) { @@ -508,7 +567,8 @@ int handle_encrypt_menu(void) { } int handle_decrypt_menu(void) { - printf("\n=== Smart Decrypt ===\n"); + printf("\n"); + print_centered_header("Smart Decrypt"); printf("Enter encrypted data (paste ASCII armor), file path, or press Enter to browse files:\n"); char input_line[MAX_LINE_LENGTH]; @@ -742,7 +802,7 @@ int show_pad_info(const char* chksum) { uint64_t used_bytes; read_state_offset(chksum, &used_bytes); - printf("=== Pad Information ===\n"); + print_centered_header("Pad Information"); printf("ChkSum: %s\n", chksum); printf("File: %s\n", pad_filename); @@ -1797,6 +1857,136 @@ void get_default_file_path(const char* filename, char* result_path, size_t resul snprintf(result_path, result_size, "%s/%s", files_dir, filename); } +void get_directory_display(const char* file_path, char* result, size_t result_size) { + // Extract directory path from full file path + char dir_path[512]; + char* last_slash = strrchr(file_path, '/'); + + if (last_slash) { + size_t dir_len = last_slash - file_path; + if (dir_len >= sizeof(dir_path)) { + dir_len = sizeof(dir_path) - 1; + } + strncpy(dir_path, file_path, dir_len); + dir_path[dir_len] = '\0'; + } else { + // No directory separator, assume current directory + strcpy(dir_path, "."); + } + + // USB Drive Detection and Smart Shortening + char* home_dir = getenv("HOME"); + + // Check for USB/removable media mount patterns + if (strstr(dir_path, "/media/") || strstr(dir_path, "/run/media/") || strstr(dir_path, "/mnt/")) { + // Extract USB label/name + char* media_start = NULL; + if (strstr(dir_path, "/media/")) { + media_start = strstr(dir_path, "/media/"); + } else if (strstr(dir_path, "/run/media/")) { + media_start = strstr(dir_path, "/run/media/"); + } else if (strstr(dir_path, "/mnt/")) { + media_start = strstr(dir_path, "/mnt/"); + } + + if (media_start) { + // Find the USB label part + char* path_after_media = strchr(media_start + 1, '/'); + if (path_after_media) { + path_after_media++; // Skip the slash + + // For /media/user/LABEL pattern, skip the username to get to the drive label + if (strstr(media_start, "/media/")) { + char* next_slash = strchr(path_after_media, '/'); + if (next_slash) { + path_after_media = next_slash + 1; + } + } + // For /run/media/user/LABEL pattern, skip the username + else if (strstr(media_start, "/run/media/")) { + char* next_slash = strchr(path_after_media, '/'); + if (next_slash) { + path_after_media = next_slash + 1; + } + } + + // Extract just the USB label (up to next slash or end) + char* label_end = strchr(path_after_media, '/'); + char usb_label[32]; + if (label_end) { + size_t label_len = label_end - path_after_media; + if (label_len > sizeof(usb_label) - 1) label_len = sizeof(usb_label) - 1; + strncpy(usb_label, path_after_media, label_len); + usb_label[label_len] = '\0'; + } else { + // USB label is the last part + strncpy(usb_label, path_after_media, sizeof(usb_label) - 1); + usb_label[sizeof(usb_label) - 1] = '\0'; + } + + // Format with USB: prefix, limiting total length to fit in result + snprintf(result, result_size, "USB:%s", usb_label); + // Truncate if too long + if (strlen(result) > 11) { + result[11] = '\0'; + } + return; + } + } + } + + // Home directory shortening + if (home_dir && strncmp(dir_path, home_dir, strlen(home_dir)) == 0) { + if (dir_path[strlen(home_dir)] == '/' || dir_path[strlen(home_dir)] == '\0') { + // Replace home directory with ~ + char temp[512]; + snprintf(temp, sizeof(temp), "~%s", dir_path + strlen(home_dir)); + + // If result is too long, truncate intelligently + if (strlen(temp) > 11) { + // Show ~/...end_part + char* last_part = strrchr(temp, '/'); + if (last_part && strlen(last_part) < 8) { + snprintf(result, result_size, "~...%s", last_part); + } else { + strncpy(result, temp, 11); + result[11] = '\0'; + } + } else { + strncpy(result, temp, result_size - 1); + result[result_size - 1] = '\0'; + } + return; + } + } + + // Current working directory + if (strcmp(dir_path, ".") == 0 || strcmp(dir_path, current_pads_dir) == 0) { + strncpy(result, "pads", result_size - 1); + result[result_size - 1] = '\0'; + return; + } + + // System/other paths - smart truncation with ellipsis + if (strlen(dir_path) > 11) { + // Try to show the most meaningful part + char* last_part = strrchr(dir_path, '/'); + if (last_part && strlen(last_part) < 9) { + // Show .../last_part + snprintf(result, result_size, "...%s", last_part); + } else { + // Show first part with ellipsis + strncpy(result, dir_path, 8); + strncpy(result + 8, "...", result_size - 8 - 1); + result[result_size - 1] = '\0'; + } + } else { + // Short enough, use as-is + strncpy(result, dir_path, result_size - 1); + result[result_size - 1] = '\0'; + } +} + void get_pad_path(const char* chksum, char* pad_path, char* state_path) { snprintf(pad_path, 1024, "%s/%s.pad", current_pads_dir, chksum); snprintf(state_path, 1024, "%s/%s.state", current_pads_dir, chksum); @@ -2186,36 +2376,9 @@ int detect_otp_thumb_drive(char* otp_drive_path, size_t path_size) { -// To be removed -// Format file size for display -// void format_size_string(uint64_t bytes, char* result, size_t result_size) { -// if (bytes == 0) { -// strncpy(result, "Unknown", result_size - 1); -// result[result_size - 1] = '\0'; -// return; -// } - -// if (bytes < 1024) { -// snprintf(result, result_size, "%luB", bytes); -// } else if (bytes < 1024 * 1024) { -// snprintf(result, result_size, "%.1fKB", (double)bytes / 1024.0); -// } else if (bytes < 1024 * 1024 * 1024) { -// snprintf(result, result_size, "%.1fMB", (double)bytes / (1024.0 * 1024.0)); -// } else if (bytes < 1024ULL * 1024 * 1024 * 1024) { -// snprintf(result, result_size, "%.2fGB", (double)bytes / (1024.0 * 1024.0 * 1024.0)); -// } else { -// snprintf(result, result_size, "%.2fTB", (double)bytes / (1024.0 * 1024.0 * 1024.0 * 1024.0)); -// } -// } - - - - // Custom base64 encode function - - char* custom_base64_encode(const unsigned char* input, int length) { int output_length = 4 * ((length + 2) / 3); char* encoded = malloc(output_length + 1); @@ -2551,6 +2714,21 @@ int collect_truerng_entropy(unsigned char* entropy_buffer, size_t target_bytes, return 0; // Success } +// Helper function to format time in human-readable format +void format_time_remaining(double seconds, char* buffer, size_t buffer_size) { + if (seconds < 60) { + snprintf(buffer, buffer_size, "%.0fs", seconds); + } else if (seconds < 3600) { + int mins = (int)(seconds / 60); + int secs = (int)(seconds) % 60; + snprintf(buffer, buffer_size, "%dm %02ds", mins, secs); + } else { + int hours = (int)(seconds / 3600); + int mins = (int)(seconds / 60) % 60; + snprintf(buffer, buffer_size, "%dh %02dm", hours, mins); + } +} + // Streaming TrueRNG entropy collection for full pad enhancement // This function applies entropy directly to the pad in chunks to avoid memory issues int collect_truerng_entropy_streaming(const char* pad_chksum, size_t total_bytes, int display_progress) { @@ -2586,6 +2764,85 @@ int collect_truerng_entropy_streaming(const char* pad_chksum, size_t total_bytes return 2; // Serial port setup failed } + // For large pads (>10MB), do a 1MB test to estimate completion time + double estimated_rate = 0.0; + int user_confirmed = 1; // Default to confirmed for small pads + + if (total_bytes > 10 * 1024 * 1024 && display_progress) { + printf("\nLarge pad detected (%.1f MB). Running 1MB speed test...\n", + (double)total_bytes / (1024.0 * 1024.0)); + + // Test with 1MB sample + size_t test_bytes = 1024 * 1024; // 1MB + unsigned char* test_buffer = malloc(test_bytes); + if (!test_buffer) { + printf("Error: Cannot allocate test buffer\n"); + close(serial_fd); + return 3; + } + + time_t test_start = time(NULL); + size_t test_collected = 0; + + while (test_collected < test_bytes) { + size_t bytes_needed = test_bytes - test_collected; + size_t read_size = (bytes_needed > 1024) ? 1024 : bytes_needed; + + ssize_t result = read(serial_fd, test_buffer + test_collected, read_size); + if (result <= 0) { + printf("Error: TrueRNG test failed\n"); + free(test_buffer); + close(serial_fd); + return 4; + } + test_collected += result; + + // Show test progress + double test_progress = (double)test_collected / test_bytes * 100.0; + printf("\rSpeed test: %.1f%% complete", test_progress); + fflush(stdout); + } + + double test_time = difftime(time(NULL), test_start); + estimated_rate = (double)test_bytes / test_time; // bytes per second + + // Calculate estimated total time + double estimated_total_time = (double)total_bytes / estimated_rate; + + char time_str[64]; + format_time_remaining(estimated_total_time, time_str, sizeof(time_str)); + + printf("\nSpeed test complete: %.1f KB/s\n", estimated_rate / 1024.0); + printf("Estimated completion time: %s\n", time_str); + printf("\nProceed with full pad enhancement? (y/N): "); + fflush(stdout); + + char response[10]; + if (fgets(response, sizeof(response), stdin) == NULL || + (response[0] != 'y' && response[0] != 'Y')) { + printf("Operation cancelled by user.\n"); + free(test_buffer); + close(serial_fd); + return 5; // User cancelled + } + + user_confirmed = 1; + free(test_buffer); + + // Reset serial port for main operation + close(serial_fd); + serial_fd = setup_truerng_serial_port(port_path); + if (serial_fd < 0) { + printf("Error: Cannot reopen TrueRNG device\n"); + return 6; + } + } + + if (!user_confirmed) { + close(serial_fd); + return 5; // User cancelled + } + // Get pad paths char pad_path[1024]; char state_path[1024]; @@ -2762,12 +3019,54 @@ int collect_truerng_entropy_streaming(const char* pad_chksum, size_t total_bytes bytes_processed += current_chunk_size; - // Show progress for large pads - if (display_progress && bytes_processed % (64 * 1024 * 1024) == 0) { // Every 64MB - double percentage = (double)bytes_processed / total_bytes * 100.0; - printf("Progress: %.1f%% (%zu/%zu MB)\r", percentage, - bytes_processed / (1024*1024), total_bytes / (1024*1024)); - fflush(stdout); + // Show progress and entropy samples for visual verification + if (display_progress) { + // Update progress more frequently for better user experience - always show cumulative amount + if (bytes_processed % (4 * 1024 * 1024) == 0 || bytes_processed == total_bytes) { // Every 4MB or at completion + double percentage = (double)bytes_processed / total_bytes * 100.0; + double elapsed = difftime(time(NULL), start_time); + double rate = 0.0; + if (elapsed > 0) { + rate = (double)bytes_processed / elapsed / (1024.0 * 1024.0); + } + + // Calculate estimated time remaining + char eta_str[64] = ""; + if (rate > 0.0 && bytes_processed < total_bytes) { + double remaining_bytes = (double)(total_bytes - bytes_processed); + double eta_seconds = remaining_bytes / (rate * 1024.0 * 1024.0); // Convert rate back to bytes/sec + format_time_remaining(eta_seconds, eta_str, sizeof(eta_str)); + } + + // Clear previous line and show progress bar with cumulative TrueRNG data generated + printf("\r\033[K"); // Clear line + printf("["); + int bar_width = 30; + int filled = (int)(percentage / 100.0 * bar_width); + for (int i = 0; i < filled; i++) printf("ā–ˆ"); + for (int i = filled; i < bar_width; i++) printf("ā–‘"); + + if (strlen(eta_str) > 0) { + printf("] %.1f%% - TrueRNG: %zu MB / %zu MB (%.1f MB/s) ETA: %s", + percentage, bytes_processed / (1024*1024), total_bytes / (1024*1024), rate, eta_str); + } else { + printf("] %.1f%% - TrueRNG: %zu MB / %zu MB (%.1f MB/s)", + percentage, bytes_processed / (1024*1024), total_bytes / (1024*1024), rate); + } + fflush(stdout); + } + + // Show entropy samples every 64MB for visual verification of randomness + if (bytes_processed % (64 * 1024 * 1024) == 0 && bytes_processed > 0) { + printf("\nšŸ”¬ TrueRNG entropy sample: "); + // Display first 16 bytes of current entropy chunk as hex + size_t sample_size = (current_chunk_size < 16) ? current_chunk_size : 16; + for (size_t i = 0; i < sample_size; i++) { + printf("%02x", entropy_chunk[i]); + if (i == 7) printf(" "); // Space in middle for readability + } + printf("\n"); + } } } @@ -2805,7 +3104,7 @@ int collect_truerng_entropy_streaming(const char* pad_chksum, size_t total_bytes int collect_dice_entropy(unsigned char* entropy_buffer, size_t target_bytes, size_t* collected_bytes, int display_progress) { if (display_progress) { - printf("=== Dice Entropy Collection ===\n"); + print_centered_header("Dice Entropy Collection"); printf("Enter dice rolls as sequences of digits 1-6.\n"); printf("Target: %zu bytes (%zu dice rolls needed)\n", target_bytes, target_bytes * 4); printf("Press Enter after each sequence, or 'done' when finished.\n\n"); @@ -3493,7 +3792,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: v0.3.9\n"); + snprintf(temp_line, sizeof(temp_line), "Version: v0.3.10\n"); strcat(*ascii_output, temp_line); snprintf(temp_line, sizeof(temp_line), "Pad-ChkSum: %s\n", chksum); @@ -4157,7 +4456,8 @@ int launch_file_manager(const char* start_directory, char* selected_file, size_t } int handle_text_encrypt(void) { - printf("\n=== Text Encrypt ===\n"); + printf("\n"); + print_centered_header("Text Encrypt"); // Launch text editor directly char text_buffer[MAX_INPUT_SIZE]; @@ -4172,7 +4472,7 @@ int handle_text_encrypt(void) { } // Use unified pad selection - char* selected_pad = select_pad_interactive("=== Select Pad for Text Encryption ===", + char* selected_pad = select_pad_interactive("Select Pad for Text Encryption", "Select pad (by prefix)", PAD_FILTER_ALL, 1); if (!selected_pad) { @@ -4186,7 +4486,8 @@ int handle_text_encrypt(void) { } int handle_file_encrypt(void) { - printf("\n=== File Encrypt ===\n"); + printf("\n"); + print_centered_header("File Encrypt"); // Launch file manager directly char input_file[512]; @@ -4202,7 +4503,7 @@ int handle_file_encrypt(void) { } // Use unified pad selection - char* selected_pad = select_pad_interactive("=== Select Pad for File Encryption ===", + char* selected_pad = select_pad_interactive("Select Pad for File Encryption", "Select pad (by prefix)", PAD_FILTER_ALL, 1); if (!selected_pad) { @@ -4373,7 +4674,7 @@ char* select_pad_interactive(const char* title, const char* prompt, pad_filter_t 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)); + get_directory_display(full_path, pads[pad_count].location, sizeof(pads[pad_count].location)); pad_count++; } @@ -4543,7 +4844,8 @@ char* select_pad_interactive(const char* title, const char* prompt, pad_filter_t } int handle_pads_menu(void) { - printf("\n=== Pad Management ===\n"); + printf("\n"); + print_centered_header("Pad Management"); // Get list of pads from current directory DIR* dir = opendir(current_pads_dir); @@ -4606,7 +4908,7 @@ int handle_pads_menu(void) { 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)); + get_directory_display(full_path, pads[pad_count].location, sizeof(pads[pad_count].location)); pad_count++; } @@ -4712,6 +5014,8 @@ int handle_pads_menu(void) { printf("\nActions:\n"); printf(" \033[4mG\033[0menerate new pad\n"); printf(" \033[4mA\033[0mdd entropy to pad\n"); + printf(" \033[4mV\033[0merify pad integrity\n"); + printf(" \033[4mD\033[0melete pad\n"); printf(" \033[4mS\033[0met default pad\n"); printf(" E\033[4mx\033[0mit\n"); printf("\nSelect action: "); @@ -4733,7 +5037,7 @@ int handle_pads_menu(void) { return result; } 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 ===", + char* selected_pad = select_pad_interactive("Select Unused Pad for Entropy Addition", "Select unused pad (by prefix)", PAD_FILTER_UNUSED_ONLY, 1); if (!selected_pad) { @@ -4749,9 +5053,37 @@ int handle_pads_menu(void) { return handle_pads_menu(); } return result; + } else if (toupper(input[0]) == 'V') { + // Verify pad integrity - use unified function + char* selected_pad = select_pad_interactive("Select Pad for Verification", + "Select pad to verify (by prefix)", + PAD_FILTER_ALL, 1); + if (!selected_pad) { + printf("Pad verification cancelled.\n"); + return handle_pads_menu(); + } + + // Verify the selected pad + handle_verify_pad(selected_pad); + free(selected_pad); + return handle_pads_menu(); // Always return to pads menu after verification + } else if (toupper(input[0]) == 'D') { + // Delete pad - use unified function + char* selected_pad = select_pad_interactive("Select Pad for Deletion", + "Select pad to delete (by prefix)", + PAD_FILTER_ALL, 1); + if (!selected_pad) { + printf("Pad deletion cancelled.\n"); + return handle_pads_menu(); + } + + // Delete the selected pad + handle_delete_pad(selected_pad); + free(selected_pad); + return handle_pads_menu(); // Always return to pads menu after deletion attempt } else if (toupper(input[0]) == 'S') { // Set default pad - use unified function - char* selected_pad = select_pad_interactive("=== Select Default Pad ===", + char* selected_pad = select_pad_interactive("Select Default Pad", "Select pad to set as default (by prefix)", PAD_FILTER_ALL, 1); if (!selected_pad) { @@ -4811,139 +5143,11 @@ int handle_pads_menu(void) { } } -// To be removed -// void get_directory_display(const char* file_path, char* result, size_t result_size) { -// // Extract directory path from full file path -// char dir_path[512]; -// char* last_slash = strrchr(file_path, '/'); - -// if (last_slash) { -// size_t dir_len = last_slash - file_path; -// if (dir_len >= sizeof(dir_path)) { -// dir_len = sizeof(dir_path) - 1; -// } -// strncpy(dir_path, file_path, dir_len); -// dir_path[dir_len] = '\0'; -// } else { -// // No directory separator, assume current directory -// strcpy(dir_path, "."); -// } - -// // USB Drive Detection and Smart Shortening -// char* home_dir = getenv("HOME"); - -// // Check for USB/removable media mount patterns -// if (strstr(dir_path, "/media/") || strstr(dir_path, "/run/media/") || strstr(dir_path, "/mnt/")) { -// // Extract USB label/name -// char* media_start = NULL; -// if (strstr(dir_path, "/media/")) { -// media_start = strstr(dir_path, "/media/"); -// } else if (strstr(dir_path, "/run/media/")) { -// media_start = strstr(dir_path, "/run/media/"); -// } else if (strstr(dir_path, "/mnt/")) { -// media_start = strstr(dir_path, "/mnt/"); -// } - -// if (media_start) { -// // Find the USB label part -// char* path_after_media = strchr(media_start + 1, '/'); -// if (path_after_media) { -// path_after_media++; // Skip the slash - -// // For /media/user/LABEL pattern, skip the username to get to the drive label -// if (strstr(media_start, "/media/")) { -// char* next_slash = strchr(path_after_media, '/'); -// if (next_slash) { -// path_after_media = next_slash + 1; -// } -// } -// // For /run/media/user/LABEL pattern, skip the username -// else if (strstr(media_start, "/run/media/")) { -// char* next_slash = strchr(path_after_media, '/'); -// if (next_slash) { -// path_after_media = next_slash + 1; -// } -// } - -// // Extract just the USB label (up to next slash or end) -// char* label_end = strchr(path_after_media, '/'); -// char usb_label[32]; -// if (label_end) { -// size_t label_len = label_end - path_after_media; -// if (label_len > sizeof(usb_label) - 1) label_len = sizeof(usb_label) - 1; -// strncpy(usb_label, path_after_media, label_len); -// usb_label[label_len] = '\0'; -// } else { -// // USB label is the last part -// strncpy(usb_label, path_after_media, sizeof(usb_label) - 1); -// usb_label[sizeof(usb_label) - 1] = '\0'; -// } - -// // Format with USB: prefix, limiting total length to fit in result -// snprintf(result, result_size, "USB:%s", usb_label); -// // Truncate if too long -// if (strlen(result) > 11) { -// result[11] = '\0'; -// } -// return; -// } -// } -// } - -// // Home directory shortening -// if (home_dir && strncmp(dir_path, home_dir, strlen(home_dir)) == 0) { -// if (dir_path[strlen(home_dir)] == '/' || dir_path[strlen(home_dir)] == '\0') { -// // Replace home directory with ~ -// char temp[512]; -// snprintf(temp, sizeof(temp), "~%s", dir_path + strlen(home_dir)); - -// // If result is too long, truncate intelligently -// if (strlen(temp) > 11) { -// // Show ~/...end_part -// char* last_part = strrchr(temp, '/'); -// if (last_part && strlen(last_part) < 8) { -// snprintf(result, result_size, "~...%s", last_part); -// } else { -// strncpy(result, temp, 11); -// result[11] = '\0'; -// } -// } else { -// strncpy(result, temp, result_size - 1); -// result[result_size - 1] = '\0'; -// } -// return; -// } -// } - -// // Current working directory -// if (strcmp(dir_path, ".") == 0 || strcmp(dir_path, current_pads_dir) == 0) { -// strncpy(result, "pads", result_size - 1); -// result[result_size - 1] = '\0'; -// return; -// } - -// // System/other paths - smart truncation with ellipsis -// if (strlen(dir_path) > 11) { -// // Try to show the most meaningful part -// char* last_part = strrchr(dir_path, '/'); -// if (last_part && strlen(last_part) < 9) { -// // Show .../last_part -// snprintf(result, result_size, "...%s", last_part); -// } else { -// // Show first part with ellipsis -// strncpy(result, dir_path, 8); -// strncpy(result + 8, "...", result_size - 8 - 1); -// result[result_size - 1] = '\0'; -// } -// } else { -// // Short enough, use as-is -// strncpy(result, dir_path, result_size - 1); -// result[result_size - 1] = '\0'; -// } -// } - int handle_add_entropy_to_pad(const char* pad_chksum) { - printf("\n=== Add Entropy to Pad: %.16s... ===\n", pad_chksum); + char header_text[128]; + snprintf(header_text, sizeof(header_text), "Add Entropy to Pad: %.16s...", pad_chksum); + printf("\n"); + print_centered_header(header_text); // Present entropy source selection menu with consistent formatting printf("Select entropy source:\n"); @@ -5130,9 +5334,199 @@ int handle_add_entropy_to_pad(const char* pad_chksum) { return 0; } +int handle_verify_pad(const char* pad_chksum) { + char header_text[128]; + snprintf(header_text, sizeof(header_text), "Verify Pad Integrity: %.16s...", pad_chksum); + printf("\n"); + print_centered_header(header_text); + + // Construct pad file path + char pad_path[1024]; + char state_path[1024]; + get_pad_path(pad_chksum, pad_path, state_path); + + // Check if pad file exists + if (access(pad_path, R_OK) != 0) { + printf("āŒ ERROR: Pad file not found: %s\n", pad_path); + return 1; + } + + printf("Calculating pad checksum...\n"); + + // Calculate actual checksum of the pad file + char calculated_checksum[65]; + if (calculate_checksum(pad_path, calculated_checksum) != 0) { + printf("āŒ ERROR: Failed to calculate pad checksum\n"); + return 1; + } + + // Compare calculated checksum with filename (expected checksum) + if (strcmp(pad_chksum, calculated_checksum) == 0) { + printf("āœ… SUCCESS: Pad integrity verified!\n"); + printf(" Expected: %.16s...\n", pad_chksum); + printf(" Actual: %.16s...\n", calculated_checksum); + printf(" Status: MATCH - Pad is intact and valid\n"); + + // Get additional pad info + struct stat pad_stat; + if (stat(pad_path, &pad_stat) == 0) { + uint64_t used_bytes; + read_state_offset(pad_chksum, &used_bytes); + + double size_gb = (double)pad_stat.st_size / (1024.0 * 1024.0 * 1024.0); + double used_gb = (double)used_bytes / (1024.0 * 1024.0 * 1024.0); + double usage_percent = (double)used_bytes / pad_stat.st_size * 100.0; + + printf(" Size: %.2f GB (%lu bytes)\n", size_gb, pad_stat.st_size); + printf(" Used: %.2f GB (%lu bytes)\n", used_gb, used_bytes); + printf(" Usage: %.1f%%\n", usage_percent); + } + + printf("\nāœ… This pad is safe to use for encryption.\n"); + return 0; + } else { + printf("āŒ FAILURE: Pad integrity check failed!\n"); + printf(" Expected: %.16s...\n", pad_chksum); + printf(" Actual: %.16s...\n", calculated_checksum); + printf(" Status: MISMATCH - Pad may be corrupted!\n"); + printf("\nāš ļø WARNING: This pad should NOT be used for encryption.\n"); + printf(" The pad file may have been modified or corrupted.\n"); + printf(" Consider regenerating this pad or using a different one.\n"); + return 1; + } +} + +int handle_delete_pad(const char* pad_chksum) { + char header_text[128]; + snprintf(header_text, sizeof(header_text), "Delete Pad: %.16s...", pad_chksum); + printf("\n"); + print_centered_header(header_text); + + // Construct pad and state file paths + char pad_path[1024]; + char state_path[1024]; + get_pad_path(pad_chksum, pad_path, state_path); + + // Check if pad file exists + if (access(pad_path, F_OK) != 0) { + printf("āŒ ERROR: Pad file not found: %s\n", pad_path); + return 1; + } + + // Get pad information for display + struct stat pad_stat; + if (stat(pad_path, &pad_stat) == 0) { + uint64_t used_bytes; + read_state_offset(pad_chksum, &used_bytes); + + double size_gb = (double)pad_stat.st_size / (1024.0 * 1024.0 * 1024.0); + double used_gb = (double)used_bytes / (1024.0 * 1024.0 * 1024.0); + double usage_percent = (double)used_bytes / pad_stat.st_size * 100.0; + + printf("Pad Information:\n"); + printf(" Checksum: %s\n", pad_chksum); + printf(" Size: %.2f GB (%lu bytes)\n", size_gb, pad_stat.st_size); + printf(" Used: %.2f GB (%lu bytes)\n", used_gb, used_bytes); + printf(" Usage: %.1f%%\n", usage_percent); + printf(" Path: %s\n", pad_path); + } + + // Check if this is the default pad + char* current_default = get_default_pad_path(); + int is_default_pad = 0; + if (current_default) { + // Check if the pad to be deleted is the current default + if (strstr(current_default, pad_chksum)) { + is_default_pad = 1; + printf(" Status: āš ļø This is your DEFAULT pad\n"); + } + free(current_default); + } + + // Warning and confirmation + printf("\nāš ļø WARNING: This action cannot be undone!\n"); + if (is_default_pad) { + printf("āš ļø Deleting the default pad will require setting a new default.\n"); + } + printf("\nAre you absolutely sure you want to delete this pad? (y/N): "); + + char response[10]; + if (!fgets(response, sizeof(response), stdin)) { + printf("Error: Failed to read input\n"); + return 1; + } + + // Require explicit 'y' or 'Y' to proceed + if (response[0] != 'y' && response[0] != 'Y') { + printf("Pad deletion cancelled.\n"); + return 0; // User cancelled - not an error + } + + // Double confirmation for extra safety + printf("\nFinal confirmation - type 'DELETE' to proceed: "); + char final_response[20]; + if (!fgets(final_response, sizeof(final_response), stdin)) { + printf("Error: Failed to read input\n"); + return 1; + } + + // Remove newline + final_response[strcspn(final_response, "\n")] = 0; + + if (strcmp(final_response, "DELETE") != 0) { + printf("Confirmation text did not match. Pad deletion cancelled.\n"); + return 0; // User didn't confirm - not an error + } + + // Proceed with deletion + printf("\nDeleting pad files...\n"); + + // Delete pad file + if (unlink(pad_path) != 0) { + printf("āŒ ERROR: Failed to delete pad file: %s\n", pad_path); + perror("unlink"); + return 1; + } else { + printf("āœ… Deleted pad file: %s\n", pad_path); + } + + // Delete state file (if it exists) + if (access(state_path, F_OK) == 0) { + if (unlink(state_path) != 0) { + printf("āš ļø WARNING: Failed to delete state file: %s\n", state_path); + perror("unlink"); + // Continue - pad file was deleted successfully + } else { + printf("āœ… Deleted state file: %s\n", state_path); + } + } else { + printf("ā„¹ļø No state file found (this is normal)\n"); + } + + // Handle default pad update if necessary + if (is_default_pad) { + printf("\nšŸ”„ Updating default pad preference...\n"); + + // Clear the current default pad + if (set_preference("default_pad", NULL) == 0) { + printf("āœ… Default pad preference cleared\n"); + printf("ā„¹ļø You can set a new default pad from the pad management menu\n"); + } else { + printf("āš ļø WARNING: Failed to clear default pad preference\n"); + printf(" You may need to manually update your configuration\n"); + } + } + + printf("\nāœ… SUCCESS: Pad deleted successfully!\n"); + printf(" Checksum: %.16s...\n", pad_chksum); + printf(" Both pad and state files have been removed\n"); + + return 0; +} + void print_usage(const char* program_name) { - printf("OTP Cipher - One Time Pad Implementation v0.3.9\n"); + printf("OTP Cipher - One Time Pad Implementation v0.3.10\n"); printf("Built for testing entropy system\n"); printf("Usage:\n"); printf(" %s - Interactive mode\n", program_name); diff --git a/otp.h b/otp.h index df93e29..2600e5f 100644 --- a/otp.h +++ b/otp.h @@ -29,7 +29,7 @@ #define PROGRESS_UPDATE_INTERVAL (64 * 1024 * 1024) // 64MB intervals #define DEFAULT_PADS_DIR "pads" #define FILES_DIR "files" -#define MAX_ENTROPY_BUFFER 32768 // 32KB entropy buffer +#define MAX_ENTROPY_BUFFER (4 * 1024 * 1024) // 4MB entropy buffer for large operations //////////////////////////////////////////////////////////////////////////////// // TYPE DEFINITIONS @@ -248,6 +248,14 @@ int universal_decrypt(const char* input_data, const char* output_target, decrypt char* custom_base64_encode(const unsigned char* input, int length); unsigned char* custom_base64_decode(const char* input, int* output_length); +//////////////////////////////////////////////////////////////////////////////// +// TERMINAL UI FUNCTIONS +//////////////////////////////////////////////////////////////////////////////// + +// Terminal dimension and UI functions +void init_terminal_dimensions(void); +void print_centered_header(const char* text); + //////////////////////////////////////////////////////////////////////////////// // MENU SYSTEM FUNCTIONS //////////////////////////////////////////////////////////////////////////////// @@ -260,6 +268,8 @@ int handle_decrypt_menu(void); int handle_pads_menu(void); int handle_text_encrypt(void); int handle_file_encrypt(void); +int handle_verify_pad(const char* pad_chksum); +int handle_delete_pad(const char* pad_chksum); //////////////////////////////////////////////////////////////////////////////// // ENHANCED INPUT FUNCTIONS