Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| aea69148a8 | |||
| d537bc4948 | |||
| 42a8f5c358 | |||
| 7a30949ddd | |||
| eb8a5b6565 | |||
| d0a5628072 | |||
| 5498a2321e | |||
| fe2eb40ead | |||
| 0db1988d8f | |||
| 97530c8eb3 | |||
| a85c4ed55b | |||
| a9974c7e87 | |||
| 592d54728b | |||
| 21b3c4de52 | |||
| 3a854c3ccf | |||
| 877add0dbf | |||
| 482687cb68 | |||
| e35d94243e |
@@ -1,7 +1,29 @@
|
||||
|
||||
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.
|
||||
|
||||
## Buffer Size Guidelines
|
||||
|
||||
### Path Handling
|
||||
- Always use buffers of size 1024 or PATH_MAX (4096) for file paths
|
||||
- When concatenating paths with snprintf, ensure buffer is at least 2x the expected maximum input
|
||||
- Use safer path construction patterns that check lengths before concatenation
|
||||
|
||||
### String Formatting Safety
|
||||
- Before using snprintf with dynamic strings, validate that buffer size >= sum of all input string lengths + format characters + 1
|
||||
- Use strnlen() to check actual string lengths before formatting
|
||||
- Consider using asprintf() for dynamic allocation when exact size is unknown
|
||||
- Add length validation before snprintf calls
|
||||
|
||||
### Compiler Warning Prevention
|
||||
- Always size string buffers generously (minimum 1024 for paths, 512 for general strings)
|
||||
- Use buffer size calculations: `size >= strlen(str1) + strlen(str2) + format_overhead + 1`
|
||||
- Add runtime length checks before snprintf operations
|
||||
- Consider using safer alternatives like strlcpy/strlcat if available
|
||||
|
||||
### Code Patterns to Avoid
|
||||
- Fixed-size buffers (512 bytes) for path operations where inputs could be 255+ bytes each
|
||||
- Concatenating unchecked strings with snprintf
|
||||
- Assuming maximum path component sizes without validation
|
||||
|
||||
54
README.md
54
README.md
@@ -1,6 +1,47 @@
|
||||
# OTP Cipher - One Time Pad Implementation
|
||||
|
||||
A secure one-time pad (OTP) cipher implementation in C with automatic versioning system.
|
||||
|
||||
## Introduction
|
||||
|
||||
A secure one-time pad (OTP) cipher implementation in C.
|
||||
|
||||
## Why One-Time Pads
|
||||
|
||||
Nostr and much of the web runs on public key cryptography. Public key cryptography is great, but it is vulnerable. Cryptographers know this, and they know what it takes to attack it, so what they do is just make the keys large enough such that the system is resistant to attack given computers as they are today.
|
||||
|
||||
There is one type of cryptography, however, that is invulnerable to any type of attack in our universe, and that is known as a one-time pad.
|
||||
|
||||
One-time pads rely directly on the laws of physics and what it means for a number to be truly random.
|
||||
|
||||
If you take your secret message and mix it with truly random numbers, and don't use those random numbers again, then that message is unbreakable by any computer, no matter how powerful, quantum or not, forever.
|
||||
|
||||
In fact, one-time pads are so powerful that if you have data encrypted by a one-time pad located in a distant galaxy, and that data is not kept anywhere else, then by destroying the pad used for encryption in your galaxy, the data is wiped from the universe and can never be recovered.
|
||||
|
||||
## Advantages and Limitations
|
||||
|
||||
### Limitations
|
||||
|
||||
1. The pad must be shared between the parties wanting to use it.
|
||||
2. The pad must be as long or longer than what you want to encrypt, and it can't be used a second time.
|
||||
|
||||
### Modern Advantages
|
||||
|
||||
While in the past, pad length might have been a problem, readily available USB drives in the terabytes make size less of a problem for many uses.
|
||||
|
||||
We are also becoming very accustomed to YubiKey authenticators in the USB ports of our computers. A small USB drive in our devices can now easily contain a key of greater length than all the text messages we would expect to send over a lifetime.
|
||||
|
||||
### Multi-Device Coordination
|
||||
|
||||
One of the problems to address is the fact that to use an OTP across several devices means that they have to coordinate to know when they are encrypting new plaintext and where to start in the key. Reusing the same section of the pad, while not necessarily fatal, degrades the encryption from its status as "Information Theoretically Secure".
|
||||
|
||||
To address this problem, we can use Nostr to share among devices the place in the pad that was last left off.
|
||||
|
||||
### Additional Benefits
|
||||
|
||||
One-time pads can be trivially encrypted and decrypted using pencil and paper, making them accessible even without electronic devices.
|
||||
|
||||
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
@@ -13,15 +54,6 @@ A secure one-time pad (OTP) cipher implementation in C with automatic versioning
|
||||
- **Multiple Build Options**: Standard and static linking builds
|
||||
- **Cross-Platform**: Works on Linux and other UNIX-like systems
|
||||
|
||||
## Version Information
|
||||
|
||||
This project uses an automatic versioning system that:
|
||||
- Automatically increments the patch version on each build
|
||||
- Embeds build timestamp, git commit hash, and branch information
|
||||
- Creates git tags for version tracking
|
||||
- Generates version header files with detailed build metadata
|
||||
|
||||
Current version can be viewed with: `./otp --help` or by running the interactive mode.
|
||||
|
||||
## Building
|
||||
|
||||
@@ -31,7 +63,7 @@ Current version can be viewed with: `./otp --help` or by running the interactive
|
||||
- Git (for version tracking)
|
||||
- Make
|
||||
|
||||
**Note: OpenSSL is no longer required! This implementation is now completely self-contained.**
|
||||
|
||||
|
||||
### Build Commands
|
||||
|
||||
|
||||
25
TODO.md
Normal file
25
TODO.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# TODO
|
||||
|
||||
|
||||
## Change technique for adding keyboard entropy.
|
||||
|
||||
## Some of the processing seems similar, so maybe code could be more compact.
|
||||
|
||||
|
||||
## There is the problem of the location of the pad revealing metadata about how many messages have been sent in the past, or at least the size of the messsages.
|
||||
|
||||
One solution could be to start the pad at a random location, and then wrap around, so an attacker could never tell the size of the past text sent. This helps. But then you have to store the start location, which you could do within the header of the pad along with the pad?
|
||||
|
||||
Or, better yet, assume the offset is a very large size, and use the pad itself to encrypt the offset.
|
||||
|
||||
## Take a look at how the file header is being handled.
|
||||
|
||||
## We have three different decrypt file functions
|
||||
|
||||
|
||||
|
||||
## Setup for multiple USB drives
|
||||
|
||||
|
||||
## Change back in pad menu to exit
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Test file content for decryption
|
||||
@@ -1,11 +0,0 @@
|
||||
|
||||
|
||||
-----BEGIN OTP MESSAGE-----
|
||||
Version: v0.2.72
|
||||
Pad-ChkSum: 97d9d82b5414a9439102f3811fb90ab1d6368a00d33229a18b306476f9d04f82
|
||||
Pad-Offset: 2873419
|
||||
|
||||
iR6J7HHK1Oc6
|
||||
-----END OTP MESSAGE-----
|
||||
|
||||
|
||||
341
otp.c
341
otp.c
@@ -131,6 +131,16 @@ void get_directory_display(const char* file_path, char* result, size_t result_si
|
||||
|
||||
void print_usage(const char* program_name);
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// MAIN
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// Load preferences first
|
||||
load_preferences();
|
||||
@@ -138,11 +148,16 @@ int main(int argc, char* argv[]) {
|
||||
// Check for piped input first (before any output)
|
||||
int is_pipe_mode = (argc == 1 && has_stdin_data());
|
||||
|
||||
// Check for decrypt command with piped input
|
||||
int is_decrypt_pipe = (argc == 2 &&
|
||||
(strcmp(argv[1], "decrypt") == 0 || strcmp(argv[1], "-d") == 0) &&
|
||||
has_stdin_data());
|
||||
|
||||
// Check for OTP thumb drive on startup
|
||||
char otp_drive_path[512];
|
||||
if (detect_otp_thumb_drive(otp_drive_path, sizeof(otp_drive_path))) {
|
||||
// Only show messages in interactive/command mode, not pipe mode
|
||||
if (!is_pipe_mode) {
|
||||
if (!is_pipe_mode && !is_decrypt_pipe) {
|
||||
printf("Detected OTP thumb drive: %s\n", otp_drive_path);
|
||||
printf("Using as default pads directory for this session.\n\n");
|
||||
}
|
||||
@@ -229,13 +244,68 @@ int command_line_mode(int argc, char* argv[]) {
|
||||
return generate_pad_with_entropy(size, 1, 0); // No keyboard entropy for command line
|
||||
}
|
||||
else if (strcmp(argv[1], "encrypt") == 0 || strcmp(argv[1], "-e") == 0) {
|
||||
if (argc < 3 || argc > 4) {
|
||||
printf("Usage: %s encrypt|-e <pad_chksum_or_prefix> [text_to_encrypt]\n", argv[0]);
|
||||
if (argc < 2 || argc > 4) {
|
||||
printf("Usage: %s encrypt|-e [pad_chksum_or_prefix] [text_to_encrypt]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
// Pass text if provided, otherwise NULL for interactive mode
|
||||
const char* text = (argc == 4) ? argv[3] : NULL;
|
||||
return encrypt_text(argv[2], text);
|
||||
|
||||
// Check if pad was specified or use default
|
||||
const char* pad_identifier = NULL;
|
||||
const char* text = NULL;
|
||||
|
||||
if (argc == 2) {
|
||||
// Just -e, use default pad, no text (interactive)
|
||||
pad_identifier = NULL;
|
||||
text = NULL;
|
||||
} else if (argc == 3) {
|
||||
// Could be -e <pad> or -e <text> (using default pad)
|
||||
// Check if default pad is available to determine interpretation
|
||||
char* default_pad = get_default_pad_path();
|
||||
if (default_pad) {
|
||||
// Default pad available, treat argument as text
|
||||
pad_identifier = NULL;
|
||||
text = argv[2];
|
||||
free(default_pad);
|
||||
} else {
|
||||
// No default pad, treat as pad identifier
|
||||
pad_identifier = argv[2];
|
||||
text = NULL;
|
||||
}
|
||||
} else {
|
||||
// argc == 4: -e <pad> <text>
|
||||
pad_identifier = argv[2];
|
||||
text = argv[3];
|
||||
}
|
||||
|
||||
// If pad_identifier is NULL, we need to use default pad
|
||||
if (pad_identifier == NULL) {
|
||||
char* default_pad = get_default_pad_path();
|
||||
if (default_pad) {
|
||||
// Extract checksum from default pad path
|
||||
char* filename = strrchr(default_pad, '/');
|
||||
if (!filename) filename = default_pad;
|
||||
else filename++; // Skip the '/'
|
||||
|
||||
// Extract checksum (remove .pad extension)
|
||||
if (strlen(filename) >= 68 && strstr(filename, ".pad")) {
|
||||
static char default_checksum[65];
|
||||
strncpy(default_checksum, filename, 64);
|
||||
default_checksum[64] = '\0';
|
||||
pad_identifier = default_checksum;
|
||||
}
|
||||
free(default_pad);
|
||||
|
||||
// Call encrypt_text and then comment about using default pad
|
||||
int result = encrypt_text(pad_identifier, text);
|
||||
return result;
|
||||
} else {
|
||||
printf("Error: No default pad configured. Specify pad explicitly or configure default pad.\n");
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
// Explicit pad specified, normal operation
|
||||
return encrypt_text(pad_identifier, text);
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[1], "decrypt") == 0 || strcmp(argv[1], "-d") == 0) {
|
||||
if (argc == 2) {
|
||||
@@ -324,11 +394,11 @@ void show_main_menu(void) {
|
||||
|
||||
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[4mP\033[0mads\n");
|
||||
printf(" E\033[4mx\033[0mit\n");
|
||||
printf(" \033[4mT\033[0mext encrypt\n"); //TEXT ENCRYPT
|
||||
printf(" \033[4mF\033[0mile encrypt\n"); //FILE ENCRYPT
|
||||
printf(" \033[4mD\033[0mecrypt\n"); //DECRYPT
|
||||
printf(" \033[4mP\033[0mads\n"); //PADS
|
||||
printf(" E\033[4mx\033[0mit\n"); //EXIT
|
||||
printf("\nSelect option: ");
|
||||
}
|
||||
|
||||
@@ -802,9 +872,27 @@ int list_available_pads(void) {
|
||||
struct dirent* entry;
|
||||
int count = 0;
|
||||
|
||||
// Get current default pad path for comparison
|
||||
char* current_default = get_default_pad_path();
|
||||
char default_pad_checksum[65] = "";
|
||||
|
||||
if (current_default) {
|
||||
// Extract checksum from default pad path
|
||||
char* filename = strrchr(current_default, '/');
|
||||
if (!filename) filename = current_default;
|
||||
else filename++; // Skip the '/'
|
||||
|
||||
// Extract checksum (remove .pad extension)
|
||||
if (strlen(filename) >= 68 && strstr(filename, ".pad")) {
|
||||
strncpy(default_pad_checksum, filename, 64);
|
||||
default_pad_checksum[64] = '\0';
|
||||
}
|
||||
free(current_default);
|
||||
}
|
||||
|
||||
printf("\nAvailable pads:\n");
|
||||
printf("%-4s %-20s %-12s %-12s %-8s\n", "No.", "ChkSum", "Size", "Used", "% Used");
|
||||
printf("%-4s %-20s %-12s %-12s %-8s\n", "---", "-------------------", "----------", "----------", "------");
|
||||
printf("%-4s %-7s %-20s %-12s %-12s %-8s\n", "No.", "Default", "ChkSum", "Size", "Used", "% Used");
|
||||
printf("%-4s %-7s %-20s %-12s %-12s %-8s\n", "---", "-------", "-------------------", "----------", "----------", "------");
|
||||
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
if (strstr(entry->d_name, ".pad") && strlen(entry->d_name) == 68) {
|
||||
@@ -813,6 +901,10 @@ int list_available_pads(void) {
|
||||
strncpy(chksum, entry->d_name, 64);
|
||||
chksum[64] = '\0';
|
||||
|
||||
// Check if this is the default pad
|
||||
int is_default = (strlen(default_pad_checksum) > 0 &&
|
||||
strncmp(chksum, default_pad_checksum, 64) == 0);
|
||||
|
||||
// Get pad file size
|
||||
char full_path[1024]; // Increased buffer size to accommodate longer paths
|
||||
snprintf(full_path, sizeof(full_path), "%s/%s", current_pads_dir, entry->d_name);
|
||||
@@ -850,7 +942,7 @@ int list_available_pads(void) {
|
||||
// Calculate percentage
|
||||
double percentage = (double)used_bytes / st.st_size * 100.0;
|
||||
|
||||
printf("%-4d %-20.16s %-12s %-12s %.1f%%\n", count, chksum, size_str, used_str, percentage);
|
||||
printf("%-4d %-7s %-20.16s %-12s %-12s %.1f%%\n", count, is_default ? "*" : "", chksum, size_str, used_str, percentage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1614,7 +1706,6 @@ int decrypt_text_silent(const char* pad_identifier, const char* encrypted_messag
|
||||
// For piped decrypt mode - silent operation with minimal output
|
||||
(void)pad_identifier; // Suppress unused parameter warning
|
||||
|
||||
char line[MAX_LINE_LENGTH];
|
||||
char stored_chksum[MAX_HASH_LENGTH];
|
||||
char current_chksum[MAX_HASH_LENGTH];
|
||||
uint64_t pad_offset;
|
||||
@@ -1648,6 +1739,10 @@ int decrypt_text_silent(const char* pad_identifier, const char* encrypted_messag
|
||||
else if (in_data_section) {
|
||||
strncat(base64_data, line_ptr, sizeof(base64_data) - strlen(base64_data) - 1);
|
||||
}
|
||||
else if (strncmp(line_ptr, "Version:", 8) != 0 && strncmp(line_ptr, "Pad-", 4) != 0) {
|
||||
// This might be base64 data without a blank line separator
|
||||
strncat(base64_data, line_ptr, sizeof(base64_data) - strlen(base64_data) - 1);
|
||||
}
|
||||
}
|
||||
line_ptr = strtok(NULL, "\n");
|
||||
}
|
||||
@@ -1724,8 +1819,9 @@ int decrypt_text_silent(const char* pad_identifier, const char* encrypted_messag
|
||||
}
|
||||
plaintext[ciphertext_len] = '\0';
|
||||
|
||||
// Output only the decrypted text - no extra messages
|
||||
// Output only the decrypted text with newline and flush
|
||||
printf("%s\n", plaintext);
|
||||
fflush(stdout);
|
||||
|
||||
// Cleanup
|
||||
free(ciphertext);
|
||||
@@ -2602,13 +2698,72 @@ int load_preferences(void) {
|
||||
}
|
||||
|
||||
char preferences_dir[1024];
|
||||
char preferences_file[1024];
|
||||
char preferences_file[2048]; // Increased buffer size to accommodate longer paths
|
||||
snprintf(preferences_dir, sizeof(preferences_dir), "%s/.otp", home_dir);
|
||||
snprintf(preferences_file, sizeof(preferences_file), "%s/otp.conf", preferences_dir);
|
||||
|
||||
FILE* file = fopen(preferences_file, "r");
|
||||
if (!file) {
|
||||
return 0; // No preferences file, use defaults
|
||||
// No preferences file exists - create it and set first pad as default
|
||||
|
||||
// Create .otp directory if it doesn't exist
|
||||
struct stat st = {0};
|
||||
if (stat(preferences_dir, &st) == -1) {
|
||||
if (mkdir(preferences_dir, 0755) != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Find the first available pad to set as default
|
||||
DIR* dir = opendir(current_pads_dir);
|
||||
if (dir) {
|
||||
struct dirent* entry;
|
||||
char first_pad_path[1024];
|
||||
int found_pad = 0;
|
||||
|
||||
while ((entry = readdir(dir)) != NULL && !found_pad) {
|
||||
if (strstr(entry->d_name, ".pad") && strlen(entry->d_name) == 68) {
|
||||
// Found a pad file - construct full absolute path
|
||||
char absolute_path[1024];
|
||||
if (current_pads_dir[0] == '/') {
|
||||
// Already absolute path
|
||||
int ret = snprintf(first_pad_path, sizeof(first_pad_path), "%s/%s", current_pads_dir, entry->d_name);
|
||||
if (ret >= (int)sizeof(first_pad_path)) {
|
||||
// Path was truncated, skip this entry
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// Relative path - make it absolute
|
||||
char current_dir[512];
|
||||
if (getcwd(current_dir, sizeof(current_dir))) {
|
||||
int ret = snprintf(first_pad_path, sizeof(first_pad_path), "%s/%s/%s", current_dir, current_pads_dir, entry->d_name);
|
||||
if (ret >= (int)sizeof(first_pad_path)) {
|
||||
// Path was truncated, skip this entry
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// Fallback to relative path
|
||||
int ret = snprintf(first_pad_path, sizeof(first_pad_path), "%s/%s", current_pads_dir, entry->d_name);
|
||||
if (ret >= (int)sizeof(first_pad_path)) {
|
||||
// Path was truncated, skip this entry
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
strncpy(default_pad_path, first_pad_path, sizeof(default_pad_path) - 1);
|
||||
default_pad_path[sizeof(default_pad_path) - 1] = '\0';
|
||||
found_pad = 1;
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
// Create the preferences file with the default pad
|
||||
if (found_pad) {
|
||||
save_preferences();
|
||||
}
|
||||
}
|
||||
|
||||
return 0; // Successfully initialized
|
||||
}
|
||||
|
||||
char line[1024];
|
||||
@@ -2650,7 +2805,7 @@ int save_preferences(void) {
|
||||
}
|
||||
|
||||
char preferences_dir[1024];
|
||||
char preferences_file[1024];
|
||||
char preferences_file[2048]; // Increased buffer size to accommodate longer paths
|
||||
snprintf(preferences_dir, sizeof(preferences_dir), "%s/.otp", home_dir);
|
||||
snprintf(preferences_file, sizeof(preferences_file), "%s/otp.conf", preferences_dir);
|
||||
|
||||
@@ -2708,7 +2863,29 @@ char* get_default_pad_path(void) {
|
||||
}
|
||||
|
||||
int set_default_pad_path(const char* pad_path) {
|
||||
return set_preference("default_pad", pad_path);
|
||||
if (!pad_path) {
|
||||
return set_preference("default_pad", NULL);
|
||||
}
|
||||
|
||||
// Ensure we store the full absolute path
|
||||
char absolute_path[1024];
|
||||
if (pad_path[0] == '/') {
|
||||
// Already absolute path
|
||||
strncpy(absolute_path, pad_path, sizeof(absolute_path) - 1);
|
||||
absolute_path[sizeof(absolute_path) - 1] = '\0';
|
||||
} else {
|
||||
// Relative path - make it absolute
|
||||
char current_dir[512];
|
||||
if (getcwd(current_dir, sizeof(current_dir))) {
|
||||
snprintf(absolute_path, sizeof(absolute_path), "%s/%s", current_dir, pad_path);
|
||||
} else {
|
||||
// Fallback to using the path as-is if getcwd fails
|
||||
strncpy(absolute_path, pad_path, sizeof(absolute_path) - 1);
|
||||
absolute_path[sizeof(absolute_path) - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
return set_preference("default_pad", absolute_path);
|
||||
}
|
||||
|
||||
// OTP thumb drive detection function implementation
|
||||
@@ -2723,7 +2900,7 @@ int detect_otp_thumb_drive(char* otp_drive_path, size_t path_size) {
|
||||
while ((mount_entry = readdir(mount_dir)) != NULL) {
|
||||
if (mount_entry->d_name[0] == '.') continue;
|
||||
|
||||
char mount_path[512];
|
||||
char mount_path[1024]; // Increased buffer size
|
||||
snprintf(mount_path, sizeof(mount_path), "%s/%s", mount_dirs[mount_idx], mount_entry->d_name);
|
||||
|
||||
// For /media, we need to go one level deeper (user directories)
|
||||
@@ -2739,7 +2916,11 @@ int detect_otp_thumb_drive(char* otp_drive_path, size_t path_size) {
|
||||
// Check if drive name starts with "OTP"
|
||||
if (strncmp(user_entry->d_name, "OTP", 3) != 0) continue;
|
||||
|
||||
char user_mount_path[512];
|
||||
char user_mount_path[2048]; // Increased buffer size
|
||||
// Verify buffer has enough space before concatenation
|
||||
size_t mount_len = strlen(mount_path);
|
||||
size_t entry_len = strlen(user_entry->d_name);
|
||||
if (mount_len + entry_len + 2 < sizeof(user_mount_path)) {
|
||||
snprintf(user_mount_path, sizeof(user_mount_path), "%s/%s", mount_path, user_entry->d_name);
|
||||
|
||||
// Check if this is a readable directory
|
||||
@@ -2753,6 +2934,7 @@ int detect_otp_thumb_drive(char* otp_drive_path, size_t path_size) {
|
||||
return 1; // Found OTP drive
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(user_dir);
|
||||
} else if (strcmp(mount_dirs[mount_idx], "/run/media") == 0) {
|
||||
// For /run/media, we need to go one level deeper (skip username)
|
||||
@@ -2766,7 +2948,7 @@ int detect_otp_thumb_drive(char* otp_drive_path, size_t path_size) {
|
||||
// Check if drive name starts with "OTP"
|
||||
if (strncmp(user_entry->d_name, "OTP", 3) != 0) continue;
|
||||
|
||||
char user_mount_path[512];
|
||||
char user_mount_path[2048]; // Increased buffer size
|
||||
snprintf(user_mount_path, sizeof(user_mount_path), "%s/%s", mount_path, user_entry->d_name);
|
||||
|
||||
// Check if this is a readable directory
|
||||
@@ -3383,7 +3565,7 @@ int handle_pads_menu(void) {
|
||||
pads[pad_count].chksum[64] = '\0';
|
||||
|
||||
// Get pad file size and usage info
|
||||
char full_path[512];
|
||||
char full_path[1024]; // Increased buffer size
|
||||
snprintf(full_path, sizeof(full_path), "%s/%s", current_pads_dir, entry->d_name);
|
||||
struct stat st;
|
||||
if (stat(full_path, &st) == 0) {
|
||||
@@ -3429,7 +3611,7 @@ int handle_pads_menu(void) {
|
||||
printf("No pads found.\n");
|
||||
printf("\nOptions:\n");
|
||||
printf(" \033[4mG\033[0menerate new pad\n");
|
||||
printf(" \033[4mB\033[0mack to main menu\n");
|
||||
printf(" E\033[4mx\033[0mit\n");
|
||||
printf("\nSelect option: ");
|
||||
|
||||
char input[10];
|
||||
@@ -3477,18 +3659,41 @@ int handle_pads_menu(void) {
|
||||
prefixes[i][prefix_lengths[i]] = '\0';
|
||||
}
|
||||
|
||||
// Display pads with minimal prefixes underlined
|
||||
// Display pads with minimal prefixes underlined and default indicator
|
||||
printf("\nAvailable pads:\n");
|
||||
printf("%-8s %-12s %-12s %-12s %-8s\n", "ChkSum", "Dir", "Size", "Used", "% Used");
|
||||
printf("%-8s %-12s %-12s %-12s %-8s\n", "--------", "------------", "----------", "----------", "------");
|
||||
printf("%-7s %-8s %-12s %-12s %-12s %-8s\n", "Default", "ChkSum", "Dir", "Size", "Used", "% Used");
|
||||
printf("%-7s %-8s %-12s %-12s %-12s %-8s\n", "-------", "--------", "------------", "----------", "----------", "------");
|
||||
|
||||
// Get current default pad path for comparison
|
||||
char* current_default = get_default_pad_path();
|
||||
char default_pad_checksum[65] = "";
|
||||
|
||||
if (current_default) {
|
||||
// Extract checksum from default pad path
|
||||
char* filename = strrchr(current_default, '/');
|
||||
if (!filename) filename = current_default;
|
||||
else filename++; // Skip the '/'
|
||||
|
||||
// Extract checksum (remove .pad extension)
|
||||
if (strlen(filename) >= 68 && strstr(filename, ".pad")) {
|
||||
strncpy(default_pad_checksum, filename, 64);
|
||||
default_pad_checksum[64] = '\0';
|
||||
}
|
||||
free(current_default);
|
||||
}
|
||||
|
||||
for (int i = 0; i < pad_count; i++) {
|
||||
// Check if this is the default pad
|
||||
int is_default = (strlen(default_pad_checksum) > 0 &&
|
||||
strncmp(pads[i].chksum, default_pad_checksum, 64) == 0);
|
||||
|
||||
// Display first 8 characters of checksum with prefix underlined
|
||||
char checksum_8char[9];
|
||||
strncpy(checksum_8char, pads[i].chksum, 8);
|
||||
checksum_8char[8] = '\0';
|
||||
|
||||
printf("\033[4m%.*s\033[0m%s %-12s %-12s %-12s %.1f%%\n",
|
||||
printf("%-7s \033[4m%.*s\033[0m%s %-12s %-12s %-12s %.1f%%\n",
|
||||
is_default ? "*" : "", // Default indicator
|
||||
prefix_lengths[i], checksum_8char, // Underlined prefix
|
||||
checksum_8char + prefix_lengths[i], // Rest of 8-char checksum
|
||||
pads[i].location, // Use the stored location info
|
||||
@@ -3499,7 +3704,8 @@ int handle_pads_menu(void) {
|
||||
|
||||
printf("\nActions:\n");
|
||||
printf(" \033[4mG\033[0menerate new pad\n");
|
||||
printf(" \033[4mB\033[0mack to main menu\n");
|
||||
printf(" \033[4mS\033[0met default pad\n");
|
||||
printf(" E\033[4mx\033[0mit\n");
|
||||
printf("\nSelect pad (by prefix) or action: ");
|
||||
|
||||
char input[MAX_HASH_LENGTH];
|
||||
@@ -3517,8 +3723,77 @@ int handle_pads_menu(void) {
|
||||
return handle_pads_menu();
|
||||
}
|
||||
return result;
|
||||
} else if (toupper(input[0]) == 'B') {
|
||||
return 0; // Back to main menu
|
||||
} else if (toupper(input[0]) == 'S') {
|
||||
// Set default pad
|
||||
printf("\nSelect pad to set as default (by 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;
|
||||
|
||||
// Find matching pad by prefix using the same logic as pad selection
|
||||
int matched_pad = -1;
|
||||
int match_count = 0;
|
||||
|
||||
for (int i = 0; i < pad_count; i++) {
|
||||
if (strncmp(pad_input, pads[i].chksum, strlen(pad_input)) == 0) {
|
||||
matched_pad = i;
|
||||
match_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (match_count == 0) {
|
||||
printf("No pad found matching prefix '%s'\n", pad_input);
|
||||
return handle_pads_menu();
|
||||
} else if (match_count > 1) {
|
||||
printf("Ambiguous prefix. Multiple matches found.\n");
|
||||
return handle_pads_menu();
|
||||
}
|
||||
|
||||
// Construct the full absolute pad path and set as default
|
||||
char new_default_path[1024];
|
||||
if (current_pads_dir[0] == '/') {
|
||||
// Already absolute path
|
||||
int ret = snprintf(new_default_path, sizeof(new_default_path), "%s/%s.pad", current_pads_dir, pads[matched_pad].chksum);
|
||||
if (ret >= (int)sizeof(new_default_path)) {
|
||||
printf("Error: Path too long for default pad setting\n");
|
||||
return handle_pads_menu();
|
||||
}
|
||||
} else {
|
||||
// Relative path - make it absolute
|
||||
char current_dir[512];
|
||||
if (getcwd(current_dir, sizeof(current_dir))) {
|
||||
int ret = snprintf(new_default_path, sizeof(new_default_path), "%s/%s/%s.pad", current_dir, current_pads_dir, pads[matched_pad].chksum);
|
||||
if (ret >= (int)sizeof(new_default_path)) {
|
||||
// Path was truncated, fall back to relative path
|
||||
int ret2 = snprintf(new_default_path, sizeof(new_default_path), "%s/%s.pad", current_pads_dir, pads[matched_pad].chksum);
|
||||
if (ret2 >= (int)sizeof(new_default_path)) {
|
||||
printf("Error: Path too long for default pad setting\n");
|
||||
return handle_pads_menu();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Fallback to relative path
|
||||
int ret = snprintf(new_default_path, sizeof(new_default_path), "%s/%s.pad", current_pads_dir, pads[matched_pad].chksum);
|
||||
if (ret >= (int)sizeof(new_default_path)) {
|
||||
printf("Error: Path too long for default pad setting\n");
|
||||
return handle_pads_menu();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (set_default_pad_path(new_default_path) == 0) {
|
||||
printf("Default pad set to: %.16s...\n", pads[matched_pad].chksum);
|
||||
printf("Full path: %s\n", new_default_path);
|
||||
} else {
|
||||
printf("Error: Failed to update default pad preference\n");
|
||||
}
|
||||
|
||||
return handle_pads_menu();
|
||||
} else if (toupper(input[0]) == 'X') {
|
||||
return 0; // Exit to main menu
|
||||
}
|
||||
|
||||
// Find matching pad by prefix
|
||||
@@ -3701,7 +3976,7 @@ void print_usage(const char* program_name) {
|
||||
printf("Usage:\n");
|
||||
printf(" %s - Interactive mode\n", program_name);
|
||||
printf(" %s generate|-g <size> - Generate new pad\n", program_name);
|
||||
printf(" %s encrypt|-e <pad_checksum_prefix> [text] - Encrypt text\n", program_name);
|
||||
printf(" %s encrypt|-e [pad_checksum_prefix] [text] - Encrypt text\n", program_name);
|
||||
printf(" %s decrypt|-d [encrypted_message] - Decrypt message\n", program_name);
|
||||
printf(" %s -f <file> <pad_prefix> [-a] [-o <out>] - Encrypt file\n", program_name);
|
||||
printf(" %s list|-l - List available pads\n", program_name);
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Testing updated files directory functionality
|
||||
@@ -1 +0,0 @@
|
||||
Testing files directory functionality
|
||||
BIN
test_new.txt.otp
BIN
test_new.txt.otp
Binary file not shown.
Reference in New Issue
Block a user