diff --git a/otp.c b/otp.c index 3720813..e6e1ec4 100644 --- a/otp.c +++ b/otp.c @@ -81,6 +81,7 @@ int generate_pad(uint64_t size_bytes, int show_progress); int generate_pad_with_entropy(uint64_t size_bytes, int show_progress, int use_keyboard_entropy); 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_silent(const char* pad_identifier, const char* encrypted_message); int encrypt_file(const char* pad_identifier, const char* input_file, const char* output_file, int ascii_armor); int decrypt_file(const char* input_file, const char* output_file); int decrypt_binary_file(FILE* input_fp, const char* output_file); @@ -238,6 +239,16 @@ int command_line_mode(int argc, char* argv[]) { } else if (strcmp(argv[1], "decrypt") == 0 || strcmp(argv[1], "-d") == 0) { if (argc == 2) { + // Check for piped input first + if (has_stdin_data()) { + // Piped decrypt mode - read stdin and decrypt silently + char* piped_message = read_stdin_text(); + if (piped_message) { + int result = decrypt_text_silent(NULL, piped_message); + free(piped_message); + return result; + } + } // Interactive mode - no arguments needed return decrypt_text(NULL, NULL); } @@ -1599,6 +1610,131 @@ int decrypt_text(const char* pad_identifier, const char* encrypted_message) { return 0; } +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 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) { + fprintf(stderr, "Error: Invalid message format - missing BEGIN header\n"); + return 1; + } + } else { + fprintf(stderr, "Error: No encrypted message provided\n"); + return 1; + } + + // Now we have the pad chksum from the message, construct filename + 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 + 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) { + fprintf(stderr, "Error: Pad integrity check failed!\n"); + return 1; + } + + // Decode base64 + int ciphertext_len; + unsigned char* ciphertext = custom_base64_decode(base64_data, &ciphertext_len); + if (!ciphertext) { + fprintf(stderr, "Error: Invalid base64 data\n"); + 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); + 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"); + free(ciphertext); + free(pad_data); + fclose(pad_file); + 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 - no extra messages + printf("%s\n", plaintext); + + // 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) { char* pad_chksum = find_pad_by_prefix(pad_identifier); if (!pad_chksum) {