#define _POSIX_C_SOURCE 200809L #define _DEFAULT_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "otp.h" int main(int argc, char* argv[]) { // Initialize terminal dimensions first init_terminal_dimensions(); // Load preferences load_preferences(); // Detect interactive mode: true when running with no arguments AND no piped input int is_interactive = (argc == 1 && !has_stdin_data()); set_interactive_mode(is_interactive); // Check for OTP thumb drive on startup char otp_drive_path[512]; if (detect_otp_thumb_drive(otp_drive_path, sizeof(otp_drive_path))) { // Only show messages in interactive mode if (get_interactive_mode()) { printf("Detected OTP thumb drive: %s\n", otp_drive_path); printf("Using as default pads directory for this session.\n\n"); } set_current_pads_dir(otp_drive_path); } if (get_interactive_mode()) { return interactive_mode(); } else { return command_line_mode(argc, argv); } } int command_line_mode(int argc, char* argv[]) { // Check for help flags first (only if we have arguments) if (argc > 1 && (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--h") == 0 || strcmp(argv[1], "-help") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "help") == 0)) { print_usage(argv[0]); return 0; } // If no arguments but piped input, default to encrypt mode if (argc == 1 && has_stdin_data()) { char* piped_text = read_stdin_text(); if (piped_text) { int result = pipe_mode(argc, argv, piped_text); free(piped_text); return result; } } if (argc > 1 && (strcmp(argv[1], "generate") == 0 || strcmp(argv[1], "-g") == 0)) { if (argc != 3) { printf("Usage: %s generate|-g \n", argv[0]); printf("Size examples: 1024, 1GB, 5TB, 512MB\n"); return 1; } uint64_t size = parse_size_string(argv[2]); if (size == 0) { printf("Error: Invalid size format\n"); return 1; } return generate_pad(size, 1); // Use simplified pad generation } else if (strcmp(argv[1], "encrypt") == 0 || strcmp(argv[1], "-e") == 0) { // Check for piped input first if (has_stdin_data()) { char* piped_text = read_stdin_text(); if (piped_text) { int result = pipe_mode(argc, argv, piped_text); free(piped_text); return result; } } if (argc < 2 || argc > 4) { printf("Usage: %s encrypt|-e [pad_chksum_or_prefix] [text_to_encrypt]\n", argv[0]); return 1; } // Check if pad was specified or use default const char* pad_identifier = NULL; const char* text = NULL; if (argc == 2) { // Just -e, use default pad, no text (interactive) pad_identifier = NULL; text = NULL; } else if (argc == 3) { // Could be -e or -e (using default pad) // Check if default pad is available to determine interpretation char* default_pad = get_default_pad_path(); if (default_pad) { // Default pad available, treat argument as text pad_identifier = NULL; text = argv[2]; free(default_pad); } else { // No default pad, treat as pad identifier pad_identifier = argv[2]; text = NULL; } } else { // argc == 4: -e pad_identifier = argv[2]; text = argv[3]; } // If pad_identifier is NULL, we need to use default pad if (pad_identifier == NULL) { char* default_pad = get_default_pad_path(); if (default_pad) { // Extract checksum from default pad path char* filename = strrchr(default_pad, '/'); if (!filename) filename = default_pad; else filename++; // Skip the '/' // Extract checksum (remove .pad extension) if (strlen(filename) >= 68 && strstr(filename, ".pad")) { static char default_checksum[65]; strncpy(default_checksum, filename, 64); default_checksum[64] = '\0'; pad_identifier = default_checksum; } free(default_pad); // Call encrypt_text and return result return encrypt_text(pad_identifier, text); } else { printf("Error: No default pad configured. Specify pad explicitly or configure default pad.\n"); return 1; } } else { // Explicit pad specified, normal operation return encrypt_text(pad_identifier, text); } } else if (strcmp(argv[1], "decrypt") == 0 || strcmp(argv[1], "-d") == 0) { if (argc == 2) { // Check for piped input first if (has_stdin_data()) { // Piped decrypt mode - read stdin and decrypt silently char* piped_message = read_stdin_text(); if (piped_message) { int result = decrypt_text(NULL, piped_message); free(piped_message); return result; } } // Interactive mode - no arguments needed return decrypt_text(NULL, NULL); } else if (argc == 3) { // Check if the argument looks like an encrypted message (starts with -----) if (strncmp(argv[2], "-----BEGIN OTP MESSAGE-----", 27) == 0) { // Inline decrypt with message only - use silent mode for command line return decrypt_text(NULL, argv[2]); } else { // Check if it's a file (contains . or ends with known extensions) if (strstr(argv[2], ".") != NULL) { // Treat as file return decrypt_file(argv[2], NULL); } else { // Interactive decrypt with pad hint (legacy support) return decrypt_text(argv[2], NULL); } } } else if (argc == 4) { // Check for -o flag for output file if (strcmp(argv[2], "-o") == 0) { printf("Usage: %s decrypt|-d [-o ]\n", argv[0]); return 1; } else { // Legacy format: pad_chksum and message, or file with output // Use silent mode for command line when message is provided return decrypt_text(argv[2], argv[3]); } } else if (argc == 5 && strcmp(argv[3], "-o") == 0) { // File decryption with output: -d -o return decrypt_file(argv[2], argv[4]); } else { printf("Usage: %s decrypt|-d [encrypted_message|file] [-o output_file]\n", argv[0]); printf(" %s decrypt|-d [encrypted_message] (pad info from message)\n", argv[0]); return 1; } } else if (strcmp(argv[1], "-f") == 0) { // File encryption mode: -f [-a] [-o ] if (argc < 4) { printf("Usage: %s -f [-a] [-o ]\n", argv[0]); return 1; } const char* input_file = argv[2]; const char* pad_prefix = argv[3]; int ascii_armor = 0; const char* output_file = NULL; // Parse optional flags for (int i = 4; i < argc; i++) { if (strcmp(argv[i], "-a") == 0) { ascii_armor = 1; } else if (strcmp(argv[i], "-o") == 0 && i + 1 < argc) { output_file = argv[++i]; } } return encrypt_file(pad_prefix, input_file, output_file, ascii_armor); } else if (strcmp(argv[1], "list") == 0 || strcmp(argv[1], "-l") == 0) { printf("Available pads:\n"); char* selected = select_pad_interactive("Available pads:", "Select pad (or press Enter to exit)", PAD_FILTER_ALL, 0); if (selected) { free(selected); } return 0; } else { print_usage(argv[0]); return 1; } } void print_usage(const char* program_name) { printf("OTP Cipher - One Time Pad Implementation v0.3.16\n"); printf("Built for testing entropy system\n"); printf("Usage:\n"); printf(" %s - Interactive mode\n", program_name); printf(" %s generate|-g - Generate new pad\n", program_name); printf(" %s encrypt|-e [pad_checksum_prefix] [text] - Encrypt text\n", program_name); printf(" %s decrypt|-d [encrypted_message] - Decrypt message\n", program_name); printf(" %s -f [-a] [-o ] - Encrypt file\n", program_name); printf(" %s list|-l - List available pads\n", program_name); printf("\nFile Operations:\n"); printf(" -f - Encrypt file (binary .otp format)\n"); printf(" -f -a - Encrypt file (ASCII .otp.asc format)\n"); printf(" -o - Specify output filename\n"); printf("\nShort flags:\n"); printf(" -g generate -e encrypt -d decrypt -l list -f file\n"); printf("\nExamples:\n"); printf(" %s -e 1a2b3c \"Hello world\" - Encrypt inline text\n", program_name); printf(" %s -f document.pdf 1a2b - Encrypt file (binary)\n", program_name); printf(" %s -f document.pdf 1a2b -a - Encrypt file (ASCII)\n", program_name); printf(" %s -f document.pdf 1a2b -o secret.otp - Encrypt with custom output\n", program_name); printf(" %s -d \"-----BEGIN OTP MESSAGE-----...\" - Decrypt message/file\n", 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("\nSize examples: 1GB, 5TB, 512MB, 2048 (bytes)\n"); printf("Pad selection: Full chksum or prefix\n"); }