Updated steps to make them easier to understand
also added --paranoid mode
This commit is contained in:
@@ -3,6 +3,7 @@ __pycache__/
|
|||||||
*.py[cod]
|
*.py[cod]
|
||||||
*$py.class
|
*$py.class
|
||||||
*.so
|
*.so
|
||||||
|
.claude
|
||||||
|
|
||||||
# Log files - may contain sensitive paths/device info
|
# Log files - may contain sensitive paths/device info
|
||||||
*.log
|
*.log
|
||||||
|
|||||||
@@ -66,9 +66,12 @@ sudo ./covert_sd_card_tool.py [options]
|
|||||||
- `-c`, `--custom` : Create a custom ISO bootable USB (uses Kali-style partitioning with persistence)
|
- `-c`, `--custom` : Create a custom ISO bootable USB (uses Kali-style partitioning with persistence)
|
||||||
- `-d`, `--docs` : Create an encrypted documents partition
|
- `-d`, `--docs` : Create an encrypted documents partition
|
||||||
- `-i`, `--iso` : Path to the ISO file (Kali, Tails, or custom)
|
- `-i`, `--iso` : Path to the ISO file (Kali, Tails, or custom)
|
||||||
- `--fast` : Enable fast setup mode (Note: Documents partition always uses maximum security)
|
- `--fast` : Enable fast setup mode (weaker encryption, faster setup - not recommended)
|
||||||
|
- `--paranoid` : Enable paranoid mode (maximum security: 3-pass wipe, Argon2id, PIM 5000)
|
||||||
- `--debug` : Enable debug mode with verbose logging
|
- `--debug` : Enable debug mode with verbose logging
|
||||||
|
|
||||||
|
**Note:** `--fast` and `--paranoid` are mutually exclusive. Documents partition always uses strong encryption even in fast mode.
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
- **Install Kali with Encrypted Persistence and Encrypted Documents Partition:**
|
- **Install Kali with Encrypted Persistence and Encrypted Documents Partition:**
|
||||||
@@ -107,31 +110,75 @@ sudo ./covert_sd_card_tool.py [options]
|
|||||||
sudo ./covert_sd_card_tool.py -c -i /path/to/custom.iso
|
sudo ./covert_sd_card_tool.py -c -i /path/to/custom.iso
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- **Paranoid Mode - Maximum Security (Tails + Docs):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ./covert_sd_card_tool.py -t -d -i /path/to/tails.iso --paranoid
|
||||||
|
```
|
||||||
|
|
||||||
## Security Features
|
## Security Features
|
||||||
|
|
||||||
### Documents Partition Encryption
|
### Documents Partition Encryption
|
||||||
|
|
||||||
The documents partition uses **maximum security settings** regardless of the `--fast` flag:
|
The documents partition uses **strong security** in all modes:
|
||||||
|
|
||||||
|
**Standard Mode (default):**
|
||||||
- **Triple Cascade Encryption:** AES-Twofish-Serpent (3 layers)
|
- **Triple Cascade Encryption:** AES-Twofish-Serpent (3 layers)
|
||||||
- **Hash Algorithm:** SHA-512
|
- **Hash Algorithm:** SHA-512
|
||||||
- **Key Derivation:** PIM 2000 (enforced for strong key stretching)
|
- **Key Derivation:** PIM 2000 (strong key stretching)
|
||||||
|
- **Unlock Time:** ~2-3 seconds
|
||||||
- **Filesystem:** ext4
|
- **Filesystem:** ext4
|
||||||
- **Full Format:** Always performs full format (no quick format) to overwrite old data
|
- **Full Format:** Always overwrites old data
|
||||||
|
|
||||||
This configuration provides **military-grade security** suitable for sensitive documents like travel documents, credentials, and confidential files.
|
**Paranoid Mode (`--paranoid`):**
|
||||||
|
- **Triple Cascade Encryption:** AES-Twofish-Serpent (3 layers)
|
||||||
|
- **Hash Algorithm:** SHA-512
|
||||||
|
- **Key Derivation:** PIM 5000 (maximum key stretching)
|
||||||
|
- **Unlock Time:** ~5-7 seconds
|
||||||
|
- **Security:** Would take trillions of years to brute force
|
||||||
|
|
||||||
### Persistence Partition Encryption (Kali)
|
**Fast Mode (`--fast`):**
|
||||||
|
- Documents still use standard mode (PIM 2000) - no compromise on docs security
|
||||||
|
|
||||||
- **Normal Mode:** AES-XTS-PLAIN64, 512-bit keys, SHA-512, 5 second iteration time
|
### Persistence Partition Encryption (Kali/Custom)
|
||||||
- **Fast Mode:** AES-CBC-ESSIV:SHA256, 256-bit keys, SHA-256, 1 second iteration time
|
|
||||||
|
**Standard Mode (default):**
|
||||||
|
- **Algorithm:** AES-XTS-PLAIN64
|
||||||
|
- **Key Size:** 512-bit
|
||||||
|
- **Hash:** SHA-512
|
||||||
|
- **KDF:** LUKS2 PBKDF2
|
||||||
|
- **Iteration Time:** 5 seconds
|
||||||
|
|
||||||
|
**Paranoid Mode (`--paranoid`):**
|
||||||
|
- **Algorithm:** AES-XTS-PLAIN64
|
||||||
|
- **Key Size:** 512-bit
|
||||||
|
- **Hash:** SHA-512
|
||||||
|
- **KDF:** LUKS2 Argon2id (memory-hard, GPU-resistant)
|
||||||
|
- **Memory:** 1GB
|
||||||
|
- **Parallel Threads:** 4
|
||||||
|
- **Iteration Time:** 10 seconds
|
||||||
|
|
||||||
|
**Fast Mode (`--fast`):**
|
||||||
|
- **Algorithm:** AES-CBC-ESSIV:SHA256
|
||||||
|
- **Key Size:** 256-bit
|
||||||
|
- **Hash:** SHA-256
|
||||||
|
- **KDF:** LUKS1 PBKDF2
|
||||||
|
- **Iteration Time:** 1 second
|
||||||
|
|
||||||
### Secure Drive Wiping
|
### Secure Drive Wiping
|
||||||
|
|
||||||
When you choose to wipe the drive, the tool uses `shred`:
|
**Standard Mode (default):**
|
||||||
- **3 passes** of random data overwriting
|
- **1 pass** with zeros (`dd if=/dev/zero`)
|
||||||
|
- Fast and sufficient for most use cases
|
||||||
|
- Prevents casual data recovery
|
||||||
|
- Confirmation required (must type 'WIPE')
|
||||||
|
|
||||||
|
**Paranoid Mode (`--paranoid`):**
|
||||||
|
- **3 passes** with random data (`shred`)
|
||||||
- **Final pass** with zeros
|
- **Final pass** with zeros
|
||||||
- Makes data recovery virtually impossible
|
- Makes data recovery virtually impossible
|
||||||
|
- Defense against forensic recovery techniques
|
||||||
|
- **Much slower** (can take hours on large drives)
|
||||||
- Confirmation required (must type 'WIPE')
|
- Confirmation required (must type 'WIPE')
|
||||||
|
|
||||||
### OPSEC (Operational Security)
|
### OPSEC (Operational Security)
|
||||||
@@ -165,6 +212,25 @@ The tool creates a small unencrypted partition (TOOLS) containing:
|
|||||||
- Generic terminology (no encryption disclosure)
|
- Generic terminology (no encryption disclosure)
|
||||||
- Step-by-step mount/lock procedures
|
- Step-by-step mount/lock procedures
|
||||||
|
|
||||||
|
## Security Mode Comparison
|
||||||
|
|
||||||
|
| Feature | Fast Mode | Standard Mode (Default) | Paranoid Mode |
|
||||||
|
|---------|-----------|------------------------|---------------|
|
||||||
|
| **Drive Wipe** | Partition table clear only | 1-pass zeros | 3-pass shred + zeros |
|
||||||
|
| **Wipe Time (64GB)** | Instant | ~5-10 min | ~2-3 hours |
|
||||||
|
| **Persistence KDF** | LUKS1 PBKDF2 | LUKS2 PBKDF2 | LUKS2 Argon2id |
|
||||||
|
| **Persistence Unlock** | ~1 sec | ~5 sec | ~10 sec |
|
||||||
|
| **Docs Encryption** | AES-Twofish-Serpent | AES-Twofish-Serpent | AES-Twofish-Serpent |
|
||||||
|
| **Docs PIM** | 2000 | 2000 | 5000 |
|
||||||
|
| **Docs Unlock** | ~2-3 sec | ~2-3 sec | ~5-7 sec |
|
||||||
|
| **Best For** | Testing/dev | Travel, daily use | Maximum security, high-value targets |
|
||||||
|
|
||||||
|
**Recommendation:** Use **standard mode** for most cases. Use **paranoid mode** if:
|
||||||
|
- You're protecting extremely sensitive data
|
||||||
|
- You face nation-state level threats
|
||||||
|
- You have time for longer setup and unlock times
|
||||||
|
- You want defense against forensic analysis
|
||||||
|
|
||||||
## Important Security Notes
|
## Important Security Notes
|
||||||
|
|
||||||
⚠️ **Password Strength:** Use strong passphrases (20+ characters, mixed case, numbers, symbols)
|
⚠️ **Password Strength:** Use strong passphrases (20+ characters, mixed case, numbers, symbols)
|
||||||
|
|||||||
+231
-40
@@ -12,6 +12,7 @@ import json
|
|||||||
# Global variables
|
# Global variables
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
FAST_MODE = False
|
FAST_MODE = False
|
||||||
|
PARANOID_MODE = False
|
||||||
TIMESTAMP = datetime.now().strftime('%Y%m%d_%H%M%S')
|
TIMESTAMP = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||||
LOG_FILE = f"covert_sd_setup_{TIMESTAMP}.log"
|
LOG_FILE = f"covert_sd_setup_{TIMESTAMP}.log"
|
||||||
CREATE_KALI = False
|
CREATE_KALI = False
|
||||||
@@ -29,14 +30,15 @@ def log(message):
|
|||||||
log_file.write(message + "\n")
|
log_file.write(message + "\n")
|
||||||
print(message)
|
print(message)
|
||||||
|
|
||||||
def run_command(command, shell=False, interactive=False):
|
def run_command(command, shell=False, interactive=False, ignore_enospc=False):
|
||||||
"""
|
"""
|
||||||
Runs a system command.
|
Runs a system command.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
command (list or str): The command to execute.
|
command (list or str): The command to execute.
|
||||||
shell (bool): Whether to execute the command through the shell.
|
shell (bool): Whether to execute the command through the shell.
|
||||||
interactive (bool): If True, streams the command's output live.
|
interactive (bool): If True, streams the command's output live.
|
||||||
|
ignore_enospc (bool): If True, don't exit on "No space left" error (for dd filling disk).
|
||||||
"""
|
"""
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
log(f"Running command: {command}")
|
log(f"Running command: {command}")
|
||||||
@@ -44,7 +46,13 @@ def run_command(command, shell=False, interactive=False):
|
|||||||
if interactive:
|
if interactive:
|
||||||
# Use subprocess.run with no stdout/stderr capture for truly interactive commands
|
# Use subprocess.run with no stdout/stderr capture for truly interactive commands
|
||||||
# This allows the command to directly interact with the terminal
|
# This allows the command to directly interact with the terminal
|
||||||
result = subprocess.run(command, shell=shell, check=True)
|
# Don't use check=True if we want to ignore ENOSPC
|
||||||
|
result = subprocess.run(command, shell=shell, check=not ignore_enospc)
|
||||||
|
if ignore_enospc and result.returncode != 0:
|
||||||
|
# For dd, exit code 1 with ENOSPC is success (filled the disk)
|
||||||
|
return
|
||||||
|
elif result.returncode != 0:
|
||||||
|
raise subprocess.CalledProcessError(result.returncode, command)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
# Handle non-interactive commands
|
# Handle non-interactive commands
|
||||||
@@ -170,38 +178,101 @@ def setup_usb():
|
|||||||
Sets up the bootable USB (Tails or Kali) and creates additional partitions if required.
|
Sets up the bootable USB (Tails or Kali) and creates additional partitions if required.
|
||||||
"""
|
"""
|
||||||
global DRIVE
|
global DRIVE
|
||||||
log("Setting up bootable USB or preparing partitions...")
|
log("\n" + "="*70)
|
||||||
|
log("STEP 1: DRIVE SELECTION")
|
||||||
|
log("="*70)
|
||||||
|
log("Available storage devices on your system:")
|
||||||
list_drives()
|
list_drives()
|
||||||
|
log("\nIMPORTANT: Double-check the drive path! All data will be erased.")
|
||||||
DRIVE = input("Enter the drive to use for USB (e.g., /dev/sda) [Default: /dev/sda]: ") or "/dev/sda"
|
DRIVE = input("Enter the drive to use for USB (e.g., /dev/sda) [Default: /dev/sda]: ") or "/dev/sda"
|
||||||
|
|
||||||
confirm = input(f"You have selected {DRIVE}. Is this correct? (y/n) [Default: y]: ") or "y"
|
confirm = input(f"\nYou have selected {DRIVE}. Is this correct? (y/n) [Default: y]: ") or "y"
|
||||||
if confirm.lower() != "y":
|
if confirm.lower() != "y":
|
||||||
log("Drive selection canceled. Exiting.")
|
log("Drive selection canceled. Exiting.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
log("\n" + "="*70)
|
||||||
|
log("STEP 2: PREPARING DRIVE")
|
||||||
|
log("="*70)
|
||||||
prepare_drive(DRIVE)
|
prepare_drive(DRIVE)
|
||||||
|
|
||||||
if CREATE_KALI or CREATE_TAILS or CREATE_DOCS:
|
if CREATE_KALI or CREATE_TAILS or CREATE_DOCS:
|
||||||
wipe = input(f"Do you want to wipe the drive {DRIVE} before starting? (y/n) [Default: n]: ") or "n"
|
log("\n" + "="*70)
|
||||||
|
log("STEP 3: DRIVE WIPING (OPTIONAL)")
|
||||||
|
log("="*70)
|
||||||
|
log("Wiping destroys all existing data on the drive.")
|
||||||
|
log("This prevents recovery of old files and ensures a clean setup.")
|
||||||
|
log("")
|
||||||
|
if PARANOID_MODE:
|
||||||
|
log("PARANOID MODE: 3-pass overwrite (very slow, ~2-3 hours for 64GB)")
|
||||||
|
else:
|
||||||
|
log("STANDARD MODE: 1-pass zero overwrite (~10-20 min for 64GB)")
|
||||||
|
log("Skip wiping if this is already a blank/new drive.")
|
||||||
|
log("")
|
||||||
|
|
||||||
|
wipe = input(f"Do you want to wipe {DRIVE} before starting? (y/n) [Default: n]: ") or "n"
|
||||||
if wipe.lower() == "y":
|
if wipe.lower() == "y":
|
||||||
log(f"Wiping {DRIVE} and clearing any existing file system or encryption signatures...")
|
if PARANOID_MODE:
|
||||||
log("This will securely overwrite the entire drive with random data. This may take a while...")
|
log("\n" + "-"*70)
|
||||||
confirm_wipe = input(f"Are you ABSOLUTELY sure you want to completely wipe {DRIVE}? Type 'WIPE' to confirm: ")
|
log("PARANOID WIPE: 3 passes with random data + final zero pass")
|
||||||
if confirm_wipe == "WIPE":
|
log("WARNING: This will take HOURS on large drives!")
|
||||||
run_command(["sudo", "wipefs", "--all", DRIVE])
|
log("Estimated time: 2-3 hours for 64GB drive")
|
||||||
run_command(["sudo", "sgdisk", "--zap-all", DRIVE])
|
log("-"*70)
|
||||||
# Secure wipe using shred - 3 passes with random data, then zeros
|
confirm_wipe = input(f"Type 'WIPE' to confirm complete wipe of {DRIVE}: ")
|
||||||
run_command(["sudo", "shred", "-vfz", "-n", "3", DRIVE], interactive=True)
|
if confirm_wipe == "WIPE":
|
||||||
log(f"{DRIVE} securely wiped successfully.")
|
log("\nClearing partition table and filesystem signatures...")
|
||||||
|
run_command(["sudo", "wipefs", "--all", DRIVE])
|
||||||
|
run_command(["sudo", "sgdisk", "--zap-all", DRIVE])
|
||||||
|
log("\nStarting 3-pass shred (this will take a long time)...")
|
||||||
|
log("Pass 1/3: Random data")
|
||||||
|
log("Pass 2/3: Random data")
|
||||||
|
log("Pass 3/3: Random data")
|
||||||
|
log("Final pass: Zeros")
|
||||||
|
log("You can monitor progress below:")
|
||||||
|
# Paranoid: 3 passes with random data, then zeros
|
||||||
|
run_command(["sudo", "shred", "-vfz", "-n", "3", DRIVE], interactive=True)
|
||||||
|
log(f"\n✓ {DRIVE} securely wiped successfully (paranoid mode).")
|
||||||
|
else:
|
||||||
|
log("\nFull wipe canceled. Clearing partition table only...")
|
||||||
|
run_command(["sudo", "wipefs", "--all", DRIVE])
|
||||||
|
run_command(["sudo", "sgdisk", "--zap-all", DRIVE])
|
||||||
|
log("✓ Partition table cleared.")
|
||||||
else:
|
else:
|
||||||
log("Wipe canceled. Proceeding without full wipe (only clearing partition table)...")
|
log("\n" + "-"*70)
|
||||||
run_command(["sudo", "wipefs", "--all", DRIVE])
|
log("STANDARD WIPE: Single pass with zeros")
|
||||||
run_command(["sudo", "sgdisk", "--zap-all", DRIVE])
|
log("Estimated time: ~10-20 minutes for 64GB drive")
|
||||||
|
log("-"*70)
|
||||||
|
confirm_wipe = input(f"Type 'WIPE' to confirm wipe of {DRIVE}: ")
|
||||||
|
if confirm_wipe == "WIPE":
|
||||||
|
log("\nClearing partition table and filesystem signatures...")
|
||||||
|
run_command(["sudo", "wipefs", "--all", DRIVE])
|
||||||
|
run_command(["sudo", "sgdisk", "--zap-all", DRIVE])
|
||||||
|
log("\nOverwriting entire drive with zeros...")
|
||||||
|
log("Progress will be shown below (this may take 10-20 minutes):")
|
||||||
|
log("(Note: dd will show 'No space left on device' when complete - this is normal)")
|
||||||
|
log("")
|
||||||
|
# Standard: Single pass with zeros (much faster)
|
||||||
|
# Note: dd will report "No space left on device" when it fills the drive - this is expected and means success
|
||||||
|
run_command(["sudo", "dd", "if=/dev/zero", f"of={DRIVE}", "bs=1M", "status=progress", "conv=fdatasync"], interactive=True, ignore_enospc=True)
|
||||||
|
log(f"\n✓ {DRIVE} wiped successfully (standard mode).")
|
||||||
|
else:
|
||||||
|
log("\nFull wipe canceled. Clearing partition table only...")
|
||||||
|
run_command(["sudo", "wipefs", "--all", DRIVE])
|
||||||
|
run_command(["sudo", "sgdisk", "--zap-all", DRIVE])
|
||||||
|
log("✓ Partition table cleared.")
|
||||||
|
else:
|
||||||
|
log("\nSkipping full drive wipe. Clearing partition table only...")
|
||||||
|
run_command(["sudo", "wipefs", "--all", DRIVE])
|
||||||
|
run_command(["sudo", "sgdisk", "--zap-all", DRIVE])
|
||||||
|
log("✓ Partition table cleared.")
|
||||||
|
|
||||||
# Initialize variables to track if ISO has been written
|
# Initialize variables to track if ISO has been written
|
||||||
iso_written = False
|
iso_written = False
|
||||||
|
|
||||||
if CREATE_KALI or CREATE_TAILS or CREATE_CUSTOM:
|
if CREATE_KALI or CREATE_TAILS or CREATE_CUSTOM:
|
||||||
|
log("\n" + "="*70)
|
||||||
|
log("STEP 4: WRITING BOOTABLE ISO")
|
||||||
|
log("="*70)
|
||||||
global KALI_ISO, TAILS_ISO, CUSTOM_ISO
|
global KALI_ISO, TAILS_ISO, CUSTOM_ISO
|
||||||
if CREATE_KALI:
|
if CREATE_KALI:
|
||||||
if not KALI_ISO:
|
if not KALI_ISO:
|
||||||
@@ -210,6 +281,7 @@ def setup_usb():
|
|||||||
log(f"Error: Kali ISO file not found at {KALI_ISO}")
|
log(f"Error: Kali ISO file not found at {KALI_ISO}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
ISO_PATH = KALI_ISO
|
ISO_PATH = KALI_ISO
|
||||||
|
iso_name = "Kali Linux"
|
||||||
elif CREATE_TAILS:
|
elif CREATE_TAILS:
|
||||||
if not TAILS_ISO:
|
if not TAILS_ISO:
|
||||||
TAILS_ISO = input("Enter the path to the Tails ISO file: ")
|
TAILS_ISO = input("Enter the path to the Tails ISO file: ")
|
||||||
@@ -217,6 +289,7 @@ def setup_usb():
|
|||||||
log(f"Error: Tails ISO file not found at {TAILS_ISO}")
|
log(f"Error: Tails ISO file not found at {TAILS_ISO}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
ISO_PATH = TAILS_ISO
|
ISO_PATH = TAILS_ISO
|
||||||
|
iso_name = "Tails"
|
||||||
elif CREATE_CUSTOM:
|
elif CREATE_CUSTOM:
|
||||||
if not CUSTOM_ISO:
|
if not CUSTOM_ISO:
|
||||||
CUSTOM_ISO = input("Enter the path to your custom ISO file: ")
|
CUSTOM_ISO = input("Enter the path to your custom ISO file: ")
|
||||||
@@ -224,18 +297,33 @@ def setup_usb():
|
|||||||
log(f"Error: Custom ISO file not found at {CUSTOM_ISO}")
|
log(f"Error: Custom ISO file not found at {CUSTOM_ISO}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
ISO_PATH = CUSTOM_ISO
|
ISO_PATH = CUSTOM_ISO
|
||||||
|
iso_name = "Custom"
|
||||||
|
|
||||||
|
# Get ISO size for time estimate
|
||||||
|
iso_size_bytes = os.path.getsize(ISO_PATH)
|
||||||
|
iso_size_gb = iso_size_bytes / (1024**3)
|
||||||
|
estimated_time = int((iso_size_gb / 0.5) * 60) # Rough estimate: 30 seconds per GB at 50MB/s
|
||||||
|
|
||||||
|
log(f"ISO file: {ISO_PATH}")
|
||||||
|
log(f"ISO size: {iso_size_gb:.2f} GB")
|
||||||
|
log(f"Estimated write time: ~{estimated_time} seconds ({estimated_time//60} min)")
|
||||||
|
log("")
|
||||||
|
|
||||||
if CREATE_TAILS:
|
if CREATE_TAILS:
|
||||||
# For Tails, flash the ISO to the entire drive without any partitioning
|
# For Tails, flash the ISO to the entire drive without any partitioning
|
||||||
log(f"Flashing Tails ISO to {DRIVE}...")
|
log(f"Writing {iso_name} ISO to {DRIVE}...")
|
||||||
|
log("Progress will be shown below:")
|
||||||
|
log("")
|
||||||
run_command(f"sudo dd if='{ISO_PATH}' of='{DRIVE}' bs=64M status=progress conv=fdatasync", shell=True, interactive=True)
|
run_command(f"sudo dd if='{ISO_PATH}' of='{DRIVE}' bs=64M status=progress conv=fdatasync", shell=True, interactive=True)
|
||||||
log(f"Tails ISO flashed to {DRIVE} successfully.")
|
log(f"\n✓ {iso_name} ISO written to {DRIVE} successfully.")
|
||||||
iso_written = True
|
iso_written = True
|
||||||
else:
|
else:
|
||||||
# For Kali or Custom ISO, flash and proceed with partition setup
|
# For Kali or Custom ISO, flash and proceed with partition setup
|
||||||
log(f"Flashing ISO to {DRIVE}...")
|
log(f"Writing {iso_name} ISO to {DRIVE}...")
|
||||||
|
log("Progress will be shown below:")
|
||||||
|
log("")
|
||||||
run_command(f"sudo dd if='{ISO_PATH}' of='{DRIVE}' bs=64M status=progress conv=fdatasync", shell=True, interactive=True)
|
run_command(f"sudo dd if='{ISO_PATH}' of='{DRIVE}' bs=64M status=progress conv=fdatasync", shell=True, interactive=True)
|
||||||
log(f"ISO flashed to {DRIVE} successfully.")
|
log(f"\n✓ {iso_name} ISO written to {DRIVE} successfully.")
|
||||||
iso_written = True
|
iso_written = True
|
||||||
|
|
||||||
# After writing ISO, set up partitions accordingly
|
# After writing ISO, set up partitions accordingly
|
||||||
@@ -258,15 +346,24 @@ def fix_partition_table_docs_only():
|
|||||||
"""
|
"""
|
||||||
Sets up partitions solely for encrypted documents without altering existing OS partitions.
|
Sets up partitions solely for encrypted documents without altering existing OS partitions.
|
||||||
"""
|
"""
|
||||||
log("Setting up partitions for documents only...")
|
log("\n" + "="*70)
|
||||||
|
log("STEP 5: CREATING PARTITION LAYOUT")
|
||||||
|
log("="*70)
|
||||||
|
log("Creating 2 partitions:")
|
||||||
|
log(" 1. Encrypted documents partition (VeraCrypt)")
|
||||||
|
log(" 2. Tools partition (1GB, unencrypted, contains mount scripts)")
|
||||||
|
log("")
|
||||||
|
|
||||||
# Clear existing GPT label to start fresh
|
# Clear existing GPT label to start fresh
|
||||||
|
log("Creating fresh GPT partition table...")
|
||||||
run_command(f"sudo parted -a optimal -s {DRIVE} mklabel gpt", shell=True)
|
run_command(f"sudo parted -a optimal -s {DRIVE} mklabel gpt", shell=True)
|
||||||
run_command(f"sudo partprobe {DRIVE}", shell=True)
|
run_command(f"sudo partprobe {DRIVE}", shell=True)
|
||||||
run_command("sudo udevadm settle", shell=True)
|
run_command("sudo udevadm settle", shell=True)
|
||||||
time.sleep(5) # Increased sleep to ensure partitions are recognized
|
time.sleep(5) # Increased sleep to ensure partitions are recognized
|
||||||
|
log("✓ GPT partition table created")
|
||||||
|
|
||||||
# Get the total size of the drive in bytes
|
# Get the total size of the drive in bytes
|
||||||
|
log("\nCalculating partition sizes...")
|
||||||
result = subprocess.run(["lsblk", "-b", "-d", "-n", "-o", "SIZE", DRIVE], capture_output=True, text=True)
|
result = subprocess.run(["lsblk", "-b", "-d", "-n", "-o", "SIZE", DRIVE], capture_output=True, text=True)
|
||||||
try:
|
try:
|
||||||
total_size_bytes = int(result.stdout.strip())
|
total_size_bytes = int(result.stdout.strip())
|
||||||
@@ -277,8 +374,9 @@ def fix_partition_table_docs_only():
|
|||||||
total_size_gb = total_size_mib / 1024 # Convert to GiB
|
total_size_gb = total_size_mib / 1024 # Convert to GiB
|
||||||
available_gb = (total_size_mib - 1024) / 1024 # Minus 1GB reserved for scripts
|
available_gb = (total_size_mib - 1024) / 1024 # Minus 1GB reserved for scripts
|
||||||
|
|
||||||
log(f"Total drive size: {total_size_gb:.2f} GB ({total_size_mib:.0f} MiB)")
|
log(f" Total drive size: {total_size_gb:.2f} GB ({total_size_mib:.0f} MiB)")
|
||||||
log(f"Available space for documents (minus 1GB for scripts): {available_gb:.2f} GB")
|
log(f" Available for documents: {available_gb:.2f} GB (after reserving 1GB for tools)")
|
||||||
|
log("")
|
||||||
|
|
||||||
# Ask for document partition size
|
# Ask for document partition size
|
||||||
size_docs = input("Enter size for documents partition in GB (leave blank to use remaining space minus 1GB): ")
|
size_docs = input("Enter size for documents partition in GB (leave blank to use remaining space minus 1GB): ")
|
||||||
@@ -297,18 +395,22 @@ def fix_partition_table_docs_only():
|
|||||||
end_docs_mib = total_size_mib - 1024 # Reserve 1GB for unencrypted partition
|
end_docs_mib = total_size_mib - 1024 # Reserve 1GB for unencrypted partition
|
||||||
|
|
||||||
# Create documents partition
|
# Create documents partition
|
||||||
|
log(f"\nCreating partition 1 (documents): {(end_docs_mib - start_docs_mib)/1024:.2f} GB...")
|
||||||
run_command(f"sudo parted -a optimal -s {DRIVE} mkpart primary {start_docs_mib}MiB {end_docs_mib}MiB", shell=True)
|
run_command(f"sudo parted -a optimal -s {DRIVE} mkpart primary {start_docs_mib}MiB {end_docs_mib}MiB", shell=True)
|
||||||
log("Created documents partition.")
|
log("✓ Documents partition created")
|
||||||
|
|
||||||
# Create unencrypted partition
|
# Create unencrypted partition
|
||||||
start_unencrypted_mib = end_docs_mib
|
start_unencrypted_mib = end_docs_mib
|
||||||
|
log(f"Creating partition 2 (tools): ~1 GB...")
|
||||||
run_command(f"sudo parted -a optimal -s {DRIVE} mkpart primary {start_unencrypted_mib}MiB 100%", shell=True)
|
run_command(f"sudo parted -a optimal -s {DRIVE} mkpart primary {start_unencrypted_mib}MiB 100%", shell=True)
|
||||||
log("Created unencrypted partition for scripts/instructions.")
|
log("✓ Tools partition created")
|
||||||
|
|
||||||
# Refresh partition table to recognize new partitions
|
# Refresh partition table to recognize new partitions
|
||||||
|
log("\nRefreshing partition table...")
|
||||||
run_command(f"sudo partprobe {DRIVE}", shell=True)
|
run_command(f"sudo partprobe {DRIVE}", shell=True)
|
||||||
run_command("sudo udevadm settle", shell=True)
|
run_command("sudo udevadm settle", shell=True)
|
||||||
time.sleep(5) # Increased sleep to ensure partitions are recognized
|
time.sleep(5) # Increased sleep to ensure partitions are recognized
|
||||||
|
log("✓ Partition table refreshed")
|
||||||
|
|
||||||
setup_unencrypted_partition()
|
setup_unencrypted_partition()
|
||||||
setup_docs_partition()
|
setup_docs_partition()
|
||||||
@@ -536,9 +638,24 @@ def setup_kali_partition():
|
|||||||
f"--verify-passphrase"
|
f"--verify-passphrase"
|
||||||
)
|
)
|
||||||
mkfs_cmd = f"sudo mkfs.ext3 -L persistence /dev/mapper/kali_USB"
|
mkfs_cmd = f"sudo mkfs.ext3 -L persistence /dev/mapper/kali_USB"
|
||||||
|
elif PARANOID_MODE:
|
||||||
|
luks_format_cmd = (
|
||||||
|
f"sudo cryptsetup luksFormat '{PERSIST_PART}' "
|
||||||
|
f"--type luks2 "
|
||||||
|
f"--cipher aes-xts-plain64 "
|
||||||
|
f"--key-size 512 "
|
||||||
|
f"--hash sha512 "
|
||||||
|
f"--pbkdf argon2id "
|
||||||
|
f"--iter-time 10000 "
|
||||||
|
f"--pbkdf-memory 1048576 "
|
||||||
|
f"--pbkdf-parallel 4 "
|
||||||
|
f"--verify-passphrase"
|
||||||
|
)
|
||||||
|
mkfs_cmd = f"sudo mkfs.ext4 -L persistence /dev/mapper/kali_USB"
|
||||||
else:
|
else:
|
||||||
luks_format_cmd = (
|
luks_format_cmd = (
|
||||||
f"sudo cryptsetup luksFormat '{PERSIST_PART}' "
|
f"sudo cryptsetup luksFormat '{PERSIST_PART}' "
|
||||||
|
f"--type luks2 "
|
||||||
f"--cipher aes-xts-plain64 "
|
f"--cipher aes-xts-plain64 "
|
||||||
f"--key-size 512 "
|
f"--key-size 512 "
|
||||||
f"--hash sha512 "
|
f"--hash sha512 "
|
||||||
@@ -567,14 +684,19 @@ def setup_docs_partition():
|
|||||||
global DRIVE
|
global DRIVE
|
||||||
DOCS_PART = get_partition_name(DRIVE, get_last_partition_number() - 1)
|
DOCS_PART = get_partition_name(DRIVE, get_last_partition_number() - 1)
|
||||||
|
|
||||||
|
log("\n" + "="*70)
|
||||||
|
log("STEP 6: ENCRYPTING DOCUMENTS PARTITION")
|
||||||
|
log("="*70)
|
||||||
|
|
||||||
# Check if the partition exists
|
# Check if the partition exists
|
||||||
if not os.path.exists(DOCS_PART):
|
if not os.path.exists(DOCS_PART):
|
||||||
log(f"Error: Partition {DOCS_PART} does not exist.")
|
log(f"Error: Partition {DOCS_PART} does not exist.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Force wipe existing filesystem signatures
|
# Force wipe existing filesystem signatures
|
||||||
|
log(f"Preparing partition {DOCS_PART}...")
|
||||||
run_command(["sudo", "wipefs", "--all", "--force", DOCS_PART])
|
run_command(["sudo", "wipefs", "--all", "--force", DOCS_PART])
|
||||||
log(f"Removed existing filesystem signatures from {DOCS_PART}.")
|
log(f"✓ Partition prepared")
|
||||||
|
|
||||||
log("\n" + "="*70)
|
log("\n" + "="*70)
|
||||||
log("ENCRYPTED VOLUME SETUP")
|
log("ENCRYPTED VOLUME SETUP")
|
||||||
@@ -586,9 +708,12 @@ def setup_docs_partition():
|
|||||||
log(" - Mix uppercase, lowercase, numbers, and symbols")
|
log(" - Mix uppercase, lowercase, numbers, and symbols")
|
||||||
log(" - Avoid dictionary words or personal information")
|
log(" - Avoid dictionary words or personal information")
|
||||||
log(" 2. PIM (Personal Iterations Multiplier):")
|
log(" 2. PIM (Personal Iterations Multiplier):")
|
||||||
log(" - RECOMMENDED: Enter 2000 for maximum security")
|
if PARANOID_MODE:
|
||||||
log(" - Minimum acceptable: 1000")
|
log(" - PARANOID MODE: PIM set to 5000 (maximum security)")
|
||||||
log(" - Higher = more secure but slower unlock (2-3 seconds)")
|
log(" - Unlock time: ~5-7 seconds")
|
||||||
|
else:
|
||||||
|
log(" - STANDARD: PIM set to 2000 (high security)")
|
||||||
|
log(" - Unlock time: ~2-3 seconds")
|
||||||
log(" 3. KEYFILES: Leave blank unless you know what you're doing")
|
log(" 3. KEYFILES: Leave blank unless you know what you're doing")
|
||||||
log("\nIMPORTANT: Remember your password! There is NO password recovery!")
|
log("\nIMPORTANT: Remember your password! There is NO password recovery!")
|
||||||
log("="*70)
|
log("="*70)
|
||||||
@@ -598,17 +723,29 @@ def setup_docs_partition():
|
|||||||
|
|
||||||
# Always use maximum security for documents partition (ignore FAST_MODE)
|
# Always use maximum security for documents partition (ignore FAST_MODE)
|
||||||
# Triple cascade encryption with strongest hash
|
# Triple cascade encryption with strongest hash
|
||||||
|
pim_value = 5000 if PARANOID_MODE else 2000
|
||||||
veracrypt_create_cmd = (
|
veracrypt_create_cmd = (
|
||||||
f"veracrypt --text --create '{DOCS_PART}' "
|
f"veracrypt --text --create '{DOCS_PART}' "
|
||||||
f"--encryption AES-Twofish-Serpent "
|
f"--encryption AES-Twofish-Serpent "
|
||||||
f"--hash SHA-512 "
|
f"--hash SHA-512 "
|
||||||
f"--filesystem ext4 "
|
f"--filesystem ext4 "
|
||||||
f"--volume-type normal "
|
f"--volume-type normal "
|
||||||
f"--pim 2000 " # Enforce strong PIM for maximum security
|
f"--pim {pim_value} " # 2000 standard, 5000 paranoid
|
||||||
)
|
)
|
||||||
|
|
||||||
|
log("\nStarting VeraCrypt encryption (this may take a few minutes)...")
|
||||||
|
log("You will be prompted for:")
|
||||||
|
log(" 1. Password (enter twice)")
|
||||||
|
log(" 2. PIM (press Enter to use default)")
|
||||||
|
log(" 3. Keyfiles (press Enter to skip)")
|
||||||
|
log(" 4. Filesystem (will use ext4 automatically)")
|
||||||
|
log("")
|
||||||
run_command(veracrypt_create_cmd, shell=True, interactive=True)
|
run_command(veracrypt_create_cmd, shell=True, interactive=True)
|
||||||
log("Encrypted documents partition setup complete.")
|
log("\n✓ Documents partition encrypted successfully!")
|
||||||
|
log(f" Encryption: AES-Twofish-Serpent (triple cascade)")
|
||||||
|
log(f" Hash: SHA-512")
|
||||||
|
log(f" PIM: {pim_value}")
|
||||||
|
log(f" Filesystem: ext4")
|
||||||
|
|
||||||
def setup_unencrypted_partition():
|
def setup_unencrypted_partition():
|
||||||
"""
|
"""
|
||||||
@@ -617,17 +754,23 @@ def setup_unencrypted_partition():
|
|||||||
global DRIVE
|
global DRIVE
|
||||||
UNENCRYPTED_PART = get_partition_name(DRIVE, get_last_partition_number())
|
UNENCRYPTED_PART = get_partition_name(DRIVE, get_last_partition_number())
|
||||||
|
|
||||||
|
log("\n" + "="*70)
|
||||||
|
log("STEP 7: SETTING UP TOOLS PARTITION")
|
||||||
|
log("="*70)
|
||||||
|
|
||||||
# Check if the partition exists
|
# Check if the partition exists
|
||||||
if not os.path.exists(UNENCRYPTED_PART):
|
if not os.path.exists(UNENCRYPTED_PART):
|
||||||
log(f"Error: Partition {UNENCRYPTED_PART} does not exist.")
|
log(f"Error: Partition {UNENCRYPTED_PART} does not exist.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
log(f"Attempting to format partition {UNENCRYPTED_PART} with FAT32 filesystem.")
|
log(f"Formatting {UNENCRYPTED_PART} as FAT32...")
|
||||||
run_command(f"sudo mkfs.vfat -n 'TOOLS' {UNENCRYPTED_PART}", shell=True)
|
run_command(f"sudo mkfs.vfat -n 'TOOLS' {UNENCRYPTED_PART}", shell=True)
|
||||||
log("Formatted unencrypted partition with FAT32 filesystem.")
|
log("✓ FAT32 filesystem created")
|
||||||
|
|
||||||
|
log("Mounting tools partition...")
|
||||||
run_command("sudo mkdir -p /mnt/unencrypted", shell=True)
|
run_command("sudo mkdir -p /mnt/unencrypted", shell=True)
|
||||||
run_command(f"sudo mount {UNENCRYPTED_PART} /mnt/unencrypted", shell=True)
|
run_command(f"sudo mount {UNENCRYPTED_PART} /mnt/unencrypted", shell=True)
|
||||||
|
log("✓ Tools partition mounted")
|
||||||
|
|
||||||
instructions = f"""
|
instructions = f"""
|
||||||
INSTRUCTIONS FOR ACCESSING SECURE STORAGE
|
INSTRUCTIONS FOR ACCESSING SECURE STORAGE
|
||||||
@@ -645,11 +788,12 @@ To safely lock your storage:
|
|||||||
IMPORTANT: Always lock your storage before removing the device.
|
IMPORTANT: Always lock your storage before removing the device.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
log("\nCreating helper files...")
|
||||||
with open("/tmp/README.txt", "w") as readme_file:
|
with open("/tmp/README.txt", "w") as readme_file:
|
||||||
readme_file.write(instructions)
|
readme_file.write(instructions)
|
||||||
run_command("sudo cp /tmp/README.txt /mnt/unencrypted/README.txt", shell=True)
|
run_command("sudo cp /tmp/README.txt /mnt/unencrypted/README.txt", shell=True)
|
||||||
run_command("sudo rm /tmp/README.txt", shell=True)
|
run_command("sudo rm /tmp/README.txt", shell=True)
|
||||||
log("Created README.txt with mounting instructions.")
|
log(" ✓ README.txt created")
|
||||||
|
|
||||||
mount_script = """#!/bin/bash
|
mount_script = """#!/bin/bash
|
||||||
# Script to mount secure storage partition
|
# Script to mount secure storage partition
|
||||||
@@ -694,7 +838,7 @@ fi
|
|||||||
run_command("sudo cp /tmp/mount_storage.sh /mnt/unencrypted/mount_storage.sh", shell=True)
|
run_command("sudo cp /tmp/mount_storage.sh /mnt/unencrypted/mount_storage.sh", shell=True)
|
||||||
run_command("sudo chmod +x /mnt/unencrypted/mount_storage.sh", shell=True)
|
run_command("sudo chmod +x /mnt/unencrypted/mount_storage.sh", shell=True)
|
||||||
run_command("sudo rm /tmp/mount_storage.sh", shell=True)
|
run_command("sudo rm /tmp/mount_storage.sh", shell=True)
|
||||||
log("Created mount_storage.sh script.")
|
log(" ✓ mount_storage.sh created")
|
||||||
|
|
||||||
cleanup_script = """#!/bin/bash
|
cleanup_script = """#!/bin/bash
|
||||||
# Script to safely lock secure storage
|
# Script to safely lock secure storage
|
||||||
@@ -748,10 +892,11 @@ fi
|
|||||||
run_command("sudo cp /tmp/lock_storage.sh /mnt/unencrypted/lock_storage.sh", shell=True)
|
run_command("sudo cp /tmp/lock_storage.sh /mnt/unencrypted/lock_storage.sh", shell=True)
|
||||||
run_command("sudo chmod +x /mnt/unencrypted/lock_storage.sh", shell=True)
|
run_command("sudo chmod +x /mnt/unencrypted/lock_storage.sh", shell=True)
|
||||||
run_command("sudo rm /tmp/lock_storage.sh", shell=True)
|
run_command("sudo rm /tmp/lock_storage.sh", shell=True)
|
||||||
log("Created lock_storage.sh script.")
|
log(" ✓ lock_storage.sh created")
|
||||||
|
|
||||||
|
log("\nUnmounting tools partition...")
|
||||||
run_command("sudo umount /mnt/unencrypted", shell=True)
|
run_command("sudo umount /mnt/unencrypted", shell=True)
|
||||||
log("Unencrypted partition setup complete.")
|
log("✓ Tools partition setup complete")
|
||||||
|
|
||||||
def get_last_partition_number():
|
def get_last_partition_number():
|
||||||
"""
|
"""
|
||||||
@@ -803,6 +948,7 @@ def main():
|
|||||||
parser.add_argument("-c", "--custom", action="store_true", help="Create custom ISO bootable USB (like Kali, with persistence)")
|
parser.add_argument("-c", "--custom", action="store_true", help="Create custom ISO bootable USB (like Kali, with persistence)")
|
||||||
parser.add_argument("-i", "--iso", help="Path to the ISO file (Kali, Tails, or custom)")
|
parser.add_argument("-i", "--iso", help="Path to the ISO file (Kali, Tails, or custom)")
|
||||||
parser.add_argument("--fast", action="store_true", help="Enable fast setup with less secure encryption")
|
parser.add_argument("--fast", action="store_true", help="Enable fast setup with less secure encryption")
|
||||||
|
parser.add_argument("--paranoid", action="store_true", help="Enable paranoid mode: maximum security, 3-pass shred, highest encryption")
|
||||||
parser.add_argument("--debug", action="store_true", help="Enable debug mode")
|
parser.add_argument("--debug", action="store_true", help="Enable debug mode")
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
@@ -819,8 +965,17 @@ def main():
|
|||||||
log("Debug mode enabled")
|
log("Debug mode enabled")
|
||||||
|
|
||||||
FAST_MODE = args.fast
|
FAST_MODE = args.fast
|
||||||
|
PARANOID_MODE = args.paranoid
|
||||||
|
|
||||||
|
# Paranoid and Fast are mutually exclusive
|
||||||
|
if FAST_MODE and PARANOID_MODE:
|
||||||
|
log("Error: Cannot use --fast and --paranoid modes together.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
if FAST_MODE:
|
if FAST_MODE:
|
||||||
log("Fast mode enabled: Using less secure encryption for quicker setup.")
|
log("Fast mode enabled: Using less secure encryption for quicker setup.")
|
||||||
|
elif PARANOID_MODE:
|
||||||
|
log("PARANOID MODE enabled: Maximum security - 3-pass wipe, strongest encryption, highest PIM.")
|
||||||
|
|
||||||
if args.all:
|
if args.all:
|
||||||
CREATE_DOCS = True
|
CREATE_DOCS = True
|
||||||
@@ -842,7 +997,43 @@ def main():
|
|||||||
|
|
||||||
check_dependencies()
|
check_dependencies()
|
||||||
setup_usb()
|
setup_usb()
|
||||||
log("Partition setup complete.")
|
|
||||||
|
# Final summary
|
||||||
|
log("\n" + "="*70)
|
||||||
|
log("SETUP COMPLETE!")
|
||||||
|
log("="*70)
|
||||||
|
log("")
|
||||||
|
log("Your secure storage device is ready!")
|
||||||
|
log("")
|
||||||
|
log("What was created:")
|
||||||
|
if CREATE_KALI:
|
||||||
|
log(" ✓ Kali Linux bootable drive")
|
||||||
|
log(" ✓ LUKS encrypted persistence partition")
|
||||||
|
elif CREATE_TAILS:
|
||||||
|
log(" ✓ Tails bootable drive")
|
||||||
|
elif CREATE_CUSTOM:
|
||||||
|
log(" ✓ Custom bootable drive")
|
||||||
|
log(" ✓ LUKS encrypted persistence partition")
|
||||||
|
|
||||||
|
if CREATE_DOCS:
|
||||||
|
log(" ✓ VeraCrypt encrypted documents partition")
|
||||||
|
if PARANOID_MODE:
|
||||||
|
log(" - Triple cascade encryption (AES-Twofish-Serpent)")
|
||||||
|
log(" - PIM 5000 (PARANOID mode)")
|
||||||
|
else:
|
||||||
|
log(" - Triple cascade encryption (AES-Twofish-Serpent)")
|
||||||
|
log(" - PIM 2000 (standard security)")
|
||||||
|
log(" ✓ Tools partition with helper scripts")
|
||||||
|
log("")
|
||||||
|
log("Next steps:")
|
||||||
|
log(" 1. Safely eject the device")
|
||||||
|
log(" 2. On your target system, mount the TOOLS partition")
|
||||||
|
log(" 3. Read README.txt for instructions")
|
||||||
|
log(" 4. Run: sudo ./mount_storage.sh")
|
||||||
|
log("")
|
||||||
|
|
||||||
|
log(f"Log file saved: {LOG_FILE}")
|
||||||
|
log("="*70)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
Reference in New Issue
Block a user