Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| aff8bea0a2 | |||
| 864c0356da | |||
| 35175790e2 | |||
| 04ea4fb848 | |||
| 5c61ba7ea8 | |||
| a45b304d22 | |||
| 403d013224 | |||
| 82533d96e4 | |||
| 5b619384a1 | |||
| 12b9884572 | |||
| 83b60b5cc2 | |||
| 2d6546ab83 | |||
| c255185084 | |||
| 24800d69d5 | |||
| 7e50727163 |
1
decrypted.bin
Normal file
1
decrypted.bin
Normal file
@@ -0,0 +1 @@
|
||||
Test file content for decryption
|
||||
BIN
files/out2.otp
Normal file
BIN
files/out2.otp
Normal file
Binary file not shown.
BIN
files/output.otp
Normal file
BIN
files/output.otp
Normal file
Binary file not shown.
1
files/test_decrypt.txt
Normal file
1
files/test_decrypt.txt
Normal file
@@ -0,0 +1 @@
|
||||
Test file content for decryption
|
||||
BIN
files/test_decrypt.txt.otp
Normal file
BIN
files/test_decrypt.txt.otp
Normal file
Binary file not shown.
1
files/test_file.txt
Normal file
1
files/test_file.txt
Normal file
@@ -0,0 +1 @@
|
||||
Hello, this is a test file for encryption!
|
||||
7
files/test_file.txt.otp.asc
Normal file
7
files/test_file.txt.otp.asc
Normal file
@@ -0,0 +1,7 @@
|
||||
-----BEGIN OTP MESSAGE-----
|
||||
Version: v0.2.29
|
||||
Pad-ChkSum: d0d4a489354348b08d8c7b324814d8c50010042e9da47f2c973f32a16a09101b
|
||||
Pad-Offset: 57
|
||||
|
||||
05S8GfS0tFfczNMUz0xrieFGoPSREM4uo5QhFGoBCcOzjfTXTDMt3hRtAQ==
|
||||
-----END OTP MESSAGE-----
|
||||
BIN
files/test_files_dir.txt.otp
Normal file
BIN
files/test_files_dir.txt.otp
Normal file
Binary file not shown.
1
files/test_input.txt
Normal file
1
files/test_input.txt
Normal file
@@ -0,0 +1 @@
|
||||
This is a test file for encryption.
|
||||
BIN
files/toc.txt.otp
Normal file
BIN
files/toc.txt.otp
Normal file
Binary file not shown.
498
otp.c
498
otp.c
@@ -40,6 +40,7 @@ static const int base64_decode_table[256] = {
|
||||
#define MAX_HASH_LENGTH 65
|
||||
#define PROGRESS_UPDATE_INTERVAL (64 * 1024 * 1024) // 64MB intervals
|
||||
#define PADS_DIR "pads"
|
||||
#define FILES_DIR "files"
|
||||
#define MAX_ENTROPY_BUFFER 32768 // 32KB entropy buffer
|
||||
|
||||
// Function prototypes
|
||||
@@ -73,20 +74,20 @@ void simple_entropy_mix(unsigned char* urandom_buffer, size_t buffer_size,
|
||||
// Directory management
|
||||
int ensure_pads_directory(void);
|
||||
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
|
||||
uint64_t parse_size_string(const char* size_str);
|
||||
char* find_pad_by_prefix(const char* prefix);
|
||||
int list_available_pads(void);
|
||||
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);
|
||||
|
||||
// File operations
|
||||
int read_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);
|
||||
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);
|
||||
unsigned char* custom_base64_decode(const char* input, int* output_length);
|
||||
|
||||
@@ -97,7 +98,9 @@ int handle_encrypt_menu(void);
|
||||
int handle_decrypt_menu(void);
|
||||
int handle_text_encrypt(void);
|
||||
int handle_file_encrypt(void);
|
||||
int handle_smart_decrypt(void);
|
||||
|
||||
// Enhanced input functions
|
||||
int get_filename_with_default(const char* prompt, const char* default_path, char* result, size_t result_size);
|
||||
|
||||
void print_usage(const char* program_name);
|
||||
|
||||
@@ -110,7 +113,7 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
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) {
|
||||
show_main_menu();
|
||||
@@ -126,7 +129,7 @@ int interactive_mode(void) {
|
||||
handle_file_encrypt();
|
||||
break;
|
||||
case 'D':
|
||||
handle_smart_decrypt();
|
||||
handle_decrypt_menu();
|
||||
break;
|
||||
case 'G':
|
||||
handle_generate_menu();
|
||||
@@ -268,14 +271,16 @@ int command_line_mode(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
void show_main_menu(void) {
|
||||
printf("=== Main Menu ===\n\n");
|
||||
printf("\033[4mT\033[0mext encrypt\n");
|
||||
printf("\033[4mF\033[0mile encrypt\n");
|
||||
printf("\033[4mD\033[0mecrypt\n");
|
||||
printf("\033[4mG\033[0menerate new pad\n");
|
||||
printf("\033[4mL\033[0mist available pads\n");
|
||||
printf("\033[4mS\033[0mhow pad information\n");
|
||||
printf("E\033[4mx\033[0mit\n");
|
||||
|
||||
printf("\n\n\n\n=========================== Main Menu - OTP %s ===========================\n\n", get_version() );
|
||||
|
||||
printf(" \033[4mT\033[0mext encrypt\n");
|
||||
printf(" \033[4mF\033[0mile encrypt\n");
|
||||
printf(" \033[4mD\033[0mecrypt\n");
|
||||
printf(" \033[4mG\033[0menerate new pad\n");
|
||||
printf(" \033[4mL\033[0mist available pads\n");
|
||||
printf(" \033[4mS\033[0mhow pad information\n");
|
||||
printf(" E\033[4mx\033[0mit\n");
|
||||
printf("\nSelect option: ");
|
||||
}
|
||||
|
||||
@@ -329,8 +334,8 @@ int handle_encrypt_menu(void) {
|
||||
|
||||
// Ask user to choose between text and file encryption
|
||||
printf("\nSelect encryption type:\n");
|
||||
printf("1. Text message\n");
|
||||
printf("2. File\n");
|
||||
printf(" 1. Text message\n");
|
||||
printf(" 2. File\n");
|
||||
printf("Enter choice (1-2): ");
|
||||
|
||||
char choice_input[10];
|
||||
@@ -344,9 +349,9 @@ int handle_encrypt_menu(void) {
|
||||
if (choice == 1) {
|
||||
// Text encryption
|
||||
printf("\nPad selection options:\n");
|
||||
printf("1. Select from numbered list\n");
|
||||
printf("2. Enter checksum/prefix manually\n");
|
||||
printf("3. Browse pad files\n");
|
||||
printf(" 1. Select from numbered list\n");
|
||||
printf(" 2. Enter checksum/prefix manually\n");
|
||||
printf(" 3. Browse pad files\n");
|
||||
printf("Enter choice (1-3): ");
|
||||
|
||||
char pad_choice[10];
|
||||
@@ -397,8 +402,8 @@ int handle_encrypt_menu(void) {
|
||||
else if (choice == 2) {
|
||||
// File encryption
|
||||
printf("\nFile selection options:\n");
|
||||
printf("1. Type file path directly\n");
|
||||
printf("2. Use file manager\n");
|
||||
printf(" 1. Type file path directly\n");
|
||||
printf(" 2. Use file manager\n");
|
||||
printf("Enter choice (1-2): ");
|
||||
|
||||
char file_choice[10];
|
||||
@@ -446,8 +451,8 @@ int handle_encrypt_menu(void) {
|
||||
|
||||
// Ask for output format
|
||||
printf("\nSelect output format:\n");
|
||||
printf("1. Binary (.otp) - preserves file permissions\n");
|
||||
printf("2. ASCII (.otp.asc) - text-safe format\n");
|
||||
printf(" 1. Binary (.otp) - preserves file permissions\n");
|
||||
printf(" 2. ASCII (.otp.asc) - text-safe format\n");
|
||||
printf("Enter choice (1-2): ");
|
||||
|
||||
char format_input[10];
|
||||
@@ -458,16 +463,27 @@ int handle_encrypt_menu(void) {
|
||||
|
||||
int ascii_armor = (atoi(format_input) == 2) ? 1 : 0;
|
||||
|
||||
// Ask for custom output filename (optional)
|
||||
printf("\nEnter output filename (or press Enter for default): ");
|
||||
// Generate default output filename with files directory and use enhanced input function
|
||||
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];
|
||||
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");
|
||||
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);
|
||||
}
|
||||
@@ -478,59 +494,113 @@ int handle_encrypt_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
|
||||
printf("\nSelect decryption type:\n");
|
||||
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)) {
|
||||
char input_line[MAX_LINE_LENGTH];
|
||||
if (!fgets(input_line, sizeof(input_line), stdin)) {
|
||||
printf("Error: Failed to read input\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int choice = atoi(choice_input);
|
||||
// Remove newline
|
||||
input_line[strcspn(input_line, "\n")] = 0;
|
||||
|
||||
if (choice == 1) {
|
||||
// Text/message decryption - interactive input
|
||||
return decrypt_text(NULL, NULL); // No pad selection needed - chksum comes from message
|
||||
}
|
||||
else if (choice == 2) {
|
||||
// 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);
|
||||
if (strlen(input_line) == 0) {
|
||||
// Empty input - launch file manager to browse for files
|
||||
char selected_file[512];
|
||||
if (launch_file_manager(get_files_directory(), selected_file, sizeof(selected_file)) != 0) {
|
||||
printf("Error: Could not launch file manager\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Ask for custom output filename (optional)
|
||||
printf("\nEnter output filename (or press Enter for default): ");
|
||||
// Generate smart default output filename with files directory and use enhanced input function
|
||||
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];
|
||||
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");
|
||||
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 {
|
||||
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 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) {
|
||||
@@ -779,20 +849,6 @@ int show_pad_info(const char* chksum) {
|
||||
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) {
|
||||
time_t now = time(NULL);
|
||||
@@ -1158,8 +1214,8 @@ int encrypt_text(const char* pad_identifier, const char* input_text) {
|
||||
} else {
|
||||
// Get input text from user (interactive mode)
|
||||
printf("\nText input options:\n");
|
||||
printf("1. Type text directly\n");
|
||||
printf("2. Use text editor\n");
|
||||
printf(" 1. Type text directly\n");
|
||||
printf(" 2. Use text editor\n");
|
||||
printf("Enter choice (1-2): ");
|
||||
|
||||
char input_choice[10];
|
||||
@@ -1541,14 +1597,18 @@ int encrypt_file(const char* pad_identifier, const char* input_file, const char*
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Generate output filename if not specified
|
||||
// Generate output filename if not specified, using files directory
|
||||
char default_output[512];
|
||||
if (output_file == NULL) {
|
||||
char temp_output[512];
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -2205,20 +2265,35 @@ int ensure_pads_directory(void) {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
// 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
|
||||
char* custom_base64_encode(const unsigned char* input, int length) {
|
||||
@@ -2297,6 +2372,194 @@ void simple_entropy_mix(unsigned char* urandom_buffer, size_t buffer_size,
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// Find the last directory separator
|
||||
char* last_slash = strrchr(default_path, '/');
|
||||
char directory[1024] = "";
|
||||
char filename[512] = "";
|
||||
|
||||
if (last_slash) {
|
||||
// Extract directory path
|
||||
size_t dir_len = last_slash - default_path + 1; // Include the trailing slash
|
||||
if (dir_len < sizeof(directory)) {
|
||||
strncpy(directory, default_path, dir_len);
|
||||
directory[dir_len] = '\0';
|
||||
}
|
||||
|
||||
// Extract filename
|
||||
strncpy(filename, last_slash + 1, sizeof(filename) - 1);
|
||||
filename[sizeof(filename) - 1] = '\0';
|
||||
} else {
|
||||
// No directory separator, treat as filename only
|
||||
strncpy(filename, default_path, sizeof(filename) - 1);
|
||||
filename[sizeof(filename) - 1] = '\0';
|
||||
}
|
||||
|
||||
// Setup terminal for raw input
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
char* get_preferred_editor(void) {
|
||||
@@ -2567,71 +2830,18 @@ int handle_file_encrypt(void) {
|
||||
snprintf(default_output, sizeof(default_output), "%s.otp", input_file);
|
||||
}
|
||||
|
||||
// Ask for output filename with pre-filled default
|
||||
printf("\nOutput filename [%s]: ", default_output);
|
||||
// Use enhanced input function for output filename
|
||||
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");
|
||||
return 1;
|
||||
}
|
||||
output_file[strcspn(output_file, "\n")] = 0;
|
||||
|
||||
// Use default if user just pressed Enter
|
||||
const char* output_filename = (strlen(output_file) > 0) ? output_file : default_output;
|
||||
const char* output_filename = output_file;
|
||||
|
||||
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) {
|
||||
printf("OTP Cipher - One Time Pad Implementation %s\n", get_version());
|
||||
|
||||
1
test_files_dir.txt
Normal file
1
test_files_dir.txt
Normal file
@@ -0,0 +1 @@
|
||||
Testing updated files directory functionality
|
||||
1
test_new.txt
Normal file
1
test_new.txt
Normal file
@@ -0,0 +1 @@
|
||||
Testing files directory functionality
|
||||
BIN
test_new.txt.otp
Normal file
BIN
test_new.txt.otp
Normal file
Binary file not shown.
Reference in New Issue
Block a user