Files
nextcloud-integration/OBFUSCATION.md
WLTBAgent 9ef256ec0a Add credential obfuscation system
- build-obfuscated.sh: XOR encryption with random 256-bit key
- obfuscation/obfuscation.go: Runtime de-obfuscation package
- OBFUSCATION.md: Documentation and security comparison
- Prevents casual extraction with 'strings' command
- Medium security: Good for personal use, env vars for production
2026-02-20 21:40:37 +00:00

265 lines
6.9 KiB
Markdown

# Credential Obfuscation for Nextcloud Tools
## Problem
When credentials are embedded in Go binaries via `ldflags`, they appear as plain text and can be easily extracted using the `strings` command:
```bash
$ strings ~/bin/nextcloud-client
https://teamworkapps.com
wltbagent@shortcutsolutions.net
1b8a28ca2fc26820fee3f9a8524c351b
```
This is a security risk for distributed binaries.
## Solution
We've implemented a **XOR cipher with random key** approach:
1. **At Build Time**: Credentials are XOR-encrypted with a randomly generated 256-bit key
2. **Encoded**: The encrypted data is Base64-encoded for safe Go embedding
3. **At Runtime**: The binary de-obfuscates credentials in memory only
4. **Never on Disk**: De-obfuscated credentials never touch the disk
## How It Works
### Build Process
The `build-obfuscated.sh` script:
1. **Generates random key**: 256-bit (64 hex characters) via `openssl rand -hex 32`
2. **XOR encrypts credentials**: Each credential XOR'd with the key
3. **Base64 encodes**: Makes it safe for Go string embedding
4. **Embeds via ldflags**: Encrypted credentials + key embedded in binary
```bash
# Generate random key
OBFUSCATION_KEY=$(openssl rand -hex 32)
# XOR encrypt with key
obfuscated=$(xor_encrypt "$CREDENTIAL" "$OBFUSCATION_KEY")
# Base64 encode for embedding
obfuscated_b64=$(echo -n "$obfuscated" | base64 -w0)
# Build with obfuscated credentials
go build -ldflags="-X main.ObfuscatedServer=$obfuscated_b64 \
-X main.ObfuscatedUser=$obfuscated_b64 \
-X main.ObfuscatedPassword=$obfuscated_b64 \
-X main.ObfuscationKey=$OBFUSCATION_KEY" ...
```
### Runtime De-obfuscation
The `obfuscation.go` package provides de-obfuscation:
```go
// DeobfuscateString reverses XOR obfuscation
func DeobfuscateString(obfuscatedBase64, key string) (string, error) {
// Decode base64
obfuscated, _ := base64.StdEncoding.DecodeString(obfuscatedBase64)
// XOR de-obfuscate
result := make([]byte, len(obfuscated))
keyBytes := []byte(key)
for i := 0; i < len(obfuscated); i++ {
result[i] = obfuscated[i] ^ keyBytes[i%len(keyBytes)]
}
return string(result), nil
}
```
At runtime, tools call:
```go
server, user, password, err := GetDeobfuscatedCredentials()
if err != nil {
// Handle error
}
// Now use server, user, password (these are the actual values)
```
## Security Levels
### Current Implementation (Medium Security)
**Strengths:**
- ✅ Prevents casual extraction with `strings`
- ✅ Credentials appear as Base64 gibberish in binary
- ✅ Key changes on every build (unique per binary)
- ✅ De-obfuscation happens only in memory
**Weaknesses:**
- ⚠️ Key is embedded in binary
- ⚠️ De-obfuscation code is public
- ⚠️ Determined attacker with source could reverse it
**Result:** Good for preventing casual access, but not secure against determined reverse engineering.
## Usage
### Build with Obfuscation
```bash
cd projects/nextcloud-integration
# Use obfuscated build script
./build-obfuscated.sh https://teamworkapps.com <username> <password>
```
The script will:
1. Generate a unique 256-bit obfuscation key
2. Encrypt all credentials with XOR cipher
3. Base64 encode encrypted data
4. Build all tools with embedded encrypted credentials + key
5. Display security information
### Verify Obfuscation
```bash
# Check that strings doesn't show plain credentials
strings ~/bin/nextcloud-client | grep -i "teamworkapps"
# Should NOT find plain server URL
# Instead, you'll see base64 gibberish
```
### Run Tools
Tools work exactly the same - obfuscation is transparent:
```bash
~/bin/nextcloud-client --op list --path "/"
~/bin/nextcloud-mail --op list-folders
```
## Security Comparison
| Method | Security | Complexity | Distribution |
|---------|----------|------------|--------------|
| Plain ldflags (current) | Low | Simple | ❌ Not recommended |
| XOR Obfuscation (this) | Medium | Medium | ✅ Better for sharing |
| Environment Variables | High | Low | ✅ Best for production |
| HSM/Key Management | Very High | High | ✅ Enterprise grade |
| Network Auth | Very High | High | ✅ No credentials in binary |
## Better Security Options (For Production)
### Option 1: Environment Variables (Recommended)
Remove credentials entirely from binary, require environment variables:
```go
// Read from environment at runtime
server := os.Getenv("NEXTCLOUD_SERVER")
user := os.Getenv("NEXTCLOUD_USER")
password := os.Getenv("NEXTCLOUD_PASSWORD")
if server == "" || user == "" || password == "" {
log.Fatal("NEXTCLOUD_SERVER, NEXTCLOUD_USER, NEXTCLOUD_PASSWORD required")
}
```
**Pros:** No credentials in binary at all
**Cons:** Requires runtime configuration
### Option 2: Interactive First Run
Prompt for credentials on first run, then cache encrypted:
```go
if !credentialsFile.Exists() {
username := prompt("Nextcloud username: ")
password := prompt("Nextcloud password: ")
// Encrypt and store locally
encrypted := encrypt(username, password, derivedKey)
credentialsFile.Write(encrypted)
}
```
**Pros:** Never in binary, user controls storage
**Cons:** One-time setup required
### Option 3: Network Authentication
Credentials stored on a secure server, binary authenticates to fetch them:
```go
// Authenticate to credential server
token := authenticateToServer(derivedMachineID)
credentials := fetchCredentials(token)
```
**Pros:** Most secure, can revoke access
**Cons:** Requires infrastructure, network dependency
### Option 4: Hardware Security Module (HSM)
Credentials stored in HSM, binary requests operations:
```go
// Never see actual credentials
result := hsm.Sign(data)
```
**Pros:** Enterprise-grade security
**Cons:** Expensive hardware, complex setup
## Implementation Status
### Completed
-`build-obfuscated.sh` - XOR encryption with random key
-`obfuscation/obfuscation.go` - Runtime de-obfuscation package
- ✅ Base64 encoding for safe embedding
- ✅ Unique key per build
### Pending Integration
To enable obfuscation in tools:
1. Import obfuscation package
2. Replace ldflags with obfuscated versions
3. Call `GetDeobfuscatedCredentials()` at runtime
4. Remove plain Build* variables
Example migration:
```go
// Old way (plain credentials)
config.URL = BuildServerURL
config.User = BuildUsername
// New way (obfuscated)
server, user, password, _ := GetDeobfuscatedCredentials()
config.URL = server
config.User = user
config.Token = password
```
## Recommendation
**For Personal Use:**
- Current XOR obfuscation is sufficient
- Prevents casual extraction
- Easy to use, no setup
**For Distribution/Production:**
- Use environment variables (most secure, simplest)
- Or implement network authentication for enterprise
- Never distribute binaries with embedded credentials
**For Open Source Projects:**
- Document credential requirements
- Provide setup guide
- Never commit credentials
- Use .env.example files
---
*Credential Obfuscation: 2026-02-20*