Skip to content

Phase 03 — Cryptography Layer

Implement all cryptographic primitives so license keys are signed, stored encrypted, and device fingerprints are anonymized before touching the database.

  • src/Crypto/KeyVault.php — Encrypts/decrypts license key strings with AES-256-GCM (prefers hardware-accelerated sodium_crypto_aead_aes256gcm_*; falls back to XChaCha20-Poly1305). Nonce prepended to ciphertext, whole blob stored as base64.
  • src/Crypto/Signer.php — Signs arbitrary payloads with Ed25519 (sodium_crypto_sign_detached). Output format: base64url(json_payload).base64url(signature). Clients split on . and verify without calling the server.
  • src/Crypto/Fingerprint.php — HMAC-SHA256 anonymization of device fingerprints. Also provides a static sha256() helper for the license hash column.
MethodDescription
KeyVault::encrypt(string $plaintext): stringEncrypt a license key for storage
KeyVault::decrypt(string $ciphertext): stringDecrypt a stored license key
Signer::sign(array $payload): stringSign a payload, return compact token
Signer::verify(string $token): ?arrayVerify and decode a signed token
Signer::get_public_key_base64(): stringReturn the public key for REST exposure
Fingerprint::hash(string $raw): stringHMAC-SHA256 a device fingerprint
Fingerprint::sha256(string $data): stringPlain SHA-256 hash
eyJrZXkiOiJBQkNELUVGR0gtSUpLTC1NTk9QIn0.dD3...
└──────────────────────────────────────── └────────
base64url(json_payload) base64url(Ed25519 sig)

Clients verify offline:

$parts = explode('.', $token, 2);
$valid = sodium_crypto_sign_verify_detached(
WPLM\Crypto\Signer::base64url_decode($parts[1]),
$parts[0],
base64_decode($public_key)
);
Terminal window
# 1. Activate the plugin (Seeder generates keypair + encryption key).
# 2. Create a license via the UI or REST.
# 3. Check the DB: license_key column must be ciphertext, hash must be hex.
# SELECT license_key, hash FROM wp_wplm_licenses LIMIT 1;
# PHPUnit:
# vendor/bin/phpunit --filter CryptoTest
  • Key issue + signwplm_create_license() returns a key whose signature verifies with the public key.
  • Encrypt at restlicense_key column is ciphertext; plaintext never persisted.