diff --git a/.gitignore b/.gitignore index e6cb23b..a12cb66 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,6 @@ files/ Gemini.md TropicOfCancer-HenryMiller.txt .gitea_token +true_rng/ # Auto-generated files (none currently) diff --git a/otp-arm64 b/otp-arm64 deleted file mode 100755 index 0ce9cc6..0000000 Binary files a/otp-arm64 and /dev/null differ diff --git a/otp-x86_64 b/otp-x86_64 deleted file mode 100755 index 9290feb..0000000 Binary files a/otp-x86_64 and /dev/null differ diff --git a/otp.c b/otp.c index 99bac68..9901c65 100644 --- a/otp.c +++ b/otp.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -60,6 +61,464 @@ static int is_interactive_mode = 0; // MAIN //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// NEW SIMPLIFIED USB DETECTION SYSTEM v2 +// Uses lsusb cross-referencing for reliable USB device identification +//////////////////////////////////////////////////////////////////////////////// + +/** + * Decode octal escape sequences in mount paths (e.g., \040 for space) + * Used by the new v2 USB detection system + */ +void decode_octal_escapes(const char* input, char* output, size_t output_size) { + if (!input || !output || output_size == 0) return; + + size_t src = 0, dst = 0; + size_t input_len = strlen(input); + + while (src < input_len && dst < output_size - 1) { + if (input[src] == '\\' && src + 3 < input_len && + input[src + 1] >= '0' && input[src + 1] <= '7' && + input[src + 2] >= '0' && input[src + 2] <= '7' && + input[src + 3] >= '0' && input[src + 3] <= '7') { + // Decode octal escape sequence + int octal_val = (input[src + 1] - '0') * 64 + + (input[src + 2] - '0') * 8 + + (input[src + 3] - '0'); + output[dst++] = (char)octal_val; + src += 4; + } else { + output[dst++] = input[src++]; + } + } + output[dst] = '\0'; +} + +/** + * Build USB device registry by parsing lsusb output + * Returns array of USB devices found on system + */ +int build_usb_device_registry(usb_device_registry_t **devices, int *device_count) { + if (!devices || !device_count) return 0; + + *devices = NULL; + *device_count = 0; + + // Execute lsusb command and capture output + FILE *lsusb_pipe = popen("lsusb", "r"); + if (!lsusb_pipe) { + fprintf(stderr, "Error: Failed to execute lsusb command\n"); + return 0; + } + + // Allocate initial array for USB devices + int capacity = 16; + usb_device_registry_t *registry = malloc(capacity * sizeof(usb_device_registry_t)); + if (!registry) { + pclose(lsusb_pipe); + return 0; + } + + char line[512]; + int count = 0; + + // Parse each line of lsusb output + // Format: "Bus 001 Device 003: ID 0781:5583 SanDisk Corp. Ultra Fit" + while (fgets(line, sizeof(line), lsusb_pipe)) { + // Expand array if needed + if (count >= capacity) { + capacity *= 2; + usb_device_registry_t *new_registry = realloc(registry, capacity * sizeof(usb_device_registry_t)); + if (!new_registry) { + free(registry); + pclose(lsusb_pipe); + return 0; + } + registry = new_registry; + } + + usb_device_registry_t *device = ®istry[count]; + memset(device, 0, sizeof(usb_device_registry_t)); + + // Parse: "Bus 001 Device 003: ID 0781:5583 SanDisk Corp. Ultra Fit" + char *pos = line; + + // Extract bus number + if (sscanf(pos, "Bus %3s", device->bus_number) != 1) continue; + pos = strstr(pos, "Device "); + if (!pos) continue; + + // Extract device number + pos += 7; // Skip "Device " + if (sscanf(pos, "%3s", device->device_number) != 1) continue; + + // Find ID field + pos = strstr(pos, "ID "); + if (!pos) continue; + pos += 3; // Skip "ID " + + // Extract vendor:product IDs + if (sscanf(pos, "%7[^:]:%7s", device->vendor_id, device->product_id) != 2) continue; + + // Find start of vendor/product names after ID + pos = strchr(pos, ' '); + if (!pos) continue; + pos++; // Skip space + + // Extract vendor and product names (rest of line) + char *newline = strchr(pos, '\n'); + if (newline) *newline = '\0'; + + // Split vendor and product names + // Look for common patterns like "Corp.", "Inc.", "Ltd." + char *vendor_end = strstr(pos, " Corp."); + if (!vendor_end) vendor_end = strstr(pos, " Inc."); + if (!vendor_end) vendor_end = strstr(pos, " Ltd."); + if (!vendor_end) vendor_end = strstr(pos, " Co."); + + if (vendor_end) { + // Include the company suffix + if (strstr(vendor_end, " Corp.")) vendor_end += 6; + else if (strstr(vendor_end, " Inc.")) vendor_end += 5; + else if (strstr(vendor_end, " Ltd.")) vendor_end += 5; + else if (strstr(vendor_end, " Co.")) vendor_end += 4; + + size_t vendor_len = vendor_end - pos; + if (vendor_len >= sizeof(device->vendor_name)) vendor_len = sizeof(device->vendor_name) - 1; + strncpy(device->vendor_name, pos, vendor_len); + device->vendor_name[vendor_len] = '\0'; + + // Product name is what remains after vendor + char *product_start = vendor_end; + while (*product_start == ' ') product_start++; // Skip spaces + strncpy(device->product_name, product_start, sizeof(device->product_name) - 1); + } else { + // Fallback: split at first word boundary after reasonable vendor length + char *space = strchr(pos + 8, ' '); // Look for space after ~8 chars + if (space) { + size_t vendor_len = space - pos; + if (vendor_len >= sizeof(device->vendor_name)) vendor_len = sizeof(device->vendor_name) - 1; + strncpy(device->vendor_name, pos, vendor_len); + device->vendor_name[vendor_len] = '\0'; + + strncpy(device->product_name, space + 1, sizeof(device->product_name) - 1); + } else { + // Single word - treat as vendor + strncpy(device->vendor_name, pos, sizeof(device->vendor_name) - 1); + strcpy(device->product_name, "Unknown"); + } + } + + count++; + } + + pclose(lsusb_pipe); + + *devices = registry; + *device_count = count; + return 1; +} + +/** + * Free USB device registry memory + */ +void free_usb_device_registry(usb_device_registry_t *devices) { + if (devices) { + free(devices); + } +} + +/** + * Find USB device in registry by matching device path to USB bus info + * Maps /dev/sdX to USB device via /sys/block/sdX/device tree + */ +usb_device_registry_t* find_usb_device_by_path(const char* device_path, + usb_device_registry_t* usb_devices, int usb_count) { + if (!device_path || !usb_devices || usb_count <= 0) return NULL; + + // Extract device name from path: /dev/sda1 -> sda + char device_name[16]; + const char *dev_start = strrchr(device_path, '/'); + if (!dev_start) dev_start = device_path; + else dev_start++; // Skip '/' + + // Copy device name, removing partition number + strncpy(device_name, dev_start, sizeof(device_name) - 1); + device_name[sizeof(device_name) - 1] = '\0'; + + // Remove partition number (digits at end) + char *digit_pos = device_name; + while (*digit_pos && !isdigit(*digit_pos)) digit_pos++; + if (*digit_pos) *digit_pos = '\0'; // Truncate at first digit + + // Read vendor and product info from sysfs + char vendor_path[256], product_path[256]; + char model_path[256], manufacturer_path[256]; + snprintf(vendor_path, sizeof(vendor_path), "/sys/block/%s/device/vendor", device_name); + snprintf(product_path, sizeof(product_path), "/sys/block/%s/device/model", device_name); + snprintf(manufacturer_path, sizeof(manufacturer_path), "/sys/block/%s/device/manufacturer", device_name); + snprintf(model_path, sizeof(model_path), "/sys/block/%s/device/product", device_name); + + // Try to read device info from multiple possible sysfs locations + char vendor_info[64] = {0}, product_info[64] = {0}; + FILE *fp; + + // Try vendor file + fp = fopen(vendor_path, "r"); + if (fp) { + fgets(vendor_info, sizeof(vendor_info), fp); + fclose(fp); + // Trim whitespace + char *end = vendor_info + strlen(vendor_info) - 1; + while (end > vendor_info && isspace(*end)) *end-- = '\0'; + } + + // Try product/model file + fp = fopen(product_path, "r"); + if (!fp) fp = fopen(model_path, "r"); + if (fp) { + fgets(product_info, sizeof(product_info), fp); + fclose(fp); + // Trim whitespace + char *end = product_info + strlen(product_info) - 1; + while (end > product_info && isspace(*end)) *end-- = '\0'; + } + + // If we couldn't get device info from sysfs, check if it's in common USB mount locations + if (strlen(vendor_info) == 0 && strlen(product_info) == 0) { + // For devices in /media/ or /mnt/, assume they could be USB and do partial matching + // This handles cases where sysfs info isn't available + return usb_count > 0 ? &usb_devices[0] : NULL; // Return first USB device as fallback + } + + // Try to match vendor/product info with USB device registry + for (int i = 0; i < usb_count; i++) { + usb_device_registry_t *usb_dev = &usb_devices[i]; + + // Try partial string matching for vendor names + if (strlen(vendor_info) > 0 && strlen(usb_dev->vendor_name) > 0) { + if (strstr(usb_dev->vendor_name, vendor_info) || strstr(vendor_info, usb_dev->vendor_name)) { + return usb_dev; + } + } + + // Try partial string matching for product names + if (strlen(product_info) > 0 && strlen(usb_dev->product_name) > 0) { + if (strstr(usb_dev->product_name, product_info) || strstr(product_info, usb_dev->product_name)) { + return usb_dev; + } + } + } + + return NULL; // No USB device found for this path +} + +/** + * Get user-friendly status string for USB safety status + */ +const char* get_usb_status_string(usb_safety_status_t status) { + switch (status) { + case USB_SAFE: return "SAFE"; + case USB_TOO_LARGE: return "TOO_LARGE"; + case USB_NOT_USB: return "NOT_USB"; + default: return "UNKNOWN"; + } +} + +/** + * Detect drive information using new simplified v2 system + * Cross-references with USB device registry for validation + */ +int detect_drive_info_v2(const char* mount_path, drive_info_v2_t* drive_info, + usb_device_registry_t* usb_devices, int usb_count) { + if (!mount_path || !drive_info) return 0; + + // Initialize drive info structure + memset(drive_info, 0, sizeof(drive_info_v2_t)); + strncpy(drive_info->mount_path, mount_path, sizeof(drive_info->mount_path) - 1); + + // Get device path using existing working Method 1 from get_usb_drive_info + FILE* mounts_file = fopen("/proc/mounts", "r"); + if (!mounts_file) return 0; + + char line[1024]; + int device_found = 0; + char device_path[256] = {0}; + + while (fgets(line, sizeof(line), mounts_file)) { + char source_field[256], mount_field[256], fs_type[64]; + if (sscanf(line, "%255s %255s %63s", source_field, mount_field, fs_type) == 3) { + // Decode octal escape sequences in mount path + char decoded_mount[512]; + decode_octal_escapes(mount_field, decoded_mount, sizeof(decoded_mount)); + + if (strcmp(decoded_mount, mount_path) == 0) { + strncpy(device_path, source_field, sizeof(device_path) - 1); + strncpy(drive_info->filesystem, fs_type, sizeof(drive_info->filesystem) - 1); + device_found = 1; + break; + } + } + } + fclose(mounts_file); + + if (!device_found) return 0; + + // CRITICAL FIX: Filter out internal encrypted drives (luks/mapper devices) + if (strstr(device_path, "/dev/mapper/") || strstr(device_path, "luks-")) { + return 0; // Skip internal encrypted drives - these are not USB devices + } + + // Store device path and extract device name + strncpy(drive_info->device_path, device_path, sizeof(drive_info->device_path) - 1); + + const char *dev_start = strrchr(device_path, '/'); + if (dev_start) dev_start++; else dev_start = device_path; + + char temp_name[16]; + strncpy(temp_name, dev_start, sizeof(temp_name) - 1); + temp_name[sizeof(temp_name) - 1] = '\0'; + + // Remove partition number to get base device name + char *digit_pos = temp_name; + while (*digit_pos && !isdigit(*digit_pos)) digit_pos++; + if (*digit_pos) *digit_pos = '\0'; + + strncpy(drive_info->device_name, temp_name, sizeof(drive_info->device_name) - 1); + + // ENHANCED FIX: Validate USB connectivity using sysfs path check + char sysfs_path[512]; + char link_target[512]; + snprintf(sysfs_path, sizeof(sysfs_path), "/sys/block/%s", drive_info->device_name); + + ssize_t link_len = readlink(sysfs_path, link_target, sizeof(link_target) - 1); + if (link_len > 0) { + link_target[link_len] = '\0'; + // Check if the device path contains 'usb' - genuine USB devices have USB paths + if (!strstr(link_target, "/usb")) { + return 0; // Skip non-USB devices based on sysfs path validation + } + } else { + return 0; // Skip devices without valid sysfs paths + } + + // Extract label from mount path + const char *label_start = strrchr(mount_path, '/'); + if (label_start) { + label_start++; // Skip '/' + strncpy(drive_info->label, label_start, sizeof(drive_info->label) - 1); + } + + // Get filesystem stats for sizes + struct statvfs vfs_stat; + if (statvfs(mount_path, &vfs_stat) == 0) { + drive_info->total_size = (uint64_t)vfs_stat.f_blocks * vfs_stat.f_frsize; + drive_info->free_size = (uint64_t)vfs_stat.f_bavail * vfs_stat.f_frsize; + } + + // Count .pad files on drive + DIR *dir = opendir(mount_path); + if (dir) { + struct dirent *entry; + while ((entry = readdir(dir))) { + if (strstr(entry->d_name, ".pad")) { + drive_info->pad_count++; + } + } + closedir(dir); + } + + // Cross-reference with USB device registry + drive_info->usb_device = find_usb_device_by_path(device_path, usb_devices, usb_count); + + // Determine safety status + if (drive_info->usb_device) { + // Found in USB registry - check size limits + if (drive_info->total_size > (6ULL * 1024 * 1024 * 1024 * 1024)) { // 6TB limit + drive_info->status = USB_TOO_LARGE; + } else { + drive_info->status = USB_SAFE; + } + } else { + drive_info->status = USB_NOT_USB; + } + + return 1; +} + +/** + * New simplified USB drive listing function + * Replaces the complex list_usb_drives with lsusb cross-referencing + */ +void list_usb_drives_v2(void) { + // Build USB device registry from lsusb + usb_device_registry_t *usb_devices = NULL; + int usb_count = 0; + + if (!build_usb_device_registry(&usb_devices, &usb_count)) { + printf("Error: Failed to build USB device registry\n"); + return; + } + + // Parse mounted drives from /proc/mounts + FILE* mounts_file = fopen("/proc/mounts", "r"); + if (!mounts_file) { + printf("Error: Cannot read /proc/mounts\n"); + free_usb_device_registry(usb_devices); + return; + } + + drive_info_v2_t drives[MAX_USB_DRIVES]; + int drive_count = 0; + + char line[1024]; + while (fgets(line, sizeof(line), mounts_file) && drive_count < MAX_USB_DRIVES) { + char mount_point[512]; + if (sscanf(line, "%*s %511s", mount_point) == 1) { + // Decode octal escapes + char decoded_mount[512]; + decode_octal_escapes(mount_point, decoded_mount, sizeof(decoded_mount)); + + // Only check drives in common user mount locations + if (strstr(decoded_mount, "/media/") || strstr(decoded_mount, "/mnt/")) { + drive_info_v2_t drive_info; + if (detect_drive_info_v2(decoded_mount, &drive_info, usb_devices, usb_count)) { + drives[drive_count] = drive_info; + drive_count++; + } + } + } + } + fclose(mounts_file); + + // Display results + if (drive_count == 0) { + printf("No drives found in /media/ or /mnt/ locations.\n"); + } else { + printf("%-20s %-10s %-12s %-12s %-8s %-4s %-30s\n", + "Label", "Type", "Total", "Free", "FS", "Pads", "Mount Path"); + printf("%-20s %-10s %-12s %-12s %-8s %-4s %-30s\n", + "--------------------", "----------", "------------", "------------", + "--------", "----", "------------------------------"); + + for (int i = 0; i < drive_count; i++) { + drive_info_v2_t *drive = &drives[i]; + + char total_str[32], free_str[32]; + format_size_string(drive->total_size, total_str, sizeof(total_str)); + format_size_string(drive->free_size, free_str, sizeof(free_str)); + + const char *type = drive->usb_device ? "USB" : "Local"; + + printf("%-20s %-10s %-12s %-12s %-8s %-4d %-30s\n", + drive->label, type, total_str, free_str, drive->filesystem, + drive->pad_count, drive->mount_path); + } + } + + free_usb_device_registry(usb_devices); +} + int main(int argc, char* argv[]) { // Load preferences first @@ -273,6 +732,48 @@ int command_line_mode(int argc, char* argv[]) { } return 0; } + else if (strcmp(argv[1], "usb-list") == 0) { + list_usb_drives_v2(); + return 0; + } + else if (strcmp(argv[1], "usb-list-v2") == 0) { + list_usb_drives_v2(); + return 0; + } + else if (strcmp(argv[1], "usb-init") == 0) { + if (argc < 3) { + printf("Usage: %s usb-init [drive_path]\n", argv[0]); + printf("Examples:\n"); + printf(" %s usb-init OTP_BACKUP (interactive drive selection)\n", argv[0]); + printf(" %s usb-init OTP_BACKUP /media/user/USB_DRIVE\n", argv[0]); + return 1; + } + return handle_usb_init_cli(argc, argv); + } + else if (strcmp(argv[1], "usb-copy") == 0) { + if (argc < 4) { + printf("Usage: %s usb-copy \n", argv[0]); + printf("Example: %s usb-copy 1a2b3c /media/user/OTP_BACKUP\n", argv[0]); + return 1; + } + return handle_usb_copy_cli(argv[2], argv[3]); + } + else if (strcmp(argv[1], "usb-import") == 0) { + if (argc < 4) { + printf("Usage: %s usb-import \n", argv[0]); + printf("Example: %s usb-import 1a2b3c4d... /media/user/OTP_BACKUP\n", argv[0]); + return 1; + } + return handle_usb_import_cli(argv[2], argv[3]); + } + else if (strcmp(argv[1], "usb-verify") == 0) { + if (argc < 3) { + printf("Usage: %s usb-verify \n", argv[0]); + printf("Example: %s usb-verify /media/user/OTP_BACKUP\n", argv[0]); + return 1; + } + return handle_usb_verify_cli(argv[2]); + } else { print_usage(argv[0]); return 1; @@ -2183,10 +2684,1327 @@ int detect_otp_thumb_drive(char* otp_drive_path, size_t path_size) { return 0; // No OTP drive found } +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// USB DRIVE MANAGEMENT FUNCTIONS +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// USB Device Safety Functions +int is_device_removable_usb(const char* device_path) { + char removable_path[512]; + FILE* file; + char value; + + // Extract device name from path (e.g., /dev/sdb -> sdb) + const char* device_name = strrchr(device_path, '/'); + if (!device_name) return 0; + device_name++; // Skip the '/' + + // Remove partition number if present (e.g., sdb1 -> sdb) + char base_device[64]; + strncpy(base_device, device_name, sizeof(base_device) - 1); + base_device[sizeof(base_device) - 1] = '\0'; + + // Remove digits at the end to get base device name + int len = strlen(base_device); + while (len > 0 && isdigit(base_device[len - 1])) { + base_device[len - 1] = '\0'; + len--; + } + + // Check if device is marked as removable + snprintf(removable_path, sizeof(removable_path), "/sys/block/%s/removable", base_device); + file = fopen(removable_path, "r"); + if (!file) return 0; + + if (fread(&value, 1, 1, file) != 1 || value != '1') { + fclose(file); + return 0; + } + fclose(file); + + return 1; +} + +int get_device_bus_type(const char* device_path, char* bus_type, size_t bus_type_size) { + char sys_path[512]; + char link_target[512]; + ssize_t link_len; + + // Extract device name from path + const char* device_name = strrchr(device_path, '/'); + if (!device_name) return 0; + device_name++; // Skip the '/' + + // Remove partition number if present + char base_device[64]; + strncpy(base_device, device_name, sizeof(base_device) - 1); + base_device[sizeof(base_device) - 1] = '\0'; + + int len = strlen(base_device); + while (len > 0 && isdigit(base_device[len - 1])) { + base_device[len - 1] = '\0'; + len--; + } + + // Read the device symlink to determine bus type + snprintf(sys_path, sizeof(sys_path), "/sys/block/%s/device", base_device); + link_len = readlink(sys_path, link_target, sizeof(link_target) - 1); + if (link_len == -1) return 0; + + link_target[link_len] = '\0'; + + // Check for USB in the path + if (strstr(link_target, "usb")) { + strncpy(bus_type, "usb", bus_type_size - 1); + bus_type[bus_type_size - 1] = '\0'; + return 1; + } + + // Check for other bus types + if (strstr(link_target, "ata") || strstr(link_target, "scsi")) { + strncpy(bus_type, "ata", bus_type_size - 1); + bus_type[bus_type_size - 1] = '\0'; + return 1; + } + + strncpy(bus_type, "unknown", bus_type_size - 1); + bus_type[bus_type_size - 1] = '\0'; + return 1; +} + +int is_system_critical_mount(const char* mount_path) { + // List of critical system mount points that should never be formatted + const char* critical_mounts[] = { + "/", "/boot", "/boot/efi", "/home", "/usr", "/var", "/tmp", "/opt", + "/etc", "/lib", "/lib64", "/bin", "/sbin", "/sys", "/proc", "/dev" + }; + + const int num_critical_mounts = sizeof(critical_mounts) / sizeof(critical_mounts[0]); + + for (int i = 0; i < num_critical_mounts; i++) { + if (strcmp(mount_path, critical_mounts[i]) == 0) { + return 1; // This is a critical system mount + } + } + + return 0; // Not a critical system mount +} + +int validate_usb_device_safety(const usb_drive_info_t* drive) { + // Check if it's a system critical mount + if (is_system_critical_mount(drive->mount_path)) { + return 0; // Not safe - system critical + } + + // Check if device is removable + if (!drive->is_removable) { + return 0; // Not safe - not removable + } + + // Check if it's actually a USB device + if (!drive->is_usb_device) { + return 0; // Not safe - not USB + } + + // Check if bus type is USB + if (strcmp(drive->bus_type, "usb") != 0) { + return 0; // Not safe - not USB bus + } + + // Check drive size limit (1.1 TB = 1.1 * 1024^4 bytes) + const uint64_t max_drive_size = 1100ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL / 1000ULL; // 1.1 TB + if (drive->total_size > max_drive_size) { + return 0; // Not safe - drive too large (safety limit) + } + + return 1; // Safe for USB operations +} + +// Generate safety status letters for detailed failure reporting +void get_usb_safety_status(const usb_drive_info_t* drive, char* status, size_t status_size) { + if (!drive || !status || status_size < 6) { + if (status && status_size > 0) { + strncpy(status, "ERROR", status_size - 1); + status[status_size - 1] = '\0'; + } + return; + } + + // Check if all safety tests pass + if (validate_usb_device_safety(drive)) { + strncpy(status, "SAFE", status_size - 1); + status[status_size - 1] = '\0'; + return; + } + + // Build failure status with letters + char failures[6] = {0}; // Max 5 failure letters + null terminator + int failure_count = 0; + + // C - Critical Mount Check + if (is_system_critical_mount(drive->mount_path)) { + failures[failure_count++] = 'C'; + } + + // R - Removable Device Check + if (!drive->is_removable) { + failures[failure_count++] = 'R'; + } + + // U - USB Device Check + if (!drive->is_usb_device) { + failures[failure_count++] = 'U'; + } + + // B - Bus Type Validation + if (strcmp(drive->bus_type, "usb") != 0) { + failures[failure_count++] = 'B'; + } + + // S - Size Limit Check + const uint64_t max_drive_size = 1100ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL / 1000ULL; // 1.1 TB + if (drive->total_size > max_drive_size) { + failures[failure_count++] = 'S'; + } + + // Copy failure letters to status + if (failure_count > 0) { + strncpy(status, failures, status_size - 1); + status[status_size - 1] = '\0'; + } else { + // Shouldn't happen, but fallback + strncpy(status, "UNK", status_size - 1); + status[status_size - 1] = '\0'; + } +} + +int extract_device_name_from_path(const char* device_path, char* device_name, size_t device_name_size) { + const char* name_start = strrchr(device_path, '/'); + if (!name_start) return 0; + + name_start++; // Skip the '/' + strncpy(device_name, name_start, device_name_size - 1); + device_name[device_name_size - 1] = '\0'; + + return 1; +} + + +// Discover all available USB drives on the system +int discover_usb_drives(usb_drive_info_t** drives, int* drive_count) { + if (!drives || !drive_count) { + return 1; // Error: invalid parameters + } + + // Initialize output + *drives = NULL; + *drive_count = 0; + + // Allocate array for USB drive information + usb_drive_info_t* drive_array = malloc(MAX_USB_DRIVES * sizeof(usb_drive_info_t)); + if (!drive_array) { + return 2; // Error: memory allocation failed + } + + int found_count = 0; + const char* mount_dirs[] = {"/media", "/run/media", "/mnt", NULL}; + + // Search through common mount directories + for (int mount_idx = 0; mount_dirs[mount_idx] != NULL && found_count < MAX_USB_DRIVES; mount_idx++) { + DIR* mount_dir = opendir(mount_dirs[mount_idx]); + if (!mount_dir) continue; + + struct dirent* mount_entry; + while ((mount_entry = readdir(mount_dir)) != NULL && found_count < MAX_USB_DRIVES) { + if (mount_entry->d_name[0] == '.') continue; + + char mount_path[1024]; + snprintf(mount_path, sizeof(mount_path), "%s/%s", mount_dirs[mount_idx], mount_entry->d_name); + + // Handle different mount directory structures + if (strcmp(mount_dirs[mount_idx], "/media") == 0) { + // /media/[username] - look inside for drives + DIR* user_dir = opendir(mount_path); + if (!user_dir) continue; + + struct dirent* user_entry; + while ((user_entry = readdir(user_dir)) != NULL && found_count < MAX_USB_DRIVES) { + if (user_entry->d_name[0] == '.') continue; + + char drive_path[2048]; + snprintf(drive_path, sizeof(drive_path), "%s/%s", mount_path, user_entry->d_name); + + // Check if this is a readable directory (mounted drive) + DIR* drive_dir = opendir(drive_path); + if (drive_dir) { + closedir(drive_dir); + + // Get drive information - include ALL drives for debugging + usb_drive_info_t* drive = &drive_array[found_count]; + if (get_usb_drive_info(drive_path, user_entry->d_name, drive) == 0) { + // Store safety validation result in the drive structure + drive->is_safe = validate_usb_device_safety(drive); + found_count++; + } + } + } + closedir(user_dir); + + } else if (strcmp(mount_dirs[mount_idx], "/run/media") == 0) { + // /run/media/[username] - look inside for drives + DIR* user_dir = opendir(mount_path); + if (!user_dir) continue; + + struct dirent* user_entry; + while ((user_entry = readdir(user_dir)) != NULL && found_count < MAX_USB_DRIVES) { + if (user_entry->d_name[0] == '.') continue; + + char drive_path[2048]; + snprintf(drive_path, sizeof(drive_path), "%s/%s", mount_path, user_entry->d_name); + + DIR* drive_dir = opendir(drive_path); + if (drive_dir) { + closedir(drive_dir); + + usb_drive_info_t* drive = &drive_array[found_count]; + if (get_usb_drive_info(drive_path, user_entry->d_name, drive) == 0) { + // Store safety validation result in the drive structure + drive->is_safe = validate_usb_device_safety(drive); + found_count++; + } + } + } + closedir(user_dir); + + } else { + // Direct mount point (like /mnt/DRIVE_NAME) + DIR* drive_dir = opendir(mount_path); + if (drive_dir) { + closedir(drive_dir); + + usb_drive_info_t* drive = &drive_array[found_count]; + if (get_usb_drive_info(mount_path, mount_entry->d_name, drive) == 0) { + // Store safety validation result in the drive structure + drive->is_safe = validate_usb_device_safety(drive); + found_count++; + } + } + } + } + closedir(mount_dir); + } + + if (found_count == 0) { + free(drive_array); + return 3; // Error: no drives found + } + + // Resize array to actual count + usb_drive_info_t* final_array = realloc(drive_array, found_count * sizeof(usb_drive_info_t)); + if (!final_array) { + // Keep original array if realloc fails + final_array = drive_array; + } + + *drives = final_array; + *drive_count = found_count; + + return 0; // Success +} + +// Get detailed information about a USB drive +int get_usb_drive_info(const char* mount_path, const char* drive_label, usb_drive_info_t* drive_info) { + if (!mount_path || !drive_label || !drive_info) { + return 1; + } + + // Initialize drive info structure + memset(drive_info, 0, sizeof(usb_drive_info_t)); + + // Set basic information + strncpy(drive_info->mount_path, mount_path, sizeof(drive_info->mount_path) - 1); + strncpy(drive_info->volume_label, drive_label, sizeof(drive_info->volume_label) - 1); + + // Check if it's an OTP drive (label starts with "OTP_") + drive_info->is_otp_drive = (strncmp(drive_label, "OTP_", 4) == 0); + + // Enhanced device path detection with multiple methods + char device_path[256] = ""; + int device_found = 0; + + // Method 1: Enhanced /proc/mounts parsing + FILE* mounts = fopen("/proc/mounts", "r"); + if (mounts) { + char line[1024]; + while (fgets(line, sizeof(line), mounts)) { + char device[256], mountpoint[512], fstype[64]; + // Use more robust parsing that handles escaped characters + if (sscanf(line, "%255s %511s %63s", device, mountpoint, fstype) == 3) { + // Handle escaped characters in mount paths (octal sequences like \040 for space) + char decoded_mountpoint[512]; + size_t src = 0, dst = 0; + size_t mountpoint_len = strlen(mountpoint); + while (src < mountpoint_len && dst < sizeof(decoded_mountpoint) - 1) { + if (mountpoint[src] == '\\' && src + 3 < mountpoint_len && + mountpoint[src + 1] >= '0' && mountpoint[src + 1] <= '7') { + // Decode octal escape sequence + int octal_val = (mountpoint[src + 1] - '0') * 64 + + (mountpoint[src + 2] - '0') * 8 + + (mountpoint[src + 3] - '0'); + decoded_mountpoint[dst++] = (char)octal_val; + src += 4; + } else { + decoded_mountpoint[dst++] = mountpoint[src++]; + } + } + decoded_mountpoint[dst] = '\0'; + + // Debug: Print comparison details for DUAL DRIVE debugging + if (strstr(mount_path, "DUAL DRIVE") || strstr(decoded_mountpoint, "DUAL DRIVE")) { + printf("DEBUG Method1: mount_path='%s', decoded='%s', device='%s', match=%d\n", + mount_path, decoded_mountpoint, device, + strcmp(decoded_mountpoint, mount_path) == 0); + } + + if (strcmp(decoded_mountpoint, mount_path) == 0) { + strncpy(device_path, device, sizeof(device_path) - 1); + device_path[sizeof(device_path) - 1] = '\0'; + strncpy(drive_info->filesystem, fstype, sizeof(drive_info->filesystem) - 1); + drive_info->filesystem[sizeof(drive_info->filesystem) - 1] = '\0'; + device_found = 1; + break; + } + } + } + fclose(mounts); + } + + // Method 2: Try /proc/self/mountinfo for more detailed information + if (!device_found) { + FILE* mountinfo = fopen("/proc/self/mountinfo", "r"); + if (mountinfo) { + char line[1024]; + while (fgets(line, sizeof(line), mountinfo)) { + // Parse mountinfo format: mountid parentid major:minor root mount_point options - fstype source + char *token = strtok(line, " "); + int field_count = 0; + char *mount_field = NULL, *source_field = NULL; + + while (token && field_count < 10) { + field_count++; + if (field_count == 5) { // mount point field + mount_field = token; + } else if (field_count == 9) { // source field (after fstype) + source_field = token; + break; + } + token = strtok(NULL, " "); + } + + if (mount_field && source_field) { + // Decode escaped characters in mount point + char decoded_mount[512]; + size_t src = 0, dst = 0; + size_t mount_field_len = strlen(mount_field); + while (src < mount_field_len && dst < sizeof(decoded_mount) - 1) { + if (mount_field[src] == '\\' && src + 3 < mount_field_len) { + int octal_val = (mount_field[src + 1] - '0') * 64 + + (mount_field[src + 2] - '0') * 8 + + (mount_field[src + 3] - '0'); + decoded_mount[dst++] = (char)octal_val; + src += 4; + } else { + decoded_mount[dst++] = mount_field[src++]; + } + } + decoded_mount[dst] = '\0'; + + // Debug: Print comparison details for DUAL DRIVE debugging + if (strstr(mount_path, "DUAL DRIVE") || strstr(decoded_mount, "DUAL DRIVE")) { + printf("DEBUG Method2: mount_path='%s', decoded='%s', source='%s', match=%d\n", + mount_path, decoded_mount, source_field, + strcmp(decoded_mount, mount_path) == 0); + } + + if (strcmp(decoded_mount, mount_path) == 0) { + strncpy(device_path, source_field, sizeof(device_path) - 1); + device_path[sizeof(device_path) - 1] = '\0'; + device_found = 1; + break; + } + } + } + fclose(mountinfo); + } + } + + // Method 3: Enhanced smart inference from mount path patterns if device detection failed + int inferred_usb = 0; + if (!device_found) { + // Enhanced USB mount path pattern detection + if (strstr(mount_path, "/media/") || strstr(mount_path, "/run/media/")) { + // All /media/ and /run/media/ paths are highly likely to be USB drives + inferred_usb = 1; + strncpy(drive_info->device_name, "inferred_usb", sizeof(drive_info->device_name) - 1); + strncpy(drive_info->bus_type, "usb", sizeof(drive_info->bus_type) - 1); + } else if (strstr(mount_path, "/mnt/") && + (strstr(mount_path, "USB") || strstr(mount_path, "usb") || + strstr(mount_path, "DRIVE") || strstr(mount_path, "DISK"))) { + // /mnt/ paths with USB-like naming + inferred_usb = 1; + strncpy(drive_info->device_name, "inferred_usb", sizeof(drive_info->device_name) - 1); + strncpy(drive_info->bus_type, "usb", sizeof(drive_info->bus_type) - 1); + } else { + strncpy(drive_info->device_name, "unknown", sizeof(drive_info->device_name) - 1); + strncpy(drive_info->bus_type, "unknown", sizeof(drive_info->bus_type) - 1); + } + + // Set filesystem to unknown if not determined above + if (strlen(drive_info->filesystem) == 0) { + strncpy(drive_info->filesystem, "unknown", sizeof(drive_info->filesystem) - 1); + } + } + + // Debug: Print final device detection results for DUAL DRIVE + if (strstr(mount_path, "DUAL DRIVE")) { + printf("DEBUG Final: mount_path='%s', device_found=%d, device_path='%s', inferred_usb=%d\n", + mount_path, device_found, device_path, inferred_usb); + } + + // Populate safety fields using the USB safety functions + if (device_found && strlen(device_path) > 0) { + // Extract device name from device path + extract_device_name_from_path(device_path, drive_info->device_name, sizeof(drive_info->device_name)); + + // Check if device is removable + drive_info->is_removable = is_device_removable_usb(device_path); + + // Get bus type + get_device_bus_type(device_path, drive_info->bus_type, sizeof(drive_info->bus_type)); + + // Check if it's a USB device (based on bus type) + drive_info->is_usb_device = (strcmp(drive_info->bus_type, "usb") == 0); + + // Check if it's a system critical mount + drive_info->is_system_mount = is_system_critical_mount(mount_path); + } else if (inferred_usb) { + // Use smart inference for likely USB drives when device detection fails + drive_info->is_removable = 1; // Assume removable for USB mount paths + drive_info->is_usb_device = 1; // Inferred as USB device + drive_info->is_system_mount = is_system_critical_mount(mount_path); + } else { + // Conservative fallback - mark as unknown but not unsafe unless proven otherwise + drive_info->is_removable = 0; // Cannot determine, assume non-removable + drive_info->is_usb_device = 0; // Cannot determine, assume non-USB + drive_info->is_system_mount = is_system_critical_mount(mount_path); + } + + // Get filesystem information using statvfs + struct statvfs vfs; + if (statvfs(mount_path, &vfs) == 0) { + drive_info->total_size = (uint64_t)vfs.f_blocks * vfs.f_frsize; + drive_info->available_size = (uint64_t)vfs.f_bavail * vfs.f_frsize; + } else { + // Fallback: try to get basic directory info + struct stat st; + if (stat(mount_path, &st) == 0) { + drive_info->total_size = 0; // Unknown + drive_info->available_size = 0; // Unknown + } else { + return 2; // Cannot access drive + } + } + + // Count OTP pad files if it's an OTP drive + drive_info->pad_count = 0; + if (drive_info->is_otp_drive) { + DIR* dir = opendir(mount_path); + if (dir) { + struct dirent* entry; + while ((entry = readdir(dir)) != NULL) { + if (strstr(entry->d_name, ".pad") && strlen(entry->d_name) == 68) { + drive_info->pad_count++; + } + } + closedir(dir); + } + } + + // Set mount status (assume mounted since we can access it) + drive_info->is_mounted = 1; + + return 0; // Success +} + +// Initialize a USB drive for OTP use +usb_operation_result_t initialize_usb_drive(const char* mount_path, const char* drive_name, + int format_drive, const char* filesystem_type) { + usb_operation_result_t result = {0}; + + if (!mount_path || !drive_name) { + result.success = 0; + strncpy(result.error_message, "Invalid parameters", sizeof(result.error_message) - 1); + return result; + } + + // Validate drive name format + if (strncmp(drive_name, "OTP_", 4) != 0) { + result.success = 0; + strncpy(result.error_message, "Drive name must start with 'OTP_'", sizeof(result.error_message) - 1); + return result; + } + + if (strlen(drive_name) > 32 || strlen(drive_name) < 5) { + result.success = 0; + strncpy(result.error_message, "Drive name must be 5-32 characters", sizeof(result.error_message) - 1); + return result; + } + + // Check if drive is writable + if (access(mount_path, W_OK) != 0) { + result.success = 0; + strncpy(result.error_message, "Drive is not writable", sizeof(result.error_message) - 1); + return result; + } + + // Format drive if requested + if (format_drive) { + printf("Formatting USB drive (this may take several minutes)...\n"); + + // Get device path from mount path + char device_path[256] = ""; + if (get_device_from_mount(mount_path, device_path, sizeof(device_path)) != 0) { + result.success = 0; + strncpy(result.error_message, "Cannot determine device path", sizeof(result.error_message) - 1); + return result; + } + + // Unmount before formatting + char umount_cmd[512]; + snprintf(umount_cmd, sizeof(umount_cmd), "umount '%s' 2>/dev/null", mount_path); + system(umount_cmd); // Ignore errors + + // Format with specified filesystem + char format_cmd[512]; + if (strcmp(filesystem_type, "fat32") == 0) { + snprintf(format_cmd, sizeof(format_cmd), + "mkfs.fat -F32 -n '%s' '%s' 2>/dev/null", drive_name, device_path); + } else if (strcmp(filesystem_type, "ext4") == 0) { + snprintf(format_cmd, sizeof(format_cmd), + "mkfs.ext4 -L '%s' '%s' -F 2>/dev/null", drive_name, device_path); + } else { + result.success = 0; + strncpy(result.error_message, "Unsupported filesystem type", sizeof(result.error_message) - 1); + return result; + } + + if (system(format_cmd) != 0) { + result.success = 0; + strncpy(result.error_message, "Format operation failed", sizeof(result.error_message) - 1); + return result; + } + + // Wait for system to recognize the new filesystem + sleep(2); + + // Remount (let system handle this automatically) + printf("Format completed. Please remount the drive if necessary.\n"); + } + + // Set volume label if not formatting + if (!format_drive) { + if (set_volume_label(mount_path, drive_name) != 0) { + result.success = 0; + strncpy(result.error_message, "Failed to set volume label", sizeof(result.error_message) - 1); + return result; + } + } + + // Create OTP directory structure if needed + char otp_readme_path[1024]; + snprintf(otp_readme_path, sizeof(otp_readme_path), "%s/OTP_README.txt", mount_path); + + FILE* readme = fopen(otp_readme_path, "w"); + if (readme) { + fprintf(readme, "OTP Drive: %s\n", drive_name); + time_t init_time = time(NULL); + fprintf(readme, "Initialized: %s", ctime(&init_time)); + fprintf(readme, "\nThis USB drive has been initialized for use with the OTP program.\n"); + fprintf(readme, "OTP pad files stored on this drive use the same .pad/.state format\n"); + fprintf(readme, "as local pads and can be used for encryption/decryption operations.\n"); + fprintf(readme, "\nDO NOT modify .pad or .state files manually!\n"); + fprintf(readme, "Use the OTP program's pad management features instead.\n"); + fclose(readme); + } + + result.success = 1; + // Success details are in the error_message field for simplicity + strncpy(result.error_message, "USB drive initialized successfully", sizeof(result.error_message) - 1); + + return result; +} + +// Set volume label for a USB drive +int set_volume_label(const char* mount_path, const char* new_label) { + if (!mount_path || !new_label) { + return 1; + } + + // Get device path + char device_path[256]; + if (get_device_from_mount(mount_path, device_path, sizeof(device_path)) != 0) { + return 2; + } + + // Try different labeling methods based on filesystem + char label_cmd[512]; + + // First try FAT32 labeling + snprintf(label_cmd, sizeof(label_cmd), "fatlabel '%s' '%s' 2>/dev/null", device_path, new_label); + if (system(label_cmd) == 0) { + return 0; + } + + // Try ext filesystem labeling + snprintf(label_cmd, sizeof(label_cmd), "e2label '%s' '%s' 2>/dev/null", device_path, new_label); + if (system(label_cmd) == 0) { + return 0; + } + + // Try generic tune2fs for ext filesystems + snprintf(label_cmd, sizeof(label_cmd), "tune2fs -L '%s' '%s' 2>/dev/null", new_label, device_path); + if (system(label_cmd) == 0) { + return 0; + } + + return 3; // All methods failed +} + +// Get device path from mount path +int get_device_from_mount(const char* mount_path, char* device_path, size_t device_path_size) { + if (!mount_path || !device_path) { + return 1; + } + + FILE* mounts = fopen("/proc/mounts", "r"); + if (!mounts) { + return 2; + } + + char line[1024]; + while (fgets(line, sizeof(line), mounts)) { + char device[256], mountpoint[512]; + if (sscanf(line, "%s %s", device, mountpoint) == 2) { + if (strcmp(mountpoint, mount_path) == 0) { + strncpy(device_path, device, device_path_size - 1); + device_path[device_path_size - 1] = '\0'; + fclose(mounts); + return 0; + } + } + } + + fclose(mounts); + return 3; // Mount point not found +} + +// Select USB drive interactively +usb_drive_info_t* select_usb_drive_interactive(const char* title, const char* prompt, int require_otp) { + usb_drive_info_t* drives; + int drive_count; + + printf("\n%s\n", title); + printf("Scanning for USB drives...\n"); + + int result = discover_usb_drives(&drives, &drive_count); + if (result != 0) { + switch (result) { + case 3: // USB_ERROR_NO_DRIVES_FOUND + printf("No USB drives found.\n"); + printf("Please ensure your USB drive is properly mounted.\n"); + break; + case 2: // USB_ERROR_MEMORY_ALLOCATION + printf("Error: Memory allocation failed.\n"); + break; + default: + printf("Error: Failed to discover USB drives (code: %d).\n", result); + break; + } + return NULL; + } + + // Count safe drives that meet requirements + int safe_filtered_count = 0; + int total_filtered_count = 0; + for (int i = 0; i < drive_count; i++) { + if (!require_otp || drives[i].is_otp_drive) { + total_filtered_count++; + if (drives[i].is_safe) { + safe_filtered_count++; + } + } + } + + if (total_filtered_count == 0) { + if (require_otp) { + printf("No OTP USB drives found.\n"); + printf("Initialize a USB drive first using the 'Initialize USB drive' option.\n"); + } else { + printf("No USB drives found.\n"); + } + free(drives); + return NULL; + } + + // Display available drives with safety indicators + printf("\nFound USB drives:\n"); + printf("%-3s %-20s %-10s %-12s %-12s %-8s %-4s %-6s\n", + "#", "Label", "Type", "Total", "Free", "FS", "Pads", "Status"); + printf("%-3s %-20s %-10s %-12s %-12s %-8s %-4s %-6s\n", + "---", "--------------------", "----------", "----------", "----------", "--------", "----", "------"); + + int display_index = 1; + int safe_display_index = 1; + for (int i = 0; i < drive_count; i++) { + if (require_otp && !drives[i].is_otp_drive) { + continue; // Skip non-OTP drives when filtering + } + + // Format sizes for display + char total_str[16], free_str[16]; + format_size_string(drives[i].total_size, total_str, sizeof(total_str)); + format_size_string(drives[i].available_size, free_str, sizeof(free_str)); + + // Display with appropriate formatting + if (drives[i].is_safe) { + // Safe drive - normal display with selectable number + printf("%-3d %-20s %-10s %-12s %-12s %-8s %-4d %-6s\n", + safe_display_index, + drives[i].volume_label, + drives[i].is_otp_drive ? "OTP" : "Standard", + total_str, + free_str, + drives[i].filesystem, + drives[i].pad_count, + "SAFE"); + safe_display_index++; + } else { + // Unsafe drive - strikethrough display, no selection number + printf("%-3s \033[9m%-20s %-10s %-12s %-12s %-8s %-4d\033[0m %-6s\n", + "---", + drives[i].volume_label, + drives[i].is_otp_drive ? "OTP" : "Standard", + total_str, + free_str, + drives[i].filesystem, + drives[i].pad_count, + "UNSAFE"); + } + display_index++; + } + + if (safe_filtered_count == 0) { + printf("\n⚠ WARNING: No safe USB drives found!\n"); + printf("All detected drives failed safety validation.\n"); + printf("Common issues: System drives, non-removable media, non-USB devices\n"); + free(drives); + return NULL; + } + + printf("\n%s (1-%d): ", prompt, safe_filtered_count); + + char input[10]; + if (!fgets(input, sizeof(input), stdin)) { + free(drives); + return NULL; + } + + int selection = atoi(input); + if (selection < 1 || selection > safe_filtered_count) { + printf("Invalid selection.\n"); + free(drives); + return NULL; + } + + // Find the selected safe drive (accounting for filtering and safety) + int current_safe_index = 1; + for (int i = 0; i < drive_count; i++) { + if (require_otp && !drives[i].is_otp_drive) { + continue; + } + + if (drives[i].is_safe) { + if (current_safe_index == selection) { + // Create a copy of the selected drive info + usb_drive_info_t* selected_drive = malloc(sizeof(usb_drive_info_t)); + if (selected_drive) { + *selected_drive = drives[i]; + } + free(drives); + return selected_drive; + } + current_safe_index++; + } + } + + free(drives); + return NULL; +} + +// Format file size for display +void format_size_string(uint64_t bytes, char* result, size_t result_size) { + if (bytes == 0) { + strncpy(result, "Unknown", result_size - 1); + result[result_size - 1] = '\0'; + return; + } + + if (bytes < 1024) { + snprintf(result, result_size, "%luB", bytes); + } else if (bytes < 1024 * 1024) { + snprintf(result, result_size, "%.1fKB", (double)bytes / 1024.0); + } else if (bytes < 1024 * 1024 * 1024) { + snprintf(result, result_size, "%.1fMB", (double)bytes / (1024.0 * 1024.0)); + } else if (bytes < 1024ULL * 1024 * 1024 * 1024) { + snprintf(result, result_size, "%.2fGB", (double)bytes / (1024.0 * 1024.0 * 1024.0)); + } else { + snprintf(result, result_size, "%.2fTB", (double)bytes / (1024.0 * 1024.0 * 1024.0 * 1024.0)); + } +} + + // Custom base64 encode function + +// Copy pad from local storage to USB drive +int copy_pad_to_usb(const char* pad_checksum, const char* usb_mount_path) { + if (!pad_checksum || !usb_mount_path) { + printf("Error: Invalid parameters for pad copy operation\n"); + return 1; + } + + // Build source paths + char local_pad_path[1024], local_state_path[1024]; + get_pad_path(pad_checksum, local_pad_path, local_state_path); + + // Check if local pad exists + if (access(local_pad_path, R_OK) != 0) { + printf("Error: Local pad file not found: %s\n", local_pad_path); + return 2; + } + + // Build destination paths + char usb_pad_path[1024], usb_state_path[1024]; + snprintf(usb_pad_path, sizeof(usb_pad_path), "%s/%s.pad", usb_mount_path, pad_checksum); + snprintf(usb_state_path, sizeof(usb_state_path), "%s/%s.state", usb_mount_path, pad_checksum); + + // Check if destination pad already exists + if (access(usb_pad_path, F_OK) == 0) { + printf("Warning: Pad already exists on USB drive: %s\n", pad_checksum); + printf("Overwrite? (y/N): "); + fflush(stdout); + + char response[10]; + if (fgets(response, sizeof(response), stdin) == NULL || + (response[0] != 'y' && response[0] != 'Y')) { + printf("Copy operation cancelled.\n"); + return 3; + } + } + + // Copy pad file + printf("Copying pad file...\n"); + if (copy_file(local_pad_path, usb_pad_path) != 0) { + printf("Error: Failed to copy pad file to USB drive\n"); + return 4; + } + + // Copy state file if it exists + if (access(local_state_path, R_OK) == 0) { + printf("Copying state file...\n"); + if (copy_file(local_state_path, usb_state_path) != 0) { + printf("Warning: Failed to copy state file (pad file copied successfully)\n"); + // This is not fatal - pad can still be used + } + } + + // Verify the copy + printf("Verifying integrity...\n"); + if (verify_pad_integrity_cross_drive(local_pad_path, usb_pad_path) != 0) { + printf("Error: Integrity verification failed - removing corrupted copy\n"); + unlink(usb_pad_path); + unlink(usb_state_path); + return 5; + } + + printf("✓ Pad successfully copied to USB drive: %.16s...\n", pad_checksum); + return 0; +} + +// Copy pad from USB drive to local storage +int copy_pad_from_usb(const char* usb_mount_path, const char* pad_checksum) { + if (!usb_mount_path || !pad_checksum) { + printf("Error: Invalid parameters for pad import operation\n"); + return 1; + } + + // Build source paths on USB + char usb_pad_path[1024], usb_state_path[1024]; + snprintf(usb_pad_path, sizeof(usb_pad_path), "%s/%s.pad", usb_mount_path, pad_checksum); + snprintf(usb_state_path, sizeof(usb_state_path), "%s/%s.state", usb_mount_path, pad_checksum); + + // Check if USB pad exists + if (access(usb_pad_path, R_OK) != 0) { + printf("Error: Pad file not found on USB drive: %s\n", pad_checksum); + return 2; + } + + // Build destination paths + char local_pad_path[1024], local_state_path[1024]; + get_pad_path(pad_checksum, local_pad_path, local_state_path); + + // Check if local pad already exists + if (access(local_pad_path, F_OK) == 0) { + printf("Warning: Pad already exists locally: %s\n", pad_checksum); + printf("Overwrite? (y/N): "); + fflush(stdout); + + char response[10]; + if (fgets(response, sizeof(response), stdin) == NULL || + (response[0] != 'y' && response[0] != 'Y')) { + printf("Import operation cancelled.\n"); + return 3; + } + } + + // Ensure pads directory exists + if (ensure_pads_directory() != 0) { + printf("Error: Cannot create local pads directory\n"); + return 4; + } + + // Copy pad file from USB + printf("Importing pad file...\n"); + if (copy_file(usb_pad_path, local_pad_path) != 0) { + printf("Error: Failed to import pad file from USB drive\n"); + return 5; + } + + // Set pad file to read-only + if (chmod(local_pad_path, S_IRUSR) != 0) { + printf("Warning: Cannot set pad file to read-only\n"); + } + + // Copy state file if it exists + if (access(usb_state_path, R_OK) == 0) { + printf("Importing state file...\n"); + if (copy_file(usb_state_path, local_state_path) != 0) { + printf("Warning: Failed to import state file (pad file imported successfully)\n"); + // Create a fresh state file with default offset + FILE* new_state = fopen(local_state_path, "wb"); + if (new_state) { + uint64_t default_offset = 32; // Reserved bytes + fwrite(&default_offset, sizeof(uint64_t), 1, new_state); + fclose(new_state); + printf("Created new state file with default offset\n"); + } + } + } else { + // Create state file if it doesn't exist + printf("Creating state file...\n"); + FILE* new_state = fopen(local_state_path, "wb"); + if (new_state) { + uint64_t default_offset = 32; // Reserved bytes + fwrite(&default_offset, sizeof(uint64_t), 1, new_state); + fclose(new_state); + } + } + + // Verify the import + printf("Verifying integrity...\n"); + if (verify_pad_integrity_cross_drive(usb_pad_path, local_pad_path) != 0) { + printf("Error: Integrity verification failed - removing corrupted import\n"); + unlink(local_pad_path); + unlink(local_state_path); + return 6; + } + + printf("✓ Pad successfully imported from USB drive: %.16s...\n", pad_checksum); + return 0; +} + +// Generic file copy function +int copy_file(const char* source_path, const char* dest_path) { + if (!source_path || !dest_path) { + return 1; + } + + FILE* source = fopen(source_path, "rb"); + if (!source) { + return 2; + } + + FILE* dest = fopen(dest_path, "wb"); + if (!dest) { + fclose(source); + return 3; + } + + // Copy in chunks for large files + unsigned char buffer[64 * 1024]; // 64KB buffer + size_t bytes_read; + int error = 0; + + while ((bytes_read = fread(buffer, 1, sizeof(buffer), source)) > 0) { + if (fwrite(buffer, 1, bytes_read, dest) != bytes_read) { + error = 4; // Write error + break; + } + } + + fclose(source); + fclose(dest); + + if (error) { + unlink(dest_path); // Remove incomplete file + return error; + } + + return 0; +} + +// List pads available on a USB drive +int list_pads_on_drive(const char* mount_path, char pad_list[][65], int max_pads) { + if (!mount_path || !pad_list || max_pads <= 0) { + return -1; + } + + DIR* dir = opendir(mount_path); + if (!dir) { + return -2; + } + + int pad_count = 0; + struct dirent* entry; + + while ((entry = readdir(dir)) != NULL && pad_count < max_pads) { + // Check if this is a pad file + if (strstr(entry->d_name, ".pad") && strlen(entry->d_name) == 68) { + // Extract checksum (remove .pad extension) + strncpy(pad_list[pad_count], entry->d_name, 64); + pad_list[pad_count][64] = '\0'; + pad_count++; + } + } + + closedir(dir); + return pad_count; +} + +// Verify integrity between two pad files (cross-drive verification) +int verify_pad_integrity_cross_drive(const char* source_pad, const char* dest_pad) { + if (!source_pad || !dest_pad) { + return 1; + } + + // Calculate checksums of both files + char source_checksum[65], dest_checksum[65]; + + if (calculate_checksum(source_pad, source_checksum) != 0) { + printf("Error: Cannot calculate source pad checksum\n"); + return 2; + } + + if (calculate_checksum(dest_pad, dest_checksum) != 0) { + printf("Error: Cannot calculate destination pad checksum\n"); + return 3; + } + + // Compare checksums + if (strcmp(source_checksum, dest_checksum) != 0) { + printf("Error: Pad integrity verification failed\n"); + printf("Source: %s\n", source_checksum); + printf("Destination: %s\n", dest_checksum); + return 4; + } + + // Also verify file sizes match + struct stat source_stat, dest_stat; + if (stat(source_pad, &source_stat) != 0 || stat(dest_pad, &dest_stat) != 0) { + printf("Error: Cannot verify file sizes\n"); + return 5; + } + + if (source_stat.st_size != dest_stat.st_size) { + printf("Error: File sizes don't match\n"); + printf("Source: %lu bytes, Destination: %lu bytes\n", + source_stat.st_size, dest_stat.st_size); + return 6; + } + + return 0; // Verification successful +} + +// Selective drive duplication with pad selection +int duplicate_drive_selective(const char* source_mount, const char* dest_mount, + char selected_pads[][65], int pad_count) { + if (!source_mount || !dest_mount || !selected_pads || pad_count <= 0) { + printf("Error: Invalid parameters for drive duplication\n"); + return 1; + } + + printf("Starting selective drive duplication...\n"); + printf("Source: %s\n", source_mount); + printf("Destination: %s\n", dest_mount); + printf("Pads to copy: %d\n\n", pad_count); + + int success_count = 0; + int error_count = 0; + + // Copy each selected pad + for (int i = 0; i < pad_count; i++) { + printf("[%d/%d] Copying pad: %.16s...\n", i + 1, pad_count, selected_pads[i]); + + // Build source paths + char source_pad[1024], source_state[1024]; + snprintf(source_pad, sizeof(source_pad), "%s/%s.pad", source_mount, selected_pads[i]); + snprintf(source_state, sizeof(source_state), "%s/%s.state", source_mount, selected_pads[i]); + + // Build destination paths + char dest_pad[1024], dest_state[1024]; + snprintf(dest_pad, sizeof(dest_pad), "%s/%s.pad", dest_mount, selected_pads[i]); + snprintf(dest_state, sizeof(dest_state), "%s/%s.state", dest_mount, selected_pads[i]); + + // Check source pad exists + if (access(source_pad, R_OK) != 0) { + printf(" Error: Source pad not found - skipping\n"); + error_count++; + continue; + } + + // Copy pad file + if (copy_file(source_pad, dest_pad) != 0) { + printf(" Error: Failed to copy pad file - skipping\n"); + error_count++; + continue; + } + + // Copy state file if it exists + if (access(source_state, R_OK) == 0) { + if (copy_file(source_state, dest_state) != 0) { + printf(" Warning: Failed to copy state file\n"); + // Create default state file + FILE* new_state = fopen(dest_state, "wb"); + if (new_state) { + uint64_t default_offset = 32; + fwrite(&default_offset, sizeof(uint64_t), 1, new_state); + fclose(new_state); + } + } + } else { + // Create default state file + FILE* new_state = fopen(dest_state, "wb"); + if (new_state) { + uint64_t default_offset = 32; + fwrite(&default_offset, sizeof(uint64_t), 1, new_state); + fclose(new_state); + } + } + + // Verify integrity + if (verify_pad_integrity_cross_drive(source_pad, dest_pad) != 0) { + printf(" Error: Integrity verification failed - removing copy\n"); + unlink(dest_pad); + unlink(dest_state); + error_count++; + continue; + } + + printf(" ✓ Success\n"); + success_count++; + } + + printf("\nDuplication completed:\n"); + printf("Successfully copied: %d pads\n", success_count); + printf("Errors encountered: %d pads\n", error_count); + + return (error_count > 0) ? error_count : 0; +} + +// Verify complete drive duplication +int verify_drive_duplication(const char* source_mount, const char* dest_mount) { + if (!source_mount || !dest_mount) { + return 1; + } + + printf("Verifying drive duplication...\n"); + + // Get list of pads on source drive + char source_pads[100][65]; + int source_count = list_pads_on_drive(source_mount, source_pads, 100); + if (source_count < 0) { + printf("Error: Cannot list pads on source drive\n"); + return 2; + } + + // Get list of pads on destination drive + char dest_pads[100][65]; + int dest_count = list_pads_on_drive(dest_mount, dest_pads, 100); + if (dest_count < 0) { + printf("Error: Cannot list pads on destination drive\n"); + return 3; + } + + printf("Source drive: %d pads\n", source_count); + printf("Destination drive: %d pads\n", dest_count); + + int verified_count = 0; + int error_count = 0; + + // Verify each pad on source exists on destination and matches + for (int i = 0; i < source_count; i++) { + printf("Verifying pad: %.16s...\n", source_pads[i]); + + // Check if this pad exists on destination + int found = 0; + for (int j = 0; j < dest_count; j++) { + if (strcmp(source_pads[i], dest_pads[j]) == 0) { + found = 1; + break; + } + } + + if (!found) { + printf(" Error: Pad missing on destination drive\n"); + error_count++; + continue; + } + + // Verify integrity + char source_path[1024], dest_path[1024]; + snprintf(source_path, sizeof(source_path), "%s/%s.pad", source_mount, source_pads[i]); + snprintf(dest_path, sizeof(dest_path), "%s/%s.pad", dest_mount, source_pads[i]); + + if (verify_pad_integrity_cross_drive(source_path, dest_path) != 0) { + printf(" Error: Integrity verification failed\n"); + error_count++; + continue; + } + + printf(" ✓ Verified\n"); + verified_count++; + } + + printf("\nVerification completed:\n"); + printf("Successfully verified: %d pads\n", verified_count); + printf("Errors found: %d pads\n", error_count); + + return (error_count > 0) ? error_count : 0; +} + char* custom_base64_encode(const unsigned char* input, int length) { int output_length = 4 * ((length + 2) / 3); char* encoded = malloc(output_length + 1); @@ -2258,6 +4076,372 @@ unsigned char* custom_base64_decode(const char* input, int* output_length) { //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// TRUERNG DEVICE DETECTION AND COMMUNICATION +// Ported from true_rng/main.c for entropy collection +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// Read USB device info from sysfs (ported from TrueRNG reference) +int read_usb_device_info(const char* port_name, char* vid, char* pid) { + char path[512]; + FILE *fp; + + // Try to read idVendor first (works for both ttyUSB and ttyACM devices) + snprintf(path, sizeof(path), "/sys/class/tty/%s/device/../idVendor", port_name); + fp = fopen(path, "r"); + if (fp) { + if (fgets(vid, 8, fp) != NULL) { + // Remove newline if present + int len = strlen(vid); + if (len > 0 && vid[len-1] == '\n') { + vid[len-1] = '\0'; + } + } else { + fclose(fp); + return 0; + } + fclose(fp); + } else { + return 0; + } + + // Try to read idProduct + snprintf(path, sizeof(path), "/sys/class/tty/%s/device/../idProduct", port_name); + fp = fopen(path, "r"); + if (fp) { + if (fgets(pid, 8, fp) != NULL) { + // Remove newline if present + int len = strlen(pid); + if (len > 0 && pid[len-1] == '\n') { + pid[len-1] = '\0'; + } + } else { + fclose(fp); + return 0; + } + fclose(fp); + return 1; + } else { + return 0; + } +} + +// Find TrueRNG device port (ported and adapted from TrueRNG reference) +// Returns: 0=not found, 1=TrueRNGproV2, 2=TrueRNGpro, 3=TrueRNG +int find_truerng_port(char* port_path, size_t port_path_size, truerng_device_type_t* device_type) { + DIR *dir; + struct dirent *entry; + char vid[8], pid[8]; + int device_found = 0; + + dir = opendir("/dev"); + if (dir == NULL) { + return 0; + } + + while ((entry = readdir(dir)) != NULL) { + // Look for ttyUSB* or ttyACM* devices + if (strncmp(entry->d_name, "ttyUSB", 6) == 0 || + strncmp(entry->d_name, "ttyACM", 6) == 0) { + + if (read_usb_device_info(entry->d_name, vid, pid)) { + // Convert to uppercase for comparison + for (int i = 0; vid[i]; i++) vid[i] = toupper(vid[i]); + for (int i = 0; pid[i]; i++) pid[i] = toupper(pid[i]); + + // Check for TrueRNGproV2 + if (strcmp(vid, TRUERNGPROV2_VID) == 0 && strcmp(pid, TRUERNGPROV2_PID) == 0) { + snprintf(port_path, port_path_size, "/dev/%s", entry->d_name); + *device_type = TRUERNG_PRO_V2; + device_found = 1; + break; + } + + // Check for TrueRNGpro + if (strcmp(vid, TRUERNGPRO_VID) == 0 && strcmp(pid, TRUERNGPRO_PID) == 0) { + snprintf(port_path, port_path_size, "/dev/%s", entry->d_name); + *device_type = TRUERNG_PRO; + device_found = 2; + break; + } + + // Check for TrueRNG + if (strcmp(vid, TRUERNG_VID) == 0 && strcmp(pid, TRUERNG_PID) == 0) { + snprintf(port_path, port_path_size, "/dev/%s", entry->d_name); + *device_type = TRUERNG_ORIGINAL; + device_found = 3; + break; + } + } + } + } + + closedir(dir); + return device_found; +} + +// Setup serial port for TrueRNG communication (ported from TrueRNG reference) +int setup_truerng_serial_port(const char* port_path) { + int fd; + struct termios tty; + + fd = open(port_path, O_RDWR | O_NOCTTY); + if (fd < 0) { + return -1; + } + + // Get current port settings + if (tcgetattr(fd, &tty) != 0) { + close(fd); + return -1; + } + + // Set baud rate (TrueRNG devices use 9600) + cfsetospeed(&tty, B9600); + cfsetispeed(&tty, B9600); + + // 8N1 mode + tty.c_cflag &= ~PARENB; // No parity + tty.c_cflag &= ~CSTOPB; // 1 stop bit + tty.c_cflag &= ~CSIZE; // Clear size bits + tty.c_cflag |= CS8; // 8 data bits + tty.c_cflag &= ~CRTSCTS; // No hardware flow control + tty.c_cflag |= CREAD | CLOCAL; // Enable reading and ignore modem controls + + // Raw input mode + tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); + tty.c_iflag &= ~(IXON | IXOFF | IXANY); + tty.c_oflag &= ~OPOST; + + // Set for blocking reads - wait for data indefinitely + tty.c_cc[VMIN] = 1; // Block until at least 1 character is received + tty.c_cc[VTIME] = 0; // No timeout + + // Apply settings + if (tcsetattr(fd, TCSANOW, &tty) != 0) { + close(fd); + return -1; + } + + // Flush input buffer + tcflush(fd, TCIFLUSH); + + // Set DTR + int status; + ioctl(fd, TIOCMGET, &status); + status |= TIOCM_DTR; + ioctl(fd, TIOCMSET, &status); + + return fd; +} + +// Get friendly name for TrueRNG device type +const char* get_truerng_device_name(truerng_device_type_t device_type) { + switch (device_type) { + case TRUERNG_PRO_V2: return "TrueRNGproV2"; + case TRUERNG_PRO: return "TrueRNGpro"; + case TRUERNG_ORIGINAL: return "TrueRNG"; + default: return "Unknown"; + } +} + +// Collect entropy from TrueRNG device with equivalent quality to keyboard entropy +int collect_truerng_entropy(unsigned char* entropy_buffer, size_t target_bytes, + size_t* collected_bytes, int display_progress) { + char port_path[512]; + truerng_device_type_t device_type; + int serial_fd = -1; + + // Find TrueRNG device + if (!find_truerng_port(port_path, sizeof(port_path), &device_type)) { + if (display_progress) { + printf("No TrueRNG device found.\n"); + printf("\nSupported devices:\n"); + printf(" - TrueRNG (PID: %s, VID: %s)\n", TRUERNG_VID, TRUERNG_PID); + printf(" - TrueRNGpro (PID: %s, VID: %s)\n", TRUERNGPRO_VID, TRUERNGPRO_PID); + printf(" - TrueRNGproV2 (PID: %s, VID: %s)\n", TRUERNGPROV2_VID, TRUERNGPROV2_PID); + printf("\nPlease connect a TrueRNG device and try again.\n"); + } + return 1; // Device not found + } + + if (display_progress) { + printf("Found %s at %s\n", get_truerng_device_name(device_type), port_path); + printf("Collecting %zu bytes of entropy...\n", target_bytes); + } + + // Setup serial port + serial_fd = setup_truerng_serial_port(port_path); + if (serial_fd < 0) { + if (display_progress) { + printf("Error: Cannot open TrueRNG device at %s\n", port_path); + printf("Check device permissions or run as root.\n"); + } + return 2; // Serial port setup failed + } + + // Collect entropy data + size_t bytes_read = 0; + unsigned char buffer[1024]; // Read in 1KB chunks + time_t start_time = time(NULL); + + while (bytes_read < target_bytes) { + size_t chunk_size = sizeof(buffer); + if (target_bytes - bytes_read < chunk_size) { + chunk_size = target_bytes - bytes_read; + } + + size_t bytes_in_chunk = 0; + while (bytes_in_chunk < chunk_size) { + ssize_t result = read(serial_fd, buffer + bytes_in_chunk, chunk_size - bytes_in_chunk); + if (result < 0) { + if (display_progress) { + printf("Error: Failed to read from TrueRNG device\n"); + } + close(serial_fd); + return 3; // Read failed + } else if (result == 0) { + if (display_progress) { + printf("Error: No data received from TrueRNG device\n"); + } + close(serial_fd); + return 4; // No data + } + bytes_in_chunk += result; + } + + // Copy to entropy buffer + memcpy(entropy_buffer + bytes_read, buffer, chunk_size); + bytes_read += chunk_size; + + // Show progress for large collections + if (display_progress && bytes_read % (4 * 1024) == 0) { // Every 4KB + double percentage = (double)bytes_read / target_bytes * 100.0; + printf("Progress: %.1f%% (%zu/%zu bytes)\r", percentage, bytes_read, target_bytes); + fflush(stdout); + } + } + + close(serial_fd); + + if (display_progress) { + double collection_time = difftime(time(NULL), start_time); + printf("\n✓ TrueRNG entropy collection complete!\n"); + printf(" Collected: %zu bytes in %.1f seconds\n", bytes_read, collection_time); + printf(" Device: %s\n", get_truerng_device_name(device_type)); + if (collection_time > 0) { + printf(" Rate: %.1f KB/s\n", (double)bytes_read / collection_time / 1024.0); + } + } + + *collected_bytes = bytes_read; + return 0; // Success +} + +// Collect dice entropy with manual input validation +int collect_dice_entropy(unsigned char* entropy_buffer, size_t target_bytes, + size_t* collected_bytes, int display_progress) { + if (display_progress) { + printf("=== Dice Entropy Collection ===\n"); + printf("Enter dice rolls as sequences of digits 1-6.\n"); + printf("Target: %zu bytes (%zu dice rolls needed)\n", target_bytes, target_bytes * 4); + printf("Press Enter after each sequence, or 'done' when finished.\n\n"); + } + + size_t entropy_bits = 0; + size_t target_bits = target_bytes * 8; + unsigned char current_byte = 0; + int bits_in_byte = 0; + size_t bytes_written = 0; + + char input[256]; + + while (entropy_bits < target_bits && bytes_written < target_bytes) { + if (display_progress) { + double percentage = (double)entropy_bits / target_bits * 100.0; + printf("Progress: %.1f%% (%zu/%zu bits) - Enter dice rolls: ", + percentage, entropy_bits, target_bits); + fflush(stdout); + } + + if (!fgets(input, sizeof(input), stdin)) { + if (display_progress) { + printf("Error: Failed to read input\n"); + } + return 1; + } + + // Remove newline + input[strcspn(input, "\n")] = 0; + + // Check for done command + if (strcmp(input, "done") == 0 && entropy_bits >= target_bits / 2) { + break; // Allow early exit if we have at least half the target + } + + // Process dice rolls + for (size_t i = 0; input[i] && entropy_bits < target_bits && bytes_written < target_bytes; i++) { + char c = input[i]; + if (c >= '1' && c <= '6') { + // Convert dice roll (1-6) to 3 bits of entropy + unsigned char roll_value = c - '1'; // 0-5 + + // Pack 3 bits into current byte + for (int bit = 2; bit >= 0 && entropy_bits < target_bits; bit--) { + current_byte = (current_byte << 1) | ((roll_value >> bit) & 1); + bits_in_byte++; + entropy_bits++; + + if (bits_in_byte == 8) { + entropy_buffer[bytes_written++] = current_byte; + current_byte = 0; + bits_in_byte = 0; + } + } + } + } + } + + // Handle partial byte + if (bits_in_byte > 0 && bytes_written < target_bytes) { + // Pad remaining bits with zeros + current_byte <<= (8 - bits_in_byte); + entropy_buffer[bytes_written++] = current_byte; + } + + if (display_progress) { + printf("\n✓ Dice entropy collection complete!\n"); + printf(" Collected: %zu bytes from dice rolls\n", bytes_written); + printf(" Entropy bits: %zu\n", entropy_bits); + } + + *collected_bytes = bytes_written; + return 0; // Success +} + +// Collect entropy by source type with unified interface +int collect_entropy_by_source(entropy_source_t source, unsigned char* entropy_buffer, + size_t target_bytes, size_t* collected_bytes, int display_progress) { + switch (source) { + case ENTROPY_SOURCE_KEYBOARD: + return collect_entropy_with_feedback(entropy_buffer, target_bytes, collected_bytes, 1); + + case ENTROPY_SOURCE_TRUERNG: + return collect_truerng_entropy(entropy_buffer, target_bytes, collected_bytes, display_progress); + + case ENTROPY_SOURCE_DICE: + return collect_dice_entropy(entropy_buffer, target_bytes, collected_bytes, display_progress); + + default: + if (display_progress) { + printf("Error: Unknown entropy source\n"); + } + return 1; + } +} + double get_precise_time(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); @@ -4068,6 +6252,7 @@ int handle_pads_menu(void) { 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(" \033[4mU\033[0mSB drive management\n"); printf(" E\033[4mx\033[0mit\n"); printf("\nSelect action: "); @@ -4158,10 +6343,17 @@ int handle_pads_menu(void) { free(selected_pad); return handle_pads_menu(); + } else if (toupper(input[0]) == 'U') { + // USB drive management + int result = handle_usb_submenu(); + if (result == 0) { + return handle_pads_menu(); // Return to pads menu + } + return result; } else if (toupper(input[0]) == 'X') { return 0; // Exit to main menu } else { - printf("Invalid action. Please select G, A, S, or X.\n"); + printf("Invalid action. Please select G, A, S, U, or X.\n"); return handle_pads_menu(); } } @@ -4298,26 +6490,59 @@ void get_directory_display(const char* file_path, char* result, size_t result_si int handle_add_entropy_to_pad(const char* pad_chksum) { printf("\n=== Add Entropy to Pad: %.16s... ===\n", pad_chksum); - printf("This will enhance the randomness of your pad using keyboard entropy.\n"); - printf("The entropy will be processed with Chacha20 and distributed throughout the entire pad.\n\n"); - printf("Entropy collection options:\n"); + // 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 rolls - Manual dice roll input for high-quality entropy\n"); + printf(" \033[4mT\033[0mrueRNG devices - Hardware random number generators\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 'T': + entropy_source = ENTROPY_SOURCE_TRUERNG; + break; + case 'X': + return 0; // Exit + default: + printf("Invalid choice. Please select K, D, T, or X.\n"); + return 1; + } + + // Get entropy amount + 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 choice_input[10]; - if (!fgets(choice_input, sizeof(choice_input), stdin)) { + char amount_input[10]; + if (!fgets(amount_input, sizeof(amount_input), stdin)) { printf("Error: Failed to read input\n"); return 1; } size_t target_bytes = 2048; // Default - int choice = atoi(choice_input); + int amount_choice = atoi(amount_input); - switch (choice) { + switch (amount_choice) { case 1: target_bytes = 2048; break; @@ -4347,7 +6572,7 @@ int handle_add_entropy_to_pad(const char* pad_chksum) { break; } - printf("\nCollecting %zu bytes of entropy...\n", target_bytes); + printf("\nCollecting %zu bytes of entropy from selected source...\n", target_bytes); // Allocate entropy buffer unsigned char* entropy_buffer = malloc(MAX_ENTROPY_BUFFER); @@ -4356,9 +6581,9 @@ int handle_add_entropy_to_pad(const char* pad_chksum) { return 1; } - // Collect entropy with visual feedback + // Collect entropy using unified interface size_t collected_bytes = 0; - int result = collect_entropy_with_feedback(entropy_buffer, target_bytes, &collected_bytes, 1); + int result = collect_entropy_by_source(entropy_source, entropy_buffer, target_bytes, &collected_bytes, 1); if (result != 0) { printf("Error: Entropy collection failed\n"); @@ -4393,6 +6618,598 @@ int handle_add_entropy_to_pad(const char* pad_chksum) { return 0; } +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// USB MENU HANDLERS +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +int handle_usb_submenu(void) { + printf("\n=== USB Drive Management ===\n"); + + // Auto-display USB drives above the menu (like Pad Management does) + list_usb_drives_v2(); + + printf("\nActions:\n"); + printf(" \033[4mI\033[0mnitialize USB drive\n"); + printf(" \033[4mC\033[0mopy pad to USB\n"); + printf(" \033[4mM\033[0mport pad from USB\n"); + printf(" \033[4mD\033[0muplicate USB drive\n"); + printf(" \033[4mV\033[0merify drive integrity\n"); + printf(" E\033[4mx\033[0mit\n"); + printf("\nSelect action: "); + + char input[10]; + if (!fgets(input, sizeof(input), stdin)) { + printf("Error: Failed to read input\n"); + return 1; + } + + char choice = toupper(input[0]); + + switch (choice) { + case 'I': + return handle_initialize_usb(); + case 'C': + return handle_copy_pad_to_usb(); + case 'M': + return handle_import_pad_from_usb(); + case 'D': + return handle_duplicate_usb_drive(); + case 'V': + return handle_verify_usb_drive(); + case 'X': + case 'Q': + return 0; // Exit to pads menu + default: + printf("Invalid choice. Please try again.\n"); + return handle_usb_submenu(); + } +} + +int handle_initialize_usb(void) { + printf("\n=== Initialize USB Drive for OTP ===\n"); + printf("This will prepare a USB drive for storing OTP pads.\n\n"); + + // Select USB drive + usb_drive_info_t* selected_drive = select_usb_drive_interactive( + "Available USB Drives", "Select drive to initialize", 0); + + if (!selected_drive) { + printf("USB initialization cancelled.\n"); + return handle_usb_submenu(); + } + + printf("\nSelected drive: %s (%s)\n", selected_drive->volume_label, selected_drive->mount_path); + + // Get drive name + char drive_name[64]; + printf("Enter OTP drive name (must start with 'OTP_'): "); + if (!fgets(drive_name, sizeof(drive_name), stdin)) { + printf("Error: Failed to read input\n"); + free(selected_drive); + return 1; + } + drive_name[strcspn(drive_name, "\n")] = 0; + + // Validate drive name + if (strncmp(drive_name, "OTP_", 4) != 0) { + printf("Error: Drive name must start with 'OTP_'\n"); + free(selected_drive); + return handle_usb_submenu(); + } + + // Ask about formatting + printf("\nFormat options:\n"); + printf(" 1. Initialize without formatting (recommended if drive is already formatted)\n"); + printf(" 2. Format with FAT32 filesystem\n"); + printf(" 3. Format with ext4 filesystem\n"); + printf("Enter choice (1-3): "); + + char format_input[10]; + if (!fgets(format_input, sizeof(format_input), stdin)) { + printf("Error: Failed to read input\n"); + free(selected_drive); + return 1; + } + + int format_choice = atoi(format_input); + int format_drive = (format_choice > 1); + const char* filesystem = ""; + + if (format_choice == 2) { + filesystem = "fat32"; + } else if (format_choice == 3) { + filesystem = "ext4"; + } + + // Confirm operation + printf("\nConfirmation:\n"); + printf("Drive: %s\n", selected_drive->mount_path); + printf("Name: %s\n", drive_name); + if (format_drive) { + printf("Format: YES (%s) - THIS WILL ERASE ALL DATA\n", filesystem); + } else { + printf("Format: NO (label only)\n"); + } + printf("\nProceed? (y/N): "); + + char confirm[10]; + if (!fgets(confirm, sizeof(confirm), stdin) || + (confirm[0] != 'y' && confirm[0] != 'Y')) { + printf("Operation cancelled.\n"); + free(selected_drive); + return handle_usb_submenu(); + } + + // Initialize the drive + usb_operation_result_t result = initialize_usb_drive( + selected_drive->mount_path, drive_name, format_drive, filesystem); + + if (result.success) { + printf("\n✓ USB drive initialized successfully!\n"); + printf("Drive name: %s\n", drive_name); + printf("You can now copy pads to this drive.\n"); + } else { + printf("\n✗ USB drive initialization failed: %s\n", result.error_message); + } + + free(selected_drive); + printf("\nPress Enter to continue..."); + getchar(); + return handle_usb_submenu(); +} + +int handle_copy_pad_to_usb(void) { + printf("\n=== Copy Pad to USB Drive ===\n"); + + // Select pad to copy + char* selected_pad = select_pad_interactive("=== Select Pad to Copy ===", + "Select pad to copy to USB (by prefix)", + PAD_FILTER_ALL, 1); + if (!selected_pad) { + printf("Pad selection cancelled.\n"); + return handle_usb_submenu(); + } + + // Select USB drive (OTP drives only) + usb_drive_info_t* selected_drive = select_usb_drive_interactive( + "Available OTP USB Drives", "Select destination USB drive", 1); + + if (!selected_drive) { + printf("USB drive selection cancelled.\n"); + free(selected_pad); + return handle_usb_submenu(); + } + + printf("\nCopying pad %.16s... to %s\n", selected_pad, selected_drive->volume_label); + + // Copy the pad + int result = copy_pad_to_usb(selected_pad, selected_drive->mount_path); + + if (result == 0) { + printf("✓ Pad successfully copied to USB drive!\n"); + } else { + printf("✗ Failed to copy pad to USB drive (error code: %d)\n", result); + } + + free(selected_pad); + free(selected_drive); + printf("\nPress Enter to continue..."); + getchar(); + return handle_usb_submenu(); +} + +int handle_import_pad_from_usb(void) { + printf("\n=== Import Pad from USB Drive ===\n"); + + // Select USB drive (OTP drives only) + usb_drive_info_t* selected_drive = select_usb_drive_interactive( + "Available OTP USB Drives", "Select source USB drive", 1); + + if (!selected_drive) { + printf("USB drive selection cancelled.\n"); + return handle_usb_submenu(); + } + + // List pads on the drive + char pad_list[100][65]; + int pad_count = list_pads_on_drive(selected_drive->mount_path, pad_list, 100); + + if (pad_count <= 0) { + printf("No pads found on USB drive %s\n", selected_drive->volume_label); + free(selected_drive); + printf("Press Enter to continue..."); + getchar(); + return handle_usb_submenu(); + } + + printf("\nPads available on %s:\n", selected_drive->volume_label); + printf("%-3s %-16s\n", "#", "Checksum"); + printf("%-3s %-16s\n", "---", "----------------"); + + for (int i = 0; i < pad_count; i++) { + printf("%-3d %.16s...\n", i + 1, pad_list[i]); + } + + printf("\nSelect pad number to import (1-%d) or 0 to cancel: ", pad_count); + + char input[10]; + if (!fgets(input, sizeof(input), stdin)) { + printf("Error: Failed to read input\n"); + free(selected_drive); + return 1; + } + + int selection = atoi(input); + if (selection < 1 || selection > pad_count) { + printf("Import cancelled.\n"); + free(selected_drive); + return handle_usb_submenu(); + } + + char* selected_pad = pad_list[selection - 1]; + printf("\nImporting pad %.16s... from %s\n", selected_pad, selected_drive->volume_label); + + // Import the pad + int result = copy_pad_from_usb(selected_drive->mount_path, selected_pad); + + if (result == 0) { + printf("✓ Pad successfully imported from USB drive!\n"); + } else { + printf("✗ Failed to import pad from USB drive (error code: %d)\n", result); + } + + free(selected_drive); + printf("\nPress Enter to continue..."); + getchar(); + return handle_usb_submenu(); +} + +int handle_duplicate_usb_drive(void) { + printf("\n=== Duplicate USB Drive ===\n"); + printf("Copy selected pads from one OTP USB drive to another.\n\n"); + + // Select source drive + usb_drive_info_t* source_drive = select_usb_drive_interactive( + "Source OTP USB Drives", "Select source drive to copy from", 1); + + if (!source_drive) { + printf("Source drive selection cancelled.\n"); + return handle_usb_submenu(); + } + + // Select destination drive + usb_drive_info_t* dest_drive = select_usb_drive_interactive( + "Destination OTP USB Drives", "Select destination drive to copy to", 1); + + if (!dest_drive) { + printf("Destination drive selection cancelled.\n"); + free(source_drive); + return handle_usb_submenu(); + } + + // Prevent copying to same drive + if (strcmp(source_drive->mount_path, dest_drive->mount_path) == 0) { + printf("Error: Source and destination drives cannot be the same!\n"); + free(source_drive); + free(dest_drive); + printf("Press Enter to continue..."); + getchar(); + return handle_usb_submenu(); + } + + // List pads on source drive + char pad_list[100][65]; + int pad_count = list_pads_on_drive(source_drive->mount_path, pad_list, 100); + + if (pad_count <= 0) { + printf("No pads found on source drive %s\n", source_drive->volume_label); + free(source_drive); + free(dest_drive); + printf("Press Enter to continue..."); + getchar(); + return handle_usb_submenu(); + } + + printf("\nSource: %s (%d pads)\n", source_drive->volume_label, pad_count); + printf("Destination: %s\n\n", dest_drive->volume_label); + + // For simplicity, copy all pads (could be enhanced to allow selection) + printf("This will copy all %d pads from source to destination.\n", pad_count); + printf("Proceed? (y/N): "); + + char confirm[10]; + if (!fgets(confirm, sizeof(confirm), stdin) || + (confirm[0] != 'y' && confirm[0] != 'Y')) { + printf("Duplication cancelled.\n"); + free(source_drive); + free(dest_drive); + return handle_usb_submenu(); + } + + // Perform selective duplication with all pads + int result = duplicate_drive_selective(source_drive->mount_path, + dest_drive->mount_path, pad_list, pad_count); + + if (result == 0) { + printf("\n✓ USB drive duplication completed successfully!\n"); + } else { + printf("\n⚠ USB drive duplication completed with %d errors.\n", result); + } + + free(source_drive); + free(dest_drive); + printf("\nPress Enter to continue..."); + getchar(); + return handle_usb_submenu(); +} + +int handle_verify_usb_drive(void) { + printf("\n=== Verify USB Drive Integrity ===\n"); + + // Select USB drive to verify + usb_drive_info_t* selected_drive = select_usb_drive_interactive( + "Available OTP USB Drives", "Select drive to verify", 1); + + if (!selected_drive) { + printf("Drive selection cancelled.\n"); + return handle_usb_submenu(); + } + + printf("\nVerifying integrity of drive: %s\n", selected_drive->volume_label); + printf("Mount path: %s\n\n", selected_drive->mount_path); + + // List pads on the drive and verify each one + char pad_list[100][65]; + int pad_count = list_pads_on_drive(selected_drive->mount_path, pad_list, 100); + + if (pad_count <= 0) { + printf("No pads found on USB drive.\n"); + free(selected_drive); + printf("Press Enter to continue..."); + getchar(); + return handle_usb_submenu(); + } + + printf("Found %d pads to verify:\n\n", pad_count); + + int verified_count = 0; + int error_count = 0; + + for (int i = 0; i < pad_count; i++) { + printf("[%d/%d] Verifying pad: %.16s...\n", i + 1, pad_count, pad_list[i]); + + // Build pad path + char pad_path[1024]; + snprintf(pad_path, sizeof(pad_path), "%s/%s.pad", + selected_drive->mount_path, pad_list[i]); + + // Calculate and verify checksum + char calculated_checksum[65]; + if (calculate_checksum(pad_path, calculated_checksum) == 0) { + if (strcmp(calculated_checksum, pad_list[i]) == 0) { + printf(" ✓ Integrity verified\n"); + verified_count++; + } else { + printf(" ✗ Checksum mismatch!\n"); + printf(" Expected: %.16s...\n", pad_list[i]); + printf(" Calculated: %.16s...\n", calculated_checksum); + error_count++; + } + } else { + printf(" ✗ Cannot calculate checksum\n"); + error_count++; + } + } + + printf("\nVerification completed:\n"); + printf("Successfully verified: %d pads\n", verified_count); + printf("Errors found: %d pads\n", error_count); + + if (error_count == 0) { + printf("✓ All pads on USB drive are intact!\n"); + } else { + printf("⚠ Some pads have integrity issues. Consider re-copying them.\n"); + } + + free(selected_drive); + printf("\nPress Enter to continue..."); + getchar(); + return handle_usb_submenu(); +} + +int handle_list_usb_drives(void) { + printf("\n=== List USB Drives ===\n"); + list_usb_drives_v2(); + printf("\nPress Enter to continue..."); + getchar(); + return handle_usb_submenu(); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// USB COMMAND LINE INTERFACE HANDLERS +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +int handle_list_usb_drives_cli(void) { + list_usb_drives_v2(); + return 0; +} +int handle_usb_init_cli(int argc, char* argv[]) { + const char* drive_name = argv[2]; + const char* drive_path = (argc > 3) ? argv[3] : NULL; + + // Validate drive name + if (strncmp(drive_name, "OTP_", 4) != 0) { + printf("Error: Drive name must start with 'OTP_'\n"); + return 1; + } + + if (strlen(drive_name) < 5 || strlen(drive_name) > 32) { + printf("Error: Drive name must be 5-32 characters\n"); + return 1; + } + + const char* mount_path; + usb_drive_info_t* selected_drive = NULL; + + if (drive_path) { + // Direct path specified + mount_path = drive_path; + + // Verify it's a valid mount point + if (access(drive_path, W_OK) != 0) { + printf("Error: Cannot access or write to specified path: %s\n", drive_path); + return 1; + } + } else { + // Interactive drive selection + printf("No drive path specified. Available USB drives:\n"); + selected_drive = select_usb_drive_interactive( + "Available USB Drives", "Select drive to initialize", 0); + + if (!selected_drive) { + printf("No drive selected.\n"); + return 1; + } + mount_path = selected_drive->mount_path; + } + + printf("Initializing USB drive...\n"); + printf("Drive path: %s\n", mount_path); + printf("Drive name: %s\n", drive_name); + + // Initialize without formatting by default in CLI mode + usb_operation_result_t result = initialize_usb_drive(mount_path, drive_name, 0, ""); + + if (result.success) { + printf("✓ USB drive initialized successfully!\n"); + } else { + printf("✗ USB drive initialization failed: %s\n", result.error_message); + if (selected_drive) free(selected_drive); + return 1; + } + + if (selected_drive) free(selected_drive); + return 0; +} + +int handle_usb_copy_cli(const char* pad_prefix, const char* usb_path) { + // Find pad by prefix + char* pad_checksum = find_pad_by_prefix(pad_prefix); + if (!pad_checksum) { + printf("Error: No pad found matching prefix '%s'\n", pad_prefix); + return 1; + } + + // Verify USB path is accessible + if (access(usb_path, W_OK) != 0) { + printf("Error: Cannot access USB drive path: %s\n", usb_path); + free(pad_checksum); + return 1; + } + + printf("Copying pad %.16s... to %s\n", pad_checksum, usb_path); + + int result = copy_pad_to_usb(pad_checksum, usb_path); + + if (result == 0) { + printf("✓ Pad successfully copied to USB drive!\n"); + } else { + printf("✗ Failed to copy pad to USB drive (error code: %d)\n", result); + free(pad_checksum); + return 1; + } + + free(pad_checksum); + return 0; +} + +int handle_usb_import_cli(const char* pad_checksum, const char* usb_path) { + // Verify USB path is accessible + if (access(usb_path, R_OK) != 0) { + printf("Error: Cannot access USB drive path: %s\n", usb_path); + return 1; + } + + // Verify pad exists on USB + char pad_path[1024]; + snprintf(pad_path, sizeof(pad_path), "%s/%s.pad", usb_path, pad_checksum); + + if (access(pad_path, R_OK) != 0) { + printf("Error: Pad not found on USB drive: %s\n", pad_checksum); + return 1; + } + + printf("Importing pad %.16s... from %s\n", pad_checksum, usb_path); + + int result = copy_pad_from_usb(usb_path, pad_checksum); + + if (result == 0) { + printf("✓ Pad successfully imported from USB drive!\n"); + } else { + printf("✗ Failed to import pad from USB drive (error code: %d)\n", result); + return 1; + } + + return 0; +} + +int handle_usb_verify_cli(const char* usb_path) { + // Verify USB path is accessible + if (access(usb_path, R_OK) != 0) { + printf("Error: Cannot access USB drive path: %s\n", usb_path); + return 1; + } + + printf("Verifying USB drive integrity: %s\n", usb_path); + + // List pads on the drive + char pad_list[100][65]; + int pad_count = list_pads_on_drive(usb_path, pad_list, 100); + + if (pad_count <= 0) { + printf("No pads found on USB drive.\n"); + return 1; + } + + printf("Found %d pads to verify:\n", pad_count); + + int verified_count = 0; + int error_count = 0; + + for (int i = 0; i < pad_count; i++) { + printf("[%d/%d] Verifying pad: %.16s...", i + 1, pad_count, pad_list[i]); + + // Build pad path + char pad_path[1024]; + snprintf(pad_path, sizeof(pad_path), "%s/%s.pad", usb_path, pad_list[i]); + + // Calculate and verify checksum + char calculated_checksum[65]; + if (calculate_checksum(pad_path, calculated_checksum) == 0) { + if (strcmp(calculated_checksum, pad_list[i]) == 0) { + printf(" ✓\n"); + verified_count++; + } else { + printf(" ✗ (checksum mismatch)\n"); + error_count++; + } + } else { + printf(" ✗ (cannot calculate checksum)\n"); + error_count++; + } + } + + printf("\nVerification results:\n"); + printf("Successfully verified: %d pads\n", verified_count); + printf("Errors found: %d pads\n", error_count); + + return (error_count > 0) ? 1 : 0; +} + void print_usage(const char* program_name) { printf("OTP Cipher - One Time Pad Implementation v0.3.7\n"); printf("Built for testing entropy system\n"); @@ -4418,6 +7235,19 @@ void print_usage(const char* program_name) { printf(" %s -d encrypted.otp.asc - Decrypt ASCII file\n", program_name); printf(" %s -g 1GB - Generate 1GB pad\n", program_name); printf(" %s -l - List pads\n", program_name); + printf("\nUSB Operations:\n"); + printf(" usb-list - List all USB drives\n"); + printf(" usb-init [path] - Initialize USB drive for OTP\n"); + printf(" usb-copy - Copy pad to USB drive\n"); + printf(" usb-import - Import pad from USB drive\n"); + printf(" usb-verify - Verify USB drive integrity\n"); + printf("\nUSB Examples:\n"); + printf(" %s usb-list - Show all USB drives\n", program_name); + printf(" %s usb-init OTP_BACKUP - Initialize drive (interactive)\n", program_name); + printf(" %s usb-init OTP_BACKUP /media/user/USB - Initialize specific drive\n", program_name); + printf(" %s usb-copy 1a2b3c /media/user/OTP_BACKUP - Copy pad to USB\n", program_name); + printf(" %s usb-import 1a2b3c4d /media/user/OTP_BACKUP - Import pad from USB\n", program_name); + printf(" %s usb-verify /media/user/OTP_BACKUP - Verify USB drive\n", program_name); printf("\nSize examples: 1GB, 5TB, 512MB, 2048 (bytes)\n"); printf("Pad selection: Full chksum or prefix\n"); } diff --git a/otp.h b/otp.h index ffd1ecc..855093d 100644 --- a/otp.h +++ b/otp.h @@ -14,7 +14,13 @@ #include #include #include +#include #include +#include +#include +#include +#include +#include // Constants #define MAX_INPUT_SIZE 4096 @@ -25,10 +31,74 @@ #define FILES_DIR "files" #define MAX_ENTROPY_BUFFER 32768 // 32KB entropy buffer +// USB Drive constants +#define MAX_USB_DRIVES 16 // Maximum USB drives to enumerate +#define USB_LABEL_PREFIX "OTP_" // Prefix for OTP USB drive labels +#define MAX_USB_LABEL_LENGTH 32 // Maximum length for USB volume labels + //////////////////////////////////////////////////////////////////////////////// // TYPE DEFINITIONS //////////////////////////////////////////////////////////////////////////////// +// USB Drive Information Structure +typedef struct { + char device_path[512]; // e.g., "/dev/sdb1" + char device_name[64]; // e.g., "sdb1" + char mount_path[512]; // e.g., "/media/user/OTP_ALICE" + char volume_label[64]; // e.g., "OTP_ALICE" + char filesystem[16]; // e.g., "ext4", "vfat" + char bus_type[16]; // "usb", "sata", "nvme", etc. + uint64_t total_size; // Total drive capacity in bytes + uint64_t available_size; // Available space in bytes + int is_mounted; // 1 if currently mounted, 0 otherwise + int is_otp_drive; // 1 if recognized as OTP drive + int is_removable; // 1 if removable media, 0 if fixed + int is_usb_device; // 1 if connected via USB bus + int is_system_mount; // 1 if critical system mount + int is_safe; // 1 if passed safety validation, 0 if unsafe + int pad_count; // Number of pads on drive +} usb_drive_info_t; + +// USB Operation Result Structure +typedef struct { + int success; // 1 for success, 0 for failure + char error_message[256]; // Error description if failed + int drives_found; // Number of drives discovered + int pads_transferred; // Number of pads copied/verified + uint64_t bytes_processed; // Total data processed +} usb_operation_result_t; + +// New simplified USB device structures for lsusb cross-referencing +typedef struct { + char vendor_id[8]; // "1234" from lsusb + char product_id[8]; // "5678" from lsusb + char vendor_name[64]; // "SanDisk Corp." from lsusb + char product_name[128]; // "Ultra Fit" from lsusb + char bus_number[4]; // "001" from lsusb + char device_number[4]; // "003" from lsusb +} usb_device_registry_t; + +// Simplified USB status for new detection system +typedef enum { + USB_SAFE, // ✓ Safe USB drive detected by lsusb + USB_TOO_LARGE, // ⚠ Drive over 6TB safety limit + USB_NOT_USB // ✗ Not found in USB device registry +} usb_safety_status_t; + +// New simplified drive info structure +typedef struct { + char mount_path[512]; // "/media/user/DUAL DRIVE" + char device_path[64]; // "/dev/sda1" + char device_name[16]; // "sda" + char label[64]; // "DUAL DRIVE" + char filesystem[16]; // "vfat" + uint64_t total_size; // Total bytes + uint64_t free_size; // Free bytes + int pad_count; // Number of .pad files + usb_safety_status_t status; // USB safety status + usb_device_registry_t *usb_device; // Pointer to USB device info (NULL if not USB) +} drive_info_v2_t; + // Decrypt operation modes for universal decrypt function typedef enum { DECRYPT_MODE_INTERACTIVE, // Interactive text decryption with prompts @@ -92,6 +162,67 @@ int set_default_pad_path(const char* pad_path); // OTP thumb drive detection function int detect_otp_thumb_drive(char* otp_drive_path, size_t path_size); +//////////////////////////////////////////////////////////////////////////////// +// USB DRIVE MANAGEMENT FUNCTIONS +//////////////////////////////////////////////////////////////////////////////// + +// USB Drive Discovery Functions +int discover_usb_drives(usb_drive_info_t** drives, int* drive_count); +int get_usb_drive_info(const char* mount_path, const char* drive_label, usb_drive_info_t* drive_info); +int get_device_from_mount(const char* mount_path, char* device_path, size_t device_path_size); +void format_size_string(uint64_t bytes, char* result, size_t result_size); + +// USB Device Safety Functions +int is_device_removable_usb(const char* device_path); +int get_device_bus_type(const char* device_path, char* bus_type, size_t bus_type_size); +int is_system_critical_mount(const char* mount_path); +int validate_usb_device_safety(const usb_drive_info_t* drive); +int extract_device_name_from_path(const char* device_path, char* device_name, size_t device_name_size); + +// Drive Initialization Functions +usb_operation_result_t initialize_usb_drive(const char* mount_path, const char* drive_name, + int format_drive, const char* filesystem_type); +int set_volume_label(const char* mount_path, const char* new_label); + +// Pad Transfer Functions +int copy_pad_to_usb(const char* pad_checksum, const char* usb_mount_path); +int copy_pad_from_usb(const char* usb_mount_path, const char* pad_checksum); +int copy_file(const char* source_path, const char* dest_path); +int list_pads_on_drive(const char* mount_path, char pad_list[][65], int max_pads); +int verify_pad_integrity_cross_drive(const char* local_pad, const char* usb_pad); + +// Drive Duplication Functions +int duplicate_drive_selective(const char* source_mount, const char* dest_mount, + char selected_pads[][65], int pad_count); +int verify_drive_duplication(const char* source_mount, const char* dest_mount); + +// USB Menu Integration Functions +int handle_usb_submenu(void); +int handle_initialize_usb(void); +int handle_copy_pad_to_usb(void); +int handle_import_pad_from_usb(void); +int handle_duplicate_usb_drive(void); +int handle_verify_usb_drive(void); +int handle_list_usb_drives(void); +usb_drive_info_t* select_usb_drive_interactive(const char* title, const char* prompt, int require_otp); + +// USB CLI handler functions +int handle_list_usb_drives_cli(void); +int handle_usb_init_cli(int argc, char* argv[]); +int handle_usb_copy_cli(const char* pad_prefix, const char* usb_path); +int handle_usb_import_cli(const char* pad_checksum, const char* usb_path); +int handle_usb_verify_cli(const char* usb_path); + +// New simplified USB detection system functions +int build_usb_device_registry(usb_device_registry_t **devices, int *device_count); +void free_usb_device_registry(usb_device_registry_t *devices); +usb_device_registry_t* find_usb_device_by_path(const char* device_path, + usb_device_registry_t* usb_devices, int usb_count); +int detect_drive_info_v2(const char* mount_path, drive_info_v2_t* drive_info, + usb_device_registry_t* usb_devices, int usb_count); +void list_usb_drives_v2(void); +const char* get_usb_status_string(usb_safety_status_t status); + //////////////////////////////////////////////////////////////////////////////// // EXTERNAL TOOL INTEGRATION FUNCTIONS //////////////////////////////////////////////////////////////////////////////// @@ -119,6 +250,13 @@ int decrypt_ascii_file(const char* input_file, const char* output_file); // ENHANCED ENTROPY SYSTEM FUNCTIONS //////////////////////////////////////////////////////////////////////////////// +// Entropy source types +typedef enum { + ENTROPY_SOURCE_KEYBOARD = 1, + ENTROPY_SOURCE_DICE = 2, + ENTROPY_SOURCE_TRUERNG = 3 +} entropy_source_t; + // Terminal control for entropy collection int setup_raw_terminal(struct termios* original_termios); void restore_terminal(struct termios* original_termios); @@ -130,6 +268,34 @@ void display_entropy_progress(const entropy_collection_state_t* state); void draw_progress_bar(double percentage, int width); void draw_quality_bar(double quality, int width, const char* label); +// TrueRNG Device Constants (updated to match otp.c implementation) +#define TRUERNG_VID "04D8" +#define TRUERNG_PID "F5FE" +#define TRUERNGPRO_VID "16D0" +#define TRUERNGPRO_PID "0AA0" +#define TRUERNGPROV2_VID "04D8" +#define TRUERNGPROV2_PID "EBB5" + +// TrueRNG Device Type enumeration +typedef enum { + TRUERNG_ORIGINAL = 1, + TRUERNG_PRO = 2, + TRUERNG_PRO_V2 = 3 +} truerng_device_type_t; + +// TrueRNG entropy collection functions (updated to match implementation) +int find_truerng_port(char* port_path, size_t port_path_size, truerng_device_type_t* device_type); +int setup_truerng_serial_port(const char* port_path); +int collect_truerng_entropy(unsigned char* entropy_buffer, size_t target_bytes, size_t* collected_bytes, int display_progress); +const char* get_truerng_device_name(truerng_device_type_t device_type); +int read_usb_device_info(const char* port_name, char* vid, char* pid); + +// Dice entropy collection functions (updated to match implementation) +int collect_dice_entropy(unsigned char* entropy_buffer, size_t target_bytes, size_t* collected_bytes, int display_progress); + +// Unified entropy collection interface (updated to match implementation) +int collect_entropy_by_source(entropy_source_t source, unsigned char* entropy_buffer, size_t target_bytes, size_t* collected_bytes, int display_progress); + // Entropy quality calculation double calculate_timing_quality(const entropy_collection_state_t* state); double calculate_variety_quality(const entropy_collection_state_t* state); diff --git a/true_rng b/true_rng new file mode 160000 index 0000000..52ed7af --- /dev/null +++ b/true_rng @@ -0,0 +1 @@ +Subproject commit 52ed7af980856f88ccf8efe89dba82b013291122