From 88375da30ea667ec25c2000874557fcc4785a558 Mon Sep 17 00:00:00 2001 From: gabrix73 Date: Fri, 10 Apr 2026 16:10:48 +0200 Subject: Initial commit: Veilith v0.9 - P2P Encrypted Messenger Military-grade secure messenger with: - End-to-End Encryption (Noise Protocol XX) - Forward Secrecy (automatic session rotation) - Anti-Traffic Analysis (padding + cover traffic) - Secure Deletion (DOD 5220.22-M) - Tor Integration (embedded with bridge support) - Portable Mode (no installation required) Generated with Claude Code --- security/wipe.go | 350 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 350 insertions(+) create mode 100644 security/wipe.go (limited to 'security/wipe.go') diff --git a/security/wipe.go b/security/wipe.go new file mode 100644 index 0000000..acdd658 --- /dev/null +++ b/security/wipe.go @@ -0,0 +1,350 @@ +// Package security - Emergency wipe system for military/capture scenarios +package security + +import ( + "crypto/rand" + "fmt" + "os" + "path/filepath" + "sync" + "time" +) + +// EmergencyWipe handles secure data destruction +// Critical for military scenarios if device is captured +type EmergencyWipe struct { + dataDir string + identityPath string + contactsPath string + queueDir string + tempDir string + wiping bool + mu sync.Mutex + onWipeStart func() + onWipeComplete func() +} + +// WipeConfig holds emergency wipe configuration +type WipeConfig struct { + DataDir string // Main data directory + IdentityPath string // Identity file path + ContactsPath string // Contacts file path + QueueDir string // Message queue directory + TempDir string // Temp files directory + Passes int // Number of overwrite passes (DOD 5220.22-M uses 7) +} + +// NewEmergencyWipe creates a new emergency wipe system +func NewEmergencyWipe(config *WipeConfig) *EmergencyWipe { + if config == nil { + config = &WipeConfig{ + Passes: 7, // DOD standard + } + } + + return &EmergencyWipe{ + dataDir: config.DataDir, + identityPath: config.IdentityPath, + contactsPath: config.ContactsPath, + queueDir: config.QueueDir, + tempDir: config.TempDir, + } +} + +// Wipe performs emergency data destruction +func (ew *EmergencyWipe) Wipe() error { + ew.mu.Lock() + if ew.wiping { + ew.mu.Unlock() + return fmt.Errorf("wipe already in progress") + } + ew.wiping = true + ew.mu.Unlock() + + defer func() { + ew.mu.Lock() + ew.wiping = false + ew.mu.Unlock() + }() + + fmt.Println("\n🚨 EMERGENCY WIPE INITIATED 🚨") + fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━") + + if ew.onWipeStart != nil { + ew.onWipeStart() + } + + // Step 1: Wipe identity file + if ew.identityPath != "" { + fmt.Printf("šŸ”„ Wiping identity: %s\n", ew.identityPath) + if err := ew.secureWipeFile(ew.identityPath, 7); err != nil { + fmt.Printf("āš ļø Warning: %v\n", err) + } else { + fmt.Println("āœ“ Identity wiped") + } + } + + // Step 2: Wipe contacts file + if ew.contactsPath != "" { + fmt.Printf("šŸ”„ Wiping contacts: %s\n", ew.contactsPath) + if err := ew.secureWipeFile(ew.contactsPath, 7); err != nil { + fmt.Printf("āš ļø Warning: %v\n", err) + } else { + fmt.Println("āœ“ Contacts wiped") + } + } + + // Step 3: Wipe message queue + if ew.queueDir != "" { + fmt.Printf("šŸ”„ Wiping message queue: %s\n", ew.queueDir) + if err := ew.secureWipeDirectory(ew.queueDir); err != nil { + fmt.Printf("āš ļø Warning: %v\n", err) + } else { + fmt.Println("āœ“ Message queue wiped") + } + } + + // Step 4: Wipe temp files + if ew.tempDir != "" { + fmt.Printf("šŸ”„ Wiping temp files: %s\n", ew.tempDir) + if err := ew.secureWipeDirectory(ew.tempDir); err != nil { + fmt.Printf("āš ļø Warning: %v\n", err) + } else { + fmt.Println("āœ“ Temp files wiped") + } + } + + // Step 5: Wipe entire data directory + if ew.dataDir != "" { + fmt.Printf("šŸ”„ Wiping data directory: %s\n", ew.dataDir) + if err := ew.secureWipeDirectory(ew.dataDir); err != nil { + fmt.Printf("āš ļø Warning: %v\n", err) + } else { + fmt.Println("āœ“ Data directory wiped") + } + } + + fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━") + fmt.Println("āœ… EMERGENCY WIPE COMPLETE") + fmt.Println("All sensitive data has been securely destroyed.") + fmt.Println("") + + if ew.onWipeComplete != nil { + ew.onWipeComplete() + } + + return nil +} + +// secureWipeFile overwrites a file multiple times before deletion +// Implements DOD 5220.22-M standard (7-pass wipe) +func (ew *EmergencyWipe) secureWipeFile(path string, passes int) error { + // Check if file exists + info, err := os.Stat(path) + if err != nil { + if os.IsNotExist(err) { + return nil // File doesn't exist - nothing to wipe + } + return fmt.Errorf("stat failed: %w", err) + } + + size := info.Size() + + // Open file for writing + file, err := os.OpenFile(path, os.O_WRONLY, 0) + if err != nil { + return fmt.Errorf("open failed: %w", err) + } + defer file.Close() + + // Perform multiple overwrite passes + for pass := 1; pass <= passes; pass++ { + // Seek to beginning + file.Seek(0, 0) + + // Overwrite with different patterns + var pattern []byte + switch pass % 3 { + case 0: + // All zeros + pattern = make([]byte, size) + case 1: + // All ones + pattern = make([]byte, size) + for i := range pattern { + pattern[i] = 0xFF + } + case 2: + // Random data + pattern = make([]byte, size) + rand.Read(pattern) + } + + if _, err := file.Write(pattern); err != nil { + return fmt.Errorf("write pass %d failed: %w", pass, err) + } + + // Sync to disk + file.Sync() + } + + file.Close() + + // Delete the file + if err := os.Remove(path); err != nil { + return fmt.Errorf("delete failed: %w", err) + } + + return nil +} + +// secureWipeDirectory recursively wipes all files in a directory +func (ew *EmergencyWipe) secureWipeDirectory(dir string) error { + // Walk directory tree + return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return nil // Skip errors + } + + // Skip directories (will be removed after contents wiped) + if info.IsDir() { + return nil + } + + // Wipe file + if err := ew.secureWipeFile(path, 7); err != nil { + fmt.Printf("āš ļø Failed to wipe %s: %v\n", path, err) + } + + return nil + }) + + // Remove empty directory + // os.RemoveAll(dir) // Uncomment to also delete directory structure +} + +// QuickWipe performs a fast single-pass wipe (for time-critical scenarios) +func (ew *EmergencyWipe) QuickWipe() error { + fmt.Println("\n⚔ QUICK WIPE INITIATED (Single-pass)") + fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━") + + // Single-pass wipe of critical files + if ew.identityPath != "" { + ew.secureWipeFile(ew.identityPath, 1) + } + if ew.contactsPath != "" { + ew.secureWipeFile(ew.contactsPath, 1) + } + + fmt.Println("āœ… QUICK WIPE COMPLETE (1 pass)") + return nil +} + +// SetOnWipeStart sets callback for when wipe starts +func (ew *EmergencyWipe) SetOnWipeStart(callback func()) { + ew.mu.Lock() + defer ew.mu.Unlock() + ew.onWipeStart = callback +} + +// SetOnWipeComplete sets callback for when wipe completes +func (ew *EmergencyWipe) SetOnWipeComplete(callback func()) { + ew.mu.Lock() + defer ew.mu.Unlock() + ew.onWipeComplete = callback +} + +// IsWiping returns whether wipe is in progress +func (ew *EmergencyWipe) IsWiping() bool { + ew.mu.Lock() + defer ew.mu.Unlock() + return ew.wiping +} + +// PanicButton is a simple wrapper for emergency wipe +func PanicButton(config *WipeConfig) { + fmt.Println("\n╔════════════════════════════════════════════════╗") + fmt.Println("ā•‘ 🚨 PANIC BUTTON ACTIVATED 🚨 ā•‘") + fmt.Println("ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•") + fmt.Println("") + + wipe := NewEmergencyWipe(config) + wipe.Wipe() + + fmt.Println("Press any key to exit...") + fmt.Scanln() + os.Exit(0) +} + +// String returns a string representation +func (ew *EmergencyWipe) String() string { + ew.mu.Lock() + defer ew.mu.Unlock() + + status := "ready" + if ew.wiping { + status = "WIPING" + } + + return fmt.Sprintf("EmergencyWipe(status=%s, targets=[identity,contacts,queue,temp,data])", + status) +} + +// DeadMansSwitch implements auto-wipe if no activity detected +type DeadMansSwitch struct { + timeout time.Duration + timer *time.Timer + mu sync.Mutex + active bool + onTrigger func() +} + +// NewDeadMansSwitch creates a new dead man's switch +func NewDeadMansSwitch(timeout time.Duration, onTrigger func()) *DeadMansSwitch { + dms := &DeadMansSwitch{ + timeout: timeout, + onTrigger: onTrigger, + } + return dms +} + +// Start starts the dead man's switch +func (dms *DeadMansSwitch) Start() { + dms.mu.Lock() + defer dms.mu.Unlock() + + if dms.active { + return + } + + dms.active = true + dms.timer = time.AfterFunc(dms.timeout, func() { + fmt.Println("\nā° DEAD MAN'S SWITCH TRIGGERED") + fmt.Println("No activity detected - initiating emergency wipe") + if dms.onTrigger != nil { + dms.onTrigger() + } + }) +} + +// Reset resets the dead man's switch timer +func (dms *DeadMansSwitch) Reset() { + dms.mu.Lock() + defer dms.mu.Unlock() + + if dms.timer != nil { + dms.timer.Reset(dms.timeout) + } +} + +// Stop stops the dead man's switch +func (dms *DeadMansSwitch) Stop() { + dms.mu.Lock() + defer dms.mu.Unlock() + + if dms.timer != nil { + dms.timer.Stop() + dms.timer = nil + } + dms.active = false +} -- cgit v1.2.3