Compare commits

...

1 Commits

Author SHA1 Message Date
66c6e3eea5 Version v0.3.11 - Add delete option, and TUI improvements 2025-09-23 10:39:17 -04:00
4 changed files with 593 additions and 189 deletions

BIN
otp-arm64

Binary file not shown.

Binary file not shown.

770
otp.c
View File

@@ -8,6 +8,7 @@
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/statvfs.h> #include <sys/statvfs.h>
#include <sys/ioctl.h>
#include <dirent.h> #include <dirent.h>
#include <time.h> #include <time.h>
#include <ctype.h> #include <ctype.h>
@@ -44,7 +45,6 @@ static const int base64_decode_table[256] = {
#define PROGRESS_UPDATE_INTERVAL (64 * 1024 * 1024) // 64MB intervals #define PROGRESS_UPDATE_INTERVAL (64 * 1024 * 1024) // 64MB intervals
#define DEFAULT_PADS_DIR "pads" #define DEFAULT_PADS_DIR "pads"
#define FILES_DIR "files" #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 char default_pad_path[1024] = "";
static int is_interactive_mode = 0; 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 // MAIN
@@ -63,7 +117,10 @@ static int is_interactive_mode = 0;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
// Load preferences first // Initialize terminal dimensions first
init_terminal_dimensions();
// Load preferences
load_preferences(); load_preferences();
// Detect interactive mode: only true when running with no arguments // Detect interactive mode: only true when running with no arguments
@@ -329,9 +386,9 @@ int interactive_mode(void) {
void show_main_menu(void) { void show_main_menu(void) {
printf("\n");
print_centered_header("Main Menu - OTP v0.3.10");
printf("\n=========================== Main Menu - OTP v0.3.9 ===========================\n\n"); printf("\n");
printf(" \033[4mT\033[0mext encrypt\n"); //TEXT ENCRYPT printf(" \033[4mT\033[0mext encrypt\n"); //TEXT ENCRYPT
printf(" \033[4mF\033[0mile encrypt\n"); //FILE ENCRYPT printf(" \033[4mF\033[0mile encrypt\n"); //FILE ENCRYPT
@@ -342,7 +399,8 @@ void show_main_menu(void) {
} }
int handle_generate_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): "); printf("Enter pad size (examples: 1GB, 5TB, 512MB, 2048): ");
char size_input[64]; char size_input[64];
@@ -367,7 +425,8 @@ int handle_generate_menu(void) {
} }
int handle_encrypt_menu(void) { int handle_encrypt_menu(void) {
printf("\n=== Encrypt Data ===\n"); printf("\n");
print_centered_header("Encrypt Data");
printf("Available pads:\n"); printf("Available pads:\n");
char* selected = select_pad_interactive("Available pads:", "Select pad (or press Enter to continue)", PAD_FILTER_ALL, 0); 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) { if (choice == 1) {
// Text encryption - use unified pad selection // 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)", "Select pad (by prefix)",
PAD_FILTER_ALL, 1); PAD_FILTER_ALL, 1);
if (!selected_pad) { if (!selected_pad) {
@@ -453,7 +512,7 @@ int handle_encrypt_menu(void) {
} }
// Use unified pad selection // 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)", "Select pad (by prefix)",
PAD_FILTER_ALL, 1); PAD_FILTER_ALL, 1);
if (!selected_pad) { if (!selected_pad) {
@@ -508,7 +567,8 @@ int handle_encrypt_menu(void) {
} }
int handle_decrypt_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"); printf("Enter encrypted data (paste ASCII armor), file path, or press Enter to browse files:\n");
char input_line[MAX_LINE_LENGTH]; char input_line[MAX_LINE_LENGTH];
@@ -742,7 +802,7 @@ int show_pad_info(const char* chksum) {
uint64_t used_bytes; uint64_t used_bytes;
read_state_offset(chksum, &used_bytes); read_state_offset(chksum, &used_bytes);
printf("=== Pad Information ===\n"); print_centered_header("Pad Information");
printf("ChkSum: %s\n", chksum); printf("ChkSum: %s\n", chksum);
printf("File: %s\n", pad_filename); 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); 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) { 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(pad_path, 1024, "%s/%s.pad", current_pads_dir, chksum);
snprintf(state_path, 1024, "%s/%s.state", 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 // Custom base64 encode function
char* custom_base64_encode(const unsigned char* input, int length) { char* custom_base64_encode(const unsigned char* input, int length) {
int output_length = 4 * ((length + 2) / 3); int output_length = 4 * ((length + 2) / 3);
char* encoded = malloc(output_length + 1); 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 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 // Streaming TrueRNG entropy collection for full pad enhancement
// This function applies entropy directly to the pad in chunks to avoid memory issues // 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) { 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 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 // Get pad paths
char pad_path[1024]; char pad_path[1024];
char state_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; bytes_processed += current_chunk_size;
// Show progress for large pads // Show progress and entropy samples for visual verification
if (display_progress && bytes_processed % (64 * 1024 * 1024) == 0) { // Every 64MB if (display_progress) {
double percentage = (double)bytes_processed / total_bytes * 100.0; // Update progress more frequently for better user experience - always show cumulative amount
printf("Progress: %.1f%% (%zu/%zu MB)\r", percentage, if (bytes_processed % (4 * 1024 * 1024) == 0 || bytes_processed == total_bytes) { // Every 4MB or at completion
bytes_processed / (1024*1024), total_bytes / (1024*1024)); double percentage = (double)bytes_processed / total_bytes * 100.0;
fflush(stdout); 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, int collect_dice_entropy(unsigned char* entropy_buffer, size_t target_bytes,
size_t* collected_bytes, int display_progress) { size_t* collected_bytes, int display_progress) {
if (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("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("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"); 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"); strcpy(*ascii_output, "-----BEGIN OTP MESSAGE-----\n");
char temp_line[256]; 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); strcat(*ascii_output, temp_line);
snprintf(temp_line, sizeof(temp_line), "Pad-ChkSum: %s\n", chksum); 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) { int handle_text_encrypt(void) {
printf("\n=== Text Encrypt ===\n"); printf("\n");
print_centered_header("Text Encrypt");
// Launch text editor directly // Launch text editor directly
char text_buffer[MAX_INPUT_SIZE]; char text_buffer[MAX_INPUT_SIZE];
@@ -4172,7 +4472,7 @@ int handle_text_encrypt(void) {
} }
// Use unified pad selection // 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)", "Select pad (by prefix)",
PAD_FILTER_ALL, 1); PAD_FILTER_ALL, 1);
if (!selected_pad) { if (!selected_pad) {
@@ -4186,7 +4486,8 @@ int handle_text_encrypt(void) {
} }
int handle_file_encrypt(void) { int handle_file_encrypt(void) {
printf("\n=== File Encrypt ===\n"); printf("\n");
print_centered_header("File Encrypt");
// Launch file manager directly // Launch file manager directly
char input_file[512]; char input_file[512];
@@ -4202,7 +4503,7 @@ int handle_file_encrypt(void) {
} }
// Use unified pad selection // 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)", "Select pad (by prefix)",
PAD_FILTER_ALL, 1); PAD_FILTER_ALL, 1);
if (!selected_pad) { 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; pads[pad_count].percentage = (double)used_bytes / st.st_size * 100.0;
// Set location info using directory display // 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++; pad_count++;
} }
@@ -4543,7 +4844,8 @@ char* select_pad_interactive(const char* title, const char* prompt, pad_filter_t
} }
int handle_pads_menu(void) { int handle_pads_menu(void) {
printf("\n=== Pad Management ===\n"); printf("\n");
print_centered_header("Pad Management");
// Get list of pads from current directory // Get list of pads from current directory
DIR* dir = opendir(current_pads_dir); 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; pads[pad_count].percentage = (double)used_bytes / st.st_size * 100.0;
// Set location info using directory display // 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++; pad_count++;
} }
@@ -4712,6 +5014,8 @@ int handle_pads_menu(void) {
printf("\nActions:\n"); printf("\nActions:\n");
printf(" \033[4mG\033[0menerate new pad\n"); printf(" \033[4mG\033[0menerate new pad\n");
printf(" \033[4mA\033[0mdd entropy to 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(" \033[4mS\033[0met default pad\n");
printf(" E\033[4mx\033[0mit\n"); printf(" E\033[4mx\033[0mit\n");
printf("\nSelect action: "); printf("\nSelect action: ");
@@ -4733,7 +5037,7 @@ int handle_pads_menu(void) {
return result; return result;
} else if (toupper(input[0]) == 'A') { } else if (toupper(input[0]) == 'A') {
// Add entropy to pad - use unified function with unused pads filter // 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)", "Select unused pad (by prefix)",
PAD_FILTER_UNUSED_ONLY, 1); PAD_FILTER_UNUSED_ONLY, 1);
if (!selected_pad) { if (!selected_pad) {
@@ -4749,9 +5053,37 @@ int handle_pads_menu(void) {
return handle_pads_menu(); return handle_pads_menu();
} }
return result; 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') { } else if (toupper(input[0]) == 'S') {
// Set default pad - use unified function // 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)", "Select pad to set as default (by prefix)",
PAD_FILTER_ALL, 1); PAD_FILTER_ALL, 1);
if (!selected_pad) { 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) { 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 // Present entropy source selection menu with consistent formatting
printf("Select entropy source:\n"); printf("Select entropy source:\n");
@@ -5130,9 +5334,199 @@ int handle_add_entropy_to_pad(const char* pad_chksum) {
return 0; 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) { 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("Built for testing entropy system\n");
printf("Usage:\n"); printf("Usage:\n");
printf(" %s - Interactive mode\n", program_name); printf(" %s - Interactive mode\n", program_name);

12
otp.h
View File

@@ -29,7 +29,7 @@
#define PROGRESS_UPDATE_INTERVAL (64 * 1024 * 1024) // 64MB intervals #define PROGRESS_UPDATE_INTERVAL (64 * 1024 * 1024) // 64MB intervals
#define DEFAULT_PADS_DIR "pads" #define DEFAULT_PADS_DIR "pads"
#define FILES_DIR "files" #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 // 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); char* custom_base64_encode(const unsigned char* input, int length);
unsigned char* custom_base64_decode(const char* input, int* output_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 // MENU SYSTEM FUNCTIONS
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -260,6 +268,8 @@ int handle_decrypt_menu(void);
int handle_pads_menu(void); int handle_pads_menu(void);
int handle_text_encrypt(void); int handle_text_encrypt(void);
int handle_file_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 // ENHANCED INPUT FUNCTIONS