1226 lines
44 KiB
C
1226 lines
44 KiB
C
#define _POSIX_C_SOURCE 200809L
|
||
#define _DEFAULT_SOURCE
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <stdint.h>
|
||
#include <unistd.h>
|
||
#include <sys/stat.h>
|
||
#include <sys/statvfs.h>
|
||
#include <sys/ioctl.h>
|
||
#include <dirent.h>
|
||
#include <time.h>
|
||
#include <ctype.h>
|
||
#include <termios.h>
|
||
#include <fcntl.h>
|
||
#include <math.h>
|
||
#include "../include/otp.h"
|
||
|
||
|
||
// Extracted pad management functions from otp.c
|
||
|
||
int show_pad_info(const char* chksum) {
|
||
char pad_filename[MAX_HASH_LENGTH + 10];
|
||
char state_filename[MAX_HASH_LENGTH + 10];
|
||
|
||
snprintf(pad_filename, sizeof(pad_filename), "%s.pad", chksum);
|
||
snprintf(state_filename, sizeof(state_filename), "%s.state", chksum);
|
||
|
||
struct stat st;
|
||
if (stat(pad_filename, &st) != 0) {
|
||
printf("Pad not found: %s\n", chksum);
|
||
return 1;
|
||
}
|
||
|
||
uint64_t used_bytes;
|
||
read_state_offset(chksum, &used_bytes);
|
||
|
||
print_centered_header("Pad Information", 0);
|
||
printf("ChkSum: %s\n", chksum);
|
||
printf("File: %s\n", pad_filename);
|
||
|
||
double size_gb = (double)st.st_size / (1024.0 * 1024.0 * 1024.0);
|
||
double used_gb = (double)used_bytes / (1024.0 * 1024.0 * 1024.0);
|
||
double remaining_gb = (double)(st.st_size - used_bytes) / (1024.0 * 1024.0 * 1024.0);
|
||
|
||
printf("Total size: %.2f GB (%lu bytes)\n", size_gb, st.st_size);
|
||
printf("Used: %.2f GB (%lu bytes)\n", used_gb, used_bytes);
|
||
printf("Remaining: %.2f GB (%lu bytes)\n", remaining_gb, st.st_size - used_bytes);
|
||
printf("Usage: %.1f%%\n", (double)used_bytes / st.st_size * 100.0);
|
||
|
||
return 0;
|
||
}
|
||
|
||
// Ensure pads directory exists, create if necessary
|
||
int ensure_pads_directory(void) {
|
||
const char* pads_dir = get_current_pads_dir();
|
||
struct stat st = {0};
|
||
if (stat(pads_dir, &st) == -1) {
|
||
if (mkdir(pads_dir, 0755) != 0) {
|
||
perror("Failed to create pads directory");
|
||
return -1;
|
||
}
|
||
} else if (!S_ISDIR(st.st_mode)) {
|
||
fprintf(stderr, "Pads path exists but is not a directory\n");
|
||
return -1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
// Construct pad and state file paths from checksum
|
||
void get_pad_path(const char* chksum, char* pad_path, char* state_path) {
|
||
const char* pads_dir = get_current_pads_dir();
|
||
snprintf(pad_path, 1024, "%s/%s.pad", pads_dir, chksum);
|
||
snprintf(state_path, 1024, "%s/%s.state", pads_dir, chksum);
|
||
}
|
||
|
||
int generate_pad(uint64_t size_bytes, int display_progress) {
|
||
// Ensure pads directory exists
|
||
if (ensure_pads_directory() != 0) {
|
||
printf("Error: Cannot create pads directory\n");
|
||
return 1;
|
||
}
|
||
|
||
char temp_filename[1024];
|
||
char pad_path[MAX_HASH_LENGTH + 20];
|
||
char state_path[MAX_HASH_LENGTH + 20];
|
||
char chksum_hex[MAX_HASH_LENGTH];
|
||
|
||
// Create temporary filename in the pads directory to avoid cross-filesystem issues
|
||
const char* pads_dir = get_current_pads_dir();
|
||
snprintf(temp_filename, sizeof(temp_filename), "%s/temp_%ld.pad", pads_dir, time(NULL));
|
||
|
||
FILE* urandom = fopen("/dev/urandom", "rb");
|
||
if (!urandom) {
|
||
printf("Error: Cannot open /dev/urandom\n");
|
||
return 1;
|
||
}
|
||
|
||
FILE* pad_file = fopen(temp_filename, "wb");
|
||
if (!pad_file) {
|
||
printf("Error: Cannot create temporary pad file %s\n", temp_filename);
|
||
fclose(urandom);
|
||
return 1;
|
||
}
|
||
|
||
unsigned char buffer[64 * 1024]; // 64KB buffer
|
||
uint64_t bytes_written = 0;
|
||
time_t start_time = time(NULL);
|
||
|
||
if (display_progress) {
|
||
printf("Generating pad...\n");
|
||
}
|
||
|
||
while (bytes_written < size_bytes) {
|
||
uint64_t chunk_size = sizeof(buffer);
|
||
if (size_bytes - bytes_written < chunk_size) {
|
||
chunk_size = size_bytes - bytes_written;
|
||
}
|
||
|
||
if (fread(buffer, 1, (size_t)chunk_size, urandom) != (size_t)chunk_size) {
|
||
printf("Error: Failed to read from /dev/urandom\n");
|
||
fclose(urandom);
|
||
fclose(pad_file);
|
||
unlink(temp_filename);
|
||
return 1;
|
||
}
|
||
|
||
if (fwrite(buffer, 1, (size_t)chunk_size, pad_file) != (size_t)chunk_size) {
|
||
printf("Error: Failed to write to pad file\n");
|
||
fclose(urandom);
|
||
fclose(pad_file);
|
||
unlink(temp_filename);
|
||
return 1;
|
||
}
|
||
|
||
bytes_written += chunk_size;
|
||
|
||
if (display_progress && bytes_written % PROGRESS_UPDATE_INTERVAL == 0) {
|
||
show_progress(bytes_written, size_bytes, start_time);
|
||
}
|
||
}
|
||
|
||
if (display_progress) {
|
||
show_progress(size_bytes, size_bytes, start_time);
|
||
printf("\n");
|
||
}
|
||
|
||
fclose(urandom);
|
||
fclose(pad_file);
|
||
|
||
// Calculate XOR checksum of the pad file
|
||
if (display_progress) {
|
||
printf("Calculating pad checksum...\n");
|
||
}
|
||
if (calculate_checksum_with_progress(temp_filename, chksum_hex, display_progress, size_bytes) != 0) {
|
||
printf("Error: Cannot calculate pad checksum\n");
|
||
unlink(temp_filename);
|
||
return 1;
|
||
}
|
||
|
||
// Get final paths in pads directory
|
||
get_pad_path(chksum_hex, pad_path, state_path);
|
||
|
||
// Rename temporary file to final name (atomic operation within same directory)
|
||
if (rename(temp_filename, pad_path) != 0) {
|
||
printf("Error: Cannot rename temporary pad file to final name\n");
|
||
unlink(temp_filename);
|
||
return 1;
|
||
}
|
||
|
||
// Set pad file to read-only
|
||
if (chmod(pad_path, S_IRUSR) != 0) {
|
||
printf("Warning: Cannot set pad file to read-only\n");
|
||
}
|
||
|
||
// Initialize state file with offset 32 (first 32 bytes reserved for checksum encryption)
|
||
FILE* state_file = fopen(state_path, "wb");
|
||
if (state_file) {
|
||
uint64_t reserved_bytes = 32;
|
||
fwrite(&reserved_bytes, sizeof(uint64_t), 1, state_file);
|
||
fclose(state_file);
|
||
} else {
|
||
printf("Error: Failed to create state file\n");
|
||
unlink(pad_path);
|
||
return 1;
|
||
}
|
||
|
||
double size_gb = (double)size_bytes / (1024.0 * 1024.0 * 1024.0);
|
||
printf("Generated pad: %s (%.2f GB)\n", pad_path, size_gb);
|
||
printf("Pad checksum: %s\n", chksum_hex);
|
||
printf("State file: %s\n", state_path);
|
||
printf("Pad file set to read-only\n");
|
||
printf("Use 'Add entropy' in Pads menu to enhance randomness.\n");
|
||
|
||
// Pause before returning to menu to let user see the success message (only in interactive mode)
|
||
if (get_interactive_mode()) {
|
||
print_centered_header("Pad Generation Complete", 1);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
int read_state_offset(const char* pad_chksum, uint64_t* offset) {
|
||
char state_filename[1024];
|
||
const char* pads_dir = get_current_pads_dir();
|
||
snprintf(state_filename, sizeof(state_filename), "%s/%s.state", pads_dir, pad_chksum);
|
||
|
||
FILE* state_file = fopen(state_filename, "rb");
|
||
if (!state_file) {
|
||
*offset = 0;
|
||
return 0;
|
||
}
|
||
|
||
if (fread(offset, sizeof(uint64_t), 1, state_file) != 1) {
|
||
fclose(state_file);
|
||
*offset = 0;
|
||
return 0;
|
||
}
|
||
|
||
fclose(state_file);
|
||
return 0;
|
||
}
|
||
|
||
int write_state_offset(const char* pad_chksum, uint64_t offset) {
|
||
char state_filename[1024];
|
||
const char* pads_dir = get_current_pads_dir();
|
||
snprintf(state_filename, sizeof(state_filename), "%s/%s.state", pads_dir, pad_chksum);
|
||
|
||
FILE* state_file = fopen(state_filename, "wb");
|
||
if (!state_file) {
|
||
return 1;
|
||
}
|
||
|
||
if (fwrite(&offset, sizeof(uint64_t), 1, state_file) != 1) {
|
||
fclose(state_file);
|
||
return 1;
|
||
}
|
||
|
||
fclose(state_file);
|
||
return 0;
|
||
}
|
||
|
||
// 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)
|
||
}
|
||
|
||
// 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];
|
||
const char* pads_dir = get_current_pads_dir();
|
||
|
||
// Construct file paths
|
||
snprintf(old_pad_path, sizeof(old_pad_path), "%s/%s.pad", pads_dir, old_chksum);
|
||
snprintf(new_pad_path, sizeof(new_pad_path), "%s/%s.pad", pads_dir, new_chksum);
|
||
snprintf(old_state_path, sizeof(old_state_path), "%s/%s.state", pads_dir, old_chksum);
|
||
snprintf(new_state_path, sizeof(new_state_path), "%s/%s.state", 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
|
||
}
|
||
|
||
// Unified pad selection function - extracts the best UI from handle_pads_menu()
|
||
char* select_pad_interactive(const char* title, const char* prompt, pad_filter_type_t filter_type, int allow_cancel) {
|
||
// Get list of pads from current directory
|
||
const char* pads_dir = get_current_pads_dir();
|
||
DIR* dir = opendir(pads_dir);
|
||
if (!dir) {
|
||
printf("Error: Cannot open pads directory %s\n", pads_dir);
|
||
return NULL;
|
||
}
|
||
|
||
// Structure to store pad information
|
||
struct PadInfo {
|
||
char chksum[65];
|
||
char size_str[32];
|
||
char used_str[32];
|
||
double percentage;
|
||
char location[256];
|
||
};
|
||
|
||
struct PadInfo pads[100]; // Support up to 100 pads
|
||
int pad_count = 0;
|
||
|
||
// Collect all pad information
|
||
struct dirent* entry;
|
||
while ((entry = readdir(dir)) != NULL && pad_count < 100) {
|
||
if (strstr(entry->d_name, ".pad") && strlen(entry->d_name) == 68) {
|
||
strncpy(pads[pad_count].chksum, entry->d_name, 64);
|
||
pads[pad_count].chksum[64] = '\0';
|
||
|
||
// Get pad file size and usage info
|
||
char full_path[1024];
|
||
snprintf(full_path, sizeof(full_path), "%s/%s", pads_dir, entry->d_name);
|
||
struct stat st;
|
||
if (stat(full_path, &st) == 0) {
|
||
// Get used bytes from state
|
||
uint64_t used_bytes;
|
||
read_state_offset(pads[pad_count].chksum, &used_bytes);
|
||
|
||
// Apply filter
|
||
if (filter_type == PAD_FILTER_UNUSED_ONLY && used_bytes > 32) {
|
||
continue; // Skip used pads when filtering for unused only
|
||
}
|
||
|
||
// Format total size
|
||
if (st.st_size < 1024) {
|
||
snprintf(pads[pad_count].size_str, sizeof(pads[pad_count].size_str), "%luB", st.st_size);
|
||
} else if (st.st_size < 1024 * 1024) {
|
||
snprintf(pads[pad_count].size_str, sizeof(pads[pad_count].size_str), "%.1fKB", (double)st.st_size / 1024.0);
|
||
} else if (st.st_size < 1024 * 1024 * 1024) {
|
||
snprintf(pads[pad_count].size_str, sizeof(pads[pad_count].size_str), "%.1fMB", (double)st.st_size / (1024.0 * 1024.0));
|
||
} else {
|
||
snprintf(pads[pad_count].size_str, sizeof(pads[pad_count].size_str), "%.2fGB", (double)st.st_size / (1024.0 * 1024.0 * 1024.0));
|
||
}
|
||
|
||
// Format used size
|
||
if (used_bytes < 1024) {
|
||
snprintf(pads[pad_count].used_str, sizeof(pads[pad_count].used_str), "%luB", used_bytes);
|
||
} else if (used_bytes < 1024 * 1024) {
|
||
snprintf(pads[pad_count].used_str, sizeof(pads[pad_count].used_str), "%.1fKB", (double)used_bytes / 1024.0);
|
||
} else if (used_bytes < 1024 * 1024 * 1024) {
|
||
snprintf(pads[pad_count].used_str, sizeof(pads[pad_count].used_str), "%.1fMB", (double)used_bytes / (1024.0 * 1024.0));
|
||
} else {
|
||
snprintf(pads[pad_count].used_str, sizeof(pads[pad_count].used_str), "%.2fGB", (double)used_bytes / (1024.0 * 1024.0 * 1024.0));
|
||
}
|
||
|
||
// Calculate percentage
|
||
pads[pad_count].percentage = (double)used_bytes / st.st_size * 100.0;
|
||
|
||
// Set location info using directory display
|
||
get_directory_display(full_path, pads[pad_count].location, sizeof(pads[pad_count].location));
|
||
|
||
pad_count++;
|
||
}
|
||
}
|
||
}
|
||
closedir(dir);
|
||
|
||
if (pad_count == 0) {
|
||
printf("\n%s\n", title);
|
||
if (filter_type == PAD_FILTER_UNUSED_ONLY) {
|
||
printf("No unused pads found.\n");
|
||
printf("Entropy can only be added to pads with 0%% usage (only reserved bytes used).\n");
|
||
} else {
|
||
printf("No pads found.\n");
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
// Calculate minimal unique prefixes for each pad
|
||
char prefixes[100][65];
|
||
int prefix_lengths[100];
|
||
|
||
for (int i = 0; i < pad_count; i++) {
|
||
prefix_lengths[i] = 1;
|
||
|
||
// Find minimal unique prefix
|
||
while (prefix_lengths[i] <= 64) {
|
||
int unique = 1;
|
||
|
||
// Check if current prefix is unique among all other pads
|
||
for (int j = 0; j < pad_count; j++) {
|
||
if (i != j && strncmp(pads[i].chksum, pads[j].chksum, prefix_lengths[i]) == 0) {
|
||
unique = 0;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (unique) {
|
||
break;
|
||
}
|
||
prefix_lengths[i]++;
|
||
}
|
||
|
||
// Store the minimal prefix
|
||
strncpy(prefixes[i], pads[i].chksum, prefix_lengths[i]);
|
||
prefixes[i][prefix_lengths[i]] = '\0';
|
||
}
|
||
|
||
// Display title and pads table
|
||
printf("\n%s\n", title);
|
||
printf("%-8s %-2s %-12s %-12s %-12s %-8s\n", "ChkSum", "D", "Dir", "Size", "Used", "% Used");
|
||
printf("%-8s %-2s %-12s %-12s %-12s %-8s\n", "--------", "--", "------------", "----------", "----------", "------");
|
||
|
||
// Get current default pad path for comparison
|
||
char* current_default = get_default_pad_path();
|
||
char default_pad_checksum[65] = "";
|
||
|
||
if (current_default) {
|
||
// Extract checksum from default pad path
|
||
char* filename = strrchr(current_default, '/');
|
||
if (!filename) filename = current_default;
|
||
else filename++; // Skip the '/'
|
||
|
||
// Extract checksum (remove .pad extension)
|
||
if (strlen(filename) >= 68 && strstr(filename, ".pad")) {
|
||
strncpy(default_pad_checksum, filename, 64);
|
||
default_pad_checksum[64] = '\0';
|
||
}
|
||
free(current_default);
|
||
}
|
||
|
||
for (int i = 0; i < pad_count; i++) {
|
||
// Check if this is the default pad
|
||
int is_default = (strlen(default_pad_checksum) > 0 &&
|
||
strncmp(pads[i].chksum, default_pad_checksum, 64) == 0);
|
||
|
||
// Display first 8 characters of checksum with prefix underlined
|
||
char checksum_8char[9];
|
||
strncpy(checksum_8char, pads[i].chksum, 8);
|
||
checksum_8char[8] = '\0';
|
||
|
||
printf("\033[4m%.*s\033[0m%s %-2s %-12s %-12s %-12s %.1f%%\n",
|
||
prefix_lengths[i], checksum_8char, // Underlined prefix
|
||
checksum_8char + prefix_lengths[i], // Rest of 8-char checksum
|
||
is_default ? "*" : "", // Default indicator
|
||
pads[i].location,
|
||
pads[i].size_str,
|
||
pads[i].used_str,
|
||
pads[i].percentage);
|
||
}
|
||
|
||
// Display prompt
|
||
printf("\n%s", prompt);
|
||
if (allow_cancel) {
|
||
printf(" (or 'x' to cancel)");
|
||
}
|
||
printf(": ");
|
||
|
||
char input[MAX_HASH_LENGTH];
|
||
if (!fgets(input, sizeof(input), stdin)) {
|
||
printf("Error: Failed to read input\n");
|
||
return NULL;
|
||
}
|
||
input[strcspn(input, "\n")] = 0;
|
||
|
||
// Handle empty input - select default pad if available
|
||
if (strlen(input) == 0) {
|
||
// Get current default pad path
|
||
char* current_default = get_default_pad_path();
|
||
if (current_default) {
|
||
// Extract checksum from default pad path
|
||
char* filename = strrchr(current_default, '/');
|
||
if (!filename) filename = current_default;
|
||
else filename++; // Skip the '/'
|
||
|
||
// Extract checksum (remove .pad extension)
|
||
if (strlen(filename) >= 68 && strstr(filename, ".pad")) {
|
||
char default_checksum[65];
|
||
strncpy(default_checksum, filename, 64);
|
||
default_checksum[64] = '\0';
|
||
|
||
// Verify this default pad is in our current list
|
||
for (int i = 0; i < pad_count; i++) {
|
||
if (strncmp(pads[i].chksum, default_checksum, 64) == 0) {
|
||
free(current_default);
|
||
printf("Selected default pad: %.16s...\n\n", default_checksum);
|
||
return strdup(default_checksum);
|
||
}
|
||
}
|
||
}
|
||
free(current_default);
|
||
}
|
||
// No default pad or default pad not in current list
|
||
printf("No default pad available or default pad not in current list\n");
|
||
return NULL;
|
||
}
|
||
|
||
// Handle cancel
|
||
if (allow_cancel && (toupper(input[0]) == 'X' && strlen(input) == 1)) {
|
||
return NULL;
|
||
}
|
||
|
||
// Find matching pad by prefix only
|
||
int selected_pad = -1;
|
||
int match_count = 0;
|
||
|
||
// Try prefix matching only
|
||
for (int i = 0; i < pad_count; i++) {
|
||
if (strncmp(input, pads[i].chksum, strlen(input)) == 0) {
|
||
if (match_count == 0) {
|
||
selected_pad = i;
|
||
}
|
||
match_count++;
|
||
}
|
||
}
|
||
|
||
if (match_count == 0) {
|
||
printf("No pad found matching '%s'\n", input);
|
||
return NULL;
|
||
} else if (match_count > 1) {
|
||
printf("Ambiguous prefix. Multiple matches found.\n");
|
||
return NULL;
|
||
}
|
||
|
||
// Return selected pad checksum (caller must free)
|
||
return strdup(pads[selected_pad].chksum);
|
||
}
|
||
|
||
int handle_pads_menu(void) {
|
||
printf("\n");
|
||
print_centered_header("Pad Management", 0);
|
||
|
||
// Get list of pads from current directory
|
||
const char* pads_dir = get_current_pads_dir();
|
||
DIR* dir = opendir(pads_dir);
|
||
if (!dir) {
|
||
printf("Error: Cannot open pads directory %s\n", pads_dir);
|
||
return 1;
|
||
}
|
||
|
||
// Structure to store pad information
|
||
struct PadInfo {
|
||
char chksum[65];
|
||
char size_str[32];
|
||
char used_str[32];
|
||
double percentage;
|
||
char location[256]; // Store location info
|
||
};
|
||
|
||
struct PadInfo pads[100]; // Support up to 100 pads
|
||
int pad_count = 0;
|
||
|
||
// Collect all pad information
|
||
struct dirent* entry;
|
||
while ((entry = readdir(dir)) != NULL && pad_count < 100) {
|
||
if (strstr(entry->d_name, ".pad") && strlen(entry->d_name) == 68) {
|
||
strncpy(pads[pad_count].chksum, entry->d_name, 64);
|
||
pads[pad_count].chksum[64] = '\0';
|
||
|
||
// Get pad file size and usage info
|
||
char full_path[1024]; // Increased buffer size
|
||
snprintf(full_path, sizeof(full_path), "%s/%s", pads_dir, entry->d_name);
|
||
struct stat st;
|
||
if (stat(full_path, &st) == 0) {
|
||
// Get used bytes from state
|
||
uint64_t used_bytes;
|
||
read_state_offset(pads[pad_count].chksum, &used_bytes);
|
||
|
||
// Format total size
|
||
if (st.st_size < 1024) {
|
||
snprintf(pads[pad_count].size_str, sizeof(pads[pad_count].size_str), "%luB", st.st_size);
|
||
} else if (st.st_size < 1024 * 1024) {
|
||
snprintf(pads[pad_count].size_str, sizeof(pads[pad_count].size_str), "%.1fKB", (double)st.st_size / 1024.0);
|
||
} else if (st.st_size < 1024 * 1024 * 1024) {
|
||
snprintf(pads[pad_count].size_str, sizeof(pads[pad_count].size_str), "%.1fMB", (double)st.st_size / (1024.0 * 1024.0));
|
||
} else {
|
||
snprintf(pads[pad_count].size_str, sizeof(pads[pad_count].size_str), "%.2fGB", (double)st.st_size / (1024.0 * 1024.0 * 1024.0));
|
||
}
|
||
|
||
// Format used size
|
||
if (used_bytes < 1024) {
|
||
snprintf(pads[pad_count].used_str, sizeof(pads[pad_count].used_str), "%luB", used_bytes);
|
||
} else if (used_bytes < 1024 * 1024) {
|
||
snprintf(pads[pad_count].used_str, sizeof(pads[pad_count].used_str), "%.1fKB", (double)used_bytes / 1024.0);
|
||
} else if (used_bytes < 1024 * 1024 * 1024) {
|
||
snprintf(pads[pad_count].used_str, sizeof(pads[pad_count].used_str), "%.1fMB", (double)used_bytes / (1024.0 * 1024.0));
|
||
} else {
|
||
snprintf(pads[pad_count].used_str, sizeof(pads[pad_count].used_str), "%.2fGB", (double)used_bytes / (1024.0 * 1024.0 * 1024.0));
|
||
}
|
||
|
||
// Calculate percentage
|
||
pads[pad_count].percentage = (double)used_bytes / st.st_size * 100.0;
|
||
|
||
// Set location info using directory display
|
||
get_directory_display(full_path, pads[pad_count].location, sizeof(pads[pad_count].location));
|
||
|
||
pad_count++;
|
||
}
|
||
}
|
||
}
|
||
closedir(dir);
|
||
|
||
if (pad_count == 0) {
|
||
printf("No pads found.\n");
|
||
printf("\nOptions:\n");
|
||
printf(" \033[4mG\033[0menerate new pad\n");
|
||
printf(" E\033[4mx\033[0mit\n");
|
||
printf("\nSelect option: ");
|
||
|
||
char input[10];
|
||
if (fgets(input, sizeof(input), stdin)) {
|
||
char choice = toupper(input[0]);
|
||
if (choice == 'G') {
|
||
int result = handle_generate_menu();
|
||
if (result == 0) {
|
||
// After successful pad generation, return to pads menu
|
||
return handle_pads_menu();
|
||
}
|
||
return result;
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
// Calculate minimal unique prefixes for each pad
|
||
char prefixes[100][65]; // Store the minimal prefix for each pad
|
||
int prefix_lengths[100]; // Length of minimal prefix for each pad
|
||
|
||
for (int i = 0; i < pad_count; i++) {
|
||
prefix_lengths[i] = 1;
|
||
|
||
// Find minimal unique prefix
|
||
while (prefix_lengths[i] <= 64) {
|
||
int unique = 1;
|
||
|
||
// Check if current prefix is unique among all other pads
|
||
for (int j = 0; j < pad_count; j++) {
|
||
if (i != j && strncmp(pads[i].chksum, pads[j].chksum, prefix_lengths[i]) == 0) {
|
||
unique = 0;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (unique) {
|
||
break;
|
||
}
|
||
prefix_lengths[i]++;
|
||
}
|
||
|
||
// Store the minimal prefix
|
||
strncpy(prefixes[i], pads[i].chksum, prefix_lengths[i]);
|
||
prefixes[i][prefix_lengths[i]] = '\0';
|
||
}
|
||
|
||
// Display pads with minimal prefixes underlined and default indicator
|
||
printf("\nAvailable pads:\n");
|
||
printf("%-8s %-2s %-12s %-12s %-12s %-8s\n", "ChkSum", "D", "Dir", "Size", "Used", "% Used");
|
||
printf("%-8s %-2s %-12s %-12s %-12s %-8s\n", "--------", "--", "------------", "----------", "----------", "------");
|
||
|
||
// Get current default pad path for comparison
|
||
char* current_default = get_default_pad_path();
|
||
char default_pad_checksum[65] = "";
|
||
|
||
if (current_default) {
|
||
// Extract checksum from default pad path
|
||
char* filename = strrchr(current_default, '/');
|
||
if (!filename) filename = current_default;
|
||
else filename++; // Skip the '/'
|
||
|
||
// Extract checksum (remove .pad extension)
|
||
if (strlen(filename) >= 68 && strstr(filename, ".pad")) {
|
||
strncpy(default_pad_checksum, filename, 64);
|
||
default_pad_checksum[64] = '\0';
|
||
}
|
||
free(current_default);
|
||
}
|
||
|
||
for (int i = 0; i < pad_count; i++) {
|
||
// Check if this is the default pad
|
||
int is_default = (strlen(default_pad_checksum) > 0 &&
|
||
strncmp(pads[i].chksum, default_pad_checksum, 64) == 0);
|
||
|
||
// Display first 8 characters of checksum with prefix underlined
|
||
char checksum_8char[9];
|
||
strncpy(checksum_8char, pads[i].chksum, 8);
|
||
checksum_8char[8] = '\0';
|
||
|
||
printf("\033[4m%.*s\033[0m%s %-2s %-12s %-12s %-12s %.1f%%\n",
|
||
prefix_lengths[i], checksum_8char, // Underlined prefix
|
||
checksum_8char + prefix_lengths[i], // Rest of 8-char checksum
|
||
is_default ? "*" : "", // Default indicator
|
||
pads[i].location, // Use the stored location info
|
||
pads[i].size_str,
|
||
pads[i].used_str,
|
||
pads[i].percentage);
|
||
}
|
||
|
||
printf("\nActions:\n");
|
||
printf(" \033[4mG\033[0menerate new pad\n");
|
||
printf(" \033[4mA\033[0mdd entropy to pad\n");
|
||
printf(" \033[4mV\033[0merify pad integrity\n");
|
||
printf(" \033[4mD\033[0melete pad\n");
|
||
printf(" \033[4mS\033[0met default pad\n");
|
||
printf(" E\033[4mx\033[0mit\n");
|
||
printf("\nSelect action: ");
|
||
|
||
char input[MAX_HASH_LENGTH];
|
||
if (!fgets(input, sizeof(input), stdin)) {
|
||
printf("Error: Failed to read input\n");
|
||
return 1;
|
||
}
|
||
input[strcspn(input, "\n")] = 0;
|
||
|
||
// Handle actions
|
||
if (toupper(input[0]) == 'G') {
|
||
int result = handle_generate_menu();
|
||
if (result == 0) {
|
||
// After successful pad generation, return to pads menu
|
||
return handle_pads_menu();
|
||
}
|
||
return result;
|
||
} else if (toupper(input[0]) == 'A') {
|
||
// Add entropy to pad - use unified function with unused pads filter
|
||
char* selected_pad = select_pad_interactive("Select Unused Pad for Entropy Addition",
|
||
"Select unused pad (by prefix)",
|
||
PAD_FILTER_UNUSED_ONLY, 1);
|
||
if (!selected_pad) {
|
||
printf("Entropy addition cancelled.\n");
|
||
return handle_pads_menu();
|
||
}
|
||
|
||
// Add entropy to the selected unused pad
|
||
int result = handle_add_entropy_to_pad(selected_pad);
|
||
free(selected_pad);
|
||
if (result == 0) {
|
||
// Return to pads menu after successful entropy addition
|
||
return handle_pads_menu();
|
||
}
|
||
return result;
|
||
} else if (toupper(input[0]) == 'V') {
|
||
// Verify pad integrity - use unified function
|
||
char* selected_pad = select_pad_interactive("Select Pad for Verification",
|
||
"Select pad to verify (by prefix)",
|
||
PAD_FILTER_ALL, 1);
|
||
if (!selected_pad) {
|
||
printf("Pad verification cancelled.\n");
|
||
return handle_pads_menu();
|
||
}
|
||
|
||
// Verify the selected pad
|
||
handle_verify_pad(selected_pad);
|
||
free(selected_pad);
|
||
return handle_pads_menu(); // Always return to pads menu after verification
|
||
} else if (toupper(input[0]) == 'D') {
|
||
// Delete pad - use unified function
|
||
char* selected_pad = select_pad_interactive("Select Pad for Deletion",
|
||
"Select pad to delete (by prefix)",
|
||
PAD_FILTER_ALL, 1);
|
||
if (!selected_pad) {
|
||
printf("Pad deletion cancelled.\n");
|
||
return handle_pads_menu();
|
||
}
|
||
|
||
// Delete the selected pad
|
||
handle_delete_pad(selected_pad);
|
||
free(selected_pad);
|
||
return handle_pads_menu(); // Always return to pads menu after deletion attempt
|
||
} else if (toupper(input[0]) == 'S') {
|
||
// Set default pad - use unified function
|
||
char* selected_pad = select_pad_interactive("Select Default Pad",
|
||
"Select pad to set as default (by prefix)",
|
||
PAD_FILTER_ALL, 1);
|
||
if (!selected_pad) {
|
||
printf("Default pad selection cancelled.\n");
|
||
return handle_pads_menu();
|
||
}
|
||
|
||
// Construct the full absolute pad path and set as default
|
||
char new_default_path[1024];
|
||
const char* pads_dir = get_current_pads_dir();
|
||
if (pads_dir[0] == '/') {
|
||
// Already absolute path
|
||
int ret = snprintf(new_default_path, sizeof(new_default_path), "%s/%s.pad", pads_dir, selected_pad);
|
||
if (ret >= (int)sizeof(new_default_path)) {
|
||
printf("Error: Path too long for default pad setting\n");
|
||
free(selected_pad);
|
||
return handle_pads_menu();
|
||
}
|
||
} else {
|
||
// Relative path - make it absolute
|
||
char current_dir[512];
|
||
if (getcwd(current_dir, sizeof(current_dir))) {
|
||
int ret = snprintf(new_default_path, sizeof(new_default_path), "%s/%s/%s.pad", current_dir, pads_dir, selected_pad);
|
||
if (ret >= (int)sizeof(new_default_path)) {
|
||
// Path was truncated, fall back to relative path
|
||
int ret2 = snprintf(new_default_path, sizeof(new_default_path), "%s/%s.pad", pads_dir, selected_pad);
|
||
if (ret2 >= (int)sizeof(new_default_path)) {
|
||
printf("Error: Path too long for default pad setting\n");
|
||
free(selected_pad);
|
||
return handle_pads_menu();
|
||
}
|
||
}
|
||
} else {
|
||
// Fallback to relative path
|
||
int ret = snprintf(new_default_path, sizeof(new_default_path), "%s/%s.pad", pads_dir, selected_pad);
|
||
if (ret >= (int)sizeof(new_default_path)) {
|
||
printf("Error: Path too long for default pad setting\n");
|
||
free(selected_pad);
|
||
return handle_pads_menu();
|
||
}
|
||
}
|
||
}
|
||
|
||
if (set_default_pad_path(new_default_path) == 0) {
|
||
printf("Default pad set to: %.16s...\n", selected_pad);
|
||
printf("Full path: %s\n", new_default_path);
|
||
} else {
|
||
printf("Error: Failed to update default pad preference\n");
|
||
}
|
||
|
||
free(selected_pad);
|
||
return handle_pads_menu();
|
||
} else if (toupper(input[0]) == 'X') {
|
||
return 0; // Exit to main menu
|
||
} else {
|
||
printf("Invalid action. Please select G, A, S, or X.\n");
|
||
return handle_pads_menu();
|
||
}
|
||
}
|
||
|
||
// Update pad checksum after entropy addition
|
||
int update_pad_checksum_after_entropy(const char* old_chksum, char* new_chksum) {
|
||
char pad_path[1024];
|
||
const char* pads_dir = get_current_pads_dir();
|
||
snprintf(pad_path, sizeof(pad_path), "%s/%s.pad", 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];
|
||
const char* pads_dir = get_current_pads_dir();
|
||
snprintf(new_default_path, sizeof(new_default_path), "%s/%s.pad", 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
|
||
}
|
||
|
||
// Verify pad integrity by checking its checksum
|
||
int handle_verify_pad(const char* chksum) {
|
||
char pad_filename[MAX_HASH_LENGTH + 10];
|
||
char state_filename[MAX_HASH_LENGTH + 10];
|
||
char calculated_chksum[MAX_HASH_LENGTH];
|
||
|
||
snprintf(pad_filename, sizeof(pad_filename), "%s.pad", chksum);
|
||
snprintf(state_filename, sizeof(state_filename), "%s.state", chksum);
|
||
|
||
struct stat st;
|
||
if (stat(pad_filename, &st) != 0) {
|
||
printf("Pad not found: %s\n", chksum);
|
||
return 1;
|
||
}
|
||
|
||
uint64_t used_bytes;
|
||
read_state_offset(chksum, &used_bytes);
|
||
|
||
print_centered_header("Pad Verification", 0);
|
||
printf("ChkSum: %s\n", chksum);
|
||
printf("File: %s\n", pad_filename);
|
||
|
||
double size_gb = (double)st.st_size / (1024.0 * 1024.0 * 1024.0);
|
||
double used_gb = (double)used_bytes / (1024.0 * 1024.0 * 1024.0);
|
||
double remaining_gb = (double)(st.st_size - used_bytes) / (1024.0 * 1024.0 * 1024.0);
|
||
|
||
printf("Total size: %.2f GB (%lu bytes)\n", size_gb, st.st_size);
|
||
printf("Used: %.2f GB (%lu bytes)\n", used_gb, used_bytes);
|
||
printf("Remaining: %.2f GB (%lu bytes)\n", remaining_gb, st.st_size - used_bytes);
|
||
printf("Usage: %.1f%%\n", (double)used_bytes / st.st_size * 100.0);
|
||
|
||
// Calculate actual checksum
|
||
printf("\nCalculating checksum...\n");
|
||
if (calculate_checksum(pad_filename, calculated_chksum) != 0) {
|
||
printf("Error: Cannot calculate pad checksum\n");
|
||
return 1;
|
||
}
|
||
|
||
printf("Expected checksum: %s\n", chksum);
|
||
printf("Calculated checksum: %s\n", calculated_chksum);
|
||
|
||
if (strcmp(chksum, calculated_chksum) == 0) {
|
||
printf("\n✓ Pad integrity verified - checksum matches!\n");
|
||
printf("This pad is safe to use.\n");
|
||
return 0;
|
||
} else {
|
||
printf("\n✗ Pad integrity check FAILED - checksum mismatch!\n");
|
||
printf("This pad may be corrupted and should not be used.\n");
|
||
printf("Consider regenerating this pad.\n");
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
// Delete a pad and its associated state file
|
||
int handle_delete_pad(const char* chksum) {
|
||
char pad_filename[MAX_HASH_LENGTH + 10];
|
||
char state_filename[MAX_HASH_LENGTH + 10];
|
||
|
||
snprintf(pad_filename, sizeof(pad_filename), "%s.pad", chksum);
|
||
snprintf(state_filename, sizeof(state_filename), "%s.state", chksum);
|
||
|
||
// Check if pad exists
|
||
if (access(pad_filename, F_OK) != 0) {
|
||
printf("Pad not found: %s\n", chksum);
|
||
return 1;
|
||
}
|
||
|
||
// Check if this is the default pad
|
||
char* current_default = get_default_pad_path();
|
||
int is_default = 0;
|
||
if (current_default) {
|
||
if (strstr(current_default, chksum)) {
|
||
is_default = 1;
|
||
}
|
||
free(current_default);
|
||
}
|
||
|
||
if (is_default) {
|
||
printf("Warning: This is the current default pad.\n");
|
||
printf("Deleting it will require setting a new default pad.\n");
|
||
}
|
||
|
||
// Get pad info for confirmation
|
||
struct stat st;
|
||
if (stat(pad_filename, &st) == 0) {
|
||
uint64_t used_bytes;
|
||
read_state_offset(chksum, &used_bytes);
|
||
|
||
double size_gb = (double)st.st_size / (1024.0 * 1024.0 * 1024.0);
|
||
printf("\nPad to delete:\n");
|
||
printf("Checksum: %s\n", chksum);
|
||
printf("Size: %.2f GB\n", size_gb);
|
||
printf("Used: %.1f%%\n", (double)used_bytes / st.st_size * 100.0);
|
||
}
|
||
|
||
// First confirmation
|
||
printf("\nAre you sure you want to delete this pad? (y/N): ");
|
||
char input[10];
|
||
if (!fgets(input, sizeof(input), stdin)) {
|
||
printf("Error: Failed to read input\n");
|
||
return 1;
|
||
}
|
||
if (toupper(input[0]) != 'Y') {
|
||
printf("Pad deletion cancelled.\n");
|
||
return 0;
|
||
}
|
||
|
||
// Second confirmation with checksum
|
||
printf("Type the first 8 characters of the checksum to confirm deletion: ");
|
||
if (!fgets(input, sizeof(input), stdin)) {
|
||
printf("Error: Failed to read input\n");
|
||
return 1;
|
||
}
|
||
input[strcspn(input, "\n")] = 0;
|
||
|
||
if (strlen(input) < 8 || strncmp(input, chksum, 8) != 0) {
|
||
printf("Confirmation failed. Pad deletion cancelled.\n");
|
||
return 1;
|
||
}
|
||
|
||
// Delete state file first
|
||
if (access(state_filename, F_OK) == 0) {
|
||
if (unlink(state_filename) != 0) {
|
||
printf("Error: Failed to delete state file %s\n", state_filename);
|
||
return 1;
|
||
}
|
||
printf("Deleted state file: %s\n", state_filename);
|
||
}
|
||
|
||
// Delete pad file
|
||
if (unlink(pad_filename) != 0) {
|
||
printf("Error: Failed to delete pad file %s\n", pad_filename);
|
||
return 1;
|
||
}
|
||
printf("Deleted pad file: %s\n", pad_filename);
|
||
|
||
// Clear default pad preference if this was the default
|
||
if (is_default) {
|
||
if (set_default_pad_path("") != 0) {
|
||
printf("Warning: Failed to clear default pad preference\n");
|
||
} else {
|
||
printf("Cleared default pad preference (was this pad)\n");
|
||
}
|
||
}
|
||
|
||
printf("Pad deletion completed successfully.\n");
|
||
return 0;
|
||
}
|
||
|
||
int handle_add_entropy_to_pad(const char* pad_chksum) {
|
||
char header_text[128];
|
||
snprintf(header_text, sizeof(header_text), "Add Entropy to Pad: %.16s...", pad_chksum);
|
||
printf("\n");
|
||
print_centered_header(header_text, 0);
|
||
|
||
// Present entropy source selection menu with consistent formatting
|
||
printf("Select entropy source:\n");
|
||
printf(" \033[4mK\033[0meyboard entropy - Random typing for entropy collection\n");
|
||
printf(" \033[4mD\033[0mice/Coins/Cards - Manual input for high-quality entropy\n");
|
||
printf(" \033[4mH\033[0mardware RNG - Hardware random number generators\n");
|
||
printf(" \033[4mF\033[0mile - Load entropy from binary file\n");
|
||
printf(" \033[4mT\033[0mest RNG Speed - Test TrueRNG/SwiftRNG device performance\n");
|
||
printf(" E\033[4mx\033[0mit\n");
|
||
printf("\nSelect option: ");
|
||
|
||
char source_input[10];
|
||
if (!fgets(source_input, sizeof(source_input), stdin)) {
|
||
printf("Error: Failed to read input\n");
|
||
return 1;
|
||
}
|
||
|
||
char choice = toupper(source_input[0]);
|
||
entropy_source_t entropy_source;
|
||
|
||
switch (choice) {
|
||
case 'K':
|
||
entropy_source = ENTROPY_SOURCE_KEYBOARD;
|
||
break;
|
||
case 'D':
|
||
entropy_source = ENTROPY_SOURCE_DICE;
|
||
break;
|
||
case 'H':
|
||
// Hardware RNG selected - will handle after target_bytes selection
|
||
entropy_source = ENTROPY_SOURCE_TRUERNG;
|
||
break;
|
||
case 'F':
|
||
entropy_source = ENTROPY_SOURCE_FILE;
|
||
break;
|
||
case 'T':
|
||
// Test RNG speed - this doesn't collect entropy, just tests the device
|
||
// MOVED TO src/trng.c - commented out here
|
||
// return test_truerng_speed();
|
||
printf("Test RNG speed functionality moved to TRNG module\n");
|
||
return 1;
|
||
case 'X':
|
||
return 0; // Exit
|
||
default:
|
||
printf("Invalid choice. Please select K, D, H, F, T, or X.\n");
|
||
return 1;
|
||
}
|
||
|
||
size_t target_bytes;
|
||
|
||
// For TrueRNG, automatically use the full pad size
|
||
if (entropy_source == ENTROPY_SOURCE_TRUERNG) {
|
||
// Get the pad file size
|
||
char pad_path[1024];
|
||
char state_path[1024];
|
||
get_pad_path(pad_chksum, pad_path, state_path);
|
||
|
||
struct stat pad_stat;
|
||
if (stat(pad_path, &pad_stat) != 0) {
|
||
printf("Error: Cannot get pad file size\n");
|
||
return 1;
|
||
}
|
||
|
||
target_bytes = (size_t)pad_stat.st_size;
|
||
printf("\nTrueRNG selected - will enhance entire pad with hardware entropy\n");
|
||
printf("Pad size: %.2f GB (%zu bytes)\n",
|
||
(double)target_bytes / (1024.0 * 1024.0 * 1024.0), target_bytes);
|
||
} else {
|
||
// For other entropy sources, show the selection menu
|
||
printf("\nEntropy collection options:\n");
|
||
printf(" 1. Recommended (2048 bytes) - Optimal security\n");
|
||
printf(" 2. Minimum (1024 bytes) - Good security\n");
|
||
printf(" 3. Maximum (4096 bytes) - Maximum security\n");
|
||
printf(" 4. Custom amount\n");
|
||
printf("Enter choice (1-4): ");
|
||
|
||
char amount_input[10];
|
||
if (!fgets(amount_input, sizeof(amount_input), stdin)) {
|
||
printf("Error: Failed to read input\n");
|
||
return 1;
|
||
}
|
||
|
||
target_bytes = 2048; // Default
|
||
int amount_choice = atoi(amount_input);
|
||
|
||
switch (amount_choice) {
|
||
case 1:
|
||
target_bytes = 2048;
|
||
break;
|
||
case 2:
|
||
target_bytes = 1024;
|
||
break;
|
||
case 3:
|
||
target_bytes = 4096;
|
||
break;
|
||
case 4:
|
||
printf("Enter custom amount (512-8192 bytes): ");
|
||
char custom_input[32];
|
||
if (!fgets(custom_input, sizeof(custom_input), stdin)) {
|
||
printf("Error: Failed to read input\n");
|
||
return 1;
|
||
}
|
||
|
||
size_t custom_amount = (size_t)atoi(custom_input);
|
||
if (custom_amount < 512 || custom_amount > 8192) {
|
||
printf("Error: Invalid amount. Must be between 512 and 8192 bytes.\n");
|
||
return 1;
|
||
}
|
||
target_bytes = custom_amount;
|
||
break;
|
||
default:
|
||
target_bytes = 2048; // Default to recommended
|
||
break;
|
||
}
|
||
}
|
||
|
||
// For TrueRNG, detect all devices and present selection menu
|
||
if (entropy_source == ENTROPY_SOURCE_TRUERNG) {
|
||
// Use streaming collection with selected device
|
||
int result = collect_truerng_entropy_streaming_from_device(NULL, pad_chksum, target_bytes, 1, 1);
|
||
|
||
if (result != 0) {
|
||
printf("Error: TrueRNG streaming entropy collection failed\n");
|
||
return 1;
|
||
}
|
||
|
||
// 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;
|
||
}
|
||
|
||
printf("\n🎉 SUCCESS! Your entire pad now has enhanced randomness!\n");
|
||
|
||
// Use enhanced pause mechanism instead of simple getchar
|
||
print_centered_header("Pad Enhancement Complete", 1);
|
||
|
||
return 0;
|
||
}
|
||
|
||
// For other entropy sources or smaller amounts, use traditional approach
|
||
printf("\nCollecting %zu bytes of entropy from selected source...\n", target_bytes);
|
||
|
||
// Allocate entropy buffer
|
||
unsigned char* entropy_buffer = malloc(MAX_ENTROPY_BUFFER);
|
||
if (!entropy_buffer) {
|
||
printf("Error: Cannot allocate entropy buffer\n");
|
||
return 1;
|
||
}
|
||
|
||
// Collect entropy using unified interface
|
||
size_t collected_bytes = 0;
|
||
int result = collect_entropy_by_source(entropy_source, entropy_buffer, target_bytes, &collected_bytes, 1);
|
||
|
||
if (result != 0) {
|
||
printf("Error: Entropy collection failed\n");
|
||
free(entropy_buffer);
|
||
return 1;
|
||
}
|
||
|
||
if (collected_bytes < 512) {
|
||
printf("Error: Insufficient entropy collected (%zu bytes)\n", collected_bytes);
|
||
free(entropy_buffer);
|
||
return 1;
|
||
}
|
||
|
||
printf("\nProcessing entropy and modifying pad...\n");
|
||
|
||
// Add entropy to pad
|
||
result = add_entropy_to_pad(pad_chksum, entropy_buffer, collected_bytes, 1);
|
||
|
||
// Clear entropy buffer for security
|
||
memset(entropy_buffer, 0, MAX_ENTROPY_BUFFER);
|
||
free(entropy_buffer);
|
||
|
||
if (result != 0) {
|
||
printf("Error: Failed to add entropy to pad\n");
|
||
return 1;
|
||
}
|
||
|
||
printf("\n🎉 SUCCESS! Your pad now has enhanced randomness!\n");
|
||
|
||
// Use enhanced pause mechanism instead of simple getchar
|
||
print_centered_header("Entropy Enhancement Complete", 1);
|
||
|
||
return 0;
|
||
} |