Version v0.2.94 - Refactor code

This commit is contained in:
2025-08-27 08:44:11 -04:00
parent aea69148a8
commit 12f92d2c96
2 changed files with 351 additions and 287 deletions

View File

@@ -3,8 +3,6 @@
## 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.
@@ -14,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.
## We have three different decrypt file functions
## Setup for multiple USB drives

633
otp.c
View File

@@ -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 write_state_offset(const char* pad_chksum, uint64_t offset);
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);
unsigned char* custom_base64_decode(const char* input, int* output_length);
@@ -1479,50 +1488,44 @@ int encrypt_text(const char* pad_identifier, const char* input_text) {
}
fclose(pad_file);
// XOR encrypt the input
// Use universal XOR operation for encryption
unsigned char* ciphertext = malloc(input_len);
for (size_t i = 0; i < input_len; i++) {
ciphertext[i] = text_buffer[i] ^ pad_data[i];
if (universal_xor_operation((const unsigned char*)text_buffer, input_len, pad_data, ciphertext) != 0) {
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
if (write_state_offset(pad_chksum, current_offset + input_len) != 0) {
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
if (is_interactive) {
printf("\n\n-----BEGIN OTP MESSAGE-----\n");
printf("\n\n%s\n\n", ascii_output);
} else {
printf("-----BEGIN OTP MESSAGE-----\n");
}
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");
printf("%s", ascii_output);
}
// Cleanup
free(pad_data);
free(ciphertext);
free(base64_cipher);
free(ascii_output);
free(pad_chksum);
return 0;
@@ -1532,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
(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;
char base64_data[MAX_INPUT_SIZE * 2] = {0};
int in_data_section = 0;
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);
}
}
line_ptr = strtok(NULL, "\n");
}
free(message_copy);
if (!found_begin) {
// Use universal ASCII parser to extract message components
if (parse_ascii_message(encrypted_message, stored_chksum, &pad_offset, base64_data) != 0) {
printf("Error: Invalid message format - missing BEGIN header\n");
return 1;
}
@@ -1579,49 +1549,29 @@ int decrypt_text(const char* pad_identifier, const char* encrypted_message) {
// Interactive mode - read from stdin
printf("Enter encrypted message (paste the full ASCII armor block):\n");
// Read the ASCII armor format
int found_begin = 0;
// Read entire message from stdin
char full_message[MAX_INPUT_SIZE * 4] = {0};
char line[MAX_LINE_LENGTH];
while (fgets(line, sizeof(line), stdin)) {
line[strcspn(line, "\n")] = 0;
if (strcmp(line, "-----BEGIN OTP MESSAGE-----") == 0) {
found_begin = 1;
continue;
}
if (strcmp(line, "-----END OTP MESSAGE-----") == 0) {
strncat(full_message, line, sizeof(full_message) - strlen(full_message) - 1);
if (strstr(line, "-----END OTP MESSAGE-----")) {
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");
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 state_path[MAX_HASH_LENGTH + 20];
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) {
printf("Error: Required pad not found: %s\n", stored_chksum);
printf("Available pads:\n");
@@ -1629,30 +1579,28 @@ int decrypt_text(const char* pad_identifier, const char* encrypted_message) {
return 1;
}
// Verify pad integrity
if (calculate_checksum(pad_path, current_chksum) != 0) {
printf("Error: Cannot calculate current pad checksum\n");
return 1;
}
if (strcmp(stored_chksum, current_chksum) != 0) {
// Use universal pad integrity validator
int integrity_result = validate_pad_integrity(pad_path, stored_chksum);
if (integrity_result == 3) {
printf("Warning: Pad integrity check failed!\n");
printf("Expected: %s\n", stored_chksum);
printf("Current: %s\n", current_chksum);
printf("Continue anyway? (y/N): ");
fflush(stdout);
char response[10];
if (fgets(response, sizeof(response), stdin) == NULL ||
if (fgets(response, sizeof(response), stdin) == NULL ||
(response[0] != 'y' && response[0] != 'Y')) {
printf("Decryption aborted.\n");
return 1;
}
} else if (integrity_result != 0) {
printf("Error: Cannot verify pad integrity\n");
return 1;
} else {
printf("Pad integrity: VERIFIED\n");
}
// Decode base64
// Decode base64 ciphertext
int ciphertext_len;
unsigned char* ciphertext = custom_base64_decode(base64_data, &ciphertext_len);
if (!ciphertext) {
@@ -1660,36 +1608,24 @@ int decrypt_text(const char* pad_identifier, const char* encrypted_message) {
return 1;
}
// Read pad data at specified offset
FILE* pad_file = fopen(pad_path, "rb");
if (!pad_file) {
printf("Error: Cannot open pad file %s\n", pad_path);
// Use universal pad loader
unsigned char* pad_data;
int load_result = load_pad_data(stored_chksum, pad_offset, ciphertext_len, &pad_data);
if (load_result != 0) {
printf("Error: Cannot load pad data (code %d)\n", load_result);
free(ciphertext);
return 1;
}
if (fseek(pad_file, pad_offset, SEEK_SET) != 0) {
printf("Error: Cannot seek to offset %lu in pad file\n", pad_offset);
free(ciphertext);
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");
// Use universal XOR operation for decryption
char* plaintext = malloc(ciphertext_len + 1);
if (universal_xor_operation(ciphertext, ciphertext_len, pad_data, (unsigned char*)plaintext) != 0) {
printf("Error: Decryption operation failed\n");
free(ciphertext);
free(pad_data);
fclose(pad_file);
free(plaintext);
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';
printf("Decrypted: %s\n", plaintext);
@@ -1707,79 +1643,38 @@ int decrypt_text_silent(const char* pad_identifier, const char* encrypted_messag
(void)pad_identifier; // Suppress unused parameter warning
char stored_chksum[MAX_HASH_LENGTH];
char current_chksum[MAX_HASH_LENGTH];
uint64_t pad_offset;
char base64_data[MAX_INPUT_SIZE * 2] = {0};
int in_data_section = 0;
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 {
if (encrypted_message == NULL) {
fprintf(stderr, "Error: No encrypted message provided\n");
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 state_path[MAX_HASH_LENGTH + 20];
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) {
fprintf(stderr, "Error: Required pad not found: %s\n", stored_chksum);
return 1;
}
// Verify pad integrity (silent check)
if (calculate_checksum(pad_path, current_chksum) != 0) {
fprintf(stderr, "Error: Cannot calculate current pad checksum\n");
return 1;
}
if (strcmp(stored_chksum, current_chksum) != 0) {
// Use universal pad integrity validator (silent check)
if (validate_pad_integrity(pad_path, stored_chksum) != 0) {
fprintf(stderr, "Error: Pad integrity check failed!\n");
return 1;
}
// Decode base64
// Decode base64 ciphertext
int ciphertext_len;
unsigned char* ciphertext = custom_base64_decode(base64_data, &ciphertext_len);
if (!ciphertext) {
@@ -1787,36 +1682,23 @@ int decrypt_text_silent(const char* pad_identifier, const char* encrypted_messag
return 1;
}
// Read pad data at specified offset
FILE* pad_file = fopen(pad_path, "rb");
if (!pad_file) {
fprintf(stderr, "Error: Cannot open pad file %s\n", pad_path);
// Use universal pad loader
unsigned char* pad_data;
if (load_pad_data(stored_chksum, pad_offset, ciphertext_len, &pad_data) != 0) {
fprintf(stderr, "Error: Cannot load pad data\n");
free(ciphertext);
return 1;
}
if (fseek(pad_file, pad_offset, SEEK_SET) != 0) {
fprintf(stderr, "Error: Cannot seek to offset %lu in pad file\n", pad_offset);
free(ciphertext);
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) {
fprintf(stderr, "Error: Cannot read pad data\n");
// Use universal XOR operation for decryption
char* plaintext = malloc(ciphertext_len + 1);
if (universal_xor_operation(ciphertext, ciphertext_len, pad_data, (unsigned char*)plaintext) != 0) {
fprintf(stderr, "Error: Decryption operation failed\n");
free(ciphertext);
free(pad_data);
fclose(pad_file);
free(plaintext);
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';
// Output only the decrypted text with newline and flush
@@ -1980,9 +1862,14 @@ int encrypt_file(const char* pad_identifier, const char* input_file, const char*
return 1;
}
// XOR encrypt
for (uint64_t i = 0; i < chunk_size; i++) {
encrypted_data[bytes_processed + i] = buffer[i] ^ pad_buffer[i];
// Use universal XOR operation for encryption
if (universal_xor_operation(buffer, chunk_size, pad_buffer, &encrypted_data[bytes_processed]) != 0) {
printf("Error: Encryption operation failed\n");
free(encrypted_data);
fclose(input_fp);
fclose(pad_file);
free(pad_chksum);
return 1;
}
bytes_processed += chunk_size;
@@ -2012,26 +1899,21 @@ int encrypt_file(const char* pad_identifier, const char* input_file, const char*
return 1;
}
// Encode as base64
char* base64_data = custom_base64_encode(encrypted_data, file_size);
// Write ASCII armor
fprintf(output_fp, "-----BEGIN OTP MESSAGE-----\n");
fprintf(output_fp, "Version: %s\n", get_version());
fprintf(output_fp, "Pad-ChkSum: %s\n", chksum_hex);
fprintf(output_fp, "Pad-Offset: %lu\n", current_offset);
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);
// Use universal ASCII armor generator
char* ascii_output;
if (generate_ascii_armor(chksum_hex, current_offset, encrypted_data, file_size, &ascii_output) != 0) {
printf("Error: Failed to generate ASCII armor\n");
fclose(output_fp);
free(encrypted_data);
free(pad_chksum);
return 1;
}
fprintf(output_fp, "-----END OTP MESSAGE-----\n");
// Write the ASCII armored output to file
fprintf(output_fp, "%s", ascii_output);
fclose(output_fp);
free(base64_data);
free(ascii_output);
} else {
// Binary format
FILE* output_fp = fopen(output_file, "wb");
@@ -2217,9 +2099,12 @@ int decrypt_binary_file(FILE* input_fp, const char* output_file) {
}
fclose(pad_file);
// XOR decrypt
for (uint64_t i = 0; i < file_size; i++) {
encrypted_data[i] ^= pad_data[i];
// Use universal XOR operation for decryption
if (universal_xor_operation(encrypted_data, file_size, pad_data, encrypted_data) != 0) {
printf("Error: Decryption operation failed\n");
free(encrypted_data);
free(pad_data);
return 1;
}
// Write decrypted file
@@ -2262,49 +2147,34 @@ int decrypt_ascii_file(const char* input_file, const char* output_file) {
return 1;
}
// Read the entire ASCII armored content
char line[MAX_LINE_LENGTH];
char stored_chksum[MAX_HASH_LENGTH];
uint64_t pad_offset;
char base64_data[MAX_INPUT_SIZE * 8] = {0}; // Larger buffer for files
int in_data_section = 0;
int found_begin = 0;
// Read the entire file content into a string
fseek(input_fp, 0, SEEK_END);
long file_size = ftell(input_fp);
fseek(input_fp, 0, SEEK_SET);
while (fgets(line, sizeof(line), input_fp)) {
line[strcspn(line, "\n\r")] = 0; // Remove newlines
if (strcmp(line, "-----BEGIN OTP MESSAGE-----") == 0) {
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");
char* file_content = malloc(file_size + 1);
if (!file_content) {
printf("Error: Memory allocation failed\n");
fclose(input_fp);
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");
// Check if we have the required pad
@@ -2319,7 +2189,7 @@ int decrypt_ascii_file(const char* input_file, const char* output_file) {
return 1;
}
// Decode base64
// Decode base64 ciphertext
int ciphertext_len;
unsigned char* ciphertext = custom_base64_decode(base64_data, &ciphertext_len);
if (!ciphertext) {
@@ -2344,35 +2214,21 @@ int decrypt_ascii_file(const char* input_file, const char* output_file) {
output_file = default_output;
}
// Open pad file and decrypt
FILE* pad_file = fopen(pad_path, "rb");
if (!pad_file) {
printf("Error: Cannot open pad file\n");
// Use universal pad loader
unsigned char* pad_data;
if (load_pad_data(stored_chksum, pad_offset, ciphertext_len, &pad_data) != 0) {
printf("Error: Cannot load pad data\n");
free(ciphertext);
return 1;
}
if (fseek(pad_file, pad_offset, SEEK_SET) != 0) {
printf("Error: Cannot seek to offset in pad file\n");
free(ciphertext);
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");
// Use universal XOR operation for decryption
if (universal_xor_operation(ciphertext, ciphertext_len, pad_data, ciphertext) != 0) {
printf("Error: Decryption operation failed\n");
free(ciphertext);
free(pad_data);
fclose(pad_file);
return 1;
}
fclose(pad_file);
// XOR decrypt
for (int i = 0; i < ciphertext_len; i++) {
ciphertext[i] ^= pad_data[i];
}
// Write decrypted file
FILE* output_fp = fopen(output_file, "wb");
@@ -2724,7 +2580,6 @@ int load_preferences(void) {
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);
@@ -3064,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
int get_filename_with_default(const char* prompt, const char* default_path, char* result, size_t result_size) {
// Find the last directory separator