Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2a5249d93c | |||
| 0e02eaee53 | |||
| e32eb8b2b1 | |||
| 0aecae0c5e | |||
| fa90e0eafd | |||
| 2a10d974b2 |
@@ -1,4 +1,7 @@
|
||||
|
||||
When building, use build.sh, not make.
|
||||
|
||||
Use it as follows: build.sh -m "useful comment on changes being made"
|
||||
Use it as follows: build.sh -m "useful comment on changes being made"
|
||||
|
||||
When making TUI menus, try to use the first leter of the command and the key to press to execute that command. For example, if the command is "Open file" try to use a keypress of "o" upper or lower case to signal to open the file. Use this instead of number keyed menus when possible. In the command, the letter should be underlined that signifies the command.
|
||||
|
||||
|
||||
685
otp.c
685
otp.c
@@ -47,6 +47,12 @@ int main(int argc, char* argv[]);
|
||||
int interactive_mode(void);
|
||||
int command_line_mode(int argc, char* argv[]);
|
||||
|
||||
// Editor and file manager functions
|
||||
char* get_preferred_editor(void);
|
||||
char* get_preferred_file_manager(void);
|
||||
int launch_text_editor(const char* initial_content, char* result_buffer, size_t buffer_size);
|
||||
int launch_file_manager(const char* start_directory, char* selected_file, size_t buffer_size);
|
||||
|
||||
// Core functions
|
||||
int generate_pad(uint64_t size_bytes, int show_progress);
|
||||
int generate_pad_with_entropy(uint64_t size_bytes, int show_progress, int use_keyboard_entropy);
|
||||
@@ -89,6 +95,9 @@ void show_main_menu(void);
|
||||
int handle_generate_menu(void);
|
||||
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);
|
||||
|
||||
void print_usage(const char* program_name);
|
||||
|
||||
@@ -110,14 +119,17 @@ int interactive_mode(void) {
|
||||
char choice = toupper(input[0]);
|
||||
|
||||
switch (choice) {
|
||||
case 'G':
|
||||
handle_generate_menu();
|
||||
case 'T':
|
||||
handle_text_encrypt();
|
||||
break;
|
||||
case 'E':
|
||||
handle_encrypt_menu();
|
||||
case 'F':
|
||||
handle_file_encrypt();
|
||||
break;
|
||||
case 'D':
|
||||
handle_decrypt_menu();
|
||||
handle_smart_decrypt();
|
||||
break;
|
||||
case 'G':
|
||||
handle_generate_menu();
|
||||
break;
|
||||
case 'L':
|
||||
list_available_pads();
|
||||
@@ -136,10 +148,11 @@ int interactive_mode(void) {
|
||||
break;
|
||||
}
|
||||
case 'X':
|
||||
case 'Q':
|
||||
printf("Goodbye!\n");
|
||||
return 0;
|
||||
default:
|
||||
printf("Invalid option. Please select G, E, D, L, S, or X.\n");
|
||||
printf("Invalid option. Please select T, F, D, G, L, S, or X.\n");
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
@@ -151,6 +164,14 @@ int interactive_mode(void) {
|
||||
}
|
||||
|
||||
int command_line_mode(int argc, char* argv[]) {
|
||||
// Check for help flags first
|
||||
if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--h") == 0 ||
|
||||
strcmp(argv[1], "-help") == 0 || strcmp(argv[1], "--help") == 0 ||
|
||||
strcmp(argv[1], "help") == 0) {
|
||||
print_usage(argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "generate") == 0 || strcmp(argv[1], "-g") == 0) {
|
||||
if (argc != 3) {
|
||||
printf("Usage: %s generate|-g <size>\n", argv[0]);
|
||||
@@ -247,10 +268,11 @@ int command_line_mode(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
void show_main_menu(void) {
|
||||
printf("=== Main Menu ===\n");
|
||||
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[4mE\033[0mncrypt message\n");
|
||||
printf("\033[4mD\033[0mecrypt message\n");
|
||||
printf("\033[4mL\033[0mist available pads\n");
|
||||
printf("\033[4mS\033[0mhow pad information\n");
|
||||
printf("E\033[4mx\033[0mit\n");
|
||||
@@ -297,7 +319,7 @@ int handle_generate_menu(void) {
|
||||
}
|
||||
|
||||
int handle_encrypt_menu(void) {
|
||||
printf("\n=== Encrypt Message ===\n");
|
||||
printf("\n=== Encrypt Data ===\n");
|
||||
|
||||
int pad_count = list_available_pads();
|
||||
if (pad_count == 0) {
|
||||
@@ -305,20 +327,210 @@ int handle_encrypt_menu(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("\nEnter pad selection (number, chksum, or prefix): ");
|
||||
char input[MAX_HASH_LENGTH];
|
||||
if (!fgets(input, sizeof(input), stdin)) {
|
||||
// Ask user to choose between text and file encryption
|
||||
printf("\nSelect encryption type:\n");
|
||||
printf("1. Text message\n");
|
||||
printf("2. File\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");
|
||||
return 1;
|
||||
}
|
||||
|
||||
input[strcspn(input, "\n")] = 0;
|
||||
return encrypt_text(input, NULL); // NULL for interactive mode
|
||||
int choice = atoi(choice_input);
|
||||
|
||||
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("Enter choice (1-3): ");
|
||||
|
||||
char pad_choice[10];
|
||||
if (!fgets(pad_choice, sizeof(pad_choice), stdin)) {
|
||||
printf("Error: Failed to read input\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char input[MAX_HASH_LENGTH];
|
||||
if (atoi(pad_choice) == 3) {
|
||||
// Use file manager to browse pads directory
|
||||
char selected_pad[512];
|
||||
if (launch_file_manager("pads", selected_pad, sizeof(selected_pad)) == 0) {
|
||||
// Extract checksum from selected .pad file
|
||||
char* filename = strrchr(selected_pad, '/');
|
||||
if (!filename) filename = selected_pad;
|
||||
else filename++; // Skip the '/'
|
||||
|
||||
// Remove .pad extension to get checksum
|
||||
if (strlen(filename) == 68 && strstr(filename, ".pad")) {
|
||||
strncpy(input, filename, 64);
|
||||
input[64] = '\0';
|
||||
} else {
|
||||
printf("Invalid pad file selected.\n");
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
printf("Falling back to manual pad selection.\n");
|
||||
printf("Enter pad selection (number, chksum, or prefix): ");
|
||||
if (!fgets(input, sizeof(input), stdin)) {
|
||||
printf("Error: Failed to read input\n");
|
||||
return 1;
|
||||
}
|
||||
input[strcspn(input, "\n")] = 0;
|
||||
}
|
||||
} else {
|
||||
// Manual pad selection
|
||||
printf("Enter pad selection (number, chksum, or prefix): ");
|
||||
if (!fgets(input, sizeof(input), stdin)) {
|
||||
printf("Error: Failed to read input\n");
|
||||
return 1;
|
||||
}
|
||||
input[strcspn(input, "\n")] = 0;
|
||||
}
|
||||
|
||||
return encrypt_text(input, NULL); // NULL for interactive mode
|
||||
}
|
||||
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("Enter choice (1-2): ");
|
||||
|
||||
char file_choice[10];
|
||||
char input_file[512];
|
||||
|
||||
if (!fgets(file_choice, sizeof(file_choice), stdin)) {
|
||||
printf("Error: Failed to read input\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (atoi(file_choice) == 2) {
|
||||
// Use file manager
|
||||
if (launch_file_manager(".", input_file, sizeof(input_file)) != 0) {
|
||||
printf("Falling back to manual file path entry.\n");
|
||||
printf("Enter input file path: ");
|
||||
if (!fgets(input_file, sizeof(input_file), stdin)) {
|
||||
printf("Error: Failed to read input\n");
|
||||
return 1;
|
||||
}
|
||||
input_file[strcspn(input_file, "\n")] = 0;
|
||||
}
|
||||
} else {
|
||||
// Direct file path input
|
||||
printf("Enter input file path: ");
|
||||
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;
|
||||
}
|
||||
|
||||
printf("\nEnter pad selection (number, chksum, or prefix): ");
|
||||
char pad_input[MAX_HASH_LENGTH];
|
||||
if (!fgets(pad_input, sizeof(pad_input), stdin)) {
|
||||
printf("Error: Failed to read input\n");
|
||||
return 1;
|
||||
}
|
||||
pad_input[strcspn(pad_input, "\n")] = 0;
|
||||
|
||||
// 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("Enter choice (1-2): ");
|
||||
|
||||
char format_input[10];
|
||||
if (!fgets(format_input, sizeof(format_input), stdin)) {
|
||||
printf("Error: Failed to read input\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ascii_armor = (atoi(format_input) == 2) ? 1 : 0;
|
||||
|
||||
// Ask for custom output filename (optional)
|
||||
printf("\nEnter output filename (or press Enter for default): ");
|
||||
char output_file[512];
|
||||
if (!fgets(output_file, sizeof(output_file), stdin)) {
|
||||
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 encrypt_file(pad_input, input_file, output_filename, ascii_armor);
|
||||
}
|
||||
else {
|
||||
printf("Invalid choice. Please enter 1 or 2.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int handle_decrypt_menu(void) {
|
||||
printf("\n=== Decrypt Message ===\n");
|
||||
return decrypt_text(NULL, NULL); // No pad selection needed - chksum comes from message
|
||||
printf("\n=== Decrypt Data ===\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)) {
|
||||
printf("Error: Failed to read input\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int choice = atoi(choice_input);
|
||||
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Ask for custom output filename (optional)
|
||||
printf("\nEnter output filename (or press Enter for default): ");
|
||||
char output_file[512];
|
||||
if (!fgets(output_file, sizeof(output_file), stdin)) {
|
||||
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(input_file, output_filename);
|
||||
}
|
||||
else {
|
||||
printf("Invalid choice. Please enter 1 or 2.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t parse_size_string(const char* size_str) {
|
||||
@@ -374,44 +586,45 @@ char* find_pad_by_prefix(const char* prefix) {
|
||||
char* matches[100]; // Store up to 100 matches
|
||||
int match_count = 0;
|
||||
|
||||
// Check if it's a number (for interactive menu selection)
|
||||
// Only treat as number if it's a single digit (1-9) to avoid conflicts with hex prefixes
|
||||
char* endptr;
|
||||
int selection = strtol(prefix, &endptr, 10);
|
||||
if (*endptr == '\0' && selection > 0 && selection <= 9 && strlen(prefix) == 1) {
|
||||
// It's a number, find the nth pad
|
||||
int current = 0;
|
||||
rewinddir(dir);
|
||||
while ((entry = readdir(dir)) != NULL && match_count == 0) {
|
||||
// Skip . and .. entries, and only process .pad files
|
||||
if (entry->d_name[0] == '.') continue;
|
||||
if (!strstr(entry->d_name, ".pad")) continue;
|
||||
if (strlen(entry->d_name) != 68) continue; // 64 char chksum + ".pad"
|
||||
|
||||
current++;
|
||||
if (current == selection) {
|
||||
matches[match_count] = malloc(65);
|
||||
strncpy(matches[match_count], entry->d_name, 64);
|
||||
matches[match_count][64] = '\0';
|
||||
match_count = 1;
|
||||
break;
|
||||
}
|
||||
// Always try hex prefix matching first
|
||||
size_t prefix_len = strlen(prefix);
|
||||
while ((entry = readdir(dir)) != NULL && match_count < 100) {
|
||||
// Skip . and .. entries, and only process .pad files
|
||||
if (entry->d_name[0] == '.') continue;
|
||||
if (!strstr(entry->d_name, ".pad")) continue;
|
||||
if (strlen(entry->d_name) != 68) continue; // 64 char chksum + ".pad"
|
||||
|
||||
// Compare prefix with the filename (checksum part)
|
||||
if (strncmp(entry->d_name, prefix, prefix_len) == 0) {
|
||||
matches[match_count] = malloc(65);
|
||||
strncpy(matches[match_count], entry->d_name, 64);
|
||||
matches[match_count][64] = '\0';
|
||||
match_count++;
|
||||
}
|
||||
} else {
|
||||
// Find pads that start with the prefix
|
||||
size_t prefix_len = strlen(prefix);
|
||||
while ((entry = readdir(dir)) != NULL && match_count < 100) {
|
||||
// Skip . and .. entries, and only process .pad files
|
||||
if (entry->d_name[0] == '.') continue;
|
||||
if (!strstr(entry->d_name, ".pad")) continue;
|
||||
if (strlen(entry->d_name) != 68) continue; // 64 char chksum + ".pad"
|
||||
|
||||
// Compare prefix with the filename (checksum part)
|
||||
if (strncmp(entry->d_name, prefix, prefix_len) == 0) {
|
||||
matches[match_count] = malloc(65);
|
||||
strncpy(matches[match_count], entry->d_name, 64);
|
||||
matches[match_count][64] = '\0';
|
||||
match_count++;
|
||||
}
|
||||
|
||||
// If no hex prefix matches and it looks like a small number, try number selection
|
||||
if (match_count == 0) {
|
||||
char* endptr;
|
||||
int selection = strtol(prefix, &endptr, 10);
|
||||
if (*endptr == '\0' && selection > 0 && selection <= 100) {
|
||||
// It's a number, find the nth pad
|
||||
int current = 0;
|
||||
rewinddir(dir);
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
// Skip . and .. entries, and only process .pad files
|
||||
if (entry->d_name[0] == '.') continue;
|
||||
if (!strstr(entry->d_name, ".pad")) continue;
|
||||
if (strlen(entry->d_name) != 68) continue; // 64 char chksum + ".pad"
|
||||
|
||||
current++;
|
||||
if (current == selection) {
|
||||
matches[match_count] = malloc(65);
|
||||
strncpy(matches[match_count], entry->d_name, 64);
|
||||
matches[match_count][64] = '\0';
|
||||
match_count = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -944,19 +1157,53 @@ int encrypt_text(const char* pad_identifier, const char* input_text) {
|
||||
text_buffer[sizeof(text_buffer) - 1] = '\0';
|
||||
} else {
|
||||
// Get input text from user (interactive mode)
|
||||
printf("Enter text to encrypt: ");
|
||||
fflush(stdout);
|
||||
printf("\nText input options:\n");
|
||||
printf("1. Type text directly\n");
|
||||
printf("2. Use text editor\n");
|
||||
printf("Enter choice (1-2): ");
|
||||
|
||||
if (fgets(text_buffer, sizeof(text_buffer), stdin) == NULL) {
|
||||
char input_choice[10];
|
||||
if (!fgets(input_choice, sizeof(input_choice), stdin)) {
|
||||
printf("Error: Failed to read input\n");
|
||||
free(pad_chksum);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Remove newline if present
|
||||
size_t len = strlen(text_buffer);
|
||||
if (len > 0 && text_buffer[len - 1] == '\n') {
|
||||
text_buffer[len - 1] = '\0';
|
||||
if (atoi(input_choice) == 2) {
|
||||
// Use text editor
|
||||
if (launch_text_editor(NULL, text_buffer, sizeof(text_buffer)) != 0) {
|
||||
printf("Falling back to direct text input.\n");
|
||||
printf("Enter text to encrypt: ");
|
||||
fflush(stdout);
|
||||
|
||||
if (fgets(text_buffer, sizeof(text_buffer), stdin) == NULL) {
|
||||
printf("Error: Failed to read input\n");
|
||||
free(pad_chksum);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Remove newline if present
|
||||
size_t len = strlen(text_buffer);
|
||||
if (len > 0 && text_buffer[len - 1] == '\n') {
|
||||
text_buffer[len - 1] = '\0';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Direct text input
|
||||
printf("Enter text to encrypt: ");
|
||||
fflush(stdout);
|
||||
|
||||
if (fgets(text_buffer, sizeof(text_buffer), stdin) == NULL) {
|
||||
printf("Error: Failed to read input\n");
|
||||
free(pad_chksum);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Remove newline if present
|
||||
size_t len = strlen(text_buffer);
|
||||
if (len > 0 && text_buffer[len - 1] == '\n') {
|
||||
text_buffer[len - 1] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2050,6 +2297,322 @@ void simple_entropy_mix(unsigned char* urandom_buffer, size_t buffer_size,
|
||||
}
|
||||
}
|
||||
|
||||
// Editor and file manager implementations
|
||||
|
||||
char* get_preferred_editor(void) {
|
||||
// Check EDITOR environment variable first
|
||||
char* editor = getenv("EDITOR");
|
||||
if (editor && strlen(editor) > 0) {
|
||||
// Verify the editor exists
|
||||
char command[512];
|
||||
snprintf(command, sizeof(command), "which %s >/dev/null 2>&1", editor);
|
||||
if (system(command) == 0) {
|
||||
return strdup(editor);
|
||||
}
|
||||
}
|
||||
|
||||
// Check VISUAL environment variable
|
||||
editor = getenv("VISUAL");
|
||||
if (editor && strlen(editor) > 0) {
|
||||
char command[512];
|
||||
snprintf(command, sizeof(command), "which %s >/dev/null 2>&1", editor);
|
||||
if (system(command) == 0) {
|
||||
return strdup(editor);
|
||||
}
|
||||
}
|
||||
|
||||
// Try common editors in order of preference
|
||||
const char* common_editors[] = {"vim", "vi", "nano", "emacs", "gedit", NULL};
|
||||
for (int i = 0; common_editors[i] != NULL; i++) {
|
||||
char command[512];
|
||||
snprintf(command, sizeof(command), "which %s >/dev/null 2>&1", common_editors[i]);
|
||||
if (system(command) == 0) {
|
||||
return strdup(common_editors[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL; // No editor found
|
||||
}
|
||||
|
||||
char* get_preferred_file_manager(void) {
|
||||
// Try file managers in order of preference
|
||||
const char* file_managers[] = {"ranger", "fzf", "nnn", "lf", NULL};
|
||||
|
||||
for (int i = 0; file_managers[i] != NULL; i++) {
|
||||
char command[512];
|
||||
snprintf(command, sizeof(command), "which %s >/dev/null 2>&1", file_managers[i]);
|
||||
if (system(command) == 0) {
|
||||
return strdup(file_managers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL; // No file manager found
|
||||
}
|
||||
|
||||
int launch_text_editor(const char* initial_content, char* result_buffer, size_t buffer_size) {
|
||||
char* editor = get_preferred_editor();
|
||||
if (!editor) {
|
||||
printf("Error: No text editor found. Set EDITOR environment variable or install vim/nano.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create temporary file
|
||||
char temp_filename[64];
|
||||
snprintf(temp_filename, sizeof(temp_filename), "/tmp/otp_edit_%ld.tmp", time(NULL));
|
||||
|
||||
// Write initial content to temp file if provided
|
||||
if (initial_content && strlen(initial_content) > 0) {
|
||||
FILE* temp_file = fopen(temp_filename, "w");
|
||||
if (temp_file) {
|
||||
fputs(initial_content, temp_file);
|
||||
fclose(temp_file);
|
||||
}
|
||||
} else {
|
||||
// Create empty temp file
|
||||
FILE* temp_file = fopen(temp_filename, "w");
|
||||
if (temp_file) {
|
||||
fclose(temp_file);
|
||||
}
|
||||
}
|
||||
|
||||
// Launch editor
|
||||
printf("Opening %s for text editing...\n", editor);
|
||||
char command[512];
|
||||
snprintf(command, sizeof(command), "%s %s", editor, temp_filename);
|
||||
|
||||
int result = system(command);
|
||||
|
||||
if (result == 0) {
|
||||
// Read the edited content back
|
||||
FILE* temp_file = fopen(temp_filename, "r");
|
||||
if (temp_file) {
|
||||
size_t bytes_read = fread(result_buffer, 1, buffer_size - 1, temp_file);
|
||||
result_buffer[bytes_read] = '\0';
|
||||
|
||||
// Remove trailing newline if present
|
||||
if (bytes_read > 0 && result_buffer[bytes_read - 1] == '\n') {
|
||||
result_buffer[bytes_read - 1] = '\0';
|
||||
}
|
||||
|
||||
fclose(temp_file);
|
||||
} else {
|
||||
printf("Error: Cannot read edited content\n");
|
||||
free(editor);
|
||||
unlink(temp_filename);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
printf("Editor exited with error or was cancelled\n");
|
||||
free(editor);
|
||||
unlink(temp_filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Clean up
|
||||
unlink(temp_filename);
|
||||
free(editor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int launch_file_manager(const char* start_directory, char* selected_file, size_t buffer_size) {
|
||||
char* fm = get_preferred_file_manager();
|
||||
if (!fm) {
|
||||
printf("No file manager found. Please install ranger, fzf, nnn, or lf.\n");
|
||||
printf("Falling back to manual file path entry.\n");
|
||||
return 1; // Fall back to manual entry
|
||||
}
|
||||
|
||||
char temp_filename[64];
|
||||
snprintf(temp_filename, sizeof(temp_filename), "/tmp/otp_file_%ld.tmp", time(NULL));
|
||||
|
||||
char command[512];
|
||||
int result = 1;
|
||||
|
||||
printf("Opening %s for file selection...\n", fm);
|
||||
|
||||
if (strcmp(fm, "ranger") == 0) {
|
||||
snprintf(command, sizeof(command), "cd '%s' && ranger --choosefile=%s",
|
||||
start_directory ? start_directory : ".", temp_filename);
|
||||
} else if (strcmp(fm, "fzf") == 0) {
|
||||
snprintf(command, sizeof(command), "cd '%s' && find . -type f | fzf > %s",
|
||||
start_directory ? start_directory : ".", temp_filename);
|
||||
} else if (strcmp(fm, "nnn") == 0) {
|
||||
snprintf(command, sizeof(command), "cd '%s' && nnn -p %s",
|
||||
start_directory ? start_directory : ".", temp_filename);
|
||||
} else if (strcmp(fm, "lf") == 0) {
|
||||
snprintf(command, sizeof(command), "cd '%s' && lf -selection-path=%s",
|
||||
start_directory ? start_directory : ".", temp_filename);
|
||||
}
|
||||
|
||||
result = system(command);
|
||||
|
||||
if (result == 0 || result == 256) { // Some file managers return 256 on success
|
||||
// Read selected file from temp file
|
||||
FILE* temp_file = fopen(temp_filename, "r");
|
||||
if (temp_file) {
|
||||
if (fgets(selected_file, buffer_size, temp_file)) {
|
||||
// Remove trailing newline
|
||||
selected_file[strcspn(selected_file, "\n\r")] = 0;
|
||||
|
||||
// For relative paths from fzf, make absolute if needed
|
||||
if (selected_file[0] == '.' && selected_file[1] == '/') {
|
||||
char current_dir[512];
|
||||
if (getcwd(current_dir, sizeof(current_dir))) {
|
||||
char abs_path[1024];
|
||||
snprintf(abs_path, sizeof(abs_path), "%s/%s", current_dir, selected_file + 2);
|
||||
strncpy(selected_file, abs_path, buffer_size - 1);
|
||||
selected_file[buffer_size - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
fclose(temp_file);
|
||||
unlink(temp_filename);
|
||||
free(fm);
|
||||
return 0; // Success
|
||||
}
|
||||
fclose(temp_file);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up and indicate failure
|
||||
unlink(temp_filename);
|
||||
free(fm);
|
||||
return 1; // Fall back to manual entry
|
||||
}
|
||||
|
||||
int handle_text_encrypt(void) {
|
||||
printf("\n=== Text Encrypt ===\n");
|
||||
|
||||
// Launch text editor directly
|
||||
char text_buffer[MAX_INPUT_SIZE];
|
||||
if (launch_text_editor(NULL, text_buffer, sizeof(text_buffer)) != 0) {
|
||||
printf("Error: Could not launch text editor\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strlen(text_buffer) == 0) {
|
||||
printf("No text entered - canceling encryption\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// List available pads and get selection
|
||||
int pad_count = list_available_pads();
|
||||
if (pad_count == 0) {
|
||||
printf("No pads available. Generate a pad first.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("\nEnter pad selection (number, checksum, or prefix): ");
|
||||
char pad_input[MAX_HASH_LENGTH];
|
||||
if (!fgets(pad_input, sizeof(pad_input), stdin)) {
|
||||
printf("Error: Failed to read pad selection\n");
|
||||
return 1;
|
||||
}
|
||||
pad_input[strcspn(pad_input, "\n")] = 0;
|
||||
|
||||
return encrypt_text(pad_input, text_buffer);
|
||||
}
|
||||
|
||||
int handle_file_encrypt(void) {
|
||||
printf("\n=== File Encrypt ===\n");
|
||||
|
||||
// Launch file manager directly
|
||||
char input_file[512];
|
||||
if (launch_file_manager(".", input_file, sizeof(input_file)) != 0) {
|
||||
printf("Error: Could not launch file manager\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// List available pads
|
||||
int pad_count = list_available_pads();
|
||||
if (pad_count == 0) {
|
||||
printf("No pads available. Generate a pad first.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("\nEnter pad selection (number, checksum, or prefix): ");
|
||||
char pad_input[MAX_HASH_LENGTH];
|
||||
if (!fgets(pad_input, sizeof(pad_input), stdin)) {
|
||||
printf("Error: Failed to read pad selection\n");
|
||||
return 1;
|
||||
}
|
||||
pad_input[strcspn(pad_input, "\n")] = 0;
|
||||
|
||||
// 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("Enter choice (1-2): ");
|
||||
|
||||
char format_input[10];
|
||||
if (!fgets(format_input, sizeof(format_input), stdin)) {
|
||||
printf("Error: Failed to read input\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ascii_armor = (atoi(format_input) == 2) ? 1 : 0;
|
||||
|
||||
return encrypt_file(pad_input, input_file, NULL, 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());
|
||||
printf("%s\n", get_build_info());
|
||||
|
||||
8
otp.code-workspace
Normal file
8
otp.code-workspace
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "."
|
||||
}
|
||||
],
|
||||
"settings": {}
|
||||
}
|
||||
BIN
test.txt.otp
BIN
test.txt.otp
Binary file not shown.
1
test_file.txt
Normal file
1
test_file.txt
Normal file
@@ -0,0 +1 @@
|
||||
Hello, this is a test file for encryption!
|
||||
BIN
test_file.txt.otp
Normal file
BIN
test_file.txt.otp
Normal file
Binary file not shown.
BIN
tocEncrypted
Normal file
BIN
tocEncrypted
Normal file
Binary file not shown.
Reference in New Issue
Block a user