- 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
6.9 KiB
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:
$ 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:
- At Build Time: Credentials are XOR-encrypted with a randomly generated 256-bit key
- Encoded: The encrypted data is Base64-encoded for safe Go embedding
- At Runtime: The binary de-obfuscates credentials in memory only
- Never on Disk: De-obfuscated credentials never touch the disk
How It Works
Build Process
The build-obfuscated.sh script:
- Generates random key: 256-bit (64 hex characters) via
openssl rand -hex 32 - XOR encrypts credentials: Each credential XOR'd with the key
- Base64 encodes: Makes it safe for Go string embedding
- Embeds via ldflags: Encrypted credentials + key embedded in binary
# 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:
// 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:
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
cd projects/nextcloud-integration
# Use obfuscated build script
./build-obfuscated.sh https://teamworkapps.com <username> <password>
The script will:
- Generate a unique 256-bit obfuscation key
- Encrypt all credentials with XOR cipher
- Base64 encode encrypted data
- Build all tools with embedded encrypted credentials + key
- Display security information
Verify Obfuscation
# 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:
~/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:
// 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:
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:
// 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:
// 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:
- Import obfuscation package
- Replace ldflags with obfuscated versions
- Call
GetDeobfuscatedCredentials()at runtime - Remove plain Build* variables
Example migration:
// 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