Compare commits

..

13 Commits

Author SHA1 Message Date
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
24800d69d5 Version v0.2.30 - implemented advanced interactive filename editing with cursor control and pre-filled text 2025-08-13 11:10:43 -04:00
15 changed files with 334 additions and 131 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.

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.

BIN
files/toc.txt.otp Normal file

Binary file not shown.

405
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
@@ -72,7 +73,10 @@ 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);
int ensure_files_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);
@@ -97,7 +101,6 @@ int handle_encrypt_menu(void);
int handle_decrypt_menu(void); int handle_decrypt_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);
@@ -113,7 +116,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,7 +132,7 @@ 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 'G':
handle_generate_menu(); handle_generate_menu();
@@ -271,7 +274,9 @@ int command_line_mode(int argc, char* argv[]) {
} }
void show_main_menu(void) { void show_main_menu(void) {
printf("=== Main Menu ===\n\n");
printf("\n\n\n\n=========================== Main Menu - OTP %s ===========================\n\n", get_version() );
printf(" \033[4mT\033[0mext encrypt\n"); printf(" \033[4mT\033[0mext encrypt\n");
printf(" \033[4mF\033[0mile encrypt\n"); printf(" \033[4mF\033[0mile encrypt\n");
printf(" \033[4mD\033[0mecrypt\n"); printf(" \033[4mD\033[0mecrypt\n");
@@ -461,16 +466,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,59 +497,113 @@ 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
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 1;
} }
return decrypt_file(input_line, output_file);
} else {
printf("Input not recognized as ASCII armor or valid file path.\n");
return 1;
}
}
} }
uint64_t parse_size_string(const char* size_str) { uint64_t parse_size_string(const char* size_str) {
@@ -1544,14 +1614,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,6 +2282,38 @@ int ensure_pads_directory(void) {
return 0; return 0;
} }
int ensure_files_directory(void) {
struct stat st = {0};
if (stat(FILES_DIR, &st) == -1) {
if (mkdir(FILES_DIR, 0755) != 0) {
return 1;
}
}
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);
@@ -2300,7 +2406,7 @@ void simple_entropy_mix(unsigned char* urandom_buffer, size_t buffer_size,
} }
} }
// Enhanced input function for filename with directory separation // Enhanced input function with editable pre-filled text
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) {
// Find the last directory separator // Find the last directory separator
char* last_slash = strrchr(default_path, '/'); char* last_slash = strrchr(default_path, '/');
@@ -2324,33 +2430,168 @@ int get_filename_with_default(const char* prompt, const char* default_path, char
filename[sizeof(filename) - 1] = '\0'; filename[sizeof(filename) - 1] = '\0';
} }
// Display the enhanced prompt with directory and filename separated by colon // Setup terminal for raw input
printf("\n%s\n%s: %s", prompt, directory, filename); struct termios orig_termios;
if (tcgetattr(STDIN_FILENO, &orig_termios) != 0) {
// Fallback to simple input if terminal control fails
printf("\n%s\n%s: ", prompt, directory);
fflush(stdout); fflush(stdout);
char input_buffer[512]; char input_buffer[512];
if (!fgets(input_buffer, sizeof(input_buffer), stdin)) { if (!fgets(input_buffer, sizeof(input_buffer), stdin)) {
return 1; // Error reading input return 1;
} }
// Remove newline
input_buffer[strcspn(input_buffer, "\n")] = 0; input_buffer[strcspn(input_buffer, "\n")] = 0;
// If user just pressed Enter, use the default filename
if (strlen(input_buffer) == 0) { if (strlen(input_buffer) == 0) {
strncpy(result, default_path, result_size - 1); strncpy(result, default_path, result_size - 1);
result[result_size - 1] = '\0';
} else { } else {
// Combine directory with user input
if (strlen(directory) > 0) { if (strlen(directory) > 0) {
snprintf(result, result_size, "%s%s", directory, input_buffer); snprintf(result, result_size, "%s%s", directory, input_buffer);
} else { } else {
strncpy(result, input_buffer, result_size - 1); strncpy(result, input_buffer, result_size - 1);
result[result_size - 1] = '\0';
} }
} }
result[result_size - 1] = '\0';
return 0;
}
return 0; // Success // Set up raw terminal mode
struct termios raw_termios = orig_termios;
raw_termios.c_lflag &= ~(ECHO | ICANON);
raw_termios.c_cc[VMIN] = 1;
raw_termios.c_cc[VTIME] = 0;
if (tcsetattr(STDIN_FILENO, TCSANOW, &raw_termios) != 0) {
// Fallback if terminal setup fails
printf("\n%s\n%s: ", prompt, directory);
fflush(stdout);
char input_buffer[512];
if (!fgets(input_buffer, sizeof(input_buffer), stdin)) {
return 1;
}
input_buffer[strcspn(input_buffer, "\n")] = 0;
if (strlen(input_buffer) == 0) {
strncpy(result, default_path, result_size - 1);
} else {
if (strlen(directory) > 0) {
snprintf(result, result_size, "%s%s", directory, input_buffer);
} else {
strncpy(result, input_buffer, result_size - 1);
}
}
result[result_size - 1] = '\0';
return 0;
}
// Display prompt and directory
printf("\n%s\n%s", prompt, directory);
fflush(stdout);
// Initialize editing buffer with default filename
char edit_buffer[512];
strncpy(edit_buffer, filename, sizeof(edit_buffer) - 1);
edit_buffer[sizeof(edit_buffer) - 1] = '\0';
int cursor_pos = strlen(edit_buffer);
int buffer_len = cursor_pos;
// Display initial filename
printf("%s", edit_buffer);
fflush(stdout);
// Main editing loop
int c;
while ((c = getchar()) != EOF) {
if (c == '\n' || c == '\r') {
// Enter key - accept input
break;
} else if (c == 127 || c == 8) {
// Backspace/Delete
if (cursor_pos > 0) {
// Move everything after cursor one position left
memmove(&edit_buffer[cursor_pos - 1], &edit_buffer[cursor_pos], buffer_len - cursor_pos + 1);
cursor_pos--;
buffer_len--;
// Redraw line: move cursor to start of filename area, clear to end, redraw buffer
printf("\r%s\033[K%s", directory, edit_buffer);
// Position cursor correctly
if (cursor_pos < buffer_len) {
printf("\033[%dD", buffer_len - cursor_pos);
}
fflush(stdout);
}
} else if (c == 27) {
// Escape sequence (arrow keys, etc.)
int c1 = getchar();
int c2 = getchar();
if (c1 == '[') {
if (c2 == 'C' && cursor_pos < buffer_len) {
// Right arrow
cursor_pos++;
printf("\033[1C");
fflush(stdout);
} else if (c2 == 'D' && cursor_pos > 0) {
// Left arrow
cursor_pos--;
printf("\033[1D");
fflush(stdout);
} else if (c2 == 'H') {
// Home key
printf("\033[%dD", cursor_pos);
cursor_pos = 0;
fflush(stdout);
} else if (c2 == 'F') {
// End key
printf("\033[%dC", buffer_len - cursor_pos);
cursor_pos = buffer_len;
fflush(stdout);
}
}
} else if (c >= 32 && c <= 126) {
// Printable character
if (buffer_len < (int)sizeof(edit_buffer) - 1) {
// Move everything after cursor one position right
memmove(&edit_buffer[cursor_pos + 1], &edit_buffer[cursor_pos], buffer_len - cursor_pos + 1);
edit_buffer[cursor_pos] = c;
cursor_pos++;
buffer_len++;
// Redraw from cursor position
printf("%c", c);
if (cursor_pos < buffer_len) {
// Print remaining characters and move cursor back
printf("%s\033[%dD", &edit_buffer[cursor_pos], buffer_len - cursor_pos);
}
fflush(stdout);
}
}
// Ignore other control characters
}
// Restore terminal
tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios);
printf("\n");
// Construct final result
if (buffer_len == 0) {
// Empty input, use default
strncpy(result, default_path, result_size - 1);
} else {
// Combine directory with edited filename
edit_buffer[buffer_len] = '\0';
if (strlen(directory) > 0) {
snprintf(result, result_size, "%s%s", directory, edit_buffer);
} else {
strncpy(result, edit_buffer, result_size - 1);
}
}
result[result_size - 1] = '\0';
return 0;
} }
// Editor and file manager implementations // Editor and file manager implementations
@@ -2635,56 +2876,6 @@ 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");
printf("Enter encrypted data (paste ASCII armor) or press Enter to browse files:\n");
char input_line[MAX_LINE_LENGTH];
if (!fgets(input_line, sizeof(input_line), stdin)) {
printf("Error: Failed to read input\n");
return 1;
}
// Remove newline
input_line[strcspn(input_line, "\n")] = 0;
if (strlen(input_line) == 0) {
// Empty input - launch file manager
char selected_file[512];
if (launch_file_manager(".", selected_file, sizeof(selected_file)) != 0) {
printf("Error: Could not launch file manager\n");
return 1;
}
// Decrypt selected file
return decrypt_file(selected_file, NULL);
} 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");
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 {
// Check if it looks like a file path
if (access(input_line, R_OK) == 0) {
return decrypt_file(input_line, NULL);
} else {
printf("Input not recognized as ASCII armor or valid file path.\n");
return 1;
}
}
}
void print_usage(const char* program_name) { void print_usage(const char* program_name) {
printf("OTP Cipher - One Time Pad Implementation %s\n", get_version()); printf("OTP Cipher - One Time Pad Implementation %s\n", get_version());

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.