Version v0.2.95 - Refactor code

This commit is contained in:
2025-08-27 08:56:39 -04:00
parent 12f92d2c96
commit 0ea8b2dd32
2 changed files with 244 additions and 292 deletions

View File

@@ -16,5 +16,4 @@ Or, better yet, assume the offset is a very large size, and use the pad itself t
## Setup for multiple USB drives ## Setup for multiple USB drives
## Change back in pad menu to exit

535
otp.c
View File

@@ -43,6 +43,14 @@ static const int base64_decode_table[256] = {
#define FILES_DIR "files" #define FILES_DIR "files"
#define MAX_ENTROPY_BUFFER 32768 // 32KB entropy buffer #define MAX_ENTROPY_BUFFER 32768 // 32KB entropy buffer
// Decrypt operation modes for universal decrypt function
typedef enum {
DECRYPT_MODE_INTERACTIVE, // Interactive text decryption with prompts
DECRYPT_MODE_SILENT, // Silent text decryption (no prompts/labels)
DECRYPT_MODE_FILE_TO_TEXT, // File to text output with prompts
DECRYPT_MODE_FILE_TO_FILE // File to file output (binary)
} decrypt_mode_t;
// Global variable for current pads directory (can be local or OTP thumb drive) // Global variable for current pads directory (can be local or OTP thumb drive)
static char current_pads_dir[512] = DEFAULT_PADS_DIR; static char current_pads_dir[512] = DEFAULT_PADS_DIR;
@@ -120,6 +128,9 @@ int generate_ascii_armor(const char* chksum, uint64_t offset, const unsigned cha
size_t data_length, char** ascii_output); size_t data_length, char** ascii_output);
int validate_pad_integrity(const char* pad_path, const char* expected_chksum); int validate_pad_integrity(const char* pad_path, const char* expected_chksum);
// Universal decrypt function - consolidates all decrypt operations
int universal_decrypt(const char* input_data, const char* output_target, decrypt_mode_t mode);
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);
@@ -1532,185 +1543,15 @@ int encrypt_text(const char* pad_identifier, const char* input_text) {
} }
int decrypt_text(const char* pad_identifier, const char* encrypted_message) { 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 // Use universal decrypt function with interactive mode
(void)pad_identifier; // Suppress unused parameter warning (void)pad_identifier; // Suppress unused parameter warning - chksum comes from message
return universal_decrypt(encrypted_message, NULL, DECRYPT_MODE_INTERACTIVE);
char stored_chksum[MAX_HASH_LENGTH];
uint64_t pad_offset;
char base64_data[MAX_INPUT_SIZE * 2] = {0};
if (encrypted_message != NULL) {
// 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;
}
} else {
// Interactive mode - read from stdin
printf("Enter encrypted message (paste the full ASCII armor block):\n");
// Read entire message from stdin
char full_message[MAX_INPUT_SIZE * 4] = {0};
char line[MAX_LINE_LENGTH];
while (fgets(line, sizeof(line), stdin)) {
strncat(full_message, line, sizeof(full_message) - strlen(full_message) - 1);
if (strstr(line, "-----END OTP MESSAGE-----")) {
break;
}
}
// 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;
}
}
// 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 pad exists
if (access(pad_path, R_OK) != 0) {
printf("Error: Required pad not found: %s\n", stored_chksum);
printf("Available pads:\n");
list_available_pads();
return 1;
}
// 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("Continue anyway? (y/N): ");
fflush(stdout);
char response[10];
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 ciphertext
int ciphertext_len;
unsigned char* ciphertext = custom_base64_decode(base64_data, &ciphertext_len);
if (!ciphertext) {
printf("Error: Invalid base64 data\n");
return 1;
}
// 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;
}
// 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);
free(plaintext);
return 1;
}
plaintext[ciphertext_len] = '\0';
printf("Decrypted: %s\n", plaintext);
// Cleanup
free(ciphertext);
free(pad_data);
free(plaintext);
return 0;
} }
int decrypt_text_silent(const char* pad_identifier, const char* encrypted_message) { int decrypt_text_silent(const char* pad_identifier, const char* encrypted_message) {
// For piped decrypt mode - silent operation with minimal output // Use universal decrypt function with silent mode
(void)pad_identifier; // Suppress unused parameter warning (void)pad_identifier; // Suppress unused parameter warning - chksum comes from message
return universal_decrypt(encrypted_message, NULL, DECRYPT_MODE_SILENT);
char stored_chksum[MAX_HASH_LENGTH];
uint64_t pad_offset;
char base64_data[MAX_INPUT_SIZE * 2] = {0};
if (encrypted_message == NULL) {
fprintf(stderr, "Error: No encrypted message provided\n");
return 1;
}
// 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 pad exists
if (access(pad_path, R_OK) != 0) {
fprintf(stderr, "Error: Required pad not found: %s\n", stored_chksum);
return 1;
}
// 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 ciphertext
int ciphertext_len;
unsigned char* ciphertext = custom_base64_decode(base64_data, &ciphertext_len);
if (!ciphertext) {
fprintf(stderr, "Error: Invalid base64 data\n");
return 1;
}
// 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;
}
// 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);
free(plaintext);
return 1;
}
plaintext[ciphertext_len] = '\0';
// Output only the decrypted text with newline and flush
printf("%s\n", plaintext);
fflush(stdout);
// Cleanup
free(ciphertext);
free(pad_data);
free(plaintext);
return 0;
} }
int encrypt_file(const char* pad_identifier, const char* input_file, const char* output_file, int ascii_armor) { int encrypt_file(const char* pad_identifier, const char* input_file, const char* output_file, int ascii_armor) {
@@ -2141,121 +1982,8 @@ int decrypt_binary_file(FILE* input_fp, const char* output_file) {
} }
int decrypt_ascii_file(const char* input_file, const char* output_file) { int decrypt_ascii_file(const char* input_file, const char* output_file) {
FILE* input_fp = fopen(input_file, "r"); // Use universal decrypt function with file-to-file mode
if (!input_fp) { return universal_decrypt(input_file, output_file, DECRYPT_MODE_FILE_TO_FILE);
printf("Error: Cannot open input file %s\n", input_file);
return 1;
}
// 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);
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
char pad_path[MAX_HASH_LENGTH + 20];
char state_path[MAX_HASH_LENGTH + 20];
get_pad_path(stored_chksum, pad_path, state_path);
if (access(pad_path, R_OK) != 0) {
printf("Error: Required pad not found: %s\n", stored_chksum);
printf("Available pads:\n");
list_available_pads();
return 1;
}
// Decode base64 ciphertext
int ciphertext_len;
unsigned char* ciphertext = custom_base64_decode(base64_data, &ciphertext_len);
if (!ciphertext) {
printf("Error: Invalid base64 data\n");
return 1;
}
// Determine output filename
char default_output[512];
if (output_file == NULL) {
// Remove .otp.asc extension if present
strncpy(default_output, input_file, sizeof(default_output) - 1);
default_output[sizeof(default_output) - 1] = '\0';
char* ext = strstr(default_output, ".otp.asc");
if (ext) {
*ext = '\0';
} else {
// Just add .decrypted suffix
strncat(default_output, ".decrypted", sizeof(default_output) - strlen(default_output) - 1);
}
output_file = default_output;
}
// 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;
}
// 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);
return 1;
}
// Write decrypted file
FILE* output_fp = fopen(output_file, "wb");
if (!output_fp) {
printf("Error: Cannot create output file %s\n", output_file);
free(ciphertext);
free(pad_data);
return 1;
}
if (fwrite(ciphertext, 1, ciphertext_len, output_fp) != (size_t)ciphertext_len) {
printf("Error: Cannot write decrypted data\n");
free(ciphertext);
free(pad_data);
fclose(output_fp);
return 1;
}
fclose(output_fp);
printf("File decrypted successfully: %s\n", output_file);
printf("Note: ASCII format does not preserve original filename/permissions\n");
// Cleanup
free(ciphertext);
free(pad_data);
return 0;
} }
int read_state_offset(const char* pad_chksum, uint64_t* offset) { int read_state_offset(const char* pad_chksum, uint64_t* offset) {
@@ -3133,6 +2861,231 @@ int validate_pad_integrity(const char* pad_path, const char* expected_chksum) {
return 0; // Success - pad integrity verified return 0; // Success - pad integrity verified
} }
// Universal decrypt function - consolidates all decrypt operations
// input_data: encrypted message text or file path
// output_target: output file path (NULL for stdout/interactive)
// mode: determines behavior and output format
int universal_decrypt(const char* input_data, const char* output_target, decrypt_mode_t mode) {
char stored_chksum[MAX_HASH_LENGTH];
uint64_t pad_offset;
char base64_data[MAX_INPUT_SIZE * 8] = {0};
unsigned char* ciphertext = NULL;
int ciphertext_len;
// Handle input based on mode
if (mode == DECRYPT_MODE_FILE_TO_TEXT || mode == DECRYPT_MODE_FILE_TO_FILE) {
// File input - read the entire file
FILE* input_fp = fopen(input_data, "r");
if (!input_fp) {
printf("Error: Cannot open input file %s\n", input_data);
return 1;
}
fseek(input_fp, 0, SEEK_END);
long file_size = ftell(input_fp);
fseek(input_fp, 0, SEEK_SET);
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);
// Parse ASCII message from file content
if (parse_ascii_message(file_content, stored_chksum, &pad_offset, base64_data) != 0) {
printf("Error: Invalid ASCII armored format in file\n");
free(file_content);
return 1;
}
free(file_content);
if (mode == DECRYPT_MODE_FILE_TO_TEXT) {
printf("Decrypting ASCII armored file...\n");
}
} else {
// Text input (interactive or piped)
const char* message_text;
char full_message[MAX_INPUT_SIZE * 4] = {0};
if (input_data != NULL) {
message_text = input_data;
} else {
// Interactive mode - read from stdin
if (mode == DECRYPT_MODE_INTERACTIVE) {
printf("Enter encrypted message (paste the full ASCII armor block):\n");
}
char line[MAX_LINE_LENGTH];
while (fgets(line, sizeof(line), stdin)) {
strncat(full_message, line, sizeof(full_message) - strlen(full_message) - 1);
if (strstr(line, "-----END OTP MESSAGE-----")) {
break;
}
}
message_text = full_message;
}
// Parse ASCII message from text
if (parse_ascii_message(message_text, stored_chksum, &pad_offset, base64_data) != 0) {
if (mode == DECRYPT_MODE_SILENT) {
fprintf(stderr, "Error: Invalid message format - missing BEGIN header\n");
} else {
printf("Error: Invalid message format - missing BEGIN header\n");
}
return 1;
}
}
// Get pad path and check existence
char pad_path[MAX_HASH_LENGTH + 20];
char state_path[MAX_HASH_LENGTH + 20];
get_pad_path(stored_chksum, pad_path, state_path);
if (access(pad_path, R_OK) != 0) {
if (mode == DECRYPT_MODE_SILENT) {
fprintf(stderr, "Error: Required pad not found: %s\n", stored_chksum);
} else {
printf("Error: Required pad not found: %s\n", stored_chksum);
if (mode == DECRYPT_MODE_INTERACTIVE || mode == DECRYPT_MODE_FILE_TO_TEXT) {
printf("Available pads:\n");
list_available_pads();
}
}
return 1;
}
// Validate pad integrity
int integrity_result = validate_pad_integrity(pad_path, stored_chksum);
if (integrity_result == 3) {
if (mode == DECRYPT_MODE_SILENT) {
fprintf(stderr, "Error: Pad integrity check failed!\n");
return 1;
} else if (mode == DECRYPT_MODE_INTERACTIVE) {
printf("Warning: Pad integrity check failed!\n");
printf("Expected: %s\n", stored_chksum);
printf("Continue anyway? (y/N): ");
fflush(stdout);
char response[10];
if (fgets(response, sizeof(response), stdin) == NULL ||
(response[0] != 'y' && response[0] != 'Y')) {
printf("Decryption aborted.\n");
return 1;
}
}
} else if (integrity_result != 0) {
if (mode == DECRYPT_MODE_SILENT) {
fprintf(stderr, "Error: Cannot verify pad integrity\n");
} else {
printf("Error: Cannot verify pad integrity\n");
}
return 1;
} else {
if (mode == DECRYPT_MODE_INTERACTIVE || mode == DECRYPT_MODE_FILE_TO_TEXT) {
printf("Pad integrity: VERIFIED\n");
}
}
// Decode base64 ciphertext
ciphertext = custom_base64_decode(base64_data, &ciphertext_len);
if (!ciphertext) {
if (mode == DECRYPT_MODE_SILENT) {
fprintf(stderr, "Error: Invalid base64 data\n");
} else {
printf("Error: Invalid base64 data\n");
}
return 1;
}
// Load pad data using universal function
unsigned char* pad_data;
if (load_pad_data(stored_chksum, pad_offset, ciphertext_len, &pad_data) != 0) {
if (mode == DECRYPT_MODE_SILENT) {
fprintf(stderr, "Error: Cannot load pad data\n");
} else {
printf("Error: Cannot load pad data\n");
}
free(ciphertext);
return 1;
}
// Decrypt using universal XOR operation
if (universal_xor_operation(ciphertext, ciphertext_len, pad_data, ciphertext) != 0) {
if (mode == DECRYPT_MODE_SILENT) {
fprintf(stderr, "Error: Decryption operation failed\n");
} else {
printf("Error: Decryption operation failed\n");
}
free(ciphertext);
free(pad_data);
return 1;
}
// Output based on mode
if (mode == DECRYPT_MODE_FILE_TO_FILE) {
// Write to output file
const char* output_file = output_target;
// Generate default output filename if not provided
char default_output[512];
if (output_file == NULL) {
strncpy(default_output, input_data, sizeof(default_output) - 1);
default_output[sizeof(default_output) - 1] = '\0';
char* ext = strstr(default_output, ".otp.asc");
if (ext) {
*ext = '\0';
} else {
strncat(default_output, ".decrypted", sizeof(default_output) - strlen(default_output) - 1);
}
output_file = default_output;
}
FILE* output_fp = fopen(output_file, "wb");
if (!output_fp) {
printf("Error: Cannot create output file %s\n", output_file);
free(ciphertext);
free(pad_data);
return 1;
}
if (fwrite(ciphertext, 1, ciphertext_len, output_fp) != (size_t)ciphertext_len) {
printf("Error: Cannot write decrypted data\n");
free(ciphertext);
free(pad_data);
fclose(output_fp);
return 1;
}
fclose(output_fp);
printf("File decrypted successfully: %s\n", output_file);
printf("Note: ASCII format does not preserve original filename/permissions\n");
} else {
// Text output to stdout
ciphertext[ciphertext_len] = '\0';
if (mode == DECRYPT_MODE_SILENT) {
// Silent mode - just output the text
printf("%s\n", (char*)ciphertext);
fflush(stdout);
} else {
// Interactive mode - with label
printf("Decrypted: %s\n", (char*)ciphertext);
}
}
// Cleanup
free(ciphertext);
free(pad_data);
return 0;
}
// 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