#define _POSIX_C_SOURCE 200809L #define _DEFAULT_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../include/otp.h" // Extracted pad management functions from otp.c int show_pad_info(const char* chksum) { char pad_filename[MAX_HASH_LENGTH + 10]; char state_filename[MAX_HASH_LENGTH + 10]; snprintf(pad_filename, sizeof(pad_filename), "%s.pad", chksum); snprintf(state_filename, sizeof(state_filename), "%s.state", chksum); struct stat st; if (stat(pad_filename, &st) != 0) { printf("Pad not found: %s\n", chksum); return 1; } uint64_t used_bytes; read_state_offset(chksum, &used_bytes); print_centered_header("Pad Information", 0); printf("ChkSum: %s\n", chksum); printf("File: %s\n", pad_filename); double size_gb = (double)st.st_size / (1024.0 * 1024.0 * 1024.0); double used_gb = (double)used_bytes / (1024.0 * 1024.0 * 1024.0); double remaining_gb = (double)(st.st_size - used_bytes) / (1024.0 * 1024.0 * 1024.0); printf("Total size: %.2f GB (%lu bytes)\n", size_gb, st.st_size); printf("Used: %.2f GB (%lu bytes)\n", used_gb, used_bytes); printf("Remaining: %.2f GB (%lu bytes)\n", remaining_gb, st.st_size - used_bytes); printf("Usage: %.1f%%\n", (double)used_bytes / st.st_size * 100.0); return 0; } // Ensure pads directory exists, create if necessary int ensure_pads_directory(void) { const char* pads_dir = get_current_pads_dir(); struct stat st = {0}; if (stat(pads_dir, &st) == -1) { if (mkdir(pads_dir, 0755) != 0) { perror("Failed to create pads directory"); return -1; } } else if (!S_ISDIR(st.st_mode)) { fprintf(stderr, "Pads path exists but is not a directory\n"); return -1; } return 0; } // Construct pad and state file paths from checksum void get_pad_path(const char* chksum, char* pad_path, char* state_path) { const char* pads_dir = get_current_pads_dir(); snprintf(pad_path, 1024, "%s/%s.pad", pads_dir, chksum); snprintf(state_path, 1024, "%s/%s.state", pads_dir, chksum); } int generate_pad(uint64_t size_bytes, int display_progress) { // Ensure pads directory exists if (ensure_pads_directory() != 0) { printf("Error: Cannot create pads directory\n"); return 1; } char temp_filename[1024]; char pad_path[MAX_HASH_LENGTH + 20]; char state_path[MAX_HASH_LENGTH + 20]; char chksum_hex[MAX_HASH_LENGTH]; // Create temporary filename in the pads directory to avoid cross-filesystem issues const char* pads_dir = get_current_pads_dir(); snprintf(temp_filename, sizeof(temp_filename), "%s/temp_%ld.pad", pads_dir, time(NULL)); FILE* urandom = fopen("/dev/urandom", "rb"); if (!urandom) { printf("Error: Cannot open /dev/urandom\n"); return 1; } FILE* pad_file = fopen(temp_filename, "wb"); if (!pad_file) { printf("Error: Cannot create temporary pad file %s\n", temp_filename); fclose(urandom); return 1; } unsigned char buffer[64 * 1024]; // 64KB buffer uint64_t bytes_written = 0; time_t start_time = time(NULL); if (display_progress) { printf("Generating pad...\n"); } while (bytes_written < size_bytes) { uint64_t chunk_size = sizeof(buffer); if (size_bytes - bytes_written < chunk_size) { chunk_size = size_bytes - bytes_written; } if (fread(buffer, 1, (size_t)chunk_size, urandom) != (size_t)chunk_size) { printf("Error: Failed to read from /dev/urandom\n"); fclose(urandom); fclose(pad_file); unlink(temp_filename); return 1; } if (fwrite(buffer, 1, (size_t)chunk_size, pad_file) != (size_t)chunk_size) { printf("Error: Failed to write to pad file\n"); fclose(urandom); fclose(pad_file); unlink(temp_filename); return 1; } bytes_written += chunk_size; if (display_progress && bytes_written % PROGRESS_UPDATE_INTERVAL == 0) { show_progress(bytes_written, size_bytes, start_time); } } if (display_progress) { show_progress(size_bytes, size_bytes, start_time); printf("\n"); } fclose(urandom); fclose(pad_file); // Calculate XOR checksum of the pad file if (display_progress) { printf("Calculating pad checksum...\n"); } if (calculate_checksum_with_progress(temp_filename, chksum_hex, display_progress, size_bytes) != 0) { printf("Error: Cannot calculate pad checksum\n"); unlink(temp_filename); return 1; } // Get final paths in pads directory get_pad_path(chksum_hex, pad_path, state_path); // Rename temporary file to final name (atomic operation within same directory) if (rename(temp_filename, pad_path) != 0) { printf("Error: Cannot rename temporary pad file to final name\n"); unlink(temp_filename); return 1; } // Set pad file to read-only if (chmod(pad_path, S_IRUSR) != 0) { printf("Warning: Cannot set pad file to read-only\n"); } // Initialize state file with offset 32 (first 32 bytes reserved for checksum encryption) FILE* state_file = fopen(state_path, "wb"); if (state_file) { uint64_t reserved_bytes = 32; fwrite(&reserved_bytes, sizeof(uint64_t), 1, state_file); fclose(state_file); } else { printf("Error: Failed to create state file\n"); unlink(pad_path); return 1; } double size_gb = (double)size_bytes / (1024.0 * 1024.0 * 1024.0); printf("Generated pad: %s (%.2f GB)\n", pad_path, size_gb); printf("Pad checksum: %s\n", chksum_hex); printf("State file: %s\n", state_path); printf("Pad file set to read-only\n"); printf("Use 'Add entropy' in Pads menu to enhance randomness.\n"); // Pause before returning to menu to let user see the success message print_centered_header("Pad Generation Complete", 1); return 0; } int read_state_offset(const char* pad_chksum, uint64_t* offset) { char state_filename[1024]; const char* pads_dir = get_current_pads_dir(); snprintf(state_filename, sizeof(state_filename), "%s/%s.state", pads_dir, pad_chksum); FILE* state_file = fopen(state_filename, "rb"); if (!state_file) { *offset = 0; return 0; } if (fread(offset, sizeof(uint64_t), 1, state_file) != 1) { fclose(state_file); *offset = 0; return 0; } fclose(state_file); return 0; } int write_state_offset(const char* pad_chksum, uint64_t offset) { char state_filename[1024]; const char* pads_dir = get_current_pads_dir(); snprintf(state_filename, sizeof(state_filename), "%s/%s.state", pads_dir, pad_chksum); FILE* state_file = fopen(state_filename, "wb"); if (!state_file) { return 1; } if (fwrite(&offset, sizeof(uint64_t), 1, state_file) != 1) { fclose(state_file); return 1; } fclose(state_file); return 0; } // 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]; const char* pads_dir = get_current_pads_dir(); // Construct file paths snprintf(old_pad_path, sizeof(old_pad_path), "%s/%s.pad", pads_dir, old_chksum); snprintf(new_pad_path, sizeof(new_pad_path), "%s/%s.pad", pads_dir, new_chksum); snprintf(old_state_path, sizeof(old_state_path), "%s/%s.state", pads_dir, old_chksum); snprintf(new_state_path, sizeof(new_state_path), "%s/%s.state", 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 } // 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 const char* pads_dir = get_current_pads_dir(); DIR* dir = opendir(pads_dir); if (!dir) { printf("Error: Cannot open pads directory %s\n", 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", 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\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 only int selected_pad = -1; int match_count = 0; // Try prefix matching only 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"); print_centered_header("Pad Management", 0); // Get list of pads from current directory const char* pads_dir = get_current_pads_dir(); DIR* dir = opendir(pads_dir); if (!dir) { printf("Error: Cannot open pads directory %s\n", pads_dir); return 1; } // Structure to store pad information struct PadInfo { char chksum[65]; char size_str[32]; char used_str[32]; double percentage; char location[256]; // Store location info }; 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]; // Increased buffer size snprintf(full_path, sizeof(full_path), "%s/%s", 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); // 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("No pads found.\n"); printf("\nOptions:\n"); printf(" \033[4mG\033[0menerate new pad\n"); printf(" E\033[4mx\033[0mit\n"); printf("\nSelect option: "); char input[10]; if (fgets(input, sizeof(input), stdin)) { char choice = toupper(input[0]); if (choice == 'G') { int result = handle_generate_menu(); if (result == 0) { // After successful pad generation, return to pads menu return handle_pads_menu(); } return result; } } return 0; } // Calculate minimal unique prefixes for each pad char prefixes[100][65]; // Store the minimal prefix for each pad int prefix_lengths[100]; // Length of minimal prefix for each pad 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 pads with minimal prefixes underlined and default indicator printf("\nAvailable pads:\n"); 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, // Use the stored location info pads[i].size_str, pads[i].used_str, pads[i].percentage); } 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: "); char input[MAX_HASH_LENGTH]; if (!fgets(input, sizeof(input), stdin)) { printf("Error: Failed to read input\n"); return 1; } input[strcspn(input, "\n")] = 0; // Handle actions if (toupper(input[0]) == 'G') { int result = handle_generate_menu(); if (result == 0) { // After successful pad generation, return to pads menu return handle_pads_menu(); } 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", "Select unused pad (by prefix)", PAD_FILTER_UNUSED_ONLY, 1); if (!selected_pad) { printf("Entropy addition cancelled.\n"); return handle_pads_menu(); } // 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]) == '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", "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(); } // Construct the full absolute pad path and set as default char new_default_path[1024]; const char* pads_dir = get_current_pads_dir(); if (pads_dir[0] == '/') { // Already absolute path int ret = snprintf(new_default_path, sizeof(new_default_path), "%s/%s.pad", 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, 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", 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", 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", 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 } else { printf("Invalid action. Please select G, A, S, or X.\n"); return handle_pads_menu(); } } // Update pad checksum after entropy addition int update_pad_checksum_after_entropy(const char* old_chksum, char* new_chksum) { char pad_path[1024]; const char* pads_dir = get_current_pads_dir(); snprintf(pad_path, sizeof(pad_path), "%s/%s.pad", 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]; const char* pads_dir = get_current_pads_dir(); snprintf(new_default_path, sizeof(new_default_path), "%s/%s.pad", 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 } // Verify pad integrity by checking its checksum int handle_verify_pad(const char* chksum) { char pad_filename[MAX_HASH_LENGTH + 10]; char state_filename[MAX_HASH_LENGTH + 10]; char calculated_chksum[MAX_HASH_LENGTH]; snprintf(pad_filename, sizeof(pad_filename), "%s.pad", chksum); snprintf(state_filename, sizeof(state_filename), "%s.state", chksum); struct stat st; if (stat(pad_filename, &st) != 0) { printf("Pad not found: %s\n", chksum); return 1; } uint64_t used_bytes; read_state_offset(chksum, &used_bytes); print_centered_header("Pad Verification", 0); printf("ChkSum: %s\n", chksum); printf("File: %s\n", pad_filename); double size_gb = (double)st.st_size / (1024.0 * 1024.0 * 1024.0); double used_gb = (double)used_bytes / (1024.0 * 1024.0 * 1024.0); double remaining_gb = (double)(st.st_size - used_bytes) / (1024.0 * 1024.0 * 1024.0); printf("Total size: %.2f GB (%lu bytes)\n", size_gb, st.st_size); printf("Used: %.2f GB (%lu bytes)\n", used_gb, used_bytes); printf("Remaining: %.2f GB (%lu bytes)\n", remaining_gb, st.st_size - used_bytes); printf("Usage: %.1f%%\n", (double)used_bytes / st.st_size * 100.0); // Calculate actual checksum printf("\nCalculating checksum...\n"); if (calculate_checksum(pad_filename, calculated_chksum) != 0) { printf("Error: Cannot calculate pad checksum\n"); return 1; } printf("Expected checksum: %s\n", chksum); printf("Calculated checksum: %s\n", calculated_chksum); if (strcmp(chksum, calculated_chksum) == 0) { printf("\nāœ“ Pad integrity verified - checksum matches!\n"); printf("This pad is safe to use.\n"); return 0; } else { printf("\nāœ— Pad integrity check FAILED - checksum mismatch!\n"); printf("This pad may be corrupted and should not be used.\n"); printf("Consider regenerating this pad.\n"); return 1; } } // Delete a pad and its associated state file int handle_delete_pad(const char* chksum) { char pad_filename[MAX_HASH_LENGTH + 10]; char state_filename[MAX_HASH_LENGTH + 10]; snprintf(pad_filename, sizeof(pad_filename), "%s.pad", chksum); snprintf(state_filename, sizeof(state_filename), "%s.state", chksum); // Check if pad exists if (access(pad_filename, F_OK) != 0) { printf("Pad not found: %s\n", chksum); return 1; } // Check if this is the default pad char* current_default = get_default_pad_path(); int is_default = 0; if (current_default) { if (strstr(current_default, chksum)) { is_default = 1; } free(current_default); } if (is_default) { printf("Warning: This is the current default pad.\n"); printf("Deleting it will require setting a new default pad.\n"); } // Get pad info for confirmation struct stat st; if (stat(pad_filename, &st) == 0) { uint64_t used_bytes; read_state_offset(chksum, &used_bytes); double size_gb = (double)st.st_size / (1024.0 * 1024.0 * 1024.0); printf("\nPad to delete:\n"); printf("Checksum: %s\n", chksum); printf("Size: %.2f GB\n", size_gb); printf("Used: %.1f%%\n", (double)used_bytes / st.st_size * 100.0); } // First confirmation printf("\nAre you sure you want to delete this pad? (y/N): "); char input[10]; if (!fgets(input, sizeof(input), stdin)) { printf("Error: Failed to read input\n"); return 1; } if (toupper(input[0]) != 'Y') { printf("Pad deletion cancelled.\n"); return 0; } // Second confirmation with checksum printf("Type the first 8 characters of the checksum to confirm deletion: "); if (!fgets(input, sizeof(input), stdin)) { printf("Error: Failed to read input\n"); return 1; } input[strcspn(input, "\n")] = 0; if (strlen(input) < 8 || strncmp(input, chksum, 8) != 0) { printf("Confirmation failed. Pad deletion cancelled.\n"); return 1; } // Delete state file first if (access(state_filename, F_OK) == 0) { if (unlink(state_filename) != 0) { printf("Error: Failed to delete state file %s\n", state_filename); return 1; } printf("Deleted state file: %s\n", state_filename); } // Delete pad file if (unlink(pad_filename) != 0) { printf("Error: Failed to delete pad file %s\n", pad_filename); return 1; } printf("Deleted pad file: %s\n", pad_filename); // Clear default pad preference if this was the default if (is_default) { if (set_default_pad_path("") != 0) { printf("Warning: Failed to clear default pad preference\n"); } else { printf("Cleared default pad preference (was this pad)\n"); } } printf("Pad deletion completed successfully.\n"); return 0; } int handle_add_entropy_to_pad(const char* 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, 0); // Present entropy source selection menu with consistent formatting printf("Select entropy source:\n"); printf(" \033[4mK\033[0meyboard entropy - Random typing for entropy collection\n"); printf(" \033[4mD\033[0mice/Coins/Cards - Manual input for high-quality entropy\n"); printf(" \033[4mH\033[0mardware RNG - Hardware random number generators\n"); printf(" \033[4mF\033[0mile - Load entropy from binary file\n"); printf(" \033[4mT\033[0mest RNG Speed - Test TrueRNG/SwiftRNG device performance\n"); printf(" E\033[4mx\033[0mit\n"); printf("\nSelect option: "); char source_input[10]; if (!fgets(source_input, sizeof(source_input), stdin)) { printf("Error: Failed to read input\n"); return 1; } char choice = toupper(source_input[0]); entropy_source_t entropy_source; switch (choice) { case 'K': entropy_source = ENTROPY_SOURCE_KEYBOARD; break; case 'D': entropy_source = ENTROPY_SOURCE_DICE; break; case 'H': // Hardware RNG selected - will handle after target_bytes selection entropy_source = ENTROPY_SOURCE_TRUERNG; break; case 'F': entropy_source = ENTROPY_SOURCE_FILE; break; case 'T': // Test RNG speed - this doesn't collect entropy, just tests the device // MOVED TO src/trng.c - commented out here // return test_truerng_speed(); printf("Test RNG speed functionality moved to TRNG module\n"); return 1; case 'X': return 0; // Exit default: printf("Invalid choice. Please select K, D, H, F, T, or X.\n"); return 1; } size_t target_bytes; // For TrueRNG, automatically use the full pad size if (entropy_source == ENTROPY_SOURCE_TRUERNG) { // Get the pad file size char pad_path[1024]; char state_path[1024]; get_pad_path(pad_chksum, pad_path, state_path); struct stat pad_stat; if (stat(pad_path, &pad_stat) != 0) { printf("Error: Cannot get pad file size\n"); return 1; } target_bytes = (size_t)pad_stat.st_size; printf("\nTrueRNG selected - will enhance entire pad with hardware entropy\n"); printf("Pad size: %.2f GB (%zu bytes)\n", (double)target_bytes / (1024.0 * 1024.0 * 1024.0), target_bytes); } else { // For other entropy sources, show the selection menu printf("\nEntropy collection options:\n"); printf(" 1. Recommended (2048 bytes) - Optimal security\n"); printf(" 2. Minimum (1024 bytes) - Good security\n"); printf(" 3. Maximum (4096 bytes) - Maximum security\n"); printf(" 4. Custom amount\n"); printf("Enter choice (1-4): "); char amount_input[10]; if (!fgets(amount_input, sizeof(amount_input), stdin)) { printf("Error: Failed to read input\n"); return 1; } target_bytes = 2048; // Default int amount_choice = atoi(amount_input); switch (amount_choice) { case 1: target_bytes = 2048; break; case 2: target_bytes = 1024; break; case 3: target_bytes = 4096; break; case 4: printf("Enter custom amount (512-8192 bytes): "); char custom_input[32]; if (!fgets(custom_input, sizeof(custom_input), stdin)) { printf("Error: Failed to read input\n"); return 1; } size_t custom_amount = (size_t)atoi(custom_input); if (custom_amount < 512 || custom_amount > 8192) { printf("Error: Invalid amount. Must be between 512 and 8192 bytes.\n"); return 1; } target_bytes = custom_amount; break; default: target_bytes = 2048; // Default to recommended break; } } // For TrueRNG, detect all devices and present selection menu if (entropy_source == ENTROPY_SOURCE_TRUERNG) { // Use streaming collection with selected device int result = collect_truerng_entropy_streaming_from_device(NULL, pad_chksum, target_bytes, 1, 1); if (result != 0) { printf("Error: TrueRNG streaming entropy collection failed\n"); return 1; } // 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; } printf("\nšŸŽ‰ SUCCESS! Your entire pad now has enhanced randomness!\n"); // Use enhanced pause mechanism instead of simple getchar print_centered_header("Pad Enhancement Complete", 1); return 0; } // For other entropy sources or smaller amounts, use traditional approach printf("\nCollecting %zu bytes of entropy from selected source...\n", target_bytes); // Allocate entropy buffer unsigned char* entropy_buffer = malloc(MAX_ENTROPY_BUFFER); if (!entropy_buffer) { printf("Error: Cannot allocate entropy buffer\n"); return 1; } // Collect entropy using unified interface size_t collected_bytes = 0; int result = collect_entropy_by_source(entropy_source, entropy_buffer, target_bytes, &collected_bytes, 1); if (result != 0) { printf("Error: Entropy collection failed\n"); free(entropy_buffer); return 1; } if (collected_bytes < 512) { printf("Error: Insufficient entropy collected (%zu bytes)\n", collected_bytes); free(entropy_buffer); return 1; } printf("\nProcessing entropy and modifying pad...\n"); // Add entropy to pad result = add_entropy_to_pad(pad_chksum, entropy_buffer, collected_bytes, 1); // Clear entropy buffer for security memset(entropy_buffer, 0, MAX_ENTROPY_BUFFER); free(entropy_buffer); if (result != 0) { printf("Error: Failed to add entropy to pad\n"); return 1; } printf("\nšŸŽ‰ SUCCESS! Your pad now has enhanced randomness!\n"); // Use enhanced pause mechanism instead of simple getchar print_centered_header("Entropy Enhancement Complete", 1); return 0; }