Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fa90e0eafd | |||
| 2a10d974b2 | |||
| 7e04896394 |
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
|
||||
|
||||
|
||||
226
otp.c
226
otp.c
@@ -151,6 +151,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 +257,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 +305,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 +313,143 @@ 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("\nEnter pad selection (number, chksum, or prefix): ");
|
||||
char input[MAX_HASH_LENGTH];
|
||||
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("\nEnter input file path: ");
|
||||
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;
|
||||
}
|
||||
|
||||
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 +505,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user