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.