Compare commits

...

8 Commits

4 changed files with 292 additions and 173 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
otp
pads/ pads/
Gemini.md Gemini.md

View File

@@ -199,3 +199,5 @@ When contributing:
1. The version will automatically increment on builds 1. The version will automatically increment on builds
2. For major features, consider manually creating minor version tags 2. For major features, consider manually creating minor version tags
3. Generated version files (`src/version.*`, `VERSION`) should not be committed 3. Generated version files (`src/version.*`, `VERSION`) should not be committed
# Test change
# Testing -m flag

View File

@@ -13,6 +13,23 @@ print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; } print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
print_error() { echo -e "${RED}[ERROR]${NC} $1"; } print_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# Global variable for commit message
COMMIT_MESSAGE=""
# Parse command line arguments for -m flag
while [[ $# -gt 0 ]]; do
case $1 in
-m|--message)
COMMIT_MESSAGE="$2"
shift 2
;;
*)
# Keep other arguments for main logic
break
;;
esac
done
# Function to automatically increment version # Function to automatically increment version
increment_version() { increment_version() {
print_status "Incrementing version..." print_status "Incrementing version..."
@@ -57,8 +74,22 @@ increment_version() {
print_warning "Failed to stage changes (maybe not a git repository)" print_warning "Failed to stage changes (maybe not a git repository)"
fi fi
# Commit changes with version message # Handle commit message - use global variable if set, otherwise prompt
if git commit -m "Version $NEW_VERSION - Automatic version increment" 2>/dev/null; then if [[ -z "$COMMIT_MESSAGE" ]]; then
echo ""
print_status "Please enter a meaningful commit message for version $NEW_VERSION:"
echo -n "> "
read -r COMMIT_MESSAGE
fi
# Check if user provided a message
if [[ -z "$COMMIT_MESSAGE" ]]; then
print_warning "No commit message provided. Using default message."
COMMIT_MESSAGE="Automatic version increment"
fi
# Commit changes with user-provided message
if git commit -m "Version $NEW_VERSION - $COMMIT_MESSAGE" 2>/dev/null; then
print_success "Committed changes for version $NEW_VERSION" print_success "Committed changes for version $NEW_VERSION"
else else
print_warning "Failed to commit changes (maybe no changes to commit or not a git repository)" print_warning "Failed to commit changes (maybe no changes to commit or not a git repository)"
@@ -67,6 +98,19 @@ increment_version() {
# Create new git tag # Create new git tag
if git tag "$NEW_VERSION" 2>/dev/null; then if git tag "$NEW_VERSION" 2>/dev/null; then
print_success "Created new version tag: $NEW_VERSION" print_success "Created new version tag: $NEW_VERSION"
# Push changes and tags to remote repository
if git push ssh://ubuntu@laantungir.net:/home/ubuntu/git_repos/otp 2>/dev/null; then
print_success "Pushed changes to remote repository"
else
print_warning "Failed to push changes to remote repository"
fi
if git push ssh://ubuntu@laantungir.net:/home/ubuntu/git_repos/otp --tags 2>/dev/null; then
print_success "Pushed tags to remote repository"
else
print_warning "Failed to push tags to remote repository"
fi
else else
print_warning "Tag $NEW_VERSION already exists - using existing version" print_warning "Tag $NEW_VERSION already exists - using existing version"
NEW_VERSION=$LATEST_TAG NEW_VERSION=$LATEST_TAG
@@ -227,7 +271,10 @@ case "${1:-build}" in
;; ;;
*) *)
echo "OTP Cipher Build Script" echo "OTP Cipher Build Script"
echo "Usage: $0 {build|static|clean|install|uninstall|version}" echo "Usage: $0 [-m \"commit message\"] {build|static|clean|install|uninstall|version}"
echo ""
echo "Options:"
echo " -m, --message \"text\" - Specify commit message (skips interactive prompt)"
echo "" echo ""
echo "Commands:" echo "Commands:"
echo " build - Build project with automatic version increment (default)" echo " build - Build project with automatic version increment (default)"
@@ -236,6 +283,11 @@ case "${1:-build}" in
echo " install - Install to system (requires build first)" echo " install - Install to system (requires build first)"
echo " uninstall - Remove from system" echo " uninstall - Remove from system"
echo " version - Generate version files only" echo " version - Generate version files only"
echo ""
echo "Examples:"
echo " $0 build"
echo " $0 -m \"Fixed checksum parsing bug\" build"
echo " $0 --message \"Added new feature\" static"
exit 1 exit 1
;; ;;
esac esac

404
otp.c
View File

@@ -50,8 +50,8 @@ int command_line_mode(int argc, char* argv[]);
// Core functions // Core functions
int generate_pad(uint64_t size_bytes, int show_progress); int generate_pad(uint64_t size_bytes, int show_progress);
int generate_pad_with_entropy(uint64_t size_bytes, int show_progress, int use_keyboard_entropy); int generate_pad_with_entropy(uint64_t size_bytes, int show_progress, int use_keyboard_entropy);
int encrypt_text(const char* pad_identifier); int encrypt_text(const char* pad_identifier, const char* input_text);
int decrypt_text(const char* pad_identifier); int decrypt_text(const char* pad_identifier, const char* encrypted_message);
// Keyboard entropy functions // Keyboard entropy functions
int setup_raw_terminal(struct termios* original_termios); int setup_raw_terminal(struct termios* original_termios);
@@ -62,19 +62,19 @@ void simple_entropy_mix(unsigned char* urandom_buffer, size_t buffer_size,
// Directory management // Directory management
int ensure_pads_directory(void); int ensure_pads_directory(void);
void get_pad_path(const char* hash, char* pad_path, char* state_path); void get_pad_path(const char* chksum, char* pad_path, char* state_path);
// Utility functions // Utility functions
uint64_t parse_size_string(const char* size_str); uint64_t parse_size_string(const char* size_str);
char* find_pad_by_prefix(const char* prefix); char* find_pad_by_prefix(const char* prefix);
int list_available_pads(void); int list_available_pads(void);
int show_pad_info(const char* hash); int show_pad_info(const char* chksum);
int get_user_choice(int min, int max); int get_user_choice(int min, int max);
void show_progress(uint64_t current, uint64_t total, time_t start_time); void show_progress(uint64_t current, uint64_t total, time_t start_time);
// File operations // File operations
int read_state_offset(const char* pad_hash, uint64_t* offset); int read_state_offset(const char* pad_chksum, uint64_t* offset);
int write_state_offset(const char* pad_hash, uint64_t offset); int write_state_offset(const char* pad_chksum, uint64_t offset);
int calculate_checksum(const char* filename, char* checksum_hex); int calculate_checksum(const char* filename, char* checksum_hex);
void xor_checksum_256(const unsigned char* data, size_t len, unsigned char checksum[32]); void xor_checksum_256(const unsigned char* data, size_t len, unsigned char checksum[32]);
char* custom_base64_encode(const unsigned char* input, int length); char* custom_base64_encode(const unsigned char* input, int length);
@@ -101,37 +101,46 @@ int interactive_mode(void) {
while (1) { while (1) {
show_main_menu(); show_main_menu();
int choice = get_user_choice(1, 6); char input[10];
if (fgets(input, sizeof(input), stdin)) {
switch (choice) { char choice = toupper(input[0]);
case 1:
handle_generate_menu(); switch (choice) {
break; case 'G':
case 2: handle_generate_menu();
handle_encrypt_menu(); break;
break; case 'E':
case 3: handle_encrypt_menu();
handle_decrypt_menu(); break;
break; case 'D':
case 4: handle_decrypt_menu();
list_available_pads(); break;
break; case 'L':
case 5: { list_available_pads();
printf("Enter pad checksum (or prefix): "); break;
char input[MAX_HASH_LENGTH]; case 'S': {
if (fgets(input, sizeof(input), stdin)) { printf("Enter pad checksum (or prefix): ");
input[strcspn(input, "\n")] = 0; char input[MAX_HASH_LENGTH];
char* hash = find_pad_by_prefix(input); if (fgets(input, sizeof(input), stdin)) {
if (hash) { input[strcspn(input, "\n")] = 0;
show_pad_info(hash); char* chksum = find_pad_by_prefix(input);
free(hash); if (chksum) {
show_pad_info(chksum);
free(chksum);
}
} }
break;
} }
break; case 'X':
printf("Goodbye!\n");
return 0;
default:
printf("Invalid option. Please select G, E, D, L, S, or X.\n");
continue;
} }
case 6: } else {
printf("Goodbye!\n"); printf("Error reading input. Please try again.\n");
return 0; continue;
} }
printf("\n"); printf("\n");
} }
@@ -152,18 +161,22 @@ int command_line_mode(int argc, char* argv[]) {
return generate_pad_with_entropy(size, 1, 0); // No keyboard entropy for command line return generate_pad_with_entropy(size, 1, 0); // No keyboard entropy for command line
} }
else if (strcmp(argv[1], "encrypt") == 0) { else if (strcmp(argv[1], "encrypt") == 0) {
if (argc != 3) { if (argc < 3 || argc > 4) {
printf("Usage: %s encrypt <pad_hash_or_prefix>\n", argv[0]); printf("Usage: %s encrypt <pad_chksum_or_prefix> [text_to_encrypt]\n", argv[0]);
return 1; return 1;
} }
return encrypt_text(argv[2]); // Pass text if provided, otherwise NULL for interactive mode
const char* text = (argc == 4) ? argv[3] : NULL;
return encrypt_text(argv[2], text);
} }
else if (strcmp(argv[1], "decrypt") == 0) { else if (strcmp(argv[1], "decrypt") == 0) {
if (argc != 3) { if (argc < 3 || argc > 4) {
printf("Usage: %s decrypt <pad_hash_or_prefix>\n", argv[0]); printf("Usage: %s decrypt <pad_chksum_or_prefix> [encrypted_message]\n", argv[0]);
return 1; return 1;
} }
return decrypt_text(argv[2]); // Pass message if provided, otherwise NULL for interactive mode
const char* message = (argc == 4) ? argv[3] : NULL;
return decrypt_text(argv[2], message);
} }
else if (strcmp(argv[1], "list") == 0) { else if (strcmp(argv[1], "list") == 0) {
return list_available_pads(); return list_available_pads();
@@ -176,13 +189,13 @@ int command_line_mode(int argc, char* argv[]) {
void show_main_menu(void) { void show_main_menu(void) {
printf("=== Main Menu ===\n"); printf("=== Main Menu ===\n");
printf("1. Generate new pad\n"); printf("\033[4mG\033[0menerate new pad\n");
printf("2. Encrypt message\n"); printf("\033[4mE\033[0mncrypt message\n");
printf("3. Decrypt message\n"); printf("\033[4mD\033[0mecrypt message\n");
printf("4. List available pads\n"); printf("\033[4mL\033[0mist available pads\n");
printf("5. Show pad information\n"); printf("\033[4mS\033[0mhow pad information\n");
printf("6. Exit\n"); printf("E\033[4mx\033[0mit\n");
printf("\nSelect option (1-6): "); printf("\nSelect option: ");
} }
int handle_generate_menu(void) { int handle_generate_menu(void) {
@@ -233,7 +246,7 @@ int handle_encrypt_menu(void) {
return 1; return 1;
} }
printf("\nEnter pad selection (number, hash, or prefix): "); printf("\nEnter pad selection (number, chksum, or prefix): ");
char input[MAX_HASH_LENGTH]; char input[MAX_HASH_LENGTH];
if (!fgets(input, sizeof(input), stdin)) { if (!fgets(input, sizeof(input), stdin)) {
printf("Error: Failed to read input\n"); printf("Error: Failed to read input\n");
@@ -241,12 +254,12 @@ int handle_encrypt_menu(void) {
} }
input[strcspn(input, "\n")] = 0; input[strcspn(input, "\n")] = 0;
return encrypt_text(input); return encrypt_text(input, NULL); // NULL for interactive mode
} }
int handle_decrypt_menu(void) { int handle_decrypt_menu(void) {
printf("\n=== Decrypt Message ===\n"); printf("\n=== Decrypt Message ===\n");
return decrypt_text(NULL); // No pad selection needed - hash comes from message return decrypt_text(NULL, NULL); // No pad selection needed - chksum comes from message
} }
uint64_t parse_size_string(const char* size_str) { uint64_t parse_size_string(const char* size_str) {
@@ -307,7 +320,7 @@ char* find_pad_by_prefix(const char* prefix) {
int current = 0; int current = 0;
rewinddir(dir); rewinddir(dir);
while ((entry = readdir(dir)) != NULL && match_count == 0) { while ((entry = readdir(dir)) != NULL && match_count == 0) {
if (strstr(entry->d_name, ".pad") && strlen(entry->d_name) == 68) { // 64 char hash + ".pad" if (strstr(entry->d_name, ".pad") && strlen(entry->d_name) == 68) { // 64 char chksum + ".pad"
current++; current++;
if (current == selection) { if (current == selection) {
matches[match_count] = malloc(65); matches[match_count] = malloc(65);
@@ -368,15 +381,15 @@ int list_available_pads(void) {
int count = 0; int count = 0;
printf("Available pads:\n"); printf("Available pads:\n");
printf("%-4s %-20s %-12s %-12s %-8s\n", "No.", "Hash (first 16 chars)", "Size", "Used", "% Used"); printf("%-4s %-20s %-12s %-12s %-8s\n", "No.", "ChkSum (first 16 chars)", "Size", "Used", "% Used");
printf("%-4s %-20s %-12s %-12s %-8s\n", "---", "-------------------", "----------", "----------", "------"); printf("%-4s %-20s %-12s %-12s %-8s\n", "---", "-------------------", "----------", "----------", "------");
while ((entry = readdir(dir)) != NULL) { while ((entry = readdir(dir)) != NULL) {
if (strstr(entry->d_name, ".pad") && strlen(entry->d_name) == 68) { if (strstr(entry->d_name, ".pad") && strlen(entry->d_name) == 68) {
count++; count++;
char hash[65]; char chksum[65];
strncpy(hash, entry->d_name, 64); strncpy(chksum, entry->d_name, 64);
hash[64] = '\0'; chksum[64] = '\0';
// Get pad file size // Get pad file size
char full_path[300]; // Increased buffer size to accommodate longer paths char full_path[300]; // Increased buffer size to accommodate longer paths
@@ -385,7 +398,7 @@ int list_available_pads(void) {
if (stat(full_path, &st) == 0) { if (stat(full_path, &st) == 0) {
// Get used bytes from state // Get used bytes from state
uint64_t used_bytes; uint64_t used_bytes;
read_state_offset(hash, &used_bytes); read_state_offset(chksum, &used_bytes);
// Format sizes // Format sizes
char size_str[32], used_str[32]; char size_str[32], used_str[32];
@@ -415,7 +428,7 @@ int list_available_pads(void) {
// Calculate percentage // Calculate percentage
double percentage = (double)used_bytes / st.st_size * 100.0; double percentage = (double)used_bytes / st.st_size * 100.0;
printf("%-4d %-20.16s %-12s %-12s %.1f%%\n", count, hash, size_str, used_str, percentage); printf("%-4d %-20.16s %-12s %-12s %.1f%%\n", count, chksum, size_str, used_str, percentage);
} }
} }
} }
@@ -429,24 +442,24 @@ int list_available_pads(void) {
return count; return count;
} }
int show_pad_info(const char* hash) { int show_pad_info(const char* chksum) {
char pad_filename[MAX_HASH_LENGTH + 10]; char pad_filename[MAX_HASH_LENGTH + 10];
char state_filename[MAX_HASH_LENGTH + 10]; char state_filename[MAX_HASH_LENGTH + 10];
snprintf(pad_filename, sizeof(pad_filename), "%s.pad", hash); snprintf(pad_filename, sizeof(pad_filename), "%s.pad", chksum);
snprintf(state_filename, sizeof(state_filename), "%s.state", hash); snprintf(state_filename, sizeof(state_filename), "%s.state", chksum);
struct stat st; struct stat st;
if (stat(pad_filename, &st) != 0) { if (stat(pad_filename, &st) != 0) {
printf("Pad not found: %s\n", hash); printf("Pad not found: %s\n", chksum);
return 1; return 1;
} }
uint64_t used_bytes; uint64_t used_bytes;
read_state_offset(hash, &used_bytes); read_state_offset(chksum, &used_bytes);
printf("=== Pad Information ===\n"); printf("=== Pad Information ===\n");
printf("Hash: %s\n", hash); printf("ChkSum: %s\n", chksum);
printf("File: %s\n", pad_filename); printf("File: %s\n", pad_filename);
double size_gb = (double)st.st_size / (1024.0 * 1024.0 * 1024.0); double size_gb = (double)st.st_size / (1024.0 * 1024.0 * 1024.0);
@@ -496,7 +509,7 @@ int generate_pad(uint64_t size_bytes, int display_progress) {
char temp_filename[32]; char temp_filename[32];
char pad_filename[MAX_HASH_LENGTH + 10]; char pad_filename[MAX_HASH_LENGTH + 10];
char state_filename[MAX_HASH_LENGTH + 10]; char state_filename[MAX_HASH_LENGTH + 10];
char hash_hex[MAX_HASH_LENGTH]; char chksum_hex[MAX_HASH_LENGTH];
// Create temporary filename // Create temporary filename
snprintf(temp_filename, sizeof(temp_filename), "temp_%ld.pad", time(NULL)); snprintf(temp_filename, sizeof(temp_filename), "temp_%ld.pad", time(NULL));
@@ -560,18 +573,18 @@ int generate_pad(uint64_t size_bytes, int display_progress) {
fclose(pad_file); fclose(pad_file);
// Calculate XOR checksum of the pad file // Calculate XOR checksum of the pad file
if (calculate_checksum(temp_filename, hash_hex) != 0) { if (calculate_checksum(temp_filename, chksum_hex) != 0) {
printf("Error: Cannot calculate pad checksum\n"); printf("Error: Cannot calculate pad checksum\n");
unlink(temp_filename); unlink(temp_filename);
return 1; return 1;
} }
// Rename file to its hash // Rename file to its chksum
snprintf(pad_filename, sizeof(pad_filename), "%s.pad", hash_hex); snprintf(pad_filename, sizeof(pad_filename), "%s.pad", chksum_hex);
snprintf(state_filename, sizeof(state_filename), "%s.state", hash_hex); snprintf(state_filename, sizeof(state_filename), "%s.state", chksum_hex);
if (rename(temp_filename, pad_filename) != 0) { if (rename(temp_filename, pad_filename) != 0) {
printf("Error: Cannot rename pad file to hash-based name\n"); printf("Error: Cannot rename pad file to chksum-based name\n");
unlink(temp_filename); unlink(temp_filename);
return 1; return 1;
} }
@@ -582,7 +595,7 @@ int generate_pad(uint64_t size_bytes, int display_progress) {
} }
// Initialize state file with offset 0 // Initialize state file with offset 0
if (write_state_offset(hash_hex, 0) != 0) { if (write_state_offset(chksum_hex, 0) != 0) {
printf("Error: Failed to create state file\n"); printf("Error: Failed to create state file\n");
unlink(pad_filename); unlink(pad_filename);
return 1; return 1;
@@ -590,7 +603,7 @@ int generate_pad(uint64_t size_bytes, int display_progress) {
double size_gb = (double)size_bytes / (1024.0 * 1024.0 * 1024.0); double size_gb = (double)size_bytes / (1024.0 * 1024.0 * 1024.0);
printf("Generated pad: %s (%.2f GB)\n", pad_filename, size_gb); printf("Generated pad: %s (%.2f GB)\n", pad_filename, size_gb);
printf("Pad hash: %s\n", hash_hex); printf("Pad chksum: %s\n", chksum_hex);
printf("State file: %s\n", state_filename); printf("State file: %s\n", state_filename);
printf("Pad file set to read-only\n"); printf("Pad file set to read-only\n");
@@ -606,7 +619,7 @@ int generate_pad_with_entropy(uint64_t size_bytes, int display_progress, int use
char temp_filename[64]; char temp_filename[64];
char pad_path[MAX_HASH_LENGTH + 20]; char pad_path[MAX_HASH_LENGTH + 20];
char state_path[MAX_HASH_LENGTH + 20]; char state_path[MAX_HASH_LENGTH + 20];
char hash_hex[MAX_HASH_LENGTH]; char chksum_hex[MAX_HASH_LENGTH];
// Create temporary filename // Create temporary filename
snprintf(temp_filename, sizeof(temp_filename), "temp_%ld.pad", time(NULL)); snprintf(temp_filename, sizeof(temp_filename), "temp_%ld.pad", time(NULL));
@@ -744,14 +757,14 @@ int generate_pad_with_entropy(uint64_t size_bytes, int display_progress, int use
fclose(pad_file); fclose(pad_file);
// Calculate XOR checksum of the pad file // Calculate XOR checksum of the pad file
if (calculate_checksum(temp_filename, hash_hex) != 0) { if (calculate_checksum(temp_filename, chksum_hex) != 0) {
printf("Error: Cannot calculate pad checksum\n"); printf("Error: Cannot calculate pad checksum\n");
unlink(temp_filename); unlink(temp_filename);
return 1; return 1;
} }
// Get final paths in pads directory // Get final paths in pads directory
get_pad_path(hash_hex, pad_path, state_path); get_pad_path(chksum_hex, pad_path, state_path);
if (rename(temp_filename, pad_path) != 0) { if (rename(temp_filename, pad_path) != 0) {
printf("Error: Cannot move pad file to pads directory\n"); printf("Error: Cannot move pad file to pads directory\n");
@@ -778,7 +791,7 @@ int generate_pad_with_entropy(uint64_t size_bytes, int display_progress, int use
double size_gb = (double)size_bytes / (1024.0 * 1024.0 * 1024.0); double size_gb = (double)size_bytes / (1024.0 * 1024.0 * 1024.0);
printf("Generated pad: %s (%.2f GB)\n", pad_path, size_gb); printf("Generated pad: %s (%.2f GB)\n", pad_path, size_gb);
printf("Pad checksum: %s\n", hash_hex); printf("Pad checksum: %s\n", chksum_hex);
printf("State file: %s\n", state_path); printf("State file: %s\n", state_path);
if (use_keyboard_entropy) { if (use_keyboard_entropy) {
printf("Enhanced with keyboard entropy!\n"); printf("Enhanced with keyboard entropy!\n");
@@ -788,31 +801,31 @@ int generate_pad_with_entropy(uint64_t size_bytes, int display_progress, int use
return 0; return 0;
} }
int encrypt_text(const char* pad_identifier) { int encrypt_text(const char* pad_identifier, const char* input_text) {
char* pad_hash = find_pad_by_prefix(pad_identifier); char* pad_chksum = find_pad_by_prefix(pad_identifier);
if (!pad_hash) { if (!pad_chksum) {
return 1; return 1;
} }
char input_text[MAX_INPUT_SIZE]; char text_buffer[MAX_INPUT_SIZE];
char hash_hex[MAX_HASH_LENGTH]; char chksum_hex[MAX_HASH_LENGTH];
uint64_t current_offset; uint64_t current_offset;
char pad_path[MAX_HASH_LENGTH + 20]; char pad_path[MAX_HASH_LENGTH + 20];
char state_path[MAX_HASH_LENGTH + 20]; char state_path[MAX_HASH_LENGTH + 20];
get_pad_path(pad_hash, pad_path, state_path); get_pad_path(pad_chksum, pad_path, state_path);
// Check if pad file exists // Check if pad file exists
if (access(pad_path, R_OK) != 0) { if (access(pad_path, R_OK) != 0) {
printf("Error: Pad file %s not found\n", pad_path); printf("Error: Pad file %s not found\n", pad_path);
free(pad_hash); free(pad_chksum);
return 1; return 1;
} }
// Read current offset // Read current offset
if (read_state_offset(pad_hash, &current_offset) != 0) { if (read_state_offset(pad_chksum, &current_offset) != 0) {
printf("Error: Cannot read state file\n"); printf("Error: Cannot read state file\n");
free(pad_hash); free(pad_chksum);
return 1; return 1;
} }
@@ -820,38 +833,45 @@ int encrypt_text(const char* pad_identifier) {
if (current_offset < 32) { if (current_offset < 32) {
printf("Warning: State offset below reserved area, adjusting to 32\n"); printf("Warning: State offset below reserved area, adjusting to 32\n");
current_offset = 32; current_offset = 32;
if (write_state_offset(pad_hash, current_offset) != 0) { if (write_state_offset(pad_chksum, current_offset) != 0) {
printf("Warning: Failed to update state file\n"); printf("Warning: Failed to update state file\n");
} }
} }
// Calculate XOR checksum of pad file // Calculate XOR checksum of pad file
if (calculate_checksum(pad_path, hash_hex) != 0) { if (calculate_checksum(pad_path, chksum_hex) != 0) {
printf("Error: Cannot calculate pad checksum\n"); printf("Error: Cannot calculate pad checksum\n");
free(pad_hash); free(pad_chksum);
return 1; return 1;
} }
// Get input text from user // Get input text - either from parameter or user input
printf("Enter text to encrypt: "); if (input_text != NULL) {
fflush(stdout); // Use provided text
strncpy(text_buffer, input_text, sizeof(text_buffer) - 1);
if (fgets(input_text, sizeof(input_text), stdin) == NULL) { text_buffer[sizeof(text_buffer) - 1] = '\0';
printf("Error: Failed to read input\n"); } else {
free(pad_hash); // Get input text from user (interactive mode)
return 1; printf("Enter text to encrypt: ");
} fflush(stdout);
// Remove newline if present if (fgets(text_buffer, sizeof(text_buffer), stdin) == NULL) {
size_t input_len = strlen(input_text); printf("Error: Failed to read input\n");
if (input_len > 0 && input_text[input_len - 1] == '\n') { free(pad_chksum);
input_text[input_len - 1] = '\0'; return 1;
input_len--; }
// Remove newline if present
size_t len = strlen(text_buffer);
if (len > 0 && text_buffer[len - 1] == '\n') {
text_buffer[len - 1] = '\0';
}
} }
size_t input_len = strlen(text_buffer);
if (input_len == 0) { if (input_len == 0) {
printf("Error: No input provided\n"); printf("Error: No input provided\n");
free(pad_hash); free(pad_chksum);
return 1; return 1;
} }
@@ -859,7 +879,7 @@ int encrypt_text(const char* pad_identifier) {
struct stat pad_stat; struct stat pad_stat;
if (stat(pad_path, &pad_stat) != 0) { if (stat(pad_path, &pad_stat) != 0) {
printf("Error: Cannot get pad file size\n"); printf("Error: Cannot get pad file size\n");
free(pad_hash); free(pad_chksum);
return 1; return 1;
} }
@@ -867,7 +887,7 @@ int encrypt_text(const char* pad_identifier) {
printf("Error: Not enough pad space remaining\n"); printf("Error: Not enough pad space remaining\n");
printf("Need: %lu bytes, Available: %lu bytes\n", printf("Need: %lu bytes, Available: %lu bytes\n",
input_len, (uint64_t)pad_stat.st_size - current_offset); input_len, (uint64_t)pad_stat.st_size - current_offset);
free(pad_hash); free(pad_chksum);
return 1; return 1;
} }
@@ -875,14 +895,14 @@ int encrypt_text(const char* pad_identifier) {
FILE* pad_file = fopen(pad_path, "rb"); FILE* pad_file = fopen(pad_path, "rb");
if (!pad_file) { if (!pad_file) {
printf("Error: Cannot open pad file\n"); printf("Error: Cannot open pad file\n");
free(pad_hash); free(pad_chksum);
return 1; return 1;
} }
if (fseek(pad_file, current_offset, SEEK_SET) != 0) { if (fseek(pad_file, current_offset, SEEK_SET) != 0) {
printf("Error: Cannot seek to offset in pad file\n"); printf("Error: Cannot seek to offset in pad file\n");
fclose(pad_file); fclose(pad_file);
free(pad_hash); free(pad_chksum);
return 1; return 1;
} }
@@ -891,7 +911,7 @@ int encrypt_text(const char* pad_identifier) {
printf("Error: Cannot read pad data\n"); printf("Error: Cannot read pad data\n");
free(pad_data); free(pad_data);
fclose(pad_file); fclose(pad_file);
free(pad_hash); free(pad_chksum);
return 1; return 1;
} }
fclose(pad_file); fclose(pad_file);
@@ -899,21 +919,21 @@ int encrypt_text(const char* pad_identifier) {
// XOR encrypt the input // XOR encrypt the input
unsigned char* ciphertext = malloc(input_len); unsigned char* ciphertext = malloc(input_len);
for (size_t i = 0; i < input_len; i++) { for (size_t i = 0; i < input_len; i++) {
ciphertext[i] = input_text[i] ^ pad_data[i]; ciphertext[i] = text_buffer[i] ^ pad_data[i];
} }
// Encode as base64 // Encode as base64
char* base64_cipher = custom_base64_encode(ciphertext, input_len); char* base64_cipher = custom_base64_encode(ciphertext, input_len);
// Update state offset // Update state offset
if (write_state_offset(pad_hash, current_offset + input_len) != 0) { if (write_state_offset(pad_chksum, current_offset + input_len) != 0) {
printf("Warning: Failed to update state file\n"); printf("Warning: Failed to update state file\n");
} }
// Output in ASCII armor format // Output in ASCII armor format
printf("\n-----BEGIN OTP MESSAGE-----\n"); printf("\n\n-----BEGIN OTP MESSAGE-----\n");
printf("Version: %s\n", get_version()); printf("Version: %s\n", get_version());
printf("Pad-Hash: %s\n", hash_hex); printf("Pad-ChkSum: %s\n", chksum_hex);
printf("Pad-Offset: %lu\n", current_offset); printf("Pad-Offset: %lu\n", current_offset);
printf("\n"); printf("\n");
@@ -923,89 +943,128 @@ int encrypt_text(const char* pad_identifier) {
printf("%.64s\n", base64_cipher + i); printf("%.64s\n", base64_cipher + i);
} }
printf("-----END OTP MESSAGE-----\n\n"); printf("-----END OTP MESSAGE-----\n\n\n");
// Cleanup // Cleanup
free(pad_data); free(pad_data);
free(ciphertext); free(ciphertext);
free(base64_cipher); free(base64_cipher);
free(pad_hash); free(pad_chksum);
return 0; return 0;
} }
int decrypt_text(const char* pad_identifier) { int decrypt_text(const char* pad_identifier, const char* encrypted_message) {
// For command line mode, pad_identifier is ignored - we'll get the hash from the message // For command line mode, pad_identifier is ignored - we'll get the chksum from the message
(void)pad_identifier; // Suppress unused parameter warning (void)pad_identifier; // Suppress unused parameter warning
char line[MAX_LINE_LENGTH]; char line[MAX_LINE_LENGTH];
char stored_hash[MAX_HASH_LENGTH]; char stored_chksum[MAX_HASH_LENGTH];
char current_hash[MAX_HASH_LENGTH]; char current_chksum[MAX_HASH_LENGTH];
uint64_t pad_offset; uint64_t pad_offset;
char base64_data[MAX_INPUT_SIZE * 2] = {0}; char base64_data[MAX_INPUT_SIZE * 2] = {0};
int in_data_section = 0; int in_data_section = 0;
printf("Enter encrypted message (paste the full ASCII armor block):\n"); if (encrypted_message != NULL) {
// Parse provided encrypted message
// Read the ASCII armor format char *message_copy = strdup(encrypted_message);
int found_begin = 0; char *line_ptr = strtok(message_copy, "\n");
while (fgets(line, sizeof(line), stdin)) {
line[strcspn(line, "\n")] = 0;
if (strcmp(line, "-----BEGIN OTP MESSAGE-----") == 0) { int found_begin = 0;
found_begin = 1; while (line_ptr != NULL) {
continue; if (strcmp(line_ptr, "-----BEGIN OTP MESSAGE-----") == 0) {
found_begin = 1;
}
else if (strcmp(line_ptr, "-----END OTP MESSAGE-----") == 0) {
break;
}
else if (found_begin) {
if (strncmp(line_ptr, "Pad-ChkSum: ", 12) == 0) {
strncpy(stored_chksum, line_ptr + 12, 64);
stored_chksum[64] = '\0';
}
else if (strncmp(line_ptr, "Pad-Offset: ", 12) == 0) {
pad_offset = strtoull(line_ptr + 12, NULL, 10);
}
else if (strlen(line_ptr) == 0) {
in_data_section = 1;
}
else if (in_data_section) {
strncat(base64_data, line_ptr, sizeof(base64_data) - strlen(base64_data) - 1);
}
}
line_ptr = strtok(NULL, "\n");
}
free(message_copy);
if (!found_begin) {
printf("Error: Invalid message format - missing BEGIN header\n");
return 1;
}
} else {
// Interactive mode - read from stdin
printf("Enter encrypted message (paste the full ASCII armor block):\n");
// Read the ASCII armor format
int found_begin = 0;
while (fgets(line, sizeof(line), stdin)) {
line[strcspn(line, "\n")] = 0;
if (strcmp(line, "-----BEGIN OTP MESSAGE-----") == 0) {
found_begin = 1;
continue;
}
if (strcmp(line, "-----END OTP MESSAGE-----") == 0) {
break;
}
if (!found_begin) continue;
if (strncmp(line, "Pad-ChkSum: ", 12) == 0) {
strncpy(stored_chksum, line + 12, 64);
stored_chksum[64] = '\0';
}
else if (strncmp(line, "Pad-Offset: ", 12) == 0) {
pad_offset = strtoull(line + 12, NULL, 10);
}
else if (strlen(line) == 0) {
in_data_section = 1;
}
else if (in_data_section) {
strncat(base64_data, line, sizeof(base64_data) - strlen(base64_data) - 1);
}
} }
if (strcmp(line, "-----END OTP MESSAGE-----") == 0) { if (!found_begin) {
break; printf("Error: Invalid message format - missing BEGIN header\n");
} return 1;
if (!found_begin) continue;
if (strncmp(line, "Pad-Hash: ", 10) == 0) {
strncpy(stored_hash, line + 10, 64);
stored_hash[64] = '\0';
}
else if (strncmp(line, "Pad-Offset: ", 12) == 0) {
pad_offset = strtoull(line + 12, NULL, 10);
}
else if (strlen(line) == 0) {
in_data_section = 1;
}
else if (in_data_section) {
strncat(base64_data, line, sizeof(base64_data) - strlen(base64_data) - 1);
} }
} }
if (!found_begin) { // Now we have the pad chksum from the message, construct filename
printf("Error: Invalid message format - missing BEGIN header\n");
return 1;
}
// Now we have the pad hash from the message, construct filename
char pad_path[MAX_HASH_LENGTH + 20]; char pad_path[MAX_HASH_LENGTH + 20];
char state_path[MAX_HASH_LENGTH + 20]; char state_path[MAX_HASH_LENGTH + 20];
get_pad_path(stored_hash, pad_path, state_path); get_pad_path(stored_chksum, pad_path, state_path);
// Check if we have this pad // Check if we have this pad
if (access(pad_path, R_OK) != 0) { if (access(pad_path, R_OK) != 0) {
printf("Error: Required pad not found: %s\n", stored_hash); printf("Error: Required pad not found: %s\n", stored_chksum);
printf("Available pads:\n"); printf("Available pads:\n");
list_available_pads(); list_available_pads();
return 1; return 1;
} }
// Verify pad integrity // Verify pad integrity
if (calculate_checksum(pad_path, current_hash) != 0) { if (calculate_checksum(pad_path, current_chksum) != 0) {
printf("Error: Cannot calculate current pad checksum\n"); printf("Error: Cannot calculate current pad checksum\n");
return 1; return 1;
} }
if (strcmp(stored_hash, current_hash) != 0) { if (strcmp(stored_chksum, current_chksum) != 0) {
printf("Warning: Pad integrity check failed!\n"); printf("Warning: Pad integrity check failed!\n");
printf("Expected: %s\n", stored_hash); printf("Expected: %s\n", stored_chksum);
printf("Current: %s\n", current_hash); printf("Current: %s\n", current_chksum);
printf("Continue anyway? (y/N): "); printf("Continue anyway? (y/N): ");
fflush(stdout); fflush(stdout);
@@ -1069,9 +1128,9 @@ int decrypt_text(const char* pad_identifier) {
return 0; return 0;
} }
int read_state_offset(const char* pad_hash, uint64_t* offset) { int read_state_offset(const char* pad_chksum, uint64_t* offset) {
char state_filename[MAX_HASH_LENGTH + 20]; char state_filename[MAX_HASH_LENGTH + 20];
snprintf(state_filename, sizeof(state_filename), "%s/%s.state", PADS_DIR, pad_hash); snprintf(state_filename, sizeof(state_filename), "%s/%s.state", PADS_DIR, pad_chksum);
FILE* state_file = fopen(state_filename, "rb"); FILE* state_file = fopen(state_filename, "rb");
if (!state_file) { if (!state_file) {
@@ -1089,9 +1148,9 @@ int read_state_offset(const char* pad_hash, uint64_t* offset) {
return 0; return 0;
} }
int write_state_offset(const char* pad_hash, uint64_t offset) { int write_state_offset(const char* pad_chksum, uint64_t offset) {
char state_filename[MAX_HASH_LENGTH + 20]; char state_filename[MAX_HASH_LENGTH + 20];
snprintf(state_filename, sizeof(state_filename), "%s/%s.state", PADS_DIR, pad_hash); snprintf(state_filename, sizeof(state_filename), "%s/%s.state", PADS_DIR, pad_chksum);
FILE* state_file = fopen(state_filename, "wb"); FILE* state_file = fopen(state_filename, "wb");
if (!state_file) { if (!state_file) {
@@ -1240,9 +1299,9 @@ int ensure_pads_directory(void) {
return 0; return 0;
} }
void get_pad_path(const char* hash, char* pad_path, char* state_path) { void get_pad_path(const char* chksum, char* pad_path, char* state_path) {
snprintf(pad_path, MAX_HASH_LENGTH + 20, "%s/%s.pad", PADS_DIR, hash); snprintf(pad_path, MAX_HASH_LENGTH + 20, "%s/%s.pad", PADS_DIR, chksum);
snprintf(state_path, MAX_HASH_LENGTH + 20, "%s/%s.state", PADS_DIR, hash); snprintf(state_path, MAX_HASH_LENGTH + 20, "%s/%s.state", PADS_DIR, chksum);
} }
@@ -1336,11 +1395,16 @@ void print_usage(const char* program_name) {
printf("OTP Cipher - One Time Pad Implementation %s\n", get_version()); printf("OTP Cipher - One Time Pad Implementation %s\n", get_version());
printf("%s\n", get_build_info()); printf("%s\n", get_build_info());
printf("Usage:\n"); printf("Usage:\n");
printf(" %s - Interactive mode\n", program_name); printf(" %s - Interactive mode\n", program_name);
printf(" %s generate <size> - Generate new pad\n", program_name); printf(" %s generate <size> - Generate new pad\n", program_name);
printf(" %s encrypt <pad_checksum_prefix> - Encrypt text\n", program_name); printf(" %s encrypt <pad_checksum_prefix> [text] - Encrypt text\n", program_name);
printf(" %s decrypt <pad_checksum_prefix> - Decrypt message\n", program_name); printf(" %s decrypt <pad_checksum_prefix> [message] - Decrypt message\n", program_name);
printf(" %s list - List available pads\n", program_name); printf(" %s list - List available pads\n", program_name);
printf("\nExamples:\n");
printf(" %s encrypt 1a2b3c \"Hello world\" - Encrypt inline text\n", program_name);
printf(" %s encrypt 1a2b3c - Encrypt interactively\n", program_name);
printf(" %s decrypt 1a2b3c \"-----BEGIN OTP...\" - Decrypt inline message\n", program_name);
printf(" %s decrypt 1a2b3c - Decrypt interactively\n", program_name);
printf("\nSize examples: 1GB, 5TB, 512MB, 2048 (bytes)\n"); printf("\nSize examples: 1GB, 5TB, 512MB, 2048 (bytes)\n");
printf("Pad selection: Full hash, prefix, or number from list\n"); printf("Pad selection: Full chksum, prefix, or number from list\n");
} }