Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e32eb8b2b1 | |||
| 0aecae0c5e | |||
| fa90e0eafd | |||
| 2a10d974b2 | |||
| 7e04896394 | |||
| 0cdf6e7804 | |||
| 268758a21b |
7
.clinerules/workspace_rules.md
Normal file
7
.clinerules/workspace_rules.md
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
When building, use build.sh, not make.
|
||||
|
||||
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.
|
||||
|
||||
10
README.md
10
README.md
@@ -164,11 +164,9 @@ Offset | Size | Field | Description
|
||||
4 | 2 | Version | Format version (currently 1)
|
||||
6 | 32 | Pad Checksum | Binary pad checksum (32 bytes)
|
||||
38 | 8 | Pad Offset | Offset in pad file (uint64_t)
|
||||
46 | 2 | Filename Length | Original filename length (uint16_t)
|
||||
48 | var | Original Filename | Original filename string
|
||||
var | 4 | File Mode | Original file permissions (uint32_t)
|
||||
var | 8 | File Size | Original file size (uint64_t)
|
||||
var | var | Encrypted Data | XOR-encrypted file contents
|
||||
46 | 4 | File Mode | Original file permissions (uint32_t)
|
||||
50 | 8 | File Size | Original file size (uint64_t)
|
||||
58 | var | Encrypted Data | XOR-encrypted file contents
|
||||
```
|
||||
|
||||
### .otp.asc File Format (ASCII Armored)
|
||||
@@ -185,7 +183,7 @@ Pad-Offset: <decimal-offset-value>
|
||||
-----END OTP MESSAGE-----
|
||||
```
|
||||
|
||||
**Note:** ASCII armored files lose original filename and permission metadata.
|
||||
**Note:** ASCII armored files do not preserve original file permissions metadata.
|
||||
|
||||
## Usage Examples
|
||||
|
||||
|
||||
1
debug.c
Normal file
1
debug.c
Normal file
@@ -0,0 +1 @@
|
||||
int main() { printf("Testing direct filename: %d\n", strncmp("97d9d82b5414a9439102f3811fb90ab1d6368a00d33229a18b306476f9d04f82.pad", "97", 2)); return 0; }
|
||||
591
otp.c
591
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);
|
||||
@@ -151,6 +157,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]);
|
||||
@@ -249,8 +263,8 @@ int command_line_mode(int argc, char* argv[]) {
|
||||
void show_main_menu(void) {
|
||||
printf("=== Main Menu ===\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[4mE\033[0mncrypt data (text/file)\n");
|
||||
printf("\033[4mD\033[0mecrypt data (text/file)\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 +311,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 +319,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) {
|
||||
@@ -365,40 +569,53 @@ uint64_t parse_size_string(const char* size_str) {
|
||||
|
||||
char* find_pad_by_prefix(const char* prefix) {
|
||||
DIR* dir = opendir(PADS_DIR);
|
||||
if (!dir) return NULL;
|
||||
if (!dir) {
|
||||
printf("Error: Cannot open pads directory\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct dirent* entry;
|
||||
char* matches[100]; // Store up to 100 matches
|
||||
int match_count = 0;
|
||||
|
||||
// Check if it's a number (for interactive menu selection)
|
||||
char* endptr;
|
||||
int selection = strtol(prefix, &endptr, 10);
|
||||
if (*endptr == '\0' && selection > 0) {
|
||||
// It's a number, find the nth pad
|
||||
int current = 0;
|
||||
rewinddir(dir);
|
||||
while ((entry = readdir(dir)) != NULL && match_count == 0) {
|
||||
if (strstr(entry->d_name, ".pad") && strlen(entry->d_name) == 68) { // 64 char chksum + ".pad"
|
||||
// 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++;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Find pads that start with the prefix
|
||||
size_t prefix_len = strlen(prefix);
|
||||
while ((entry = readdir(dir)) != NULL && match_count < 100) {
|
||||
if (strstr(entry->d_name, ".pad") && strlen(entry->d_name) == 68) {
|
||||
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++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -418,14 +635,35 @@ char* find_pad_by_prefix(const char* prefix) {
|
||||
printf("Multiple matches found for '%s':\n", prefix);
|
||||
for (int i = 0; i < match_count; i++) {
|
||||
printf("%d. %.16s...\n", i + 1, matches[i]);
|
||||
if (i > 0) free(matches[i]);
|
||||
}
|
||||
printf("Please be more specific.\n");
|
||||
char* result = matches[0];
|
||||
for (int i = 1; i < match_count; i++) {
|
||||
printf("Please be more specific or enter a number (1-%d): ", match_count);
|
||||
fflush(stdout);
|
||||
|
||||
char choice_input[64];
|
||||
if (fgets(choice_input, sizeof(choice_input), stdin)) {
|
||||
choice_input[strcspn(choice_input, "\n")] = 0;
|
||||
|
||||
// Check if it's a number
|
||||
char* endptr;
|
||||
int choice = strtol(choice_input, &endptr, 10);
|
||||
if (*endptr == '\0' && choice >= 1 && choice <= match_count) {
|
||||
// Valid choice, return selected pad
|
||||
char* result = matches[choice - 1];
|
||||
// Free the others
|
||||
for (int i = 0; i < match_count; i++) {
|
||||
if (i != choice - 1) {
|
||||
free(matches[i]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Invalid choice or no input, free all and return NULL
|
||||
for (int i = 0; i < match_count; i++) {
|
||||
free(matches[i]);
|
||||
}
|
||||
return result;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -911,19 +1149,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';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1412,16 +1684,6 @@ int encrypt_file(const char* pad_identifier, const char* input_file, const char*
|
||||
// Pad offset: 8 bytes
|
||||
fwrite(¤t_offset, sizeof(uint64_t), 1, output_fp);
|
||||
|
||||
// Original filename length and name
|
||||
const char* base_filename = strrchr(input_file, '/');
|
||||
if (base_filename) {
|
||||
base_filename++; // Skip the '/'
|
||||
} else {
|
||||
base_filename = input_file;
|
||||
}
|
||||
uint16_t filename_len = strlen(base_filename);
|
||||
fwrite(&filename_len, sizeof(uint16_t), 1, output_fp);
|
||||
fwrite(base_filename, 1, filename_len, output_fp);
|
||||
|
||||
// File mode: 4 bytes
|
||||
uint32_t file_mode = input_stat.st_mode;
|
||||
@@ -1494,7 +1756,6 @@ int decrypt_binary_file(FILE* input_fp, const char* output_file) {
|
||||
uint16_t version;
|
||||
unsigned char pad_chksum_bin[32];
|
||||
uint64_t pad_offset;
|
||||
uint16_t filename_len;
|
||||
uint32_t file_mode;
|
||||
uint64_t file_size;
|
||||
|
||||
@@ -1502,7 +1763,8 @@ int decrypt_binary_file(FILE* input_fp, const char* output_file) {
|
||||
fread(&version, sizeof(uint16_t), 1, input_fp) != 1 ||
|
||||
fread(pad_chksum_bin, 1, 32, input_fp) != 32 ||
|
||||
fread(&pad_offset, sizeof(uint64_t), 1, input_fp) != 1 ||
|
||||
fread(&filename_len, sizeof(uint16_t), 1, input_fp) != 1) {
|
||||
fread(&file_mode, sizeof(uint32_t), 1, input_fp) != 1 ||
|
||||
fread(&file_size, sizeof(uint64_t), 1, input_fp) != 1) {
|
||||
printf("Error: Cannot read binary header\n");
|
||||
fclose(input_fp);
|
||||
return 1;
|
||||
@@ -1514,25 +1776,6 @@ int decrypt_binary_file(FILE* input_fp, const char* output_file) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Read original filename
|
||||
char* original_filename = malloc(filename_len + 1);
|
||||
if (fread(original_filename, 1, filename_len, input_fp) != filename_len) {
|
||||
printf("Error: Cannot read original filename\n");
|
||||
free(original_filename);
|
||||
fclose(input_fp);
|
||||
return 1;
|
||||
}
|
||||
original_filename[filename_len] = '\0';
|
||||
|
||||
// Read remaining header
|
||||
if (fread(&file_mode, sizeof(uint32_t), 1, input_fp) != 1 ||
|
||||
fread(&file_size, sizeof(uint64_t), 1, input_fp) != 1) {
|
||||
printf("Error: Cannot read file metadata\n");
|
||||
free(original_filename);
|
||||
fclose(input_fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Convert binary checksum to hex
|
||||
char pad_chksum_hex[65];
|
||||
for (int i = 0; i < 32; i++) {
|
||||
@@ -1541,7 +1784,6 @@ int decrypt_binary_file(FILE* input_fp, const char* output_file) {
|
||||
pad_chksum_hex[64] = '\0';
|
||||
|
||||
printf("Decrypting binary file...\n");
|
||||
printf("Original filename: %s\n", original_filename);
|
||||
printf("File size: %lu bytes\n", file_size);
|
||||
|
||||
// Check if we have the required pad
|
||||
@@ -1553,7 +1795,6 @@ int decrypt_binary_file(FILE* input_fp, const char* output_file) {
|
||||
printf("Error: Required pad not found: %s\n", pad_chksum_hex);
|
||||
printf("Available pads:\n");
|
||||
list_available_pads();
|
||||
free(original_filename);
|
||||
fclose(input_fp);
|
||||
return 1;
|
||||
}
|
||||
@@ -1561,8 +1802,7 @@ int decrypt_binary_file(FILE* input_fp, const char* output_file) {
|
||||
// Determine output filename
|
||||
char default_output[512];
|
||||
if (output_file == NULL) {
|
||||
strncpy(default_output, original_filename, sizeof(default_output) - 1);
|
||||
default_output[sizeof(default_output) - 1] = '\0';
|
||||
snprintf(default_output, sizeof(default_output), "decrypted.bin");
|
||||
output_file = default_output;
|
||||
}
|
||||
|
||||
@@ -1570,7 +1810,6 @@ int decrypt_binary_file(FILE* input_fp, const char* output_file) {
|
||||
unsigned char* encrypted_data = malloc(file_size);
|
||||
if (fread(encrypted_data, 1, file_size, input_fp) != file_size) {
|
||||
printf("Error: Cannot read encrypted data\n");
|
||||
free(original_filename);
|
||||
free(encrypted_data);
|
||||
fclose(input_fp);
|
||||
return 1;
|
||||
@@ -1581,14 +1820,12 @@ int decrypt_binary_file(FILE* input_fp, const char* output_file) {
|
||||
FILE* pad_file = fopen(pad_path, "rb");
|
||||
if (!pad_file) {
|
||||
printf("Error: Cannot open pad file\n");
|
||||
free(original_filename);
|
||||
free(encrypted_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fseek(pad_file, pad_offset, SEEK_SET) != 0) {
|
||||
printf("Error: Cannot seek to offset in pad file\n");
|
||||
free(original_filename);
|
||||
free(encrypted_data);
|
||||
fclose(pad_file);
|
||||
return 1;
|
||||
@@ -1597,7 +1834,6 @@ int decrypt_binary_file(FILE* input_fp, const char* output_file) {
|
||||
unsigned char* pad_data = malloc(file_size);
|
||||
if (fread(pad_data, 1, file_size, pad_file) != file_size) {
|
||||
printf("Error: Cannot read pad data\n");
|
||||
free(original_filename);
|
||||
free(encrypted_data);
|
||||
free(pad_data);
|
||||
fclose(pad_file);
|
||||
@@ -1614,7 +1850,6 @@ int decrypt_binary_file(FILE* input_fp, const char* output_file) {
|
||||
FILE* output_fp = fopen(output_file, "wb");
|
||||
if (!output_fp) {
|
||||
printf("Error: Cannot create output file %s\n", output_file);
|
||||
free(original_filename);
|
||||
free(encrypted_data);
|
||||
free(pad_data);
|
||||
return 1;
|
||||
@@ -1622,7 +1857,6 @@ int decrypt_binary_file(FILE* input_fp, const char* output_file) {
|
||||
|
||||
if (fwrite(encrypted_data, 1, file_size, output_fp) != file_size) {
|
||||
printf("Error: Cannot write decrypted data\n");
|
||||
free(original_filename);
|
||||
free(encrypted_data);
|
||||
free(pad_data);
|
||||
fclose(output_fp);
|
||||
@@ -1639,7 +1873,6 @@ int decrypt_binary_file(FILE* input_fp, const char* output_file) {
|
||||
printf("Restored permissions and metadata\n");
|
||||
|
||||
// Cleanup
|
||||
free(original_filename);
|
||||
free(encrypted_data);
|
||||
free(pad_data);
|
||||
|
||||
@@ -2056,6 +2289,190 @@ 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
|
||||
}
|
||||
|
||||
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.
Reference in New Issue
Block a user