270 lines
11 KiB
C
270 lines
11 KiB
C
#define _POSIX_C_SOURCE 200809L
|
|
#define _DEFAULT_SOURCE
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/statvfs.h>
|
|
#include <sys/ioctl.h>
|
|
#include <dirent.h>
|
|
#include <time.h>
|
|
#include <ctype.h>
|
|
#include <termios.h>
|
|
#include <fcntl.h>
|
|
#include <math.h>
|
|
#include "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 <size>\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 <pad> or -e <text> (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> <text>
|
|
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 <input_file> [-o <output_file>]\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 <input_file> -o <output_file>
|
|
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 <input_file> <pad_prefix> [-a] [-o <output_file>]
|
|
if (argc < 4) {
|
|
printf("Usage: %s -f <input_file> <pad_prefix> [-a] [-o <output_file>]\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 <size> - 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 <file> <pad_prefix> [-a] [-o <out>] - Encrypt file\n", program_name);
|
|
printf(" %s list|-l - List available pads\n", program_name);
|
|
printf("\nFile Operations:\n");
|
|
printf(" -f <file> <pad> - Encrypt file (binary .otp format)\n");
|
|
printf(" -f <file> <pad> -a - Encrypt file (ASCII .otp.asc format)\n");
|
|
printf(" -o <output> - 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");
|
|
} |