Compare commits

...

17 Commits

Author SHA1 Message Date
c1aa29cd73 Version v0.2.48 - fixed checksum display to show exactly 8 characters with proper prefix highlighting 2025-08-13 14:15:20 -04:00
75e52d48dc Version v0.2.47 - implemented 8-character checksum display and USB-aware directory shortening with smart path compression 2025-08-13 14:14:27 -04:00
28947a53a3 Version v0.2.46 - fixed printf formatting error in pad display function 2025-08-13 14:03:41 -04:00
5a611a9dc0 Version v0.2.45 - implemented consolidated menu system with intelligent prefix-based pad selection 2025-08-13 14:03:13 -04:00
aff8bea0a2 Version v0.2.44 - cleaned up unused code - removed ensure_files_directory, xor_checksum_256, generate_pad, and get_user_choice functions and prototypes 2025-08-13 13:46:52 -04:00
864c0356da Version v0.2.43 - restored smart decrypt functionality with enhanced interactive input and cleaned up old code 2025-08-13 13:43:27 -04:00
35175790e2 Version v0.2.42 - fixed decrypt menu to use proper enhanced interactive input function 2025-08-13 12:06:08 -04:00
04ea4fb848 Version v0.2.41 - More menu 2025-08-13 12:01:50 -04:00
5c61ba7ea8 Version v0.2.40 - Clean up menu 2025-08-13 11:59:29 -04:00
a45b304d22 Version v0.2.39 - added proper spacing to all menu items for better visual appearance 2025-08-13 11:54:16 -04:00
403d013224 Version v0.2.38 - updated command-line file encryption to use files directory by default 2025-08-13 11:47:52 -04:00
82533d96e4 Version v0.2.37 - implemented files directory support with smart default paths for all file operations 2025-08-13 11:46:50 -04:00
5b619384a1 Version v0.2.36 - fixed build warning and corrected encrypt menu output filename generation logic 2025-08-13 11:42:14 -04:00
12b9884572 Version v0.2.34 - Formatting 2025-08-13 11:41:14 -04:00
83b60b5cc2 Version v0.2.33 - implemented enhanced interactive filename editing for decrypt file functionality with smart defaults 2025-08-13 11:37:41 -04:00
2d6546ab83 Version v0.2.32 - implemented enhanced interactive filename editing for decrypt functionality 2025-08-13 11:30:29 -04:00
c255185084 Version v0.2.31 - fixed signed/unsigned comparison warning in enhanced input function 2025-08-13 11:11:08 -04:00
16 changed files with 488 additions and 148 deletions

1
decrypted.bin Normal file
View File

@@ -0,0 +1 @@
Test file content for decryption

BIN
files/out2.otp Normal file

Binary file not shown.

BIN
files/output.otp Normal file

Binary file not shown.

1
files/test_decrypt.txt Normal file
View File

@@ -0,0 +1 @@
Test file content for decryption

BIN
files/test_decrypt.txt.otp Normal file

Binary file not shown.

1
files/test_file.txt Normal file
View File

@@ -0,0 +1 @@
Hello, this is a test file for encryption!

View File

@@ -0,0 +1,7 @@
-----BEGIN OTP MESSAGE-----
Version: v0.2.29
Pad-ChkSum: d0d4a489354348b08d8c7b324814d8c50010042e9da47f2c973f32a16a09101b
Pad-Offset: 57
05S8GfS0tFfczNMUz0xrieFGoPSREM4uo5QhFGoBCcOzjfTXTDMt3hRtAQ==
-----END OTP MESSAGE-----

Binary file not shown.

1
files/test_input.txt Normal file
View File

@@ -0,0 +1 @@
This is a test file for encryption.

623
otp.c
View File

@@ -40,6 +40,7 @@ static const int base64_decode_table[256] = {
#define MAX_HASH_LENGTH 65 #define MAX_HASH_LENGTH 65
#define PROGRESS_UPDATE_INTERVAL (64 * 1024 * 1024) // 64MB intervals #define PROGRESS_UPDATE_INTERVAL (64 * 1024 * 1024) // 64MB intervals
#define PADS_DIR "pads" #define PADS_DIR "pads"
#define FILES_DIR "files"
#define MAX_ENTROPY_BUFFER 32768 // 32KB entropy buffer #define MAX_ENTROPY_BUFFER 32768 // 32KB entropy buffer
// Function prototypes // Function prototypes
@@ -73,20 +74,20 @@ void simple_entropy_mix(unsigned char* urandom_buffer, size_t buffer_size,
// Directory management // Directory management
int ensure_pads_directory(void); int ensure_pads_directory(void);
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);
const char* get_files_directory(void);
void get_default_file_path(const char* filename, char* result_path, size_t result_size);
// Utility functions // Utility functions
uint64_t parse_size_string(const char* size_str); uint64_t parse_size_string(const char* size_str);
char* find_pad_by_prefix(const char* prefix); char* find_pad_by_prefix(const char* prefix);
int list_available_pads(void); int list_available_pads(void);
int show_pad_info(const char* chksum); int show_pad_info(const char* chksum);
int get_user_choice(int min, int max);
void show_progress(uint64_t current, uint64_t total, time_t start_time); void show_progress(uint64_t current, uint64_t total, time_t start_time);
// File operations // File operations
int read_state_offset(const char* pad_chksum, uint64_t* offset); int read_state_offset(const char* pad_chksum, uint64_t* offset);
int write_state_offset(const char* pad_chksum, uint64_t offset); int write_state_offset(const char* pad_chksum, uint64_t offset);
int calculate_checksum(const char* filename, char* checksum_hex); int calculate_checksum(const char* filename, char* checksum_hex);
void xor_checksum_256(const unsigned char* data, size_t len, unsigned char checksum[32]);
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);
@@ -95,13 +96,16 @@ void show_main_menu(void);
int handle_generate_menu(void); int handle_generate_menu(void);
int handle_encrypt_menu(void); int handle_encrypt_menu(void);
int handle_decrypt_menu(void); int handle_decrypt_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_smart_decrypt(void);
// Enhanced input functions // Enhanced input functions
int get_filename_with_default(const char* prompt, const char* default_path, char* result, size_t result_size); int get_filename_with_default(const char* prompt, const char* default_path, char* result, size_t result_size);
// Directory display functions
void get_directory_display(const char* file_path, char* result, size_t result_size);
void print_usage(const char* program_name); void print_usage(const char* program_name);
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
@@ -113,7 +117,7 @@ int main(int argc, char* argv[]) {
} }
int interactive_mode(void) { int interactive_mode(void) {
printf("\n\n\n\n=== OTP Cipher %s ===\n\n", get_version()); // printf("\n\n\n\n=== OTP Cipher %s ===\n\n", get_version());
while (1) { while (1) {
show_main_menu(); show_main_menu();
@@ -129,33 +133,17 @@ int interactive_mode(void) {
handle_file_encrypt(); handle_file_encrypt();
break; break;
case 'D': case 'D':
handle_smart_decrypt(); handle_decrypt_menu();
break; break;
case 'G': case 'P':
handle_generate_menu(); handle_pads_menu();
break; break;
case 'L':
list_available_pads();
break;
case 'S': {
printf("Enter pad checksum (or prefix): ");
char input[MAX_HASH_LENGTH];
if (fgets(input, sizeof(input), stdin)) {
input[strcspn(input, "\n")] = 0;
char* chksum = find_pad_by_prefix(input);
if (chksum) {
show_pad_info(chksum);
free(chksum);
}
}
break;
}
case 'X': case 'X':
case 'Q': case 'Q':
printf("Goodbye!\n"); printf("Goodbye!\n");
return 0; return 0;
default: default:
printf("Invalid option. Please select T, F, D, G, L, S, or X.\n"); printf("Invalid option. Please select T, F, D, P, or X.\n");
continue; continue;
} }
} else { } else {
@@ -271,14 +259,14 @@ int command_line_mode(int argc, char* argv[]) {
} }
void show_main_menu(void) { void show_main_menu(void) {
printf("=== Main Menu ===\n\n");
printf("\033[4mT\033[0mext encrypt\n"); printf("\n\n\n\n=========================== Main Menu - OTP %s ===========================\n\n", get_version() );
printf("\033[4mF\033[0mile encrypt\n");
printf("\033[4mD\033[0mecrypt\n"); printf(" \033[4mT\033[0mext encrypt\n");
printf("\033[4mG\033[0menerate new pad\n"); printf(" \033[4mF\033[0mile encrypt\n");
printf("\033[4mL\033[0mist available pads\n"); printf(" \033[4mD\033[0mecrypt\n");
printf("\033[4mS\033[0mhow pad information\n"); printf(" \033[4mP\033[0mads\n");
printf("E\033[4mx\033[0mit\n"); printf(" E\033[4mx\033[0mit\n");
printf("\nSelect option: "); printf("\nSelect option: ");
} }
@@ -332,8 +320,8 @@ int handle_encrypt_menu(void) {
// Ask user to choose between text and file encryption // Ask user to choose between text and file encryption
printf("\nSelect encryption type:\n"); printf("\nSelect encryption type:\n");
printf("1. Text message\n"); printf(" 1. Text message\n");
printf("2. File\n"); printf(" 2. File\n");
printf("Enter choice (1-2): "); printf("Enter choice (1-2): ");
char choice_input[10]; char choice_input[10];
@@ -347,9 +335,9 @@ int handle_encrypt_menu(void) {
if (choice == 1) { if (choice == 1) {
// Text encryption // Text encryption
printf("\nPad selection options:\n"); printf("\nPad selection options:\n");
printf("1. Select from numbered list\n"); printf(" 1. Select from numbered list\n");
printf("2. Enter checksum/prefix manually\n"); printf(" 2. Enter checksum/prefix manually\n");
printf("3. Browse pad files\n"); printf(" 3. Browse pad files\n");
printf("Enter choice (1-3): "); printf("Enter choice (1-3): ");
char pad_choice[10]; char pad_choice[10];
@@ -400,8 +388,8 @@ int handle_encrypt_menu(void) {
else if (choice == 2) { else if (choice == 2) {
// File encryption // File encryption
printf("\nFile selection options:\n"); printf("\nFile selection options:\n");
printf("1. Type file path directly\n"); printf(" 1. Type file path directly\n");
printf("2. Use file manager\n"); printf(" 2. Use file manager\n");
printf("Enter choice (1-2): "); printf("Enter choice (1-2): ");
char file_choice[10]; char file_choice[10];
@@ -449,8 +437,8 @@ int handle_encrypt_menu(void) {
// Ask for output format // Ask for output format
printf("\nSelect output format:\n"); printf("\nSelect output format:\n");
printf("1. Binary (.otp) - preserves file permissions\n"); printf(" 1. Binary (.otp) - preserves file permissions\n");
printf("2. ASCII (.otp.asc) - text-safe format\n"); printf(" 2. ASCII (.otp.asc) - text-safe format\n");
printf("Enter choice (1-2): "); printf("Enter choice (1-2): ");
char format_input[10]; char format_input[10];
@@ -461,16 +449,27 @@ int handle_encrypt_menu(void) {
int ascii_armor = (atoi(format_input) == 2) ? 1 : 0; int ascii_armor = (atoi(format_input) == 2) ? 1 : 0;
// Ask for custom output filename (optional) // Generate default output filename with files directory and use enhanced input function
printf("\nEnter output filename (or press Enter for default): "); char default_output[1024]; // Increased size to prevent truncation warnings
char temp_default[1024];
// Generate base filename with appropriate extension
if (ascii_armor) {
snprintf(temp_default, sizeof(temp_default), "%s.otp.asc", input_file);
} else {
snprintf(temp_default, sizeof(temp_default), "%s.otp", input_file);
}
// Apply files directory default path
get_default_file_path(temp_default, default_output, sizeof(default_output));
char output_file[512]; char output_file[512];
if (!fgets(output_file, sizeof(output_file), stdin)) { if (get_filename_with_default("Output filename:", default_output, output_file, sizeof(output_file)) != 0) {
printf("Error: Failed to read input\n"); printf("Error: Failed to read input\n");
return 1; return 1;
} }
output_file[strcspn(output_file, "\n")] = 0;
const char* output_filename = (strlen(output_file) > 0) ? output_file : NULL; const char* output_filename = output_file;
return encrypt_file(pad_input, input_file, output_filename, ascii_armor); return encrypt_file(pad_input, input_file, output_filename, ascii_armor);
} }
@@ -481,58 +480,112 @@ int handle_encrypt_menu(void) {
} }
int handle_decrypt_menu(void) { int handle_decrypt_menu(void) {
printf("\n=== Decrypt Data ===\n"); printf("\n=== Smart Decrypt ===\n");
printf("Enter encrypted data (paste ASCII armor), file path, or press Enter to browse files:\n");
// Ask user to choose between text/message and file decryption char input_line[MAX_LINE_LENGTH];
printf("\nSelect decryption type:\n"); if (!fgets(input_line, sizeof(input_line), stdin)) {
printf("1. Text message (ASCII armored)\n");
printf("2. File (.otp or .otp.asc)\n");
printf("Enter choice (1-2): ");
char choice_input[10];
if (!fgets(choice_input, sizeof(choice_input), stdin)) {
printf("Error: Failed to read input\n"); printf("Error: Failed to read input\n");
return 1; return 1;
} }
int choice = atoi(choice_input); // Remove newline
input_line[strcspn(input_line, "\n")] = 0;
if (choice == 1) { if (strlen(input_line) == 0) {
// Text/message decryption - interactive input // Empty input - launch file manager to browse for files
return decrypt_text(NULL, NULL); // No pad selection needed - chksum comes from message char selected_file[512];
} if (launch_file_manager(get_files_directory(), selected_file, sizeof(selected_file)) != 0) {
else if (choice == 2) { printf("Error: Could not launch file manager\n");
// File decryption
printf("\nEnter encrypted file path (.otp or .otp.asc): ");
char input_file[512];
if (!fgets(input_file, sizeof(input_file), stdin)) {
printf("Error: Failed to read input\n");
return 1;
}
input_file[strcspn(input_file, "\n")] = 0;
// Check if file exists
if (access(input_file, R_OK) != 0) {
printf("Error: File '%s' not found or cannot be read\n", input_file);
return 1; return 1;
} }
// Ask for custom output filename (optional) // Generate smart default output filename with files directory and use enhanced input function
printf("\nEnter output filename (or press Enter for default): "); char temp_default[512];
char default_output[512];
strncpy(temp_default, selected_file, sizeof(temp_default) - 1);
temp_default[sizeof(temp_default) - 1] = '\0';
// Remove common encrypted extensions to get a better default
if (strstr(temp_default, ".otp.asc")) {
// Replace .otp.asc with original extension or no extension
char* ext_pos = strstr(temp_default, ".otp.asc");
*ext_pos = '\0';
} else if (strstr(temp_default, ".otp")) {
// Replace .otp with original extension or no extension
char* ext_pos = strstr(temp_default, ".otp");
*ext_pos = '\0';
} else {
// No recognized encrypted extension, add .decrypted suffix
strncat(temp_default, ".decrypted", sizeof(temp_default) - strlen(temp_default) - 1);
}
// Apply files directory default path
get_default_file_path(temp_default, default_output, sizeof(default_output));
char output_file[512]; char output_file[512];
if (!fgets(output_file, sizeof(output_file), stdin)) { if (get_filename_with_default("Output filename:", default_output, output_file, sizeof(output_file)) != 0) {
printf("Error: Failed to read input\n"); printf("Error: Failed to read input\n");
return 1; return 1;
} }
output_file[strcspn(output_file, "\n")] = 0;
const char* output_filename = (strlen(output_file) > 0) ? output_file : NULL; return decrypt_file(selected_file, output_file);
}
else if (strncmp(input_line, "-----BEGIN OTP MESSAGE-----", 27) == 0) {
// Looks like ASCII armor - collect the full message
char full_message[MAX_INPUT_SIZE * 4] = {0};
strcat(full_message, input_line);
strcat(full_message, "\n");
return decrypt_file(input_file, output_filename); printf("Continue pasting the message (end with -----END OTP MESSAGE-----):\n");
char line[MAX_LINE_LENGTH];
while (fgets(line, sizeof(line), stdin)) {
strncat(full_message, line, sizeof(full_message) - strlen(full_message) - 1);
if (strstr(line, "-----END OTP MESSAGE-----")) {
break;
}
}
return decrypt_text(NULL, full_message);
} }
else { else {
printf("Invalid choice. Please enter 1 or 2.\n"); // Check if it looks like a file path
return 1; if (access(input_line, R_OK) == 0) {
// It's a valid file - decrypt it with enhanced input for output filename
char temp_default[512];
char default_output[512];
strncpy(temp_default, input_line, sizeof(temp_default) - 1);
temp_default[sizeof(temp_default) - 1] = '\0';
// Remove common encrypted extensions to get a better default
if (strstr(temp_default, ".otp.asc")) {
// Replace .otp.asc with original extension or no extension
char* ext_pos = strstr(temp_default, ".otp.asc");
*ext_pos = '\0';
} else if (strstr(temp_default, ".otp")) {
// Replace .otp with original extension or no extension
char* ext_pos = strstr(temp_default, ".otp");
*ext_pos = '\0';
} else {
// No recognized encrypted extension, add .decrypted suffix
strncat(temp_default, ".decrypted", sizeof(temp_default) - strlen(temp_default) - 1);
}
// Apply files directory default path
get_default_file_path(temp_default, default_output, sizeof(default_output));
char output_file[512];
if (get_filename_with_default("Output filename:", default_output, output_file, sizeof(output_file)) != 0) {
printf("Error: Failed to read input\n");
return 1;
}
return decrypt_file(input_line, output_file);
} else {
printf("Input not recognized as ASCII armor or valid file path.\n");
return 1;
}
} }
} }
@@ -688,8 +741,8 @@ int list_available_pads(void) {
struct dirent* entry; struct dirent* entry;
int count = 0; int count = 0;
printf("Available pads:\n"); printf("\nAvailable pads:\n");
printf("%-4s %-20s %-12s %-12s %-8s\n", "No.", "ChkSum (first 16 chars)", "Size", "Used", "% Used"); printf("%-4s %-20s %-12s %-12s %-8s\n", "No.", "ChkSum", "Size", "Used", "% Used");
printf("%-4s %-20s %-12s %-12s %-8s\n", "---", "-------------------", "----------", "----------", "------"); printf("%-4s %-20s %-12s %-12s %-8s\n", "---", "-------------------", "----------", "----------", "------");
while ((entry = readdir(dir)) != NULL) { while ((entry = readdir(dir)) != NULL) {
@@ -782,20 +835,6 @@ int show_pad_info(const char* chksum) {
return 0; return 0;
} }
int get_user_choice(int min, int max) {
char input[64];
int choice;
while (1) {
if (fgets(input, sizeof(input), stdin)) {
choice = atoi(input);
if (choice >= min && choice <= max) {
return choice;
}
}
printf("Please enter a number between %d and %d: ", min, max);
}
}
void show_progress(uint64_t current, uint64_t total, time_t start_time) { void show_progress(uint64_t current, uint64_t total, time_t start_time) {
time_t now = time(NULL); time_t now = time(NULL);
@@ -1161,8 +1200,8 @@ int encrypt_text(const char* pad_identifier, const char* input_text) {
} else { } else {
// Get input text from user (interactive mode) // Get input text from user (interactive mode)
printf("\nText input options:\n"); printf("\nText input options:\n");
printf("1. Type text directly\n"); printf(" 1. Type text directly\n");
printf("2. Use text editor\n"); printf(" 2. Use text editor\n");
printf("Enter choice (1-2): "); printf("Enter choice (1-2): ");
char input_choice[10]; char input_choice[10];
@@ -1544,14 +1583,18 @@ int encrypt_file(const char* pad_identifier, const char* input_file, const char*
return 1; return 1;
} }
// Generate output filename if not specified // Generate output filename if not specified, using files directory
char default_output[512]; char default_output[512];
if (output_file == NULL) { if (output_file == NULL) {
char temp_output[512];
if (ascii_armor) { if (ascii_armor) {
snprintf(default_output, sizeof(default_output), "%s.otp.asc", input_file); snprintf(temp_output, sizeof(temp_output), "%s.otp.asc", input_file);
} else { } else {
snprintf(default_output, sizeof(default_output), "%s.otp", input_file); snprintf(temp_output, sizeof(temp_output), "%s.otp", input_file);
} }
// Apply files directory default path
get_default_file_path(temp_output, default_output, sizeof(default_output));
output_file = default_output; output_file = default_output;
} }
@@ -2208,20 +2251,35 @@ int ensure_pads_directory(void) {
return 0; return 0;
} }
const char* get_files_directory(void) {
struct stat st = {0};
if (stat(FILES_DIR, &st) == 0 && S_ISDIR(st.st_mode)) {
return FILES_DIR;
}
return "."; // Fall back to current directory
}
void get_default_file_path(const char* filename, char* result_path, size_t result_size) {
const char* files_dir = get_files_directory();
// If filename already has a path (contains '/'), use it as-is
if (strchr(filename, '/') != NULL) {
strncpy(result_path, filename, result_size - 1);
result_path[result_size - 1] = '\0';
return;
}
// Otherwise, prepend the files directory
snprintf(result_path, result_size, "%s/%s", files_dir, filename);
}
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, MAX_HASH_LENGTH + 20, "%s/%s.pad", PADS_DIR, chksum); snprintf(pad_path, MAX_HASH_LENGTH + 20, "%s/%s.pad", PADS_DIR, chksum);
snprintf(state_path, MAX_HASH_LENGTH + 20, "%s/%s.state", PADS_DIR, chksum); snprintf(state_path, MAX_HASH_LENGTH + 20, "%s/%s.state", PADS_DIR, chksum);
} }
// Custom XOR checksum function
void xor_checksum_256(const unsigned char* data, size_t len, unsigned char checksum[32]) {
memset(checksum, 0, 32);
for (size_t i = 0; i < len; i++) {
unsigned char bucket = i % 32;
checksum[bucket] ^= data[i] ^ ((i >> 8) & 0xFF) ^ ((i >> 16) & 0xFF) ^ ((i >> 24) & 0xFF);
}
}
// 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) {
@@ -2447,7 +2505,7 @@ int get_filename_with_default(const char* prompt, const char* default_path, char
} }
} else if (c >= 32 && c <= 126) { } else if (c >= 32 && c <= 126) {
// Printable character // Printable character
if (buffer_len < sizeof(edit_buffer) - 1) { if (buffer_len < (int)sizeof(edit_buffer) - 1) {
// Move everything after cursor one position right // Move everything after cursor one position right
memmove(&edit_buffer[cursor_pos + 1], &edit_buffer[cursor_pos], buffer_len - cursor_pos + 1); memmove(&edit_buffer[cursor_pos + 1], &edit_buffer[cursor_pos], buffer_len - cursor_pos + 1);
edit_buffer[cursor_pos] = c; edit_buffer[cursor_pos] = c;
@@ -2770,55 +2828,324 @@ int handle_file_encrypt(void) {
return encrypt_file(pad_input, input_file, output_filename, ascii_armor); return encrypt_file(pad_input, input_file, output_filename, ascii_armor);
} }
int handle_smart_decrypt(void) {
printf("\n=== Smart Decrypt ===\n"); int handle_pads_menu(void) {
printf("Enter encrypted data (paste ASCII armor) or press Enter to browse files:\n"); printf("\n=== Pad Management ===\n");
char input_line[MAX_LINE_LENGTH]; // Get list of all pads
if (!fgets(input_line, sizeof(input_line), stdin)) { DIR* dir = opendir(PADS_DIR);
if (!dir) {
printf("Error: Cannot open pads directory\n");
return 1;
}
// Structure to store pad information
struct PadInfo {
char chksum[65];
char size_str[32];
char used_str[32];
double percentage;
};
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[300];
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;
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(" \033[4mB\033[0mack to main menu\n");
printf("\nSelect option: ");
char input[10];
if (fgets(input, sizeof(input), stdin)) {
char choice = toupper(input[0]);
if (choice == 'G') {
return handle_generate_menu();
}
}
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
printf("\nAvailable pads:\n");
printf("%-8s %-12s %-12s %-12s %-8s\n", "ChkSum", "Dir", "Size", "Used", "% Used");
printf("%-8s %-12s %-12s %-12s %-8s\n", "--------", "------------", "----------", "----------", "------");
for (int i = 0; i < pad_count; i++) {
// Get directory information for this pad
char full_path[300];
snprintf(full_path, sizeof(full_path), "%s/%s.pad", PADS_DIR, pads[i].chksum);
char dir_display[13]; // 12 chars + null terminator
get_directory_display(full_path, dir_display, sizeof(dir_display));
// 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 %-12s %-12s %-12s %.1f%%\n",
prefix_lengths[i], checksum_8char, // Underlined prefix
checksum_8char + prefix_lengths[i], // Rest of 8-char checksum
dir_display,
pads[i].size_str,
pads[i].used_str,
pads[i].percentage);
}
printf("\nActions:\n");
printf(" \033[4mG\033[0menerate new pad\n");
printf(" \033[4mB\033[0mack to main menu\n");
printf("\nSelect pad (by prefix) or 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 first
if (toupper(input[0]) == 'G') {
return handle_generate_menu();
} else if (toupper(input[0]) == 'B') {
return 0; // Back to main menu
}
// Find matching pad by prefix
int selected_pad = -1;
for (int i = 0; i < pad_count; i++) {
if (strncmp(input, pads[i].chksum, strlen(input)) == 0) {
if (selected_pad == -1) {
selected_pad = i;
} else {
// Multiple matches - ambiguous
printf("Ambiguous prefix. Multiple matches found.\n");
return 1;
}
}
}
if (selected_pad == -1) {
printf("No pad found matching prefix '%s'\n", input);
return 1;
}
// Show selected pad actions
printf("\n=== Pad: %.16s... ===\n", pads[selected_pad].chksum);
printf("Size: %s\n", pads[selected_pad].size_str);
printf("Used: %s (%.1f%%)\n", pads[selected_pad].used_str, pads[selected_pad].percentage);
printf("\nPad Actions:\n");
printf(" \033[4mI\033[0mnfo - Show detailed pad information\n");
printf(" \033[4mB\033[0mack to pad list\n");
printf("\nSelect action: ");
char action[10];
if (!fgets(action, sizeof(action), stdin)) {
printf("Error: Failed to read input\n"); printf("Error: Failed to read input\n");
return 1; return 1;
} }
// Remove newline char action_choice = toupper(action[0]);
input_line[strcspn(input_line, "\n")] = 0; if (action_choice == 'I') {
return show_pad_info(pads[selected_pad].chksum);
}
if (strlen(input_line) == 0) { // Default: back to pad list (recursive call)
// Empty input - launch file manager return handle_pads_menu();
char selected_file[512]; }
if (launch_file_manager(".", selected_file, sizeof(selected_file)) != 0) {
printf("Error: Could not launch file manager\n"); void get_directory_display(const char* file_path, char* result, size_t result_size) {
return 1; // 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/");
} }
// Decrypt selected file if (media_start) {
return decrypt_file(selected_file, NULL); // Find the USB label part
} else if (strncmp(input_line, "-----BEGIN OTP MESSAGE-----", 27) == 0) { char* path_after_media = strchr(media_start + 1, '/');
// Looks like ASCII armor - collect the full message if (path_after_media) {
char full_message[MAX_INPUT_SIZE * 4] = {0}; path_after_media++; // Skip the slash
strcat(full_message, input_line);
strcat(full_message, "\n"); // For /run/media/user/LABEL pattern, skip the username
if (strstr(media_start, "/run/media/")) {
printf("Continue pasting the message (end with -----END OTP MESSAGE-----):\n"); char* next_slash = strchr(path_after_media, '/');
if (next_slash) {
char line[MAX_LINE_LENGTH]; path_after_media = next_slash + 1;
while (fgets(line, sizeof(line), stdin)) { }
strncat(full_message, line, sizeof(full_message) - strlen(full_message) - 1); }
if (strstr(line, "-----END OTP MESSAGE-----")) {
break; // Extract just the USB label (up to next slash or end)
char* label_end = strchr(path_after_media, '/');
if (label_end) {
size_t label_len = label_end - path_after_media;
if (label_len > 11) label_len = 11; // Max 11 chars for display
strncpy(result, path_after_media, label_len);
result[label_len] = '\0';
} else {
// USB label is the last part
strncpy(result, path_after_media, result_size - 1);
result[result_size - 1] = '\0';
}
return;
} }
} }
}
return decrypt_text(NULL, full_message);
} else { // Home directory shortening
// Check if it looks like a file path if (home_dir && strncmp(dir_path, home_dir, strlen(home_dir)) == 0) {
if (access(input_line, R_OK) == 0) { if (dir_path[strlen(home_dir)] == '/' || dir_path[strlen(home_dir)] == '\0') {
return decrypt_file(input_line, NULL); // Replace home directory with ~
} else { char temp[512];
printf("Input not recognized as ASCII armor or valid file path.\n"); snprintf(temp, sizeof(temp), "~%s", dir_path + strlen(home_dir));
return 1;
// 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, 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 print_usage(const char* program_name) { void print_usage(const char* program_name) {

1
test_files_dir.txt Normal file
View File

@@ -0,0 +1 @@
Testing updated files directory functionality

1
test_new.txt Normal file
View File

@@ -0,0 +1 @@
Testing files directory functionality

BIN
test_new.txt.otp Normal file

Binary file not shown.