SkillAgentSearch skills...

SwiftSecretKeys

Build-time secret obfuscation for Swift projects — XOR, AES-GCM, or ChaCha20. CLI and SPM plugin.

Install / Use

/learn @MatheusMBispo/SwiftSecretKeys
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

SwiftSecretKeys

CI Swift 6 Platforms SPM License

Build-time secret obfuscation for Swift projects — keep your API keys out of strings dumps. CLI tool and SPM Build Tool Plugin that generates a SecretKeys.swift file with XOR, AES-GCM, or ChaCha20-Poly1305 encrypted values, decoded at runtime. Prevents secrets from being trivially extracted via strings or binary analysis.

Works as a CLI tool and as an SPM Build Tool Plugin — zero config for most projects.


Table of Contents


Why Use It

Shipping API keys in your iOS/macOS binary? Anyone with strings can read them in seconds. SwiftSecretKeys makes that return gibberish instead of your secrets.

  • Zero runtime dependencies — generated code uses only Foundation (XOR) or CryptoKit (AES-GCM, ChaCha20-Poly1305)
  • Three cipher modes — XOR (fast, lightweight), AES-GCM (stronger, per-value encryption), or ChaCha20-Poly1305 (modern AEAD alternative)
  • SPM Build Tool Plugin — automatic generation on every build, no Run Script Phase needed
  • CLI for CI/CDsskeys generate runs anywhere Swift runs
  • Developer toolssskeys validate checks config without generating, --dry-run previews output, .env file loading
  • Multi-environment support — define per-environment secrets with environments: block
  • Environment variable support — reference ${ENV_VAR} in your config for CI-injected secrets
  • Swift 6 strict concurrency — generated code compiles cleanly under strict concurrency checking
  • Cross-platform — macOS and Linux

🚀 Quick Start

1. Create sskeys.yml at your project root:

output: Sources/Generated/
keys:
  apiKey: ${API_KEY}
  analyticsToken: my-analytics-token

2. Generate the obfuscated file:

sskeys generate

3. Use the secrets in your code:

let key = SecretKeys.apiKey
let token = SecretKeys.analyticsToken

That's it — three steps and your secrets are obfuscated.


📦 Installation

Swift Package Manager (recommended)

Add to your Package.swift:

dependencies: [
    .package(url: "https://github.com/MatheusMBispo/SwiftSecretKeys.git", from: "1.1.0")
]

Then add the plugin to your target:

.target(
    name: "MyApp",
    plugins: [
        .plugin(name: "SwiftSecretKeysPlugin", package: "SwiftSecretKeys")
    ]
)

[!TIP] With the SPM plugin, you don't need to run the CLI manually. See SPM Build Tool Plugin for details.

Mint

mint install MatheusMBispo/SwiftSecretKeys

Build from Source

git clone https://github.com/MatheusMBispo/SwiftSecretKeys.git
cd SwiftSecretKeys
swift build -c release
cp .build/release/sskeys /usr/local/bin/sskeys

🔧 CLI Reference

The sskeys tool has two subcommands: generate (default) and validate.

sskeys generate

Generate a .swift file with obfuscated secrets.

USAGE: sskeys generate [--config <path>] [--factor <n>] [--output-dir <path>] [--env-file <path>] [--dry-run] [--environment <name>] [--verbose]

| Option | Short | Default | Description | |--------|-------|---------|-------------| | --config <path> | -c | sskeys.yml | Path to the YAML configuration file | | --factor <n> | -f | 32 | Salt length in bytes (XOR mode) | | --output-dir <path> | | | Override output directory (ignores YAML output field) | | --env-file <path> | | | Path to a .env file to load before generation | | --dry-run | | | Print generated output to stdout without writing files | | --environment <name> | -e | | Target environment when using environments: block | | --verbose | -v | | Print processing steps to stderr |

Examples

# Basic generation
sskeys generate

# Custom config file
sskeys generate --config secrets/production.yml

# Verbose output for CI debugging
sskeys generate --verbose

# Custom salt factor
sskeys generate --factor 64

# Override output directory
sskeys generate --output-dir Sources/Generated/

# Preview generated output without writing files
sskeys generate --dry-run

# Load secrets from a .env file
sskeys generate --env-file .env.local

# Generate for a specific environment
sskeys generate --environment staging

# Combine flags
sskeys generate --env-file .env.local --environment prod --verbose

When --verbose is enabled, processing steps are printed to stderr so they don't interfere with piped output or generated files.

sskeys validate

Check config and resolve environment variables without generating files.

USAGE: sskeys validate [--config <path>] [--env-file <path>] [--environment <name>]

| Option | Short | Default | Description | |--------|-------|---------|-------------| | --config <path> | -c | sskeys.yml | Path to the YAML configuration file | | --env-file <path> | | | Path to a .env file to load before validation | | --environment <name> | -e | | Target environment to validate (omit to validate all) |

Examples

# Validate default config
sskeys validate

# Validate a specific environment
sskeys validate --environment prod

# Validate with .env file loaded
sskeys validate --env-file .env.local

# Validate a specific config file
sskeys validate --config secrets/production.yml

When no --environment is specified and the config uses an environments: block, validate checks all environments and reports each one individually.


⚙️ Configuration

The configuration file is written in YAML. By default, the CLI looks for sskeys.yml in the current directory.

Full Reference

# Cipher mode: "xor" (default), "aes-gcm", or "chacha20"
cipher: xor

# Output directory for SecretKeys.swift (relative to cwd)
output: Sources/Generated/

# Secret key-value pairs
keys:
  apiKey: my-secret-api-key
  databasePassword: ${DB_PASSWORD}      # resolved from environment
  analyticsToken: ua-123456-7

Fields

| Field | Type | Required | Default | Description | |-------|------|----------|---------|-------------| | keys | {String: String} | Yes* | — | Key-value pairs. Keys become Swift property names, values are obfuscated. | | environments | {String: {String: String}} | Yes* | — | Per-environment key-value pairs. Mutually exclusive with keys. | | output | String | No | "" (cwd) | Relative path for the generated SecretKeys.swift file. | | cipher | String | No | "xor" | Cipher mode: "xor", "aes-gcm", or "chacha20". |

*One of keys or environments is required.

Environment Variables

Use ${VARIABLE_NAME} syntax to reference environment variables:

keys:
  apiKey: ${API_KEY}
  secret: ${MY_SECRET}

Variables are resolved at generation time. If a variable is not set, the tool exits with an actionable error message.

AES-GCM Mode

For stronger obfuscation, use AES-256-GCM:

cipher: aes-gcm
keys:
  apiKey: ${API_KEY}

AES-GCM mode generates a fresh 256-bit key and a unique 12-byte nonce per secret per build. The generated code uses CryptoKit on Apple platforms and swift-crypto on Linux.

[!NOTE] AES-GCM produces different ciphertext on every build even with the same input. This is by design — nonce reuse prevention.

ChaCha20-Poly1305 Mode

For a modern AEAD alternative to AES-GCM:

cipher: chacha20
keys:
  apiKey: ${API_KEY}

ChaCha20-Poly1305 uses the same security model as AES-GCM: a fresh 256-bit key and 12-byte nonce per build, with authenticated encryption. The generated code uses CryptoKit on Apple platforms and swift-crypto on Linux.

ChaCha20-Poly1305 is a modern alternative preferred in some contexts, particularly on platforms without AES hardware acceleration (AES-NI). Both ciphers provide equivalent security guarantees.

[!NOTE] Like AES-GCM, ChaCha20-Poly1305 produces different ciphertext on every build. This is by design.

Multi-Environment Configuration

For projects that need different secrets per environment (dev, staging, prod), use the environments: block instead of keys::

cipher: aes-gcm
output: Sources/Generated/
environments:
  dev:
    apiKey: dev-key-123
    apiUrl: https://dev.api.example.com
  staging:
    apiKey: ${STAGING_API_KEY}
    apiUrl: https://staging.api.example.com
  prod:
    apiKey: ${PROD_API_KEY}
    apiUrl: https://api.example.com

Select an environment with --environment <name>:

sskeys generate --environment prod

[!IMPORTANT]

  • You cannot mix keys: and environments: in the same config file.
  • All environments are validated for key name sanitization even when selecting a single one.
  • When environments: is present, --environment is required for generate.

.env File Support

Load environment variables from a .env file before resolving ${VAR} references:

sskeys generate --env-file .env.local
sskeys validate --env-file .env.local

The .env file supports standard formats:

# Database credentials
DB_PASSWORD=my-secret-password
API_KEY="quoted-value"
ANALYTICS_TOKEN='single-quoted'
  • Lines starting with # are treated as comments
  • Blank lines are ignored
  • Values can be unquoted, double-quoted, or single-quoted
  • Variables are injected into the process environment before config resolution

Key

View on GitHub
GitHub Stars20
CategoryDevelopment
Updated12d ago
Forks6

Languages

Swift

Security Score

90/100

Audited on Mar 27, 2026

No findings