From 0ea8b2dd32ad99779d799a062842ae1ed5b1a7e2 Mon Sep 17 00:00:00 2001 From: Laan Tungir Date: Wed, 27 Aug 2025 08:56:39 -0400 Subject: [PATCH] Version v0.2.95 - Refactor code --- TODO.md | 1 - otp.c | 535 ++++++++++++++++++++++++++------------------------------ 2 files changed, 244 insertions(+), 292 deletions(-) diff --git a/TODO.md b/TODO.md index 77f1c68..ef9098f 100644 --- a/TODO.md +++ b/TODO.md @@ -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 -## Change back in pad menu to exit diff --git a/otp.c b/otp.c index 1748c50..24e5c42 100644 --- a/otp.c +++ b/otp.c @@ -43,6 +43,14 @@ static const int base64_decode_table[256] = { #define FILES_DIR "files" #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) 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); 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); 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) { - // For command line mode, pad_identifier is ignored - we'll get the chksum from the message - (void)pad_identifier; // Suppress unused parameter warning - - 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; + // Use universal decrypt function with interactive mode + (void)pad_identifier; // Suppress unused parameter warning - chksum comes from message + return universal_decrypt(encrypted_message, NULL, DECRYPT_MODE_INTERACTIVE); } int decrypt_text_silent(const char* pad_identifier, const char* encrypted_message) { - // For piped decrypt mode - silent operation with minimal output - (void)pad_identifier; // Suppress unused parameter warning - - 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; + // Use universal decrypt function with silent mode + (void)pad_identifier; // Suppress unused parameter warning - chksum comes from message + return universal_decrypt(encrypted_message, NULL, DECRYPT_MODE_SILENT); } 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) { - FILE* input_fp = fopen(input_file, "r"); - if (!input_fp) { - 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; + // Use universal decrypt function with file-to-file mode + return universal_decrypt(input_file, output_file, DECRYPT_MODE_FILE_TO_FILE); } 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 } +// 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 int get_filename_with_default(const char* prompt, const char* default_path, char* result, size_t result_size) { // Find the last directory separator