summaryrefslogtreecommitdiffstats
path: root/security/wipe.go
diff options
context:
space:
mode:
authorgabrix73 <gabriel1@frozenstar.info>2026-04-10 16:10:48 +0200
committergabrix73 <gabriel1@frozenstar.info>2026-04-10 16:10:48 +0200
commit88375da30ea667ec25c2000874557fcc4785a558 (patch)
tree71364a43230977481c6d3280246aa8bb48562bdc /security/wipe.go
downloadkhimera-88375da30ea667ec25c2000874557fcc4785a558.tar.gz
khimera-88375da30ea667ec25c2000874557fcc4785a558.tar.xz
khimera-88375da30ea667ec25c2000874557fcc4785a558.zip
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
Diffstat (limited to 'security/wipe.go')
-rw-r--r--security/wipe.go350
1 files changed, 350 insertions, 0 deletions
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
+}