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

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:

  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
# 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:

  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

# 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)

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:

  1. Import obfuscation package
  2. Replace ldflags with obfuscated versions
  3. Call GetDeobfuscatedCredentials() at runtime
  4. 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