Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0978d0323a | |||
| 0ea8b2dd32 |
1
TODO.md
1
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
|
## Setup for multiple USB drives
|
||||||
|
|
||||||
|
|
||||||
## Change back in pad menu to exit
|
|
||||||
|
|
||||||
|
|||||||
539
otp.c
539
otp.c
@@ -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,235 @@ 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");
|
||||||
|
}
|
||||||
|
// Note: DECRYPT_MODE_FILE_TO_FILE should be completely silent for piping
|
||||||
|
} 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);
|
||||||
|
|
||||||
|
// Only show success messages in non-silent modes
|
||||||
|
if (mode != DECRYPT_MODE_FILE_TO_FILE) {
|
||||||
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user