Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7b5db60d80 | |||
| 84e2ee5639 | |||
| 0f3af174b0 | |||
| 3f0a258c21 | |||
| 2a5aec7dce |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -3,7 +3,4 @@ pads/
|
||||
Gemini.md
|
||||
TropicOfCancer-HenryMiller.txt
|
||||
|
||||
# Auto-generated version files
|
||||
src/version.h
|
||||
src/version.c
|
||||
VERSION
|
||||
# Auto-generated files (none currently)
|
||||
|
||||
@@ -1,361 +0,0 @@
|
||||
# Generic Automatic Version Increment System for Any Repository
|
||||
|
||||
Here's a generalized implementation guide for adding automatic versioning to any project:
|
||||
|
||||
## Core Concept
|
||||
**Automatic patch version increment with each build** - Every build automatically increments the patch version: v0.1.0 → v0.1.1 → v0.1.2, etc.
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
### 1. Add Version Increment Function to Build Script
|
||||
Add this function to your build script (bash example):
|
||||
|
||||
```bash
|
||||
# Function to automatically increment version
|
||||
increment_version() {
|
||||
echo "[INFO] Incrementing version..."
|
||||
|
||||
# Check if we're in a git repository
|
||||
if ! git rev-parse --git-dir > /dev/null 2>&1; then
|
||||
echo "[WARNING] Not in a git repository - skipping version increment"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Get the highest version tag (not chronologically latest)
|
||||
LATEST_TAG=$(git tag -l 'v*.*.*' | sort -V | tail -n 1 || echo "v0.1.0")
|
||||
if [[ -z "$LATEST_TAG" ]]; then
|
||||
LATEST_TAG="v0.1.0"
|
||||
fi
|
||||
|
||||
# Extract version components (remove 'v' prefix)
|
||||
VERSION=${LATEST_TAG#v}
|
||||
|
||||
# Parse major.minor.patch using regex
|
||||
if [[ $VERSION =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
|
||||
MAJOR=${BASH_REMATCH[1]}
|
||||
MINOR=${BASH_REMATCH[2]}
|
||||
PATCH=${BASH_REMATCH[3]}
|
||||
else
|
||||
echo "[ERROR] Invalid version format in tag: $LATEST_TAG"
|
||||
echo "[ERROR] Expected format: v0.1.0"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Increment patch version
|
||||
NEW_PATCH=$((PATCH + 1))
|
||||
NEW_VERSION="v${MAJOR}.${MINOR}.${NEW_PATCH}"
|
||||
|
||||
echo "[INFO] Current version: $LATEST_TAG"
|
||||
echo "[INFO] New version: $NEW_VERSION"
|
||||
|
||||
# Create new git tag
|
||||
if git tag "$NEW_VERSION" 2>/dev/null; then
|
||||
echo "[SUCCESS] Created new version tag: $NEW_VERSION"
|
||||
else
|
||||
echo "[WARNING] Tag $NEW_VERSION already exists - using existing version"
|
||||
NEW_VERSION=$LATEST_TAG
|
||||
fi
|
||||
|
||||
# Update VERSION file for compatibility
|
||||
echo "${NEW_VERSION#v}" > VERSION
|
||||
echo "[SUCCESS] Updated VERSION file to ${NEW_VERSION#v}"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Generate Version Header Files (For C/C++ Projects)
|
||||
Add this to the increment_version function:
|
||||
|
||||
```bash
|
||||
# Generate version.h header file (adjust path as needed)
|
||||
cat > src/version.h << EOF
|
||||
/*
|
||||
* Auto-Generated Version Header
|
||||
* DO NOT EDIT THIS FILE MANUALLY - Generated by build script
|
||||
*/
|
||||
|
||||
#ifndef VERSION_H
|
||||
#define VERSION_H
|
||||
|
||||
#define VERSION_MAJOR ${MAJOR}
|
||||
#define VERSION_MINOR ${MINOR}
|
||||
#define VERSION_PATCH ${NEW_PATCH}
|
||||
#define VERSION_STRING "${MAJOR}.${MINOR}.${NEW_PATCH}"
|
||||
#define VERSION_TAG "${NEW_VERSION}"
|
||||
|
||||
/* Build information */
|
||||
#define BUILD_DATE "$(date +%Y-%m-%d)"
|
||||
#define BUILD_TIME "$(date +%H:%M:%S)"
|
||||
#define BUILD_TIMESTAMP "$(date '+%Y-%m-%d %H:%M:%S')"
|
||||
|
||||
/* Git information */
|
||||
#define GIT_HASH "$(git rev-parse --short HEAD 2>/dev/null || echo 'unknown')"
|
||||
#define GIT_BRANCH "$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo 'unknown')"
|
||||
|
||||
/* Display versions */
|
||||
#define VERSION_DISPLAY "${NEW_VERSION}"
|
||||
#define VERSION_FULL_DISPLAY "${NEW_VERSION} ($(date '+%Y-%m-%d %H:%M:%S'), $(git rev-parse --short HEAD 2>/dev/null || echo 'unknown'))"
|
||||
|
||||
/* Version API functions */
|
||||
const char* get_version(void);
|
||||
const char* get_version_full(void);
|
||||
const char* get_build_info(void);
|
||||
|
||||
#endif /* VERSION_H */
|
||||
EOF
|
||||
|
||||
# Generate version.c implementation file
|
||||
cat > src/version.c << EOF
|
||||
/*
|
||||
* Auto-Generated Version Implementation
|
||||
* DO NOT EDIT THIS FILE MANUALLY - Generated by build script
|
||||
*/
|
||||
|
||||
#include "version.h"
|
||||
|
||||
const char* get_version(void) {
|
||||
return VERSION_TAG;
|
||||
}
|
||||
|
||||
const char* get_version_full(void) {
|
||||
return VERSION_FULL_DISPLAY;
|
||||
}
|
||||
|
||||
const char* get_build_info(void) {
|
||||
return "Built on " BUILD_DATE " at " BUILD_TIME " from commit " GIT_HASH " on branch " GIT_BRANCH;
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
### 3. Generate Version File for Other Languages
|
||||
|
||||
**Python (`src/__version__.py`):**
|
||||
```bash
|
||||
cat > src/__version__.py << EOF
|
||||
"""Auto-generated version file"""
|
||||
__version__ = "${MAJOR}.${MINOR}.${NEW_PATCH}"
|
||||
__version_tag__ = "${NEW_VERSION}"
|
||||
__build_date__ = "$(date +%Y-%m-%d)"
|
||||
__build_time__ = "$(date +%H:%M:%S)"
|
||||
__git_hash__ = "$(git rev-parse --short HEAD 2>/dev/null || echo 'unknown')"
|
||||
__git_branch__ = "$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo 'unknown')"
|
||||
EOF
|
||||
```
|
||||
|
||||
**JavaScript/Node.js (update `package.json`):**
|
||||
```bash
|
||||
# Update package.json version field
|
||||
if [ -f package.json ]; then
|
||||
sed -i "s/\"version\": \".*\"/\"version\": \"${MAJOR}.${MINOR}.${NEW_PATCH}\"/" package.json
|
||||
fi
|
||||
```
|
||||
|
||||
**Rust (update `Cargo.toml`):**
|
||||
```bash
|
||||
if [ -f Cargo.toml ]; then
|
||||
sed -i "s/^version = \".*\"/version = \"${MAJOR}.${MINOR}.${NEW_PATCH}\"/" Cargo.toml
|
||||
fi
|
||||
```
|
||||
|
||||
**Go (generate `version.go`):**
|
||||
```bash
|
||||
cat > version.go << EOF
|
||||
// Auto-generated version file
|
||||
package main
|
||||
|
||||
const (
|
||||
VersionMajor = ${MAJOR}
|
||||
VersionMinor = ${MINOR}
|
||||
VersionPatch = ${NEW_PATCH}
|
||||
VersionString = "${MAJOR}.${MINOR}.${NEW_PATCH}"
|
||||
VersionTag = "${NEW_VERSION}"
|
||||
BuildDate = "$(date +%Y-%m-%d)"
|
||||
BuildTime = "$(date +%H:%M:%S)"
|
||||
GitHash = "$(git rev-parse --short HEAD 2>/dev/null || echo 'unknown')"
|
||||
GitBranch = "$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo 'unknown')"
|
||||
)
|
||||
EOF
|
||||
```
|
||||
|
||||
**Java (generate `Version.java`):**
|
||||
```bash
|
||||
cat > src/main/java/Version.java << EOF
|
||||
// Auto-generated version class
|
||||
public class Version {
|
||||
public static final int VERSION_MAJOR = ${MAJOR};
|
||||
public static final int VERSION_MINOR = ${MINOR};
|
||||
public static final int VERSION_PATCH = ${NEW_PATCH};
|
||||
public static final String VERSION_STRING = "${MAJOR}.${MINOR}.${NEW_PATCH}";
|
||||
public static final String VERSION_TAG = "${NEW_VERSION}";
|
||||
public static final String BUILD_DATE = "$(date +%Y-%m-%d)";
|
||||
public static final String BUILD_TIME = "$(date +%H:%M:%S)";
|
||||
public static final String GIT_HASH = "$(git rev-parse --short HEAD 2>/dev/null || echo 'unknown')";
|
||||
public static final String GIT_BRANCH = "$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo 'unknown')";
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
### 4. Integrate into Build Targets
|
||||
Call `increment_version` before your main build commands:
|
||||
|
||||
```bash
|
||||
build_library() {
|
||||
increment_version
|
||||
echo "[INFO] Building library..."
|
||||
# Your actual build commands here
|
||||
make clean && make
|
||||
}
|
||||
|
||||
build_release() {
|
||||
increment_version
|
||||
echo "[INFO] Building release..."
|
||||
# Your release build commands
|
||||
}
|
||||
|
||||
build_package() {
|
||||
increment_version
|
||||
echo "[INFO] Building package..."
|
||||
# Your packaging commands
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Update .gitignore
|
||||
Add generated version files to `.gitignore`:
|
||||
|
||||
```gitignore
|
||||
# Auto-generated version files
|
||||
src/version.h
|
||||
src/version.c
|
||||
src/__version__.py
|
||||
version.go
|
||||
src/main/java/Version.java
|
||||
VERSION
|
||||
```
|
||||
|
||||
### 6. Update Build System Files
|
||||
|
||||
**For Makefile projects:**
|
||||
```makefile
|
||||
# Add version.c to your source files
|
||||
SOURCES = main.c utils.c version.c
|
||||
```
|
||||
|
||||
**For CMake projects:**
|
||||
```cmake
|
||||
# Add version files to your target
|
||||
target_sources(your_target PRIVATE src/version.c)
|
||||
```
|
||||
|
||||
**For Node.js projects:**
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"build": "node build.js && increment_version",
|
||||
"version": "node -e \"console.log(require('./package.json').version)\""
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7. Create Initial Version Tag
|
||||
```bash
|
||||
# Start with initial version
|
||||
git tag v0.1.0
|
||||
```
|
||||
|
||||
## Usage Pattern
|
||||
```bash
|
||||
./build.sh # v0.1.0 → v0.1.1
|
||||
./build.sh release # v0.1.1 → v0.1.2
|
||||
./build.sh package # v0.1.2 → v0.1.3
|
||||
```
|
||||
|
||||
## Manual Version Control
|
||||
|
||||
### Major/Minor Version Bumps
|
||||
```bash
|
||||
# For feature releases (minor bump)
|
||||
git tag v0.2.0 # Next build: v0.2.1
|
||||
|
||||
# For breaking changes (major bump)
|
||||
git tag v1.0.0 # Next build: v1.0.1
|
||||
```
|
||||
|
||||
### Version Reset
|
||||
```bash
|
||||
# Delete incorrect tags (if needed)
|
||||
git tag -d v0.2.1
|
||||
git push origin --delete v0.2.1 # If pushed to remote
|
||||
|
||||
# Create correct base version
|
||||
git tag v0.2.0
|
||||
|
||||
# Next build will create v0.2.1
|
||||
```
|
||||
|
||||
## Example Build Script Template
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
print_status() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||||
print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
|
||||
print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
|
||||
print_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
|
||||
# Insert increment_version function here
|
||||
|
||||
case "${1:-build}" in
|
||||
build)
|
||||
increment_version
|
||||
print_status "Building project..."
|
||||
# Your build commands
|
||||
;;
|
||||
clean)
|
||||
print_status "Cleaning build artifacts..."
|
||||
# Your clean commands
|
||||
;;
|
||||
test)
|
||||
print_status "Running tests..."
|
||||
# Your test commands (no version increment)
|
||||
;;
|
||||
release)
|
||||
increment_version
|
||||
print_status "Building release..."
|
||||
# Your release commands
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {build|clean|test|release}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
```
|
||||
|
||||
## Benefits
|
||||
1. **Zero maintenance** - No manual version editing
|
||||
2. **Build traceability** - Every build has unique version + metadata
|
||||
3. **Git integration** - Automatic version tags
|
||||
4. **Language agnostic** - Adapt generation for any language
|
||||
5. **CI/CD friendly** - Works in automated environments
|
||||
6. **Rollback friendly** - Easy to revert to previous versions
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Version Not Incrementing
|
||||
- Ensure you're in a git repository
|
||||
- Check that git tags exist: `git tag --list`
|
||||
- Verify tag format matches `v*.*.*` pattern
|
||||
|
||||
### Tag Already Exists
|
||||
If a tag already exists, the build continues with existing version:
|
||||
```
|
||||
[WARNING] Tag v0.2.1 already exists - using existing version
|
||||
```
|
||||
|
||||
### Missing Git Information
|
||||
If git is unavailable, version files show "unknown" for git hash and branch.
|
||||
6
Makefile
6
Makefile
@@ -5,19 +5,17 @@ LIBS_STATIC = -static -lm
|
||||
TARGET = otp
|
||||
SOURCE = otp.c
|
||||
CHACHA20_SOURCE = nostr_chacha20.c
|
||||
VERSION_SOURCE = src/version.c
|
||||
|
||||
# Default build target
|
||||
$(TARGET): $(SOURCE)
|
||||
$(CC) $(CFLAGS) -o $(TARGET) $(SOURCE) $(CHACHA20_SOURCE) $(VERSION_SOURCE) $(LIBS)
|
||||
$(CC) $(CFLAGS) -o $(TARGET) $(SOURCE) $(CHACHA20_SOURCE) $(LIBS)
|
||||
|
||||
# Static linking target
|
||||
static: $(SOURCE)
|
||||
$(CC) $(CFLAGS) -o $(TARGET) $(SOURCE) $(CHACHA20_SOURCE) $(VERSION_SOURCE) $(LIBS_STATIC)
|
||||
$(CC) $(CFLAGS) -o $(TARGET) $(SOURCE) $(CHACHA20_SOURCE) $(LIBS_STATIC)
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET) *.pad *.state
|
||||
rm -f src/version.h src/version.c VERSION
|
||||
|
||||
install:
|
||||
sudo cp $(TARGET) /usr/local/bin/
|
||||
|
||||
@@ -151,10 +151,7 @@ git tag v1.0.0 # Next build: v1.0.1
|
||||
- Full version display with metadata
|
||||
|
||||
### Generated Files
|
||||
The build system automatically generates:
|
||||
- `src/version.h` - Version constants and macros
|
||||
- `src/version.c` - Version API functions
|
||||
- `VERSION` - Plain text version number
|
||||
The build system automatically manages Git versioning by incrementing tags.
|
||||
|
||||
These files are excluded from git (.gitignore) and regenerated on each build.
|
||||
|
||||
@@ -176,9 +173,6 @@ otp/
|
||||
├── otp.c # Main source code
|
||||
├── README.md # This file
|
||||
├── .gitignore # Git ignore rules
|
||||
├── src/ # Generated version files (auto-created)
|
||||
│ ├── version.h # Version header (generated)
|
||||
│ └── version.c # Version implementation (generated)
|
||||
├── pads/ # OTP pad storage directory (created at runtime)
|
||||
└── VERSION # Plain text version (generated)
|
||||
```
|
||||
|
||||
18
TODO.md
18
TODO.md
@@ -1,19 +1,3 @@
|
||||
# TODO
|
||||
|
||||
|
||||
## Change technique for adding keyboard entropy.
|
||||
|
||||
|
||||
## There is the problem of the location of the pad revealing metadata about how many messages have been sent in the past, or at least the size of the messsages.
|
||||
|
||||
One solution could be to start the pad at a random location, and then wrap around, so an attacker could never tell the size of the past text sent. This helps. But then you have to store the start location, which you could do within the header of the pad along with the pad?
|
||||
|
||||
Or, better yet, assume the offset is a very large size, and use the pad itself to encrypt the offset.
|
||||
|
||||
## Take a look at how the file header is being handled.
|
||||
|
||||
|
||||
## Setup for multiple USB drives
|
||||
|
||||
|
||||
|
||||
## The pad menu in interactive encrypt mode gives numbers instead of checksum selection
|
||||
|
||||
100
build.sh
100
build.sh
@@ -100,13 +100,13 @@ increment_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
|
||||
if git push 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
|
||||
if git push --tags 2>/dev/null; then
|
||||
print_success "Pushed tags to remote repository"
|
||||
else
|
||||
print_warning "Failed to push tags to remote repository"
|
||||
@@ -123,71 +123,31 @@ increment_version() {
|
||||
fi
|
||||
fi
|
||||
|
||||
# Update VERSION file for compatibility
|
||||
echo "${NEW_VERSION#v}" > VERSION
|
||||
print_success "Updated VERSION file to ${NEW_VERSION#v}"
|
||||
# Update version strings in source code
|
||||
update_source_version "$NEW_VERSION"
|
||||
|
||||
# Generate version.h header file
|
||||
mkdir -p src
|
||||
cat > src/version.h << EOF
|
||||
/*
|
||||
* Auto-Generated Version Header
|
||||
* DO NOT EDIT THIS FILE MANUALLY - Generated by build script
|
||||
*/
|
||||
|
||||
#ifndef VERSION_H
|
||||
#define VERSION_H
|
||||
|
||||
#define VERSION_MAJOR ${MAJOR}
|
||||
#define VERSION_MINOR ${MINOR}
|
||||
#define VERSION_PATCH ${NEW_PATCH}
|
||||
#define VERSION_STRING "${MAJOR}.${MINOR}.${NEW_PATCH}"
|
||||
#define VERSION_TAG "${NEW_VERSION}"
|
||||
|
||||
/* Build information */
|
||||
#define BUILD_DATE "$(date +%Y-%m-%d)"
|
||||
#define BUILD_TIME "$(date +%H:%M:%S)"
|
||||
#define BUILD_TIMESTAMP "$(date '+%Y-%m-%d %H:%M:%S')"
|
||||
|
||||
/* Git information */
|
||||
#define GIT_HASH "$(git rev-parse --short HEAD 2>/dev/null || echo 'unknown')"
|
||||
#define GIT_BRANCH "$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo 'unknown')"
|
||||
|
||||
/* Display versions */
|
||||
#define VERSION_DISPLAY "${NEW_VERSION}"
|
||||
#define VERSION_FULL_DISPLAY "${NEW_VERSION} ($(date '+%Y-%m-%d %H:%M:%S'), $(git rev-parse --short HEAD 2>/dev/null || echo 'unknown'))"
|
||||
|
||||
/* Version API functions */
|
||||
const char* get_version(void);
|
||||
const char* get_version_full(void);
|
||||
const char* get_build_info(void);
|
||||
|
||||
#endif /* VERSION_H */
|
||||
EOF
|
||||
|
||||
# Generate version.c implementation file
|
||||
cat > src/version.c << EOF
|
||||
/*
|
||||
* Auto-Generated Version Implementation
|
||||
* DO NOT EDIT THIS FILE MANUALLY - Generated by build script
|
||||
*/
|
||||
|
||||
#include "version.h"
|
||||
|
||||
const char* get_version(void) {
|
||||
return VERSION_TAG;
|
||||
print_success "Version updated to ${NEW_VERSION}"
|
||||
}
|
||||
|
||||
const char* get_version_full(void) {
|
||||
return VERSION_FULL_DISPLAY;
|
||||
}
|
||||
# Function to update version strings in source code
|
||||
update_source_version() {
|
||||
local NEW_VERSION="$1"
|
||||
|
||||
const char* get_build_info(void) {
|
||||
return "Built on " BUILD_DATE " at " BUILD_TIME " from commit " GIT_HASH " on branch " GIT_BRANCH;
|
||||
}
|
||||
EOF
|
||||
print_status "Updating version strings in source code..."
|
||||
|
||||
print_success "Generated version header files"
|
||||
# Replace hardcoded version strings in otp.c with the current git tag
|
||||
if [ -f "otp.c" ]; then
|
||||
# Update main menu version
|
||||
sed -i "s/OTP v[0-9]\+\.[0-9]\+\.[0-9]\+/OTP $NEW_VERSION/g" otp.c
|
||||
# Update ASCII output version
|
||||
sed -i "s/Version: v[0-9]\+\.[0-9]\+\.[0-9]\+/Version: $NEW_VERSION/g" otp.c
|
||||
# Update usage/help text version
|
||||
sed -i "s/Implementation v[0-9]\+\.[0-9]\+\.[0-9]\+/Implementation $NEW_VERSION/g" otp.c
|
||||
|
||||
print_success "Updated version strings in otp.c to $NEW_VERSION"
|
||||
else
|
||||
print_warning "otp.c not found - skipping version string updates"
|
||||
fi
|
||||
}
|
||||
|
||||
# Build functions
|
||||
@@ -222,7 +182,6 @@ build_static() {
|
||||
clean_project() {
|
||||
print_status "Cleaning build artifacts..."
|
||||
make clean
|
||||
rm -f VERSION src/version.h src/version.c
|
||||
print_success "Clean completed"
|
||||
}
|
||||
|
||||
@@ -265,28 +224,23 @@ case "${1:-build}" in
|
||||
uninstall)
|
||||
uninstall_project
|
||||
;;
|
||||
version)
|
||||
increment_version
|
||||
print_status "Version information generated"
|
||||
;;
|
||||
*)
|
||||
echo "OTP Cipher Build Script"
|
||||
echo "Usage: $0 [-m \"commit message\"] {build|static|clean|install|uninstall|version}"
|
||||
echo "Usage: $0 [-m \"commit message\"] {build|static|clean|install|uninstall}"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " -m, --message \"text\" - Specify commit message (skips interactive prompt)"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " build - Build project with automatic version increment (default)"
|
||||
echo " static - Build with static linking"
|
||||
echo " clean - Clean build artifacts and generated files"
|
||||
echo " static - Build with static linking and version increment"
|
||||
echo " clean - Clean build artifacts"
|
||||
echo " install - Install to system (requires build first)"
|
||||
echo " uninstall - Remove from system"
|
||||
echo " version - Generate version files only"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 build"
|
||||
echo " $0 -m \"Fixed checksum parsing bug\" build"
|
||||
echo " $0"
|
||||
echo " $0 -m \"Fixed checksum parsing bug\""
|
||||
echo " $0 --message \"Added new feature\" static"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
7
files/o2.txt.otp.asc
Normal file
7
files/o2.txt.otp.asc
Normal file
@@ -0,0 +1,7 @@
|
||||
-----BEGIN OTP MESSAGE-----
|
||||
Version: v1.0.0
|
||||
Pad-ChkSum: d0aaeb745bfbc62b1ed8c0eca4f8dc016f4fd9ed49130979f2bb25a2a3c8192e
|
||||
Pad-Offset: 128
|
||||
|
||||
6+JsEJWRpLI2Z62tSw3EMiIjyTWVk0IfSek1to0/nYPXrswMzCtlultBcA==
|
||||
-----END OTP MESSAGE-----
|
||||
758
otp.c
758
otp.c
@@ -13,7 +13,6 @@
|
||||
#include <termios.h>
|
||||
#include <fcntl.h>
|
||||
#include <math.h>
|
||||
#include "src/version.h"
|
||||
#include "nostr_chacha20.h"
|
||||
|
||||
// Custom base64 character set
|
||||
@@ -125,6 +124,11 @@ int add_entropy_to_pad(const char* pad_chksum, const unsigned char* entropy_data
|
||||
size_t entropy_size, int show_progress);
|
||||
int handle_add_entropy_to_pad(const char* pad_chksum);
|
||||
|
||||
// Enhanced entropy system helper functions
|
||||
int update_pad_checksum_after_entropy(const char* old_chksum, char* new_chksum);
|
||||
int rename_pad_files_safely(const char* old_chksum, const char* new_chksum);
|
||||
int is_pad_unused(const char* pad_chksum);
|
||||
|
||||
// Directory management
|
||||
int ensure_pads_directory(void);
|
||||
void get_pad_path(const char* chksum, char* pad_path, char* state_path);
|
||||
@@ -134,7 +138,6 @@ void get_default_file_path(const char* filename, char* result_path, size_t resul
|
||||
// Utility functions
|
||||
uint64_t parse_size_string(const char* size_str);
|
||||
char* find_pad_by_prefix(const char* prefix);
|
||||
int list_available_pads(void);
|
||||
int show_pad_info(const char* chksum);
|
||||
void show_progress(uint64_t current, uint64_t total, time_t start_time);
|
||||
|
||||
@@ -172,6 +175,14 @@ int get_filename_with_default(const char* prompt, const char* default_path, char
|
||||
// Directory display functions
|
||||
void get_directory_display(const char* file_path, char* result, size_t result_size);
|
||||
|
||||
// Unified pad selection function
|
||||
typedef enum {
|
||||
PAD_FILTER_ALL, // Show all pads
|
||||
PAD_FILTER_UNUSED_ONLY // Show only unused pads (0% usage)
|
||||
} pad_filter_type_t;
|
||||
|
||||
char* select_pad_interactive(const char* title, const char* prompt, pad_filter_type_t filter_type, int allow_cancel);
|
||||
|
||||
void print_usage(const char* program_name);
|
||||
|
||||
|
||||
@@ -392,7 +403,12 @@ int command_line_mode(int argc, char* argv[]) {
|
||||
return encrypt_file(pad_prefix, input_file, output_file, ascii_armor);
|
||||
}
|
||||
else if (strcmp(argv[1], "list") == 0 || strcmp(argv[1], "-l") == 0) {
|
||||
return list_available_pads();
|
||||
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]);
|
||||
@@ -410,7 +426,7 @@ int command_line_mode(int argc, char* argv[]) {
|
||||
|
||||
int interactive_mode(void) {
|
||||
char input[10];
|
||||
|
||||
printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
|
||||
while (1) {
|
||||
show_main_menu();
|
||||
|
||||
@@ -450,7 +466,8 @@ int interactive_mode(void) {
|
||||
|
||||
void show_main_menu(void) {
|
||||
|
||||
printf("\n\n\n\n=========================== Main Menu - OTP %s ===========================\n\n", get_version() );
|
||||
|
||||
printf("\n=========================== Main Menu - OTP v1.0.0 ===========================\n\n");
|
||||
|
||||
printf(" \033[4mT\033[0mext encrypt\n"); //TEXT ENCRYPT
|
||||
printf(" \033[4mF\033[0mile encrypt\n"); //FILE ENCRYPT
|
||||
@@ -488,7 +505,14 @@ int handle_generate_menu(void) {
|
||||
int handle_encrypt_menu(void) {
|
||||
printf("\n=== Encrypt Data ===\n");
|
||||
|
||||
int pad_count = list_available_pads();
|
||||
printf("Available pads:\n");
|
||||
char* selected = select_pad_interactive("Available pads:", "Select pad (or press Enter to continue)", PAD_FILTER_ALL, 0);
|
||||
int pad_count = 1; // Assume at least 1 pad if function returned
|
||||
if (selected) {
|
||||
free(selected);
|
||||
} else {
|
||||
pad_count = 0;
|
||||
}
|
||||
if (pad_count == 0) {
|
||||
printf("No pads available. Generate a pad first.\n");
|
||||
return 1;
|
||||
@@ -509,57 +533,18 @@ int handle_encrypt_menu(void) {
|
||||
int choice = atoi(choice_input);
|
||||
|
||||
if (choice == 1) {
|
||||
// Text encryption
|
||||
printf("\nPad selection options:\n");
|
||||
printf(" 1. Select from numbered list\n");
|
||||
printf(" 2. Enter checksum/prefix manually\n");
|
||||
printf(" 3. Browse pad files\n");
|
||||
printf("Enter choice (1-3): ");
|
||||
|
||||
char pad_choice[10];
|
||||
if (!fgets(pad_choice, sizeof(pad_choice), stdin)) {
|
||||
printf("Error: Failed to read input\n");
|
||||
// Text encryption - use unified pad selection
|
||||
char* selected_pad = select_pad_interactive("=== Select Pad for Text Encryption ===",
|
||||
"Select pad (by prefix or number)",
|
||||
PAD_FILTER_ALL, 1);
|
||||
if (!selected_pad) {
|
||||
printf("Text encryption cancelled.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char input[MAX_HASH_LENGTH];
|
||||
if (atoi(pad_choice) == 3) {
|
||||
// Use file manager to browse pads directory
|
||||
char selected_pad[512];
|
||||
if (launch_file_manager("pads", selected_pad, sizeof(selected_pad)) == 0) {
|
||||
// Extract checksum from selected .pad file
|
||||
char* filename = strrchr(selected_pad, '/');
|
||||
if (!filename) filename = selected_pad;
|
||||
else filename++; // Skip the '/'
|
||||
|
||||
// Remove .pad extension to get checksum
|
||||
if (strlen(filename) == 68 && strstr(filename, ".pad")) {
|
||||
strncpy(input, filename, 64);
|
||||
input[64] = '\0';
|
||||
} else {
|
||||
printf("Invalid pad file selected.\n");
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
printf("Falling back to manual pad selection.\n");
|
||||
printf("Enter pad selection (number, chksum, or prefix): ");
|
||||
if (!fgets(input, sizeof(input), stdin)) {
|
||||
printf("Error: Failed to read input\n");
|
||||
return 1;
|
||||
}
|
||||
input[strcspn(input, "\n")] = 0;
|
||||
}
|
||||
} else {
|
||||
// Manual pad selection
|
||||
printf("Enter pad selection (number, chksum, or prefix): ");
|
||||
if (!fgets(input, sizeof(input), stdin)) {
|
||||
printf("Error: Failed to read input\n");
|
||||
return 1;
|
||||
}
|
||||
input[strcspn(input, "\n")] = 0;
|
||||
}
|
||||
|
||||
return encrypt_text(input, NULL); // NULL for interactive mode
|
||||
int result = encrypt_text(selected_pad, NULL); // NULL for interactive mode
|
||||
free(selected_pad);
|
||||
return result;
|
||||
}
|
||||
else if (choice == 2) {
|
||||
// File encryption
|
||||
@@ -603,13 +588,14 @@ int handle_encrypt_menu(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("\nEnter pad selection (number, chksum, or prefix): ");
|
||||
char pad_input[MAX_HASH_LENGTH];
|
||||
if (!fgets(pad_input, sizeof(pad_input), stdin)) {
|
||||
printf("Error: Failed to read input\n");
|
||||
// Use unified pad selection
|
||||
char* selected_pad = select_pad_interactive("=== Select Pad for File Encryption ===",
|
||||
"Select pad (by prefix)",
|
||||
PAD_FILTER_ALL, 1);
|
||||
if (!selected_pad) {
|
||||
printf("File encryption cancelled.\n");
|
||||
return 1;
|
||||
}
|
||||
pad_input[strcspn(pad_input, "\n")] = 0;
|
||||
|
||||
// Ask for output format
|
||||
printf("\nSelect output format:\n");
|
||||
@@ -647,7 +633,9 @@ int handle_encrypt_menu(void) {
|
||||
|
||||
const char* output_filename = output_file;
|
||||
|
||||
return encrypt_file(pad_input, input_file, output_filename, ascii_armor);
|
||||
int result = encrypt_file(selected_pad, input_file, output_filename, ascii_armor);
|
||||
free(selected_pad);
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
printf("Invalid choice. Please enter 1 or 2.\n");
|
||||
@@ -865,7 +853,10 @@ char* find_pad_by_prefix(const char* prefix) {
|
||||
if (match_count == 0) {
|
||||
printf("No pads found matching '%s'\n", prefix);
|
||||
printf("Available pads:\n");
|
||||
list_available_pads();
|
||||
char* selected = select_pad_interactive("Available pads:", "Available pads (press Enter to continue)", PAD_FILTER_ALL, 0);
|
||||
if (selected) {
|
||||
free(selected);
|
||||
}
|
||||
return NULL;
|
||||
} else if (match_count == 1) {
|
||||
char* result = matches[0];
|
||||
@@ -906,99 +897,14 @@ char* find_pad_by_prefix(const char* prefix) {
|
||||
}
|
||||
}
|
||||
|
||||
int list_available_pads(void) {
|
||||
DIR* dir = opendir(current_pads_dir);
|
||||
if (!dir) {
|
||||
printf("Error: Cannot open pads directory %s\n", current_pads_dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dirent* entry;
|
||||
int count = 0;
|
||||
|
||||
// Get current default pad path for comparison
|
||||
char* current_default = get_default_pad_path();
|
||||
char default_pad_checksum[65] = "";
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// PADS MENU
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
if (current_default) {
|
||||
// Extract checksum from default pad path
|
||||
char* filename = strrchr(current_default, '/');
|
||||
if (!filename) filename = current_default;
|
||||
else filename++; // Skip the '/'
|
||||
|
||||
// Extract checksum (remove .pad extension)
|
||||
if (strlen(filename) >= 68 && strstr(filename, ".pad")) {
|
||||
strncpy(default_pad_checksum, filename, 64);
|
||||
default_pad_checksum[64] = '\0';
|
||||
}
|
||||
free(current_default);
|
||||
}
|
||||
|
||||
printf("\nAvailable pads:\n");
|
||||
printf("%-4s %-7s %-20s %-12s %-12s %-8s\n", "No.", "Default", "ChkSum", "Size", "Used", "% Used");
|
||||
printf("%-4s %-7s %-20s %-12s %-12s %-8s\n", "---", "-------", "-------------------", "----------", "----------", "------");
|
||||
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
if (strstr(entry->d_name, ".pad") && strlen(entry->d_name) == 68) {
|
||||
count++;
|
||||
char chksum[65];
|
||||
strncpy(chksum, entry->d_name, 64);
|
||||
chksum[64] = '\0';
|
||||
|
||||
// Check if this is the default pad
|
||||
int is_default = (strlen(default_pad_checksum) > 0 &&
|
||||
strncmp(chksum, default_pad_checksum, 64) == 0);
|
||||
|
||||
// Get pad file size
|
||||
char full_path[1024]; // Increased buffer size to accommodate longer paths
|
||||
snprintf(full_path, sizeof(full_path), "%s/%s", current_pads_dir, entry->d_name);
|
||||
struct stat st;
|
||||
if (stat(full_path, &st) == 0) {
|
||||
// Get used bytes from state
|
||||
uint64_t used_bytes;
|
||||
read_state_offset(chksum, &used_bytes);
|
||||
|
||||
// Format sizes
|
||||
char size_str[32], used_str[32];
|
||||
|
||||
// Format total size
|
||||
if (st.st_size < 1024) {
|
||||
snprintf(size_str, sizeof(size_str), "%luB", st.st_size);
|
||||
} else if (st.st_size < 1024 * 1024) {
|
||||
snprintf(size_str, sizeof(size_str), "%.1fKB", (double)st.st_size / 1024.0);
|
||||
} else if (st.st_size < 1024 * 1024 * 1024) {
|
||||
snprintf(size_str, sizeof(size_str), "%.1fMB", (double)st.st_size / (1024.0 * 1024.0));
|
||||
} else {
|
||||
snprintf(size_str, sizeof(size_str), "%.2fGB", (double)st.st_size / (1024.0 * 1024.0 * 1024.0));
|
||||
}
|
||||
|
||||
// Format used size
|
||||
if (used_bytes < 1024) {
|
||||
snprintf(used_str, sizeof(used_str), "%luB", used_bytes);
|
||||
} else if (used_bytes < 1024 * 1024) {
|
||||
snprintf(used_str, sizeof(used_str), "%.1fKB", (double)used_bytes / 1024.0);
|
||||
} else if (used_bytes < 1024 * 1024 * 1024) {
|
||||
snprintf(used_str, sizeof(used_str), "%.1fMB", (double)used_bytes / (1024.0 * 1024.0));
|
||||
} else {
|
||||
snprintf(used_str, sizeof(used_str), "%.2fGB", (double)used_bytes / (1024.0 * 1024.0 * 1024.0));
|
||||
}
|
||||
|
||||
// Calculate percentage
|
||||
double percentage = (double)used_bytes / st.st_size * 100.0;
|
||||
|
||||
printf("%-4d %-7s %-20.16s %-12s %-12s %.1f%%\n", count, is_default ? "*" : "", chksum, size_str, used_str, percentage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
if (count == 0) {
|
||||
printf("No pads found.\n");
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int show_pad_info(const char* chksum) {
|
||||
char pad_filename[MAX_HASH_LENGTH + 10];
|
||||
@@ -1320,6 +1226,24 @@ int add_entropy_to_pad(const char* pad_chksum, const unsigned char* entropy_data
|
||||
printf("✓ Pad integrity maintained\n");
|
||||
printf("✓ %zu bytes of entropy distributed across entire pad\n", entropy_size);
|
||||
printf("✓ Pad restored to read-only mode\n");
|
||||
|
||||
// Update checksum after entropy addition
|
||||
printf("\n🔄 Updating pad checksum...\n");
|
||||
char new_chksum[65];
|
||||
int checksum_result = update_pad_checksum_after_entropy(pad_chksum, new_chksum);
|
||||
|
||||
if (checksum_result == 0) {
|
||||
printf("✓ Pad checksum updated successfully\n");
|
||||
printf(" Old checksum: %.16s...\n", pad_chksum);
|
||||
printf(" New checksum: %.16s...\n", new_chksum);
|
||||
printf("✓ Pad files renamed to new checksum\n");
|
||||
} else if (checksum_result == 2) {
|
||||
printf("ℹ Checksum unchanged (unusual but not an error)\n");
|
||||
} else {
|
||||
printf("⚠ Warning: Checksum update failed (entropy was added successfully)\n");
|
||||
printf(" You may need to manually handle the checksum update\n");
|
||||
return 1; // Report error despite successful entropy addition
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1503,7 +1427,7 @@ int encrypt_text(const char* pad_identifier, const char* input_text) {
|
||||
int is_interactive = (input_text == NULL); // Interactive if no input_text provided
|
||||
|
||||
if (is_interactive) {
|
||||
printf("\n\n%s\n\n", ascii_output);
|
||||
printf("\n\n\n%s\n\n", ascii_output);
|
||||
} else {
|
||||
printf("%s\n", ascii_output); // Add newline for proper piping with tee
|
||||
}
|
||||
@@ -1868,7 +1792,10 @@ int decrypt_binary_file(FILE* input_fp, const char* output_file) {
|
||||
if (access(pad_path, R_OK) != 0) {
|
||||
printf("Error: Required pad not found: %s\n", pad_chksum_hex);
|
||||
printf("Available pads:\n");
|
||||
list_available_pads();
|
||||
char* selected = select_pad_interactive("Available pads:", "Available pads (press Enter to continue)", PAD_FILTER_ALL, 0);
|
||||
if (selected) {
|
||||
free(selected);
|
||||
}
|
||||
fclose(input_fp);
|
||||
return 1;
|
||||
}
|
||||
@@ -2156,13 +2083,8 @@ int collect_entropy_with_feedback(unsigned char* entropy_buffer, size_t target_b
|
||||
state.unique_keys++;
|
||||
}
|
||||
} else {
|
||||
// No key available, add timing entropy
|
||||
clock_gettime(CLOCK_MONOTONIC, ×tamp);
|
||||
if (state.collected_bytes + 12 < MAX_ENTROPY_BUFFER) {
|
||||
memcpy(entropy_buffer + state.collected_bytes, ×tamp, 12);
|
||||
state.collected_bytes += 12;
|
||||
}
|
||||
usleep(1000); // 1ms delay
|
||||
// No key available, just sleep and wait for keystrokes
|
||||
usleep(10000); // 10ms delay - wait for keystrokes, don't add timing entropy
|
||||
}
|
||||
|
||||
// Auto-complete at target if enabled
|
||||
@@ -2875,6 +2797,97 @@ int derive_chacha20_params(const unsigned char* entropy_data, size_t entropy_siz
|
||||
return 0; // Success
|
||||
}
|
||||
|
||||
// Enhanced entropy system helper functions
|
||||
|
||||
// Check if a pad is unused (0% usage)
|
||||
int is_pad_unused(const char* pad_chksum) {
|
||||
uint64_t used_bytes;
|
||||
if (read_state_offset(pad_chksum, &used_bytes) != 0) {
|
||||
return 0; // Error reading state, assume used
|
||||
}
|
||||
return (used_bytes <= 32); // Only reserved bytes used (32 bytes for checksum encryption)
|
||||
}
|
||||
|
||||
|
||||
// Safely rename pad files (pad and state) from old to new checksum
|
||||
int rename_pad_files_safely(const char* old_chksum, const char* new_chksum) {
|
||||
char old_pad_path[1024], new_pad_path[1024];
|
||||
char old_state_path[1024], new_state_path[1024];
|
||||
|
||||
// Construct file paths
|
||||
snprintf(old_pad_path, sizeof(old_pad_path), "%s/%s.pad", current_pads_dir, old_chksum);
|
||||
snprintf(new_pad_path, sizeof(new_pad_path), "%s/%s.pad", current_pads_dir, new_chksum);
|
||||
snprintf(old_state_path, sizeof(old_state_path), "%s/%s.state", current_pads_dir, old_chksum);
|
||||
snprintf(new_state_path, sizeof(new_state_path), "%s/%s.state", current_pads_dir, new_chksum);
|
||||
|
||||
// Check if new files would conflict with existing files
|
||||
if (access(new_pad_path, F_OK) == 0) {
|
||||
printf("Error: New pad file already exists: %s\n", new_pad_path);
|
||||
return 1; // Conflict
|
||||
}
|
||||
|
||||
// Rename pad file
|
||||
if (rename(old_pad_path, new_pad_path) != 0) {
|
||||
printf("Error: Failed to rename pad file from %s to %s\n", old_pad_path, new_pad_path);
|
||||
return 2; // Pad rename failed
|
||||
}
|
||||
|
||||
// Rename state file (if it exists)
|
||||
if (access(old_state_path, F_OK) == 0) {
|
||||
if (rename(old_state_path, new_state_path) != 0) {
|
||||
printf("Warning: Failed to rename state file, but pad file was renamed successfully\n");
|
||||
// Try to rollback pad file rename
|
||||
rename(new_pad_path, old_pad_path);
|
||||
return 3; // State rename failed
|
||||
}
|
||||
}
|
||||
|
||||
return 0; // Success
|
||||
}
|
||||
|
||||
// Update pad checksum after entropy addition
|
||||
int update_pad_checksum_after_entropy(const char* old_chksum, char* new_chksum) {
|
||||
char pad_path[1024];
|
||||
snprintf(pad_path, sizeof(pad_path), "%s/%s.pad", current_pads_dir, old_chksum);
|
||||
|
||||
// Calculate new checksum of the modified pad
|
||||
if (calculate_checksum(pad_path, new_chksum) != 0) {
|
||||
printf("Error: Cannot calculate new pad checksum\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Check if checksum actually changed
|
||||
if (strcmp(old_chksum, new_chksum) == 0) {
|
||||
printf("Warning: Pad checksum unchanged after entropy addition\n");
|
||||
return 2; // Checksum didn't change (unusual but not fatal)
|
||||
}
|
||||
|
||||
// Rename pad files to use new checksum
|
||||
if (rename_pad_files_safely(old_chksum, new_chksum) != 0) {
|
||||
return 3; // Rename failed
|
||||
}
|
||||
|
||||
// Update default pad preference if this was the default pad
|
||||
char* current_default = get_default_pad_path();
|
||||
if (current_default) {
|
||||
// Check if the old pad was the default
|
||||
if (strstr(current_default, old_chksum)) {
|
||||
// Update to new checksum
|
||||
char new_default_path[1024];
|
||||
snprintf(new_default_path, sizeof(new_default_path), "%s/%s.pad", current_pads_dir, new_chksum);
|
||||
|
||||
if (set_default_pad_path(new_default_path) != 0) {
|
||||
printf("Warning: Failed to update default pad preference\n");
|
||||
} else {
|
||||
printf("Updated default pad to new checksum: %.16s...\n", new_chksum);
|
||||
}
|
||||
}
|
||||
free(current_default);
|
||||
}
|
||||
|
||||
return 0; // Success
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UNIVERSAL CORE FUNCTIONS FOR CODE CONSOLIDATION
|
||||
@@ -3045,7 +3058,7 @@ int generate_ascii_armor(const char* chksum, uint64_t offset, const unsigned cha
|
||||
strcpy(*ascii_output, "-----BEGIN OTP MESSAGE-----\n");
|
||||
|
||||
char temp_line[256];
|
||||
snprintf(temp_line, sizeof(temp_line), "Version: %s\n", get_version());
|
||||
snprintf(temp_line, sizeof(temp_line), "Version: v1.0.0\n");
|
||||
strcat(*ascii_output, temp_line);
|
||||
|
||||
snprintf(temp_line, sizeof(temp_line), "Pad-ChkSum: %s\n", chksum);
|
||||
@@ -3182,7 +3195,10 @@ int universal_decrypt(const char* input_data, const char* output_target, decrypt
|
||||
printf("Error: Required pad not found: %s\n", stored_chksum);
|
||||
if (mode == DECRYPT_MODE_INTERACTIVE || mode == DECRYPT_MODE_FILE_TO_TEXT) {
|
||||
printf("Available pads:\n");
|
||||
list_available_pads();
|
||||
char* selected = select_pad_interactive("Available pads:", "Available pads (press Enter to continue)", PAD_FILTER_ALL, 0);
|
||||
if (selected) {
|
||||
free(selected);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
@@ -3705,22 +3721,18 @@ int handle_text_encrypt(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// List available pads and get selection
|
||||
int pad_count = list_available_pads();
|
||||
if (pad_count == 0) {
|
||||
printf("No pads available. Generate a pad first.\n");
|
||||
// Use unified pad selection
|
||||
char* selected_pad = select_pad_interactive("=== Select Pad for Text Encryption ===",
|
||||
"Select pad (by prefix)",
|
||||
PAD_FILTER_ALL, 1);
|
||||
if (!selected_pad) {
|
||||
printf("Text encryption cancelled.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("\nEnter pad selection (number, checksum, or prefix): ");
|
||||
char pad_input[MAX_HASH_LENGTH];
|
||||
if (!fgets(pad_input, sizeof(pad_input), stdin)) {
|
||||
printf("Error: Failed to read pad selection\n");
|
||||
return 1;
|
||||
}
|
||||
pad_input[strcspn(pad_input, "\n")] = 0;
|
||||
|
||||
return encrypt_text(pad_input, text_buffer);
|
||||
int result = encrypt_text(selected_pad, text_buffer);
|
||||
free(selected_pad);
|
||||
return result;
|
||||
}
|
||||
|
||||
int handle_file_encrypt(void) {
|
||||
@@ -3739,21 +3751,15 @@ int handle_file_encrypt(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// List available pads
|
||||
int pad_count = list_available_pads();
|
||||
if (pad_count == 0) {
|
||||
printf("No pads available. Generate a pad first.\n");
|
||||
// Use unified pad selection
|
||||
char* selected_pad = select_pad_interactive("=== Select Pad for File Encryption ===",
|
||||
"Select pad (by prefix)",
|
||||
PAD_FILTER_ALL, 1);
|
||||
if (!selected_pad) {
|
||||
printf("File encryption cancelled.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("\nEnter pad selection (number, checksum, or prefix): ");
|
||||
char pad_input[MAX_HASH_LENGTH];
|
||||
if (!fgets(pad_input, sizeof(pad_input), stdin)) {
|
||||
printf("Error: Failed to read pad selection\n");
|
||||
return 1;
|
||||
}
|
||||
pad_input[strcspn(pad_input, "\n")] = 0;
|
||||
|
||||
// Ask for output format
|
||||
printf("\nSelect output format:\n");
|
||||
printf("1. Binary (.otp) - preserves file permissions\n");
|
||||
@@ -3785,10 +3791,258 @@ int handle_file_encrypt(void) {
|
||||
|
||||
const char* output_filename = output_file;
|
||||
|
||||
return encrypt_file(pad_input, input_file, output_filename, ascii_armor);
|
||||
int result = encrypt_file(selected_pad, input_file, output_filename, ascii_armor);
|
||||
free(selected_pad);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Unified pad selection function - extracts the best UI from handle_pads_menu()
|
||||
char* select_pad_interactive(const char* title, const char* prompt, pad_filter_type_t filter_type, int allow_cancel) {
|
||||
// Get list of pads from current directory
|
||||
DIR* dir = opendir(current_pads_dir);
|
||||
if (!dir) {
|
||||
printf("Error: Cannot open pads directory %s\n", current_pads_dir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Structure to store pad information
|
||||
struct PadInfo {
|
||||
char chksum[65];
|
||||
char size_str[32];
|
||||
char used_str[32];
|
||||
double percentage;
|
||||
char location[256];
|
||||
};
|
||||
|
||||
struct PadInfo pads[100]; // Support up to 100 pads
|
||||
int pad_count = 0;
|
||||
|
||||
// Collect all pad information
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dir)) != NULL && pad_count < 100) {
|
||||
if (strstr(entry->d_name, ".pad") && strlen(entry->d_name) == 68) {
|
||||
strncpy(pads[pad_count].chksum, entry->d_name, 64);
|
||||
pads[pad_count].chksum[64] = '\0';
|
||||
|
||||
// Get pad file size and usage info
|
||||
char full_path[1024];
|
||||
snprintf(full_path, sizeof(full_path), "%s/%s", current_pads_dir, entry->d_name);
|
||||
struct stat st;
|
||||
if (stat(full_path, &st) == 0) {
|
||||
// Get used bytes from state
|
||||
uint64_t used_bytes;
|
||||
read_state_offset(pads[pad_count].chksum, &used_bytes);
|
||||
|
||||
// Apply filter
|
||||
if (filter_type == PAD_FILTER_UNUSED_ONLY && used_bytes > 32) {
|
||||
continue; // Skip used pads when filtering for unused only
|
||||
}
|
||||
|
||||
// Format total size
|
||||
if (st.st_size < 1024) {
|
||||
snprintf(pads[pad_count].size_str, sizeof(pads[pad_count].size_str), "%luB", st.st_size);
|
||||
} else if (st.st_size < 1024 * 1024) {
|
||||
snprintf(pads[pad_count].size_str, sizeof(pads[pad_count].size_str), "%.1fKB", (double)st.st_size / 1024.0);
|
||||
} else if (st.st_size < 1024 * 1024 * 1024) {
|
||||
snprintf(pads[pad_count].size_str, sizeof(pads[pad_count].size_str), "%.1fMB", (double)st.st_size / (1024.0 * 1024.0));
|
||||
} else {
|
||||
snprintf(pads[pad_count].size_str, sizeof(pads[pad_count].size_str), "%.2fGB", (double)st.st_size / (1024.0 * 1024.0 * 1024.0));
|
||||
}
|
||||
|
||||
// Format used size
|
||||
if (used_bytes < 1024) {
|
||||
snprintf(pads[pad_count].used_str, sizeof(pads[pad_count].used_str), "%luB", used_bytes);
|
||||
} else if (used_bytes < 1024 * 1024) {
|
||||
snprintf(pads[pad_count].used_str, sizeof(pads[pad_count].used_str), "%.1fKB", (double)used_bytes / 1024.0);
|
||||
} else if (used_bytes < 1024 * 1024 * 1024) {
|
||||
snprintf(pads[pad_count].used_str, sizeof(pads[pad_count].used_str), "%.1fMB", (double)used_bytes / (1024.0 * 1024.0));
|
||||
} else {
|
||||
snprintf(pads[pad_count].used_str, sizeof(pads[pad_count].used_str), "%.2fGB", (double)used_bytes / (1024.0 * 1024.0 * 1024.0));
|
||||
}
|
||||
|
||||
// Calculate percentage
|
||||
pads[pad_count].percentage = (double)used_bytes / st.st_size * 100.0;
|
||||
|
||||
// Set location info using directory display
|
||||
get_directory_display(full_path, pads[pad_count].location, sizeof(pads[pad_count].location));
|
||||
|
||||
pad_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
if (pad_count == 0) {
|
||||
printf("\n%s\n", title);
|
||||
if (filter_type == PAD_FILTER_UNUSED_ONLY) {
|
||||
printf("No unused pads found.\n");
|
||||
printf("Entropy can only be added to pads with 0%% usage (only reserved bytes used).\n");
|
||||
} else {
|
||||
printf("No pads found.\n");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Calculate minimal unique prefixes for each pad
|
||||
char prefixes[100][65];
|
||||
int prefix_lengths[100];
|
||||
|
||||
for (int i = 0; i < pad_count; i++) {
|
||||
prefix_lengths[i] = 1;
|
||||
|
||||
// Find minimal unique prefix
|
||||
while (prefix_lengths[i] <= 64) {
|
||||
int unique = 1;
|
||||
|
||||
// Check if current prefix is unique among all other pads
|
||||
for (int j = 0; j < pad_count; j++) {
|
||||
if (i != j && strncmp(pads[i].chksum, pads[j].chksum, prefix_lengths[i]) == 0) {
|
||||
unique = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (unique) {
|
||||
break;
|
||||
}
|
||||
prefix_lengths[i]++;
|
||||
}
|
||||
|
||||
// Store the minimal prefix
|
||||
strncpy(prefixes[i], pads[i].chksum, prefix_lengths[i]);
|
||||
prefixes[i][prefix_lengths[i]] = '\0';
|
||||
}
|
||||
|
||||
// Display title and pads table
|
||||
printf("\n%s\n", title);
|
||||
printf("%-8s %-2s %-12s %-12s %-12s %-8s\n", "ChkSum", "D", "Dir", "Size", "Used", "% Used");
|
||||
printf("%-8s %-2s %-12s %-12s %-12s %-8s\n", "--------", "--", "------------", "----------", "----------", "------");
|
||||
|
||||
// Get current default pad path for comparison
|
||||
char* current_default = get_default_pad_path();
|
||||
char default_pad_checksum[65] = "";
|
||||
|
||||
if (current_default) {
|
||||
// Extract checksum from default pad path
|
||||
char* filename = strrchr(current_default, '/');
|
||||
if (!filename) filename = current_default;
|
||||
else filename++; // Skip the '/'
|
||||
|
||||
// Extract checksum (remove .pad extension)
|
||||
if (strlen(filename) >= 68 && strstr(filename, ".pad")) {
|
||||
strncpy(default_pad_checksum, filename, 64);
|
||||
default_pad_checksum[64] = '\0';
|
||||
}
|
||||
free(current_default);
|
||||
}
|
||||
|
||||
for (int i = 0; i < pad_count; i++) {
|
||||
// Check if this is the default pad
|
||||
int is_default = (strlen(default_pad_checksum) > 0 &&
|
||||
strncmp(pads[i].chksum, default_pad_checksum, 64) == 0);
|
||||
|
||||
// Display first 8 characters of checksum with prefix underlined
|
||||
char checksum_8char[9];
|
||||
strncpy(checksum_8char, pads[i].chksum, 8);
|
||||
checksum_8char[8] = '\0';
|
||||
|
||||
printf("\033[4m%.*s\033[0m%s %-2s %-12s %-12s %-12s %.1f%%\n",
|
||||
prefix_lengths[i], checksum_8char, // Underlined prefix
|
||||
checksum_8char + prefix_lengths[i], // Rest of 8-char checksum
|
||||
is_default ? "*" : "", // Default indicator
|
||||
pads[i].location,
|
||||
pads[i].size_str,
|
||||
pads[i].used_str,
|
||||
pads[i].percentage);
|
||||
}
|
||||
|
||||
// Display prompt
|
||||
printf("\n%s", prompt);
|
||||
if (allow_cancel) {
|
||||
printf(" (or 'x' to cancel)");
|
||||
}
|
||||
printf(": ");
|
||||
|
||||
char input[MAX_HASH_LENGTH];
|
||||
if (!fgets(input, sizeof(input), stdin)) {
|
||||
printf("Error: Failed to read input\n");
|
||||
return NULL;
|
||||
}
|
||||
input[strcspn(input, "\n")] = 0;
|
||||
|
||||
// Handle empty input - select default pad if available
|
||||
if (strlen(input) == 0) {
|
||||
// Get current default pad path
|
||||
char* current_default = get_default_pad_path();
|
||||
if (current_default) {
|
||||
// Extract checksum from default pad path
|
||||
char* filename = strrchr(current_default, '/');
|
||||
if (!filename) filename = current_default;
|
||||
else filename++; // Skip the '/'
|
||||
|
||||
// Extract checksum (remove .pad extension)
|
||||
if (strlen(filename) >= 68 && strstr(filename, ".pad")) {
|
||||
char default_checksum[65];
|
||||
strncpy(default_checksum, filename, 64);
|
||||
default_checksum[64] = '\0';
|
||||
|
||||
// Verify this default pad is in our current list
|
||||
for (int i = 0; i < pad_count; i++) {
|
||||
if (strncmp(pads[i].chksum, default_checksum, 64) == 0) {
|
||||
free(current_default);
|
||||
printf("Selected default pad: %.16s...\n\n", default_checksum);
|
||||
return strdup(default_checksum);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(current_default);
|
||||
}
|
||||
// No default pad or default pad not in current list
|
||||
printf("No default pad available or default pad not in current list\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Handle cancel
|
||||
if (allow_cancel && (toupper(input[0]) == 'X' && strlen(input) == 1)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Find matching pad by prefix or number
|
||||
int selected_pad = -1;
|
||||
int match_count = 0;
|
||||
|
||||
// Check if input is a number first
|
||||
char* endptr;
|
||||
int selection = strtol(input, &endptr, 10);
|
||||
if (*endptr == '\0' && selection >= 1 && selection <= pad_count) {
|
||||
// Valid number selection
|
||||
selected_pad = selection - 1;
|
||||
match_count = 1;
|
||||
} else {
|
||||
// Try prefix matching
|
||||
for (int i = 0; i < pad_count; i++) {
|
||||
if (strncmp(input, pads[i].chksum, strlen(input)) == 0) {
|
||||
if (match_count == 0) {
|
||||
selected_pad = i;
|
||||
}
|
||||
match_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (match_count == 0) {
|
||||
printf("No pad found matching '%s'\n", input);
|
||||
return NULL;
|
||||
} else if (match_count > 1) {
|
||||
printf("Ambiguous prefix. Multiple matches found.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Return selected pad checksum (caller must free)
|
||||
return strdup(pads[selected_pad].chksum);
|
||||
}
|
||||
|
||||
int handle_pads_menu(void) {
|
||||
printf("\n=== Pad Management ===\n");
|
||||
|
||||
@@ -3915,8 +4169,8 @@ int handle_pads_menu(void) {
|
||||
|
||||
// Display pads with minimal prefixes underlined and default indicator
|
||||
printf("\nAvailable pads:\n");
|
||||
printf("%-7s %-8s %-12s %-12s %-12s %-8s\n", "Default", "ChkSum", "Dir", "Size", "Used", "% Used");
|
||||
printf("%-7s %-8s %-12s %-12s %-12s %-8s\n", "-------", "--------", "------------", "----------", "----------", "------");
|
||||
printf("%-8s %-2s %-12s %-12s %-12s %-8s\n", "ChkSum", "D", "Dir", "Size", "Used", "% Used");
|
||||
printf("%-8s %-2s %-12s %-12s %-12s %-8s\n", "--------", "--", "------------", "----------", "----------", "------");
|
||||
|
||||
// Get current default pad path for comparison
|
||||
char* current_default = get_default_pad_path();
|
||||
@@ -3946,10 +4200,10 @@ int handle_pads_menu(void) {
|
||||
strncpy(checksum_8char, pads[i].chksum, 8);
|
||||
checksum_8char[8] = '\0';
|
||||
|
||||
printf("%-7s \033[4m%.*s\033[0m%s %-12s %-12s %-12s %.1f%%\n",
|
||||
is_default ? "*" : "", // Default indicator
|
||||
printf("\033[4m%.*s\033[0m%s %-2s %-12s %-12s %-12s %.1f%%\n",
|
||||
prefix_lengths[i], checksum_8char, // Underlined prefix
|
||||
checksum_8char + prefix_lengths[i], // Rest of 8-char checksum
|
||||
is_default ? "*" : "", // Default indicator
|
||||
pads[i].location, // Use the stored location info
|
||||
pads[i].size_str,
|
||||
pads[i].used_str,
|
||||
@@ -3958,9 +4212,10 @@ int handle_pads_menu(void) {
|
||||
|
||||
printf("\nActions:\n");
|
||||
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(" E\033[4mx\033[0mit\n");
|
||||
printf("\nSelect pad (by prefix) or action: ");
|
||||
printf("\nSelect action: ");
|
||||
|
||||
char input[MAX_HASH_LENGTH];
|
||||
if (!fgets(input, sizeof(input), stdin)) {
|
||||
@@ -3969,7 +4224,7 @@ int handle_pads_menu(void) {
|
||||
}
|
||||
input[strcspn(input, "\n")] = 0;
|
||||
|
||||
// Handle actions first
|
||||
// Handle actions
|
||||
if (toupper(input[0]) == 'G') {
|
||||
int result = handle_generate_menu();
|
||||
if (result == 0) {
|
||||
@@ -3977,32 +4232,31 @@ int handle_pads_menu(void) {
|
||||
return handle_pads_menu();
|
||||
}
|
||||
return result;
|
||||
} else if (toupper(input[0]) == 'S') {
|
||||
// Set default pad
|
||||
printf("\nSelect pad to set as default (by prefix): ");
|
||||
char pad_input[MAX_HASH_LENGTH];
|
||||
if (!fgets(pad_input, sizeof(pad_input), stdin)) {
|
||||
printf("Error: Failed to read input\n");
|
||||
return 1;
|
||||
}
|
||||
pad_input[strcspn(pad_input, "\n")] = 0;
|
||||
|
||||
// Find matching pad by prefix using the same logic as pad selection
|
||||
int matched_pad = -1;
|
||||
int match_count = 0;
|
||||
|
||||
for (int i = 0; i < pad_count; i++) {
|
||||
if (strncmp(pad_input, pads[i].chksum, strlen(pad_input)) == 0) {
|
||||
matched_pad = i;
|
||||
match_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (match_count == 0) {
|
||||
printf("No pad found matching prefix '%s'\n", pad_input);
|
||||
} else if (toupper(input[0]) == 'A') {
|
||||
// Add entropy to pad - use unified function with unused pads filter
|
||||
char* selected_pad = select_pad_interactive("=== Select Unused Pad for Entropy Addition ===",
|
||||
"Select unused pad (by prefix or number)",
|
||||
PAD_FILTER_UNUSED_ONLY, 1);
|
||||
if (!selected_pad) {
|
||||
printf("Entropy addition cancelled.\n");
|
||||
return handle_pads_menu();
|
||||
} else if (match_count > 1) {
|
||||
printf("Ambiguous prefix. Multiple matches found.\n");
|
||||
}
|
||||
|
||||
// Add entropy to the selected unused pad
|
||||
int result = handle_add_entropy_to_pad(selected_pad);
|
||||
free(selected_pad);
|
||||
if (result == 0) {
|
||||
// Return to pads menu after successful entropy addition
|
||||
return handle_pads_menu();
|
||||
}
|
||||
return result;
|
||||
} else if (toupper(input[0]) == 'S') {
|
||||
// Set default pad - use unified function
|
||||
char* selected_pad = select_pad_interactive("=== Select Default Pad ===",
|
||||
"Select pad to set as default (by prefix)",
|
||||
PAD_FILTER_ALL, 1);
|
||||
if (!selected_pad) {
|
||||
printf("Default pad selection cancelled.\n");
|
||||
return handle_pads_menu();
|
||||
}
|
||||
|
||||
@@ -4010,93 +4264,53 @@ int handle_pads_menu(void) {
|
||||
char new_default_path[1024];
|
||||
if (current_pads_dir[0] == '/') {
|
||||
// Already absolute path
|
||||
int ret = snprintf(new_default_path, sizeof(new_default_path), "%s/%s.pad", current_pads_dir, pads[matched_pad].chksum);
|
||||
int ret = snprintf(new_default_path, sizeof(new_default_path), "%s/%s.pad", current_pads_dir, selected_pad);
|
||||
if (ret >= (int)sizeof(new_default_path)) {
|
||||
printf("Error: Path too long for default pad setting\n");
|
||||
free(selected_pad);
|
||||
return handle_pads_menu();
|
||||
}
|
||||
} else {
|
||||
// Relative path - make it absolute
|
||||
char current_dir[512];
|
||||
if (getcwd(current_dir, sizeof(current_dir))) {
|
||||
int ret = snprintf(new_default_path, sizeof(new_default_path), "%s/%s/%s.pad", current_dir, current_pads_dir, pads[matched_pad].chksum);
|
||||
int ret = snprintf(new_default_path, sizeof(new_default_path), "%s/%s/%s.pad", current_dir, current_pads_dir, selected_pad);
|
||||
if (ret >= (int)sizeof(new_default_path)) {
|
||||
// Path was truncated, fall back to relative path
|
||||
int ret2 = snprintf(new_default_path, sizeof(new_default_path), "%s/%s.pad", current_pads_dir, pads[matched_pad].chksum);
|
||||
int ret2 = snprintf(new_default_path, sizeof(new_default_path), "%s/%s.pad", current_pads_dir, selected_pad);
|
||||
if (ret2 >= (int)sizeof(new_default_path)) {
|
||||
printf("Error: Path too long for default pad setting\n");
|
||||
free(selected_pad);
|
||||
return handle_pads_menu();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Fallback to relative path
|
||||
int ret = snprintf(new_default_path, sizeof(new_default_path), "%s/%s.pad", current_pads_dir, pads[matched_pad].chksum);
|
||||
int ret = snprintf(new_default_path, sizeof(new_default_path), "%s/%s.pad", current_pads_dir, selected_pad);
|
||||
if (ret >= (int)sizeof(new_default_path)) {
|
||||
printf("Error: Path too long for default pad setting\n");
|
||||
free(selected_pad);
|
||||
return handle_pads_menu();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (set_default_pad_path(new_default_path) == 0) {
|
||||
printf("Default pad set to: %.16s...\n", pads[matched_pad].chksum);
|
||||
printf("Default pad set to: %.16s...\n", selected_pad);
|
||||
printf("Full path: %s\n", new_default_path);
|
||||
} else {
|
||||
printf("Error: Failed to update default pad preference\n");
|
||||
}
|
||||
|
||||
free(selected_pad);
|
||||
return handle_pads_menu();
|
||||
} else if (toupper(input[0]) == 'X') {
|
||||
return 0; // Exit to main menu
|
||||
}
|
||||
|
||||
// Find matching pad by prefix
|
||||
int selected_pad = -1;
|
||||
for (int i = 0; i < pad_count; i++) {
|
||||
if (strncmp(input, pads[i].chksum, strlen(input)) == 0) {
|
||||
if (selected_pad == -1) {
|
||||
selected_pad = i;
|
||||
} else {
|
||||
// Multiple matches - ambiguous
|
||||
printf("Ambiguous prefix. Multiple matches found.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selected_pad == -1) {
|
||||
printf("No pad found matching prefix '%s'\n", input);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Show selected pad actions
|
||||
printf("\n=== Pad: %.16s... ===\n", pads[selected_pad].chksum);
|
||||
printf("Size: %s\n", pads[selected_pad].size_str);
|
||||
printf("Used: %s (%.1f%%)\n", pads[selected_pad].used_str, pads[selected_pad].percentage);
|
||||
|
||||
printf("\nPad Actions:\n");
|
||||
printf(" \033[4mI\033[0mnfo - Show detailed pad information\n");
|
||||
printf(" \033[4mA\033[0mdd entropy - Enhance pad randomness\n");
|
||||
printf(" \033[4mB\033[0mack to pad list\n");
|
||||
printf("\nSelect action: ");
|
||||
|
||||
char action[10];
|
||||
if (!fgets(action, sizeof(action), stdin)) {
|
||||
printf("Error: Failed to read input\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char action_choice = toupper(action[0]);
|
||||
if (action_choice == 'I') {
|
||||
return show_pad_info(pads[selected_pad].chksum);
|
||||
} else if (action_choice == 'A') {
|
||||
// Handle entropy addition
|
||||
return handle_add_entropy_to_pad(pads[selected_pad].chksum);
|
||||
}
|
||||
|
||||
// Default: back to pad list (recursive call)
|
||||
printf("Invalid action. Please select G, A, S, or X.\n");
|
||||
return handle_pads_menu();
|
||||
}
|
||||
}
|
||||
|
||||
void get_directory_display(const char* file_path, char* result, size_t result_size) {
|
||||
// Extract directory path from full file path
|
||||
@@ -4326,8 +4540,8 @@ int handle_add_entropy_to_pad(const char* pad_chksum) {
|
||||
}
|
||||
|
||||
void print_usage(const char* program_name) {
|
||||
printf("OTP Cipher - One Time Pad Implementation %s\n", get_version());
|
||||
printf("%s\n", get_build_info());
|
||||
printf("OTP Cipher - One Time Pad Implementation v1.0.0\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);
|
||||
|
||||
Reference in New Issue
Block a user