diff --git a/Makefile b/Makefile index d81032a..b43f0f9 100644 --- a/Makefile +++ b/Makefile @@ -5,19 +5,17 @@ LIBS_STATIC = -static -lm TARGET = otp SOURCE = otp.c CHACHA20_SOURCE = nostr_chacha20.c -VERSION_SOURCE = src/version.c # Default build target $(TARGET): $(SOURCE) - $(CC) $(CFLAGS) -o $(TARGET) $(SOURCE) $(CHACHA20_SOURCE) $(VERSION_SOURCE) $(LIBS) + $(CC) $(CFLAGS) -o $(TARGET) $(SOURCE) $(CHACHA20_SOURCE) $(LIBS) # Static linking target static: $(SOURCE) - $(CC) $(CFLAGS) -o $(TARGET) $(SOURCE) $(CHACHA20_SOURCE) $(VERSION_SOURCE) $(LIBS_STATIC) + $(CC) $(CFLAGS) -o $(TARGET) $(SOURCE) $(CHACHA20_SOURCE) $(LIBS_STATIC) clean: rm -f $(TARGET) *.pad *.state - rm -f src/version.h src/version.c VERSION install: sudo cp $(TARGET) /usr/local/bin/ diff --git a/otp.c b/otp.c index d905025..24aa590 100644 --- a/otp.c +++ b/otp.c @@ -13,7 +13,6 @@ #include #include #include -#include "src/version.h" #include "nostr_chacha20.h" // Custom base64 character set @@ -125,6 +124,12 @@ int add_entropy_to_pad(const char* pad_chksum, const unsigned char* entropy_data size_t entropy_size, int show_progress); int handle_add_entropy_to_pad(const char* pad_chksum); +// Enhanced entropy system helper functions +int filter_unused_pads(char unused_pads[][65], int max_pads); +int update_pad_checksum_after_entropy(const char* old_chksum, char* new_chksum); +int rename_pad_files_safely(const char* old_chksum, const char* new_chksum); +int is_pad_unused(const char* pad_chksum); + // Directory management int ensure_pads_directory(void); void get_pad_path(const char* chksum, char* pad_path, char* state_path); @@ -450,7 +455,7 @@ int interactive_mode(void) { void show_main_menu(void) { - printf("\n\n\n\n=========================== Main Menu - OTP %s ===========================\n\n", get_version() ); + printf("\n\n\n\n=========================== Main Menu - OTP v1.0.0 ===========================\n\n"); printf(" \033[4mT\033[0mext encrypt\n"); //TEXT ENCRYPT printf(" \033[4mF\033[0mile encrypt\n"); //FILE ENCRYPT @@ -1320,6 +1325,24 @@ int add_entropy_to_pad(const char* pad_chksum, const unsigned char* entropy_data printf("āœ“ Pad integrity maintained\n"); printf("āœ“ %zu bytes of entropy distributed across entire pad\n", entropy_size); printf("āœ“ Pad restored to read-only mode\n"); + + // Update checksum after entropy addition + printf("\nšŸ”„ Updating pad checksum...\n"); + char new_chksum[65]; + int checksum_result = update_pad_checksum_after_entropy(pad_chksum, new_chksum); + + if (checksum_result == 0) { + printf("āœ“ Pad checksum updated successfully\n"); + printf(" Old checksum: %.16s...\n", pad_chksum); + printf(" New checksum: %.16s...\n", new_chksum); + printf("āœ“ Pad files renamed to new checksum\n"); + } else if (checksum_result == 2) { + printf("ℹ Checksum unchanged (unusual but not an error)\n"); + } else { + printf("⚠ Warning: Checksum update failed (entropy was added successfully)\n"); + printf(" You may need to manually handle the checksum update\n"); + return 1; // Report error despite successful entropy addition + } } return 0; @@ -2156,13 +2179,8 @@ int collect_entropy_with_feedback(unsigned char* entropy_buffer, size_t target_b state.unique_keys++; } } else { - // No key available, add timing entropy - clock_gettime(CLOCK_MONOTONIC, ×tamp); - if (state.collected_bytes + 12 < MAX_ENTROPY_BUFFER) { - memcpy(entropy_buffer + state.collected_bytes, ×tamp, 12); - state.collected_bytes += 12; - } - usleep(1000); // 1ms delay + // No key available, just sleep and wait for keystrokes + usleep(10000); // 10ms delay - wait for keystrokes, don't add timing entropy } // Auto-complete at target if enabled @@ -2875,6 +2893,125 @@ int derive_chacha20_params(const unsigned char* entropy_data, size_t entropy_siz return 0; // Success } +// Enhanced entropy system helper functions + +// Check if a pad is unused (0% usage) +int is_pad_unused(const char* pad_chksum) { + uint64_t used_bytes; + if (read_state_offset(pad_chksum, &used_bytes) != 0) { + return 0; // Error reading state, assume used + } + return (used_bytes <= 32); // Only reserved bytes used (32 bytes for checksum encryption) +} + +// Filter pads to only return unused ones +int filter_unused_pads(char unused_pads[][65], int max_pads) { + DIR* dir = opendir(current_pads_dir); + if (!dir) { + return 0; + } + + struct dirent* entry; + int unused_count = 0; + + while ((entry = readdir(dir)) != NULL && unused_count < max_pads) { + if (strstr(entry->d_name, ".pad") && strlen(entry->d_name) == 68) { + // Extract checksum from filename + char chksum[65]; + strncpy(chksum, entry->d_name, 64); + chksum[64] = '\0'; + + // Check if pad is unused + if (is_pad_unused(chksum)) { + strcpy(unused_pads[unused_count], chksum); + unused_count++; + } + } + } + + closedir(dir); + return unused_count; +} + +// Safely rename pad files (pad and state) from old to new checksum +int rename_pad_files_safely(const char* old_chksum, const char* new_chksum) { + char old_pad_path[1024], new_pad_path[1024]; + char old_state_path[1024], new_state_path[1024]; + + // Construct file paths + snprintf(old_pad_path, sizeof(old_pad_path), "%s/%s.pad", current_pads_dir, old_chksum); + snprintf(new_pad_path, sizeof(new_pad_path), "%s/%s.pad", current_pads_dir, new_chksum); + snprintf(old_state_path, sizeof(old_state_path), "%s/%s.state", current_pads_dir, old_chksum); + snprintf(new_state_path, sizeof(new_state_path), "%s/%s.state", current_pads_dir, new_chksum); + + // Check if new files would conflict with existing files + if (access(new_pad_path, F_OK) == 0) { + printf("Error: New pad file already exists: %s\n", new_pad_path); + return 1; // Conflict + } + + // Rename pad file + if (rename(old_pad_path, new_pad_path) != 0) { + printf("Error: Failed to rename pad file from %s to %s\n", old_pad_path, new_pad_path); + return 2; // Pad rename failed + } + + // Rename state file (if it exists) + if (access(old_state_path, F_OK) == 0) { + if (rename(old_state_path, new_state_path) != 0) { + printf("Warning: Failed to rename state file, but pad file was renamed successfully\n"); + // Try to rollback pad file rename + rename(new_pad_path, old_pad_path); + return 3; // State rename failed + } + } + + return 0; // Success +} + +// Update pad checksum after entropy addition +int update_pad_checksum_after_entropy(const char* old_chksum, char* new_chksum) { + char pad_path[1024]; + snprintf(pad_path, sizeof(pad_path), "%s/%s.pad", current_pads_dir, old_chksum); + + // Calculate new checksum of the modified pad + if (calculate_checksum(pad_path, new_chksum) != 0) { + printf("Error: Cannot calculate new pad checksum\n"); + return 1; + } + + // Check if checksum actually changed + if (strcmp(old_chksum, new_chksum) == 0) { + printf("Warning: Pad checksum unchanged after entropy addition\n"); + return 2; // Checksum didn't change (unusual but not fatal) + } + + // Rename pad files to use new checksum + if (rename_pad_files_safely(old_chksum, new_chksum) != 0) { + return 3; // Rename failed + } + + // Update default pad preference if this was the default pad + char* current_default = get_default_pad_path(); + if (current_default) { + // Check if the old pad was the default + if (strstr(current_default, old_chksum)) { + // Update to new checksum + char new_default_path[1024]; + snprintf(new_default_path, sizeof(new_default_path), "%s/%s.pad", current_pads_dir, new_chksum); + + if (set_default_pad_path(new_default_path) != 0) { + printf("Warning: Failed to update default pad preference\n"); + } else { + printf("Updated default pad to new checksum: %.16s...\n", new_chksum); + } + } + free(current_default); + } + + return 0; // Success +} + //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // UNIVERSAL CORE FUNCTIONS FOR CODE CONSOLIDATION @@ -3045,7 +3182,7 @@ int generate_ascii_armor(const char* chksum, uint64_t offset, const unsigned cha strcpy(*ascii_output, "-----BEGIN OTP MESSAGE-----\n"); char temp_line[256]; - snprintf(temp_line, sizeof(temp_line), "Version: %s\n", get_version()); + snprintf(temp_line, sizeof(temp_line), "Version: v1.0.0\n"); strcat(*ascii_output, temp_line); snprintf(temp_line, sizeof(temp_line), "Pad-ChkSum: %s\n", chksum); @@ -3958,6 +4095,7 @@ int handle_pads_menu(void) { printf("\nActions:\n"); printf(" \033[4mG\033[0menerate new pad\n"); + printf(" \033[4mA\033[0mdd entropy to pad\n"); printf(" \033[4mS\033[0met default pad\n"); printf(" E\033[4mx\033[0mit\n"); printf("\nSelect pad (by prefix) or action: "); @@ -3977,6 +4115,88 @@ int handle_pads_menu(void) { return handle_pads_menu(); } return result; + } else if (toupper(input[0]) == 'A') { + // Add entropy to pad - filter for unused pads only + char unused_pads[100][65]; + int unused_count = filter_unused_pads(unused_pads, 100); + + if (unused_count == 0) { + printf("\nNo unused pads available for entropy addition.\n"); + printf("Entropy can only be added to pads with 0%% usage (only reserved bytes used).\n"); + printf("Use existing pads for encryption/decryption or generate new pads.\n"); + printf("\nPress Enter to continue..."); + getchar(); + return handle_pads_menu(); + } + + printf("\nUnused pads available for entropy addition:\n"); + printf("%-4s %-20s %-12s %-12s\n", "No.", "ChkSum", "Size", "Location"); + printf("%-4s %-20s %-12s %-12s\n", "---", "-------------------", "----------", "----------"); + + // Display unused pads with their details + for (int i = 0; i < unused_count; i++) { + // Find the pad info from our main list + for (int j = 0; j < pad_count; j++) { + if (strcmp(unused_pads[i], pads[j].chksum) == 0) { + printf("%-4d %-20.16s %-12s %-12s\n", + i + 1, + pads[j].chksum, + pads[j].size_str, + pads[j].location); + break; + } + } + } + + printf("\nSelect pad to add entropy to (by number or prefix): "); + char pad_input[MAX_HASH_LENGTH]; + if (!fgets(pad_input, sizeof(pad_input), stdin)) { + printf("Error: Failed to read input\n"); + return 1; + } + pad_input[strcspn(pad_input, "\n")] = 0; + + // Find matching pad by number or prefix (from unused pads only) + char* selected_chksum = NULL; + + // Check if input is a number + char* endptr; + int selection = strtol(pad_input, &endptr, 10); + if (*endptr == '\0' && selection >= 1 && selection <= unused_count) { + // Valid number selection + selected_chksum = unused_pads[selection - 1]; + } else { + // Try prefix matching in unused pads + int match_count = 0; + char* matched_chksum = NULL; + + for (int i = 0; i < unused_count; i++) { + if (strncmp(pad_input, unused_pads[i], strlen(pad_input)) == 0) { + matched_chksum = unused_pads[i]; + match_count++; + } + } + + if (match_count == 1) { + selected_chksum = matched_chksum; + } else if (match_count > 1) { + printf("Ambiguous prefix. Multiple matches found in unused pads.\n"); + return handle_pads_menu(); + } + } + + if (!selected_chksum) { + printf("No unused pad found matching '%s'\n", pad_input); + return handle_pads_menu(); + } + + // Add entropy to the selected unused pad + int result = handle_add_entropy_to_pad(selected_chksum); + if (result == 0) { + // Return to pads menu after successful entropy addition + return handle_pads_menu(); + } + return result; } else if (toupper(input[0]) == 'S') { // Set default pad printf("\nSelect pad to set as default (by prefix): "); @@ -4326,8 +4546,8 @@ int handle_add_entropy_to_pad(const char* pad_chksum) { } void print_usage(const char* program_name) { - printf("OTP Cipher - One Time Pad Implementation %s\n", get_version()); - printf("%s\n", get_build_info()); + printf("OTP Cipher - One Time Pad Implementation v1.0.0\n"); + printf("Built for testing entropy system\n"); printf("Usage:\n"); printf(" %s - Interactive mode\n", program_name); printf(" %s generate|-g - Generate new pad\n", program_name);