Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 12f92d2c96 | |||
| aea69148a8 | |||
| d537bc4948 | |||
| 42a8f5c358 |
6
TODO.md
6
TODO.md
@@ -3,9 +3,6 @@
|
|||||||
|
|
||||||
## Change technique for adding keyboard entropy.
|
## Change technique for adding keyboard entropy.
|
||||||
|
|
||||||
## Some of the processing seems similar, so maybe code could be more compact.
|
|
||||||
|
|
||||||
## Command line otp -e should go to default pad, and then comment after the fact that it used the default pad.
|
|
||||||
|
|
||||||
## 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.
|
## 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.
|
||||||
|
|
||||||
@@ -15,9 +12,6 @@ Or, better yet, assume the offset is a very large size, and use the pad itself t
|
|||||||
|
|
||||||
## Take a look at how the file header is being handled.
|
## Take a look at how the file header is being handled.
|
||||||
|
|
||||||
## We have three different decrypt file functions
|
|
||||||
|
|
||||||
## Preferences directory and files look off. Should probably have ~/.otp as the default directory, and then in there we can have otp.conf, pads/
|
|
||||||
|
|
||||||
## Setup for multiple USB drives
|
## Setup for multiple USB drives
|
||||||
|
|
||||||
|
|||||||
684
otp.c
684
otp.c
@@ -111,6 +111,15 @@ void show_progress(uint64_t current, uint64_t total, time_t start_time);
|
|||||||
int read_state_offset(const char* pad_chksum, uint64_t* offset);
|
int read_state_offset(const char* pad_chksum, uint64_t* offset);
|
||||||
int write_state_offset(const char* pad_chksum, uint64_t offset);
|
int write_state_offset(const char* pad_chksum, uint64_t offset);
|
||||||
int calculate_checksum(const char* filename, char* checksum_hex);
|
int calculate_checksum(const char* filename, char* checksum_hex);
|
||||||
|
// Universal core functions for code consolidation
|
||||||
|
int universal_xor_operation(const unsigned char* data, size_t data_len,
|
||||||
|
const unsigned char* pad_data, unsigned char* result);
|
||||||
|
int parse_ascii_message(const char* message, char* chksum, uint64_t* offset, char* base64_data);
|
||||||
|
int load_pad_data(const char* pad_chksum, uint64_t offset, size_t length, unsigned char** pad_data);
|
||||||
|
int generate_ascii_armor(const char* chksum, uint64_t offset, const unsigned char* encrypted_data,
|
||||||
|
size_t data_length, char** ascii_output);
|
||||||
|
int validate_pad_integrity(const char* pad_path, const char* expected_chksum);
|
||||||
|
|
||||||
char* custom_base64_encode(const unsigned char* input, int length);
|
char* custom_base64_encode(const unsigned char* input, int length);
|
||||||
unsigned char* custom_base64_decode(const char* input, int* output_length);
|
unsigned char* custom_base64_decode(const char* input, int* output_length);
|
||||||
|
|
||||||
@@ -297,9 +306,6 @@ int command_line_mode(int argc, char* argv[]) {
|
|||||||
|
|
||||||
// Call encrypt_text and then comment about using default pad
|
// Call encrypt_text and then comment about using default pad
|
||||||
int result = encrypt_text(pad_identifier, text);
|
int result = encrypt_text(pad_identifier, text);
|
||||||
if (result == 0) {
|
|
||||||
printf("# Used default pad: %.16s...\n", pad_identifier);
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
printf("Error: No default pad configured. Specify pad explicitly or configure default pad.\n");
|
printf("Error: No default pad configured. Specify pad explicitly or configure default pad.\n");
|
||||||
@@ -1482,50 +1488,44 @@ int encrypt_text(const char* pad_identifier, const char* input_text) {
|
|||||||
}
|
}
|
||||||
fclose(pad_file);
|
fclose(pad_file);
|
||||||
|
|
||||||
// XOR encrypt the input
|
// Use universal XOR operation for encryption
|
||||||
unsigned char* ciphertext = malloc(input_len);
|
unsigned char* ciphertext = malloc(input_len);
|
||||||
for (size_t i = 0; i < input_len; i++) {
|
if (universal_xor_operation((const unsigned char*)text_buffer, input_len, pad_data, ciphertext) != 0) {
|
||||||
ciphertext[i] = text_buffer[i] ^ pad_data[i];
|
printf("Error: Encryption operation failed\n");
|
||||||
|
free(pad_data);
|
||||||
|
free(ciphertext);
|
||||||
|
free(pad_chksum);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode as base64
|
|
||||||
char* base64_cipher = custom_base64_encode(ciphertext, input_len);
|
|
||||||
|
|
||||||
// Update state offset
|
// Update state offset
|
||||||
if (write_state_offset(pad_chksum, current_offset + input_len) != 0) {
|
if (write_state_offset(pad_chksum, current_offset + input_len) != 0) {
|
||||||
printf("Warning: Failed to update state file\n");
|
printf("Warning: Failed to update state file\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output in ASCII armor format - clean format for piping, spaced format for interactive
|
// Use universal ASCII armor generator
|
||||||
|
char* ascii_output;
|
||||||
|
if (generate_ascii_armor(chksum_hex, current_offset, ciphertext, input_len, &ascii_output) != 0) {
|
||||||
|
printf("Error: Failed to generate ASCII armor\n");
|
||||||
|
free(pad_data);
|
||||||
|
free(ciphertext);
|
||||||
|
free(pad_chksum);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output with appropriate formatting - clean format for piping, spaced format for interactive
|
||||||
int is_interactive = (input_text == NULL); // Interactive if no input_text provided
|
int is_interactive = (input_text == NULL); // Interactive if no input_text provided
|
||||||
|
|
||||||
if (is_interactive) {
|
if (is_interactive) {
|
||||||
printf("\n\n-----BEGIN OTP MESSAGE-----\n");
|
printf("\n\n%s\n\n", ascii_output);
|
||||||
} else {
|
} else {
|
||||||
printf("-----BEGIN OTP MESSAGE-----\n");
|
printf("%s", ascii_output);
|
||||||
}
|
|
||||||
|
|
||||||
printf("Version: %s\n", get_version());
|
|
||||||
printf("Pad-ChkSum: %s\n", chksum_hex);
|
|
||||||
printf("Pad-Offset: %lu\n", current_offset);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
// Print base64 data in 64-character lines
|
|
||||||
int b64_len = strlen(base64_cipher);
|
|
||||||
for (int i = 0; i < b64_len; i += 64) {
|
|
||||||
printf("%.64s\n", base64_cipher + i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_interactive) {
|
|
||||||
printf("-----END OTP MESSAGE-----\n\n\n");
|
|
||||||
} else {
|
|
||||||
printf("-----END OTP MESSAGE-----\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
free(pad_data);
|
free(pad_data);
|
||||||
free(ciphertext);
|
free(ciphertext);
|
||||||
free(base64_cipher);
|
free(ascii_output);
|
||||||
free(pad_chksum);
|
free(pad_chksum);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1535,46 +1535,13 @@ int decrypt_text(const char* pad_identifier, const char* encrypted_message) {
|
|||||||
// For command line mode, pad_identifier is ignored - we'll get the chksum from the message
|
// For command line mode, pad_identifier is ignored - we'll get the chksum from the message
|
||||||
(void)pad_identifier; // Suppress unused parameter warning
|
(void)pad_identifier; // Suppress unused parameter warning
|
||||||
|
|
||||||
char line[MAX_LINE_LENGTH];
|
|
||||||
char stored_chksum[MAX_HASH_LENGTH];
|
char stored_chksum[MAX_HASH_LENGTH];
|
||||||
char current_chksum[MAX_HASH_LENGTH];
|
|
||||||
uint64_t pad_offset;
|
uint64_t pad_offset;
|
||||||
char base64_data[MAX_INPUT_SIZE * 2] = {0};
|
char base64_data[MAX_INPUT_SIZE * 2] = {0};
|
||||||
int in_data_section = 0;
|
|
||||||
|
|
||||||
if (encrypted_message != NULL) {
|
if (encrypted_message != NULL) {
|
||||||
// Parse provided encrypted message
|
// Use universal ASCII parser to extract message components
|
||||||
char *message_copy = strdup(encrypted_message);
|
if (parse_ascii_message(encrypted_message, stored_chksum, &pad_offset, base64_data) != 0) {
|
||||||
char *line_ptr = strtok(message_copy, "\n");
|
|
||||||
|
|
||||||
int found_begin = 0;
|
|
||||||
while (line_ptr != NULL) {
|
|
||||||
if (strcmp(line_ptr, "-----BEGIN OTP MESSAGE-----") == 0) {
|
|
||||||
found_begin = 1;
|
|
||||||
}
|
|
||||||
else if (strcmp(line_ptr, "-----END OTP MESSAGE-----") == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (found_begin) {
|
|
||||||
if (strncmp(line_ptr, "Pad-ChkSum: ", 12) == 0) {
|
|
||||||
strncpy(stored_chksum, line_ptr + 12, 64);
|
|
||||||
stored_chksum[64] = '\0';
|
|
||||||
}
|
|
||||||
else if (strncmp(line_ptr, "Pad-Offset: ", 12) == 0) {
|
|
||||||
pad_offset = strtoull(line_ptr + 12, NULL, 10);
|
|
||||||
}
|
|
||||||
else if (strlen(line_ptr) == 0) {
|
|
||||||
in_data_section = 1;
|
|
||||||
}
|
|
||||||
else if (in_data_section) {
|
|
||||||
strncat(base64_data, line_ptr, sizeof(base64_data) - strlen(base64_data) - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
line_ptr = strtok(NULL, "\n");
|
|
||||||
}
|
|
||||||
free(message_copy);
|
|
||||||
|
|
||||||
if (!found_begin) {
|
|
||||||
printf("Error: Invalid message format - missing BEGIN header\n");
|
printf("Error: Invalid message format - missing BEGIN header\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1582,49 +1549,29 @@ int decrypt_text(const char* pad_identifier, const char* encrypted_message) {
|
|||||||
// Interactive mode - read from stdin
|
// Interactive mode - read from stdin
|
||||||
printf("Enter encrypted message (paste the full ASCII armor block):\n");
|
printf("Enter encrypted message (paste the full ASCII armor block):\n");
|
||||||
|
|
||||||
// Read the ASCII armor format
|
// Read entire message from stdin
|
||||||
int found_begin = 0;
|
char full_message[MAX_INPUT_SIZE * 4] = {0};
|
||||||
|
char line[MAX_LINE_LENGTH];
|
||||||
while (fgets(line, sizeof(line), stdin)) {
|
while (fgets(line, sizeof(line), stdin)) {
|
||||||
line[strcspn(line, "\n")] = 0;
|
strncat(full_message, line, sizeof(full_message) - strlen(full_message) - 1);
|
||||||
|
if (strstr(line, "-----END OTP MESSAGE-----")) {
|
||||||
if (strcmp(line, "-----BEGIN OTP MESSAGE-----") == 0) {
|
|
||||||
found_begin = 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(line, "-----END OTP MESSAGE-----") == 0) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found_begin) continue;
|
|
||||||
|
|
||||||
if (strncmp(line, "Pad-ChkSum: ", 12) == 0) {
|
|
||||||
strncpy(stored_chksum, line + 12, 64);
|
|
||||||
stored_chksum[64] = '\0';
|
|
||||||
}
|
|
||||||
else if (strncmp(line, "Pad-Offset: ", 12) == 0) {
|
|
||||||
pad_offset = strtoull(line + 12, NULL, 10);
|
|
||||||
}
|
|
||||||
else if (strlen(line) == 0) {
|
|
||||||
in_data_section = 1;
|
|
||||||
}
|
|
||||||
else if (in_data_section) {
|
|
||||||
strncat(base64_data, line, sizeof(base64_data) - strlen(base64_data) - 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found_begin) {
|
// Use universal ASCII parser
|
||||||
|
if (parse_ascii_message(full_message, stored_chksum, &pad_offset, base64_data) != 0) {
|
||||||
printf("Error: Invalid message format - missing BEGIN header\n");
|
printf("Error: Invalid message format - missing BEGIN header\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we have the pad chksum from the message, construct filename
|
// Get pad path for integrity check
|
||||||
char pad_path[MAX_HASH_LENGTH + 20];
|
char pad_path[MAX_HASH_LENGTH + 20];
|
||||||
char state_path[MAX_HASH_LENGTH + 20];
|
char state_path[MAX_HASH_LENGTH + 20];
|
||||||
get_pad_path(stored_chksum, pad_path, state_path);
|
get_pad_path(stored_chksum, pad_path, state_path);
|
||||||
|
|
||||||
// Check if we have this pad
|
// Check if pad exists
|
||||||
if (access(pad_path, R_OK) != 0) {
|
if (access(pad_path, R_OK) != 0) {
|
||||||
printf("Error: Required pad not found: %s\n", stored_chksum);
|
printf("Error: Required pad not found: %s\n", stored_chksum);
|
||||||
printf("Available pads:\n");
|
printf("Available pads:\n");
|
||||||
@@ -1632,30 +1579,28 @@ int decrypt_text(const char* pad_identifier, const char* encrypted_message) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify pad integrity
|
// Use universal pad integrity validator
|
||||||
if (calculate_checksum(pad_path, current_chksum) != 0) {
|
int integrity_result = validate_pad_integrity(pad_path, stored_chksum);
|
||||||
printf("Error: Cannot calculate current pad checksum\n");
|
if (integrity_result == 3) {
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(stored_chksum, current_chksum) != 0) {
|
|
||||||
printf("Warning: Pad integrity check failed!\n");
|
printf("Warning: Pad integrity check failed!\n");
|
||||||
printf("Expected: %s\n", stored_chksum);
|
printf("Expected: %s\n", stored_chksum);
|
||||||
printf("Current: %s\n", current_chksum);
|
|
||||||
printf("Continue anyway? (y/N): ");
|
printf("Continue anyway? (y/N): ");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
||||||
char response[10];
|
char response[10];
|
||||||
if (fgets(response, sizeof(response), stdin) == NULL ||
|
if (fgets(response, sizeof(response), stdin) == NULL ||
|
||||||
(response[0] != 'y' && response[0] != 'Y')) {
|
(response[0] != 'y' && response[0] != 'Y')) {
|
||||||
printf("Decryption aborted.\n");
|
printf("Decryption aborted.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
} else if (integrity_result != 0) {
|
||||||
|
printf("Error: Cannot verify pad integrity\n");
|
||||||
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
printf("Pad integrity: VERIFIED\n");
|
printf("Pad integrity: VERIFIED\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode base64
|
// Decode base64 ciphertext
|
||||||
int ciphertext_len;
|
int ciphertext_len;
|
||||||
unsigned char* ciphertext = custom_base64_decode(base64_data, &ciphertext_len);
|
unsigned char* ciphertext = custom_base64_decode(base64_data, &ciphertext_len);
|
||||||
if (!ciphertext) {
|
if (!ciphertext) {
|
||||||
@@ -1663,36 +1608,24 @@ int decrypt_text(const char* pad_identifier, const char* encrypted_message) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read pad data at specified offset
|
// Use universal pad loader
|
||||||
FILE* pad_file = fopen(pad_path, "rb");
|
unsigned char* pad_data;
|
||||||
if (!pad_file) {
|
int load_result = load_pad_data(stored_chksum, pad_offset, ciphertext_len, &pad_data);
|
||||||
printf("Error: Cannot open pad file %s\n", pad_path);
|
if (load_result != 0) {
|
||||||
|
printf("Error: Cannot load pad data (code %d)\n", load_result);
|
||||||
free(ciphertext);
|
free(ciphertext);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fseek(pad_file, pad_offset, SEEK_SET) != 0) {
|
// Use universal XOR operation for decryption
|
||||||
printf("Error: Cannot seek to offset %lu in pad file\n", pad_offset);
|
char* plaintext = malloc(ciphertext_len + 1);
|
||||||
free(ciphertext);
|
if (universal_xor_operation(ciphertext, ciphertext_len, pad_data, (unsigned char*)plaintext) != 0) {
|
||||||
fclose(pad_file);
|
printf("Error: Decryption operation failed\n");
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char* pad_data = malloc(ciphertext_len);
|
|
||||||
if (fread(pad_data, 1, ciphertext_len, pad_file) != (size_t)ciphertext_len) {
|
|
||||||
printf("Error: Cannot read pad data\n");
|
|
||||||
free(ciphertext);
|
free(ciphertext);
|
||||||
free(pad_data);
|
free(pad_data);
|
||||||
fclose(pad_file);
|
free(plaintext);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
fclose(pad_file);
|
|
||||||
|
|
||||||
// XOR decrypt
|
|
||||||
char* plaintext = malloc(ciphertext_len + 1);
|
|
||||||
for (int i = 0; i < ciphertext_len; i++) {
|
|
||||||
plaintext[i] = ciphertext[i] ^ pad_data[i];
|
|
||||||
}
|
|
||||||
plaintext[ciphertext_len] = '\0';
|
plaintext[ciphertext_len] = '\0';
|
||||||
|
|
||||||
printf("Decrypted: %s\n", plaintext);
|
printf("Decrypted: %s\n", plaintext);
|
||||||
@@ -1710,79 +1643,38 @@ int decrypt_text_silent(const char* pad_identifier, const char* encrypted_messag
|
|||||||
(void)pad_identifier; // Suppress unused parameter warning
|
(void)pad_identifier; // Suppress unused parameter warning
|
||||||
|
|
||||||
char stored_chksum[MAX_HASH_LENGTH];
|
char stored_chksum[MAX_HASH_LENGTH];
|
||||||
char current_chksum[MAX_HASH_LENGTH];
|
|
||||||
uint64_t pad_offset;
|
uint64_t pad_offset;
|
||||||
char base64_data[MAX_INPUT_SIZE * 2] = {0};
|
char base64_data[MAX_INPUT_SIZE * 2] = {0};
|
||||||
int in_data_section = 0;
|
|
||||||
|
|
||||||
if (encrypted_message != NULL) {
|
if (encrypted_message == NULL) {
|
||||||
// Parse provided encrypted message
|
|
||||||
char *message_copy = strdup(encrypted_message);
|
|
||||||
char *line_ptr = strtok(message_copy, "\n");
|
|
||||||
|
|
||||||
int found_begin = 0;
|
|
||||||
while (line_ptr != NULL) {
|
|
||||||
if (strcmp(line_ptr, "-----BEGIN OTP MESSAGE-----") == 0) {
|
|
||||||
found_begin = 1;
|
|
||||||
}
|
|
||||||
else if (strcmp(line_ptr, "-----END OTP MESSAGE-----") == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (found_begin) {
|
|
||||||
if (strncmp(line_ptr, "Pad-ChkSum: ", 12) == 0) {
|
|
||||||
strncpy(stored_chksum, line_ptr + 12, 64);
|
|
||||||
stored_chksum[64] = '\0';
|
|
||||||
}
|
|
||||||
else if (strncmp(line_ptr, "Pad-Offset: ", 12) == 0) {
|
|
||||||
pad_offset = strtoull(line_ptr + 12, NULL, 10);
|
|
||||||
}
|
|
||||||
else if (strlen(line_ptr) == 0) {
|
|
||||||
in_data_section = 1;
|
|
||||||
}
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
free(message_copy);
|
|
||||||
|
|
||||||
if (!found_begin) {
|
|
||||||
fprintf(stderr, "Error: Invalid message format - missing BEGIN header\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Error: No encrypted message provided\n");
|
fprintf(stderr, "Error: No encrypted message provided\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we have the pad chksum from the message, construct filename
|
// Use universal ASCII parser to extract message components
|
||||||
|
if (parse_ascii_message(encrypted_message, stored_chksum, &pad_offset, base64_data) != 0) {
|
||||||
|
fprintf(stderr, "Error: Invalid message format - missing BEGIN header\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get pad path for integrity check
|
||||||
char pad_path[MAX_HASH_LENGTH + 20];
|
char pad_path[MAX_HASH_LENGTH + 20];
|
||||||
char state_path[MAX_HASH_LENGTH + 20];
|
char state_path[MAX_HASH_LENGTH + 20];
|
||||||
get_pad_path(stored_chksum, pad_path, state_path);
|
get_pad_path(stored_chksum, pad_path, state_path);
|
||||||
|
|
||||||
// Check if we have this pad
|
// Check if pad exists
|
||||||
if (access(pad_path, R_OK) != 0) {
|
if (access(pad_path, R_OK) != 0) {
|
||||||
fprintf(stderr, "Error: Required pad not found: %s\n", stored_chksum);
|
fprintf(stderr, "Error: Required pad not found: %s\n", stored_chksum);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify pad integrity (silent check)
|
// Use universal pad integrity validator (silent check)
|
||||||
if (calculate_checksum(pad_path, current_chksum) != 0) {
|
if (validate_pad_integrity(pad_path, stored_chksum) != 0) {
|
||||||
fprintf(stderr, "Error: Cannot calculate current pad checksum\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(stored_chksum, current_chksum) != 0) {
|
|
||||||
fprintf(stderr, "Error: Pad integrity check failed!\n");
|
fprintf(stderr, "Error: Pad integrity check failed!\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode base64
|
// Decode base64 ciphertext
|
||||||
int ciphertext_len;
|
int ciphertext_len;
|
||||||
unsigned char* ciphertext = custom_base64_decode(base64_data, &ciphertext_len);
|
unsigned char* ciphertext = custom_base64_decode(base64_data, &ciphertext_len);
|
||||||
if (!ciphertext) {
|
if (!ciphertext) {
|
||||||
@@ -1790,36 +1682,23 @@ int decrypt_text_silent(const char* pad_identifier, const char* encrypted_messag
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read pad data at specified offset
|
// Use universal pad loader
|
||||||
FILE* pad_file = fopen(pad_path, "rb");
|
unsigned char* pad_data;
|
||||||
if (!pad_file) {
|
if (load_pad_data(stored_chksum, pad_offset, ciphertext_len, &pad_data) != 0) {
|
||||||
fprintf(stderr, "Error: Cannot open pad file %s\n", pad_path);
|
fprintf(stderr, "Error: Cannot load pad data\n");
|
||||||
free(ciphertext);
|
free(ciphertext);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fseek(pad_file, pad_offset, SEEK_SET) != 0) {
|
// Use universal XOR operation for decryption
|
||||||
fprintf(stderr, "Error: Cannot seek to offset %lu in pad file\n", pad_offset);
|
char* plaintext = malloc(ciphertext_len + 1);
|
||||||
free(ciphertext);
|
if (universal_xor_operation(ciphertext, ciphertext_len, pad_data, (unsigned char*)plaintext) != 0) {
|
||||||
fclose(pad_file);
|
fprintf(stderr, "Error: Decryption operation failed\n");
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char* pad_data = malloc(ciphertext_len);
|
|
||||||
if (fread(pad_data, 1, ciphertext_len, pad_file) != (size_t)ciphertext_len) {
|
|
||||||
fprintf(stderr, "Error: Cannot read pad data\n");
|
|
||||||
free(ciphertext);
|
free(ciphertext);
|
||||||
free(pad_data);
|
free(pad_data);
|
||||||
fclose(pad_file);
|
free(plaintext);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
fclose(pad_file);
|
|
||||||
|
|
||||||
// XOR decrypt
|
|
||||||
char* plaintext = malloc(ciphertext_len + 1);
|
|
||||||
for (int i = 0; i < ciphertext_len; i++) {
|
|
||||||
plaintext[i] = ciphertext[i] ^ pad_data[i];
|
|
||||||
}
|
|
||||||
plaintext[ciphertext_len] = '\0';
|
plaintext[ciphertext_len] = '\0';
|
||||||
|
|
||||||
// Output only the decrypted text with newline and flush
|
// Output only the decrypted text with newline and flush
|
||||||
@@ -1983,9 +1862,14 @@ int encrypt_file(const char* pad_identifier, const char* input_file, const char*
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// XOR encrypt
|
// Use universal XOR operation for encryption
|
||||||
for (uint64_t i = 0; i < chunk_size; i++) {
|
if (universal_xor_operation(buffer, chunk_size, pad_buffer, &encrypted_data[bytes_processed]) != 0) {
|
||||||
encrypted_data[bytes_processed + i] = buffer[i] ^ pad_buffer[i];
|
printf("Error: Encryption operation failed\n");
|
||||||
|
free(encrypted_data);
|
||||||
|
fclose(input_fp);
|
||||||
|
fclose(pad_file);
|
||||||
|
free(pad_chksum);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes_processed += chunk_size;
|
bytes_processed += chunk_size;
|
||||||
@@ -2015,26 +1899,21 @@ int encrypt_file(const char* pad_identifier, const char* input_file, const char*
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode as base64
|
// Use universal ASCII armor generator
|
||||||
char* base64_data = custom_base64_encode(encrypted_data, file_size);
|
char* ascii_output;
|
||||||
|
if (generate_ascii_armor(chksum_hex, current_offset, encrypted_data, file_size, &ascii_output) != 0) {
|
||||||
// Write ASCII armor
|
printf("Error: Failed to generate ASCII armor\n");
|
||||||
fprintf(output_fp, "-----BEGIN OTP MESSAGE-----\n");
|
fclose(output_fp);
|
||||||
fprintf(output_fp, "Version: %s\n", get_version());
|
free(encrypted_data);
|
||||||
fprintf(output_fp, "Pad-ChkSum: %s\n", chksum_hex);
|
free(pad_chksum);
|
||||||
fprintf(output_fp, "Pad-Offset: %lu\n", current_offset);
|
return 1;
|
||||||
fprintf(output_fp, "\n");
|
|
||||||
|
|
||||||
// Write base64 data in 64-character lines
|
|
||||||
int b64_len = strlen(base64_data);
|
|
||||||
for (int i = 0; i < b64_len; i += 64) {
|
|
||||||
fprintf(output_fp, "%.64s\n", base64_data + i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(output_fp, "-----END OTP MESSAGE-----\n");
|
// Write the ASCII armored output to file
|
||||||
|
fprintf(output_fp, "%s", ascii_output);
|
||||||
|
|
||||||
fclose(output_fp);
|
fclose(output_fp);
|
||||||
free(base64_data);
|
free(ascii_output);
|
||||||
} else {
|
} else {
|
||||||
// Binary format
|
// Binary format
|
||||||
FILE* output_fp = fopen(output_file, "wb");
|
FILE* output_fp = fopen(output_file, "wb");
|
||||||
@@ -2220,9 +2099,12 @@ int decrypt_binary_file(FILE* input_fp, const char* output_file) {
|
|||||||
}
|
}
|
||||||
fclose(pad_file);
|
fclose(pad_file);
|
||||||
|
|
||||||
// XOR decrypt
|
// Use universal XOR operation for decryption
|
||||||
for (uint64_t i = 0; i < file_size; i++) {
|
if (universal_xor_operation(encrypted_data, file_size, pad_data, encrypted_data) != 0) {
|
||||||
encrypted_data[i] ^= pad_data[i];
|
printf("Error: Decryption operation failed\n");
|
||||||
|
free(encrypted_data);
|
||||||
|
free(pad_data);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write decrypted file
|
// Write decrypted file
|
||||||
@@ -2265,49 +2147,34 @@ int decrypt_ascii_file(const char* input_file, const char* output_file) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the entire ASCII armored content
|
// Read the entire file content into a string
|
||||||
char line[MAX_LINE_LENGTH];
|
fseek(input_fp, 0, SEEK_END);
|
||||||
char stored_chksum[MAX_HASH_LENGTH];
|
long file_size = ftell(input_fp);
|
||||||
uint64_t pad_offset;
|
fseek(input_fp, 0, SEEK_SET);
|
||||||
char base64_data[MAX_INPUT_SIZE * 8] = {0}; // Larger buffer for files
|
|
||||||
int in_data_section = 0;
|
|
||||||
int found_begin = 0;
|
|
||||||
|
|
||||||
while (fgets(line, sizeof(line), input_fp)) {
|
char* file_content = malloc(file_size + 1);
|
||||||
line[strcspn(line, "\n\r")] = 0; // Remove newlines
|
if (!file_content) {
|
||||||
|
printf("Error: Memory allocation failed\n");
|
||||||
if (strcmp(line, "-----BEGIN OTP MESSAGE-----") == 0) {
|
fclose(input_fp);
|
||||||
found_begin = 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(line, "-----END OTP MESSAGE-----") == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found_begin) continue;
|
|
||||||
|
|
||||||
if (strncmp(line, "Pad-ChkSum: ", 12) == 0) {
|
|
||||||
strncpy(stored_chksum, line + 12, 64);
|
|
||||||
stored_chksum[64] = '\0';
|
|
||||||
}
|
|
||||||
else if (strncmp(line, "Pad-Offset: ", 12) == 0) {
|
|
||||||
pad_offset = strtoull(line + 12, NULL, 10);
|
|
||||||
}
|
|
||||||
else if (strlen(line) == 0) {
|
|
||||||
in_data_section = 1;
|
|
||||||
}
|
|
||||||
else if (in_data_section) {
|
|
||||||
strncat(base64_data, line, sizeof(base64_data) - strlen(base64_data) - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fclose(input_fp);
|
|
||||||
|
|
||||||
if (!found_begin) {
|
|
||||||
printf("Error: Invalid ASCII armored format\n");
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t bytes_read = fread(file_content, 1, file_size, input_fp);
|
||||||
|
file_content[bytes_read] = '\0';
|
||||||
|
fclose(input_fp);
|
||||||
|
|
||||||
|
// Use universal ASCII parser
|
||||||
|
char stored_chksum[MAX_HASH_LENGTH];
|
||||||
|
uint64_t pad_offset;
|
||||||
|
char base64_data[MAX_INPUT_SIZE * 8] = {0};
|
||||||
|
|
||||||
|
if (parse_ascii_message(file_content, stored_chksum, &pad_offset, base64_data) != 0) {
|
||||||
|
printf("Error: Invalid ASCII armored format\n");
|
||||||
|
free(file_content);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
free(file_content);
|
||||||
|
|
||||||
printf("Decrypting ASCII armored file...\n");
|
printf("Decrypting ASCII armored file...\n");
|
||||||
|
|
||||||
// Check if we have the required pad
|
// Check if we have the required pad
|
||||||
@@ -2322,7 +2189,7 @@ int decrypt_ascii_file(const char* input_file, const char* output_file) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode base64
|
// Decode base64 ciphertext
|
||||||
int ciphertext_len;
|
int ciphertext_len;
|
||||||
unsigned char* ciphertext = custom_base64_decode(base64_data, &ciphertext_len);
|
unsigned char* ciphertext = custom_base64_decode(base64_data, &ciphertext_len);
|
||||||
if (!ciphertext) {
|
if (!ciphertext) {
|
||||||
@@ -2347,35 +2214,21 @@ int decrypt_ascii_file(const char* input_file, const char* output_file) {
|
|||||||
output_file = default_output;
|
output_file = default_output;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open pad file and decrypt
|
// Use universal pad loader
|
||||||
FILE* pad_file = fopen(pad_path, "rb");
|
unsigned char* pad_data;
|
||||||
if (!pad_file) {
|
if (load_pad_data(stored_chksum, pad_offset, ciphertext_len, &pad_data) != 0) {
|
||||||
printf("Error: Cannot open pad file\n");
|
printf("Error: Cannot load pad data\n");
|
||||||
free(ciphertext);
|
free(ciphertext);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fseek(pad_file, pad_offset, SEEK_SET) != 0) {
|
// Use universal XOR operation for decryption
|
||||||
printf("Error: Cannot seek to offset in pad file\n");
|
if (universal_xor_operation(ciphertext, ciphertext_len, pad_data, ciphertext) != 0) {
|
||||||
free(ciphertext);
|
printf("Error: Decryption operation failed\n");
|
||||||
fclose(pad_file);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char* pad_data = malloc(ciphertext_len);
|
|
||||||
if (fread(pad_data, 1, ciphertext_len, pad_file) != (size_t)ciphertext_len) {
|
|
||||||
printf("Error: Cannot read pad data\n");
|
|
||||||
free(ciphertext);
|
free(ciphertext);
|
||||||
free(pad_data);
|
free(pad_data);
|
||||||
fclose(pad_file);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
fclose(pad_file);
|
|
||||||
|
|
||||||
// XOR decrypt
|
|
||||||
for (int i = 0; i < ciphertext_len; i++) {
|
|
||||||
ciphertext[i] ^= pad_data[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write decrypted file
|
// Write decrypted file
|
||||||
FILE* output_fp = fopen(output_file, "wb");
|
FILE* output_fp = fopen(output_file, "wb");
|
||||||
@@ -2727,18 +2580,29 @@ int load_preferences(void) {
|
|||||||
while ((entry = readdir(dir)) != NULL && !found_pad) {
|
while ((entry = readdir(dir)) != NULL && !found_pad) {
|
||||||
if (strstr(entry->d_name, ".pad") && strlen(entry->d_name) == 68) {
|
if (strstr(entry->d_name, ".pad") && strlen(entry->d_name) == 68) {
|
||||||
// Found a pad file - construct full absolute path
|
// Found a pad file - construct full absolute path
|
||||||
char absolute_path[1024];
|
|
||||||
if (current_pads_dir[0] == '/') {
|
if (current_pads_dir[0] == '/') {
|
||||||
// Already absolute path
|
// Already absolute path
|
||||||
snprintf(first_pad_path, sizeof(first_pad_path), "%s/%s", current_pads_dir, entry->d_name);
|
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 {
|
} else {
|
||||||
// Relative path - make it absolute
|
// Relative path - make it absolute
|
||||||
char current_dir[512];
|
char current_dir[512];
|
||||||
if (getcwd(current_dir, sizeof(current_dir))) {
|
if (getcwd(current_dir, sizeof(current_dir))) {
|
||||||
snprintf(first_pad_path, sizeof(first_pad_path), "%s/%s/%s", current_dir, current_pads_dir, entry->d_name);
|
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 {
|
} else {
|
||||||
// Fallback to relative path
|
// Fallback to relative path
|
||||||
snprintf(first_pad_path, sizeof(first_pad_path), "%s/%s", current_pads_dir, entry->d_name);
|
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);
|
strncpy(default_pad_path, first_pad_path, sizeof(default_pad_path) - 1);
|
||||||
@@ -3055,6 +2919,220 @@ void simple_entropy_mix(unsigned char* urandom_buffer, size_t buffer_size,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// UNIVERSAL CORE FUNCTIONS FOR CODE CONSOLIDATION
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Universal XOR operation - handles both encryption and decryption
|
||||||
|
// Since XOR is symmetric, this single function replaces all 6 duplicate XOR loops
|
||||||
|
int universal_xor_operation(const unsigned char* data, size_t data_len,
|
||||||
|
const unsigned char* pad_data, unsigned char* result) {
|
||||||
|
if (!data || !pad_data || !result) {
|
||||||
|
return 1; // Error: null pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < data_len; i++) {
|
||||||
|
result[i] = data[i] ^ pad_data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // Success
|
||||||
|
}
|
||||||
|
|
||||||
|
// Universal ASCII message parser - consolidates 4 duplicate parsing implementations
|
||||||
|
// Extracts checksum, offset, and base64 data from ASCII armored messages
|
||||||
|
int parse_ascii_message(const char* message, char* chksum, uint64_t* offset, char* base64_data) {
|
||||||
|
if (!message || !chksum || !offset || !base64_data) {
|
||||||
|
return 1; // Error: null pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
char *message_copy = strdup(message);
|
||||||
|
if (!message_copy) {
|
||||||
|
return 1; // Memory allocation failed
|
||||||
|
}
|
||||||
|
|
||||||
|
char *line_ptr = strtok(message_copy, "\n");
|
||||||
|
int found_begin = 0;
|
||||||
|
int in_data_section = 0;
|
||||||
|
int found_chksum = 0, found_offset = 0;
|
||||||
|
|
||||||
|
// Initialize output
|
||||||
|
chksum[0] = '\0';
|
||||||
|
*offset = 0;
|
||||||
|
base64_data[0] = '\0';
|
||||||
|
|
||||||
|
while (line_ptr != NULL) {
|
||||||
|
if (strcmp(line_ptr, "-----BEGIN OTP MESSAGE-----") == 0) {
|
||||||
|
found_begin = 1;
|
||||||
|
}
|
||||||
|
else if (strcmp(line_ptr, "-----END OTP MESSAGE-----") == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (found_begin) {
|
||||||
|
if (strncmp(line_ptr, "Pad-ChkSum: ", 12) == 0) {
|
||||||
|
strncpy(chksum, line_ptr + 12, 64);
|
||||||
|
chksum[64] = '\0';
|
||||||
|
found_chksum = 1;
|
||||||
|
}
|
||||||
|
else if (strncmp(line_ptr, "Pad-Offset: ", 12) == 0) {
|
||||||
|
*offset = strtoull(line_ptr + 12, NULL, 10);
|
||||||
|
found_offset = 1;
|
||||||
|
}
|
||||||
|
else if (strlen(line_ptr) == 0) {
|
||||||
|
in_data_section = 1;
|
||||||
|
}
|
||||||
|
else if (in_data_section) {
|
||||||
|
strncat(base64_data, line_ptr, MAX_INPUT_SIZE * 2 - 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, MAX_INPUT_SIZE * 2 - strlen(base64_data) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
line_ptr = strtok(NULL, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
free(message_copy);
|
||||||
|
|
||||||
|
if (!found_begin || !found_chksum || !found_offset) {
|
||||||
|
return 2; // Error: incomplete message format
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // Success
|
||||||
|
}
|
||||||
|
|
||||||
|
// Universal pad data loader - consolidates pad loading and validation logic
|
||||||
|
// Loads pad data at specified offset and validates pad availability
|
||||||
|
int load_pad_data(const char* pad_chksum, uint64_t offset, size_t length, unsigned char** pad_data) {
|
||||||
|
if (!pad_chksum || !pad_data) {
|
||||||
|
return 1; // Error: null pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
char pad_path[MAX_HASH_LENGTH + 20];
|
||||||
|
char state_path[MAX_HASH_LENGTH + 20];
|
||||||
|
get_pad_path(pad_chksum, pad_path, state_path);
|
||||||
|
|
||||||
|
// Check if pad file exists
|
||||||
|
if (access(pad_path, R_OK) != 0) {
|
||||||
|
return 2; // Error: pad file not found
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check pad file size
|
||||||
|
struct stat pad_stat;
|
||||||
|
if (stat(pad_path, &pad_stat) != 0) {
|
||||||
|
return 3; // Error: cannot get pad file size
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset + length > (uint64_t)pad_stat.st_size) {
|
||||||
|
return 4; // Error: not enough pad space
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate memory for pad data
|
||||||
|
*pad_data = malloc(length);
|
||||||
|
if (!*pad_data) {
|
||||||
|
return 5; // Error: memory allocation failed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open and read pad file
|
||||||
|
FILE* pad_file = fopen(pad_path, "rb");
|
||||||
|
if (!pad_file) {
|
||||||
|
free(*pad_data);
|
||||||
|
*pad_data = NULL;
|
||||||
|
return 6; // Error: cannot open pad file
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fseek(pad_file, offset, SEEK_SET) != 0) {
|
||||||
|
fclose(pad_file);
|
||||||
|
free(*pad_data);
|
||||||
|
*pad_data = NULL;
|
||||||
|
return 7; // Error: cannot seek to offset
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fread(*pad_data, 1, length, pad_file) != length) {
|
||||||
|
fclose(pad_file);
|
||||||
|
free(*pad_data);
|
||||||
|
*pad_data = NULL;
|
||||||
|
return 8; // Error: cannot read pad data
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(pad_file);
|
||||||
|
return 0; // Success
|
||||||
|
}
|
||||||
|
|
||||||
|
// Universal ASCII armor generator - consolidates duplicate ASCII armor generation
|
||||||
|
// Creates ASCII armored output format used by both text and file encryption
|
||||||
|
int generate_ascii_armor(const char* chksum, uint64_t offset, const unsigned char* encrypted_data,
|
||||||
|
size_t data_length, char** ascii_output) {
|
||||||
|
if (!chksum || !encrypted_data || !ascii_output) {
|
||||||
|
return 1; // Error: null pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode data as base64
|
||||||
|
char* base64_data = custom_base64_encode(encrypted_data, data_length);
|
||||||
|
if (!base64_data) {
|
||||||
|
return 2; // Error: base64 encoding failed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate required buffer size
|
||||||
|
size_t base64_len = strlen(base64_data);
|
||||||
|
size_t header_size = 200; // Approximate size for headers
|
||||||
|
size_t total_size = header_size + base64_len + (base64_len / 64) + 100; // +newlines +footer
|
||||||
|
|
||||||
|
*ascii_output = malloc(total_size);
|
||||||
|
if (!*ascii_output) {
|
||||||
|
free(base64_data);
|
||||||
|
return 3; // Error: memory allocation failed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build ASCII armor
|
||||||
|
strcpy(*ascii_output, "-----BEGIN OTP MESSAGE-----\n");
|
||||||
|
|
||||||
|
char temp_line[256];
|
||||||
|
snprintf(temp_line, sizeof(temp_line), "Version: %s\n", get_version());
|
||||||
|
strcat(*ascii_output, temp_line);
|
||||||
|
|
||||||
|
snprintf(temp_line, sizeof(temp_line), "Pad-ChkSum: %s\n", chksum);
|
||||||
|
strcat(*ascii_output, temp_line);
|
||||||
|
|
||||||
|
snprintf(temp_line, sizeof(temp_line), "Pad-Offset: %lu\n", offset);
|
||||||
|
strcat(*ascii_output, temp_line);
|
||||||
|
|
||||||
|
strcat(*ascii_output, "\n");
|
||||||
|
|
||||||
|
// Add base64 data in 64-character lines
|
||||||
|
int b64_len = strlen(base64_data);
|
||||||
|
for (int i = 0; i < b64_len; i += 64) {
|
||||||
|
char line[70];
|
||||||
|
snprintf(line, sizeof(line), "%.64s\n", base64_data + i);
|
||||||
|
strcat(*ascii_output, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
strcat(*ascii_output, "-----END OTP MESSAGE-----\n");
|
||||||
|
|
||||||
|
free(base64_data);
|
||||||
|
return 0; // Success
|
||||||
|
}
|
||||||
|
|
||||||
|
// Universal pad integrity validator - consolidates pad validation logic
|
||||||
|
// Verifies pad checksum matches expected value for security
|
||||||
|
int validate_pad_integrity(const char* pad_path, const char* expected_chksum) {
|
||||||
|
if (!pad_path || !expected_chksum) {
|
||||||
|
return 1; // Error: null pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
char current_chksum[MAX_HASH_LENGTH];
|
||||||
|
if (calculate_checksum(pad_path, current_chksum) != 0) {
|
||||||
|
return 2; // Error: cannot calculate checksum
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(expected_chksum, current_chksum) != 0) {
|
||||||
|
return 3; // Error: checksum mismatch
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // Success - pad integrity verified
|
||||||
|
}
|
||||||
|
|
||||||
// Enhanced input function with editable pre-filled text
|
// Enhanced input function with editable pre-filled text
|
||||||
int get_filename_with_default(const char* prompt, const char* default_path, char* result, size_t result_size) {
|
int get_filename_with_default(const char* prompt, const char* default_path, char* result, size_t result_size) {
|
||||||
// Find the last directory separator
|
// Find the last directory separator
|
||||||
@@ -3602,7 +3680,7 @@ int handle_pads_menu(void) {
|
|||||||
printf("No pads found.\n");
|
printf("No pads found.\n");
|
||||||
printf("\nOptions:\n");
|
printf("\nOptions:\n");
|
||||||
printf(" \033[4mG\033[0menerate new pad\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: ");
|
printf("\nSelect option: ");
|
||||||
|
|
||||||
char input[10];
|
char input[10];
|
||||||
@@ -3696,7 +3774,7 @@ int handle_pads_menu(void) {
|
|||||||
printf("\nActions:\n");
|
printf("\nActions:\n");
|
||||||
printf(" \033[4mG\033[0menerate new pad\n");
|
printf(" \033[4mG\033[0menerate new pad\n");
|
||||||
printf(" \033[4mS\033[0met default pad\n");
|
printf(" \033[4mS\033[0met default pad\n");
|
||||||
printf(" \033[4mB\033[0mack to main menu\n");
|
printf(" E\033[4mx\033[0mit\n");
|
||||||
printf("\nSelect pad (by prefix) or action: ");
|
printf("\nSelect pad (by prefix) or action: ");
|
||||||
|
|
||||||
char input[MAX_HASH_LENGTH];
|
char input[MAX_HASH_LENGTH];
|
||||||
@@ -3747,15 +3825,31 @@ int handle_pads_menu(void) {
|
|||||||
char new_default_path[1024];
|
char new_default_path[1024];
|
||||||
if (current_pads_dir[0] == '/') {
|
if (current_pads_dir[0] == '/') {
|
||||||
// Already absolute path
|
// Already absolute path
|
||||||
snprintf(new_default_path, sizeof(new_default_path), "%s/%s.pad", current_pads_dir, pads[matched_pad].chksum);
|
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 {
|
} else {
|
||||||
// Relative path - make it absolute
|
// Relative path - make it absolute
|
||||||
char current_dir[512];
|
char current_dir[512];
|
||||||
if (getcwd(current_dir, sizeof(current_dir))) {
|
if (getcwd(current_dir, sizeof(current_dir))) {
|
||||||
snprintf(new_default_path, sizeof(new_default_path), "%s/%s/%s.pad", current_dir, current_pads_dir, pads[matched_pad].chksum);
|
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 {
|
} else {
|
||||||
// Fallback to relative path
|
// Fallback to relative path
|
||||||
snprintf(new_default_path, sizeof(new_default_path), "%s/%s.pad", current_pads_dir, pads[matched_pad].chksum);
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3767,8 +3861,8 @@ int handle_pads_menu(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return handle_pads_menu();
|
return handle_pads_menu();
|
||||||
} else if (toupper(input[0]) == 'B') {
|
} else if (toupper(input[0]) == 'X') {
|
||||||
return 0; // Back to main menu
|
return 0; // Exit to main menu
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find matching pad by prefix
|
// Find matching pad by prefix
|
||||||
|
|||||||
Reference in New Issue
Block a user