Encryption Details
LicenceForge employs multiple cryptographic techniques to protect sensitive data at rest and in transit. This page documents every encryption and hashing method used throughout the plugin, the key derivation strategy, and the rationale behind each choice.
Key Dependency. Most cryptographic operations derive their keys from the
WordPress AUTH_KEY and AUTH_SALT constants defined in
wp-config.php. Changing these values will invalidate existing encrypted data. Always
back up your database before rotating salts.
License Keys
Algorithm
License keys are stored as HMAC-SHA256 hashes. This is a one-way operation — the original key cannot be recovered from the stored hash.
Key Derivation
The HMAC signing key is derived from the concatenation of the WordPress AUTH_KEY and
AUTH_SALT constants. This ensures the hash is unique to your WordPress installation.
Comparison
License key verification uses PHP's hash_equals() function for
timing-safe comparison, preventing timing side-channel attacks that could allow an
attacker to guess a valid key character by character.
// Simplified license key verification flow
$stored_hash = $license->key_hash;
$input_hash = hash_hmac( 'sha256', $input_key, AUTH_KEY . AUTH_SALT );
if ( hash_equals( $stored_hash, $input_hash ) ) {
// Key is valid
}
Plaintext keys are never stored. Once a license key is generated and shown to the customer, only the HMAC hash is persisted in the database. If the customer loses their key, a new one must be issued.
Stripe API Keys
Algorithm
Stripe API keys (secret key, webhook signing secret) are encrypted using
AES-256-CBC via the WPLF_Crypto::encrypt_option() method. Unlike
license keys, these values must be decryptable because LicenceForge needs the plaintext key to
communicate with the Stripe API.
Key Derivation
The AES encryption key is derived from the WordPress auth keys using a key derivation function. The initialisation vector (IV) is randomly generated for each encryption operation and stored alongside the ciphertext.
Backwards Compatibility
The decryption routine includes backwards-compatible handling for values encrypted with earlier versions of the plugin. If a stored value cannot be decrypted with the current method, the legacy decryption path is attempted before falling back to treating the value as plaintext (for installations upgrading from versions prior to encryption support).
// Encrypting a Stripe key
$encrypted = WPLF_Crypto::encrypt_option( $stripe_secret_key );
update_option( 'wplf_stripe_secret_key', $encrypted );
// Decrypting for API calls
$plaintext = WPLF_Crypto::decrypt_option( get_option( 'wplf_stripe_secret_key' ) );
API Keys
Algorithm
REST API keys issued for external integrations are stored as SHA-256 hashes. Like license keys, this is a one-way hash — the full API key cannot be recovered from the database.
Prefix Retention
To allow administrators to identify keys in the dashboard, the first 8 characters
of the API key are retained and stored in plaintext alongside the hash. The key is displayed as
lf_abcd1234...**** in the admin UI.
// API key storage
$api_key = WPLF_Crypto::generate_api_key();
$prefix = substr( $api_key, 0, 8 );
$hash = hash( 'sha256', $api_key );
// Store $prefix and $hash; discard $api_key after showing it once
IP Address Hashing
Algorithm
IP addresses are hashed using SHA-256 and then truncated to 16
characters via the WPLF_Crypto::hash_ip() method. This provides a consistent
pseudonymous identifier for rate limiting and audit logging without storing the actual IP.
Privacy Rationale
Under GDPR, IP addresses are considered personal data. By storing only a truncated hash, LicenceForge achieves the operational benefits of IP tracking (rate limiting, abuse detection) without retaining personally identifiable information.
// IP address hashing
$hashed_ip = WPLF_Crypto::hash_ip( $_SERVER['REMOTE_ADDR'] );
// Returns a 16-character string, e.g. "a1b2c3d4e5f6g7h8"
Client-Side Key Storage
Primary: libsodium
When the PHP sodium extension is available (included by default since PHP 7.2),
client-side license key storage uses libsodium
(sodium_crypto_secretbox). A random nonce is generated for each encryption operation
and stored alongside the ciphertext.
Fallback: XOR Cipher
On systems where libsodium is unavailable, LicenceForge falls back to a simple XOR cipher. While not as robust as libsodium, this provides basic obfuscation for environments with limited PHP extensions.
Key Derivation
Both methods derive their encryption key from the AUTH_KEY constant defined in
wp-config.php.
Recommended. Ensure your server has the sodium PHP extension
enabled (default in PHP 7.2+) for the strongest client-side encryption.
// Client-side key encryption (simplified)
if ( function_exists( 'sodium_crypto_secretbox' ) ) {
$nonce = random_bytes( SODIUM_CRYPTO_SECRETBOX_NONCEBYTES );
$key = sodium_crypto_generichash( AUTH_KEY, '', SODIUM_CRYPTO_SECRETBOX_KEYBYTES );
$ciphertext = sodium_crypto_secretbox( $license_key, $nonce, $key );
} else {
// XOR fallback
$ciphertext = wplf_xor_encrypt( $license_key, AUTH_KEY );
}
Download Tokens
Algorithm
Download tokens are HMAC-SHA256 signed payloads that are base64url-encoded for safe transport in URLs. Each token contains the license ID, product slug, and an expiry timestamp.
Lifecycle
Tokens are generated on demand when a customer requests a download, and are verified on the download endpoint. Both the signature and the expiry timestamp are checked. Expired or tampered tokens are rejected.
For full details on the download token system, see Download Security.
Summary Table
| Data Type | Method | Reversible | Key Source |
|---|---|---|---|
| License keys | HMAC-SHA256 | No (one-way hash) | AUTH_KEY + AUTH_SALT |
| Stripe API keys | AES-256-CBC | Yes (decryptable) | WordPress auth keys |
| REST API keys | SHA-256 | No (one-way hash) | N/A (unsalted hash) |
| IP addresses | SHA-256 (truncated) | No (one-way, 16 chars) | N/A |
| Client-side keys | libsodium / XOR fallback | Yes (decryptable) | AUTH_KEY |
| Download tokens | HMAC-SHA256 + base64url | Verifiable (signed) | AUTH_KEY + AUTH_SALT |
Never share your wp-config.php salts. Since most LicenceForge
cryptographic operations derive their keys from these values, exposing them would compromise
encrypted Stripe keys and allow forged license key hashes and download tokens.