How UnifiedLicensing protects your licenses against forgery, clock manipulation, key sharing, and reverse engineering.
The SDKs defend licenses with three independent layers. Each layer catches what the others miss:
| Layer | What it detects | Runs | Availability |
|---|---|---|---|
| RSA-2048 signature verification | Forged or edited license data — any field changed after signing breaks the signature | Client, on every validation | All SDKs (JS, Python, PHP, .NET) |
| Clock tampering detection | System time rolled backward, or jumped forward, to extend trials or bypass expiry | Client, during offline/hybrid validation | JS, Python, .NET |
Hardware fingerprinting (machine_id) |
A license key activated on more machines than allowed | Client collects, server decides | All SDKs (JS, Python, PHP, .NET) |
Signatures stop forgery, clock checks stop time-based bypasses, fingerprints stop key sharing. None of them alone covers the other attacks — together they cover the realistic threat model for distributed software.
Every license response your server issues is cryptographically signed. The SDK refuses to trust any license data whose signature doesn't verify.
VendorPublicKey).// Signature verification is on by default. var config = new UnifiedLicenseConfig { VendorApiKey = "your-api-key", ProductKey = "your-product-key", SignatureVerification = true, // default VendorPublicKey = "-----BEGIN PUBLIC KEY-----..." };
If an attacker edits the expiry date in a cached license file, or hand-crafts a "lifetime" license, verification fails with an invalid signature error — they'd need your private key to produce a valid signature, and forging RSA-2048 is not practical.
Only the public key belongs in your application. If your private key ever leaks, rotate it immediately and re-issue licenses — and remember the server database remains the source of truth regardless (see Q5).
Trial periods and expiry dates are checked against the system clock — so the classic bypass is "set the clock back." The SDK counters by comparing wall-clock time against a monotonic source that users can't set from the OS settings:
This is the reference implementation from the .NET SDK; the JavaScript and Python SDKs apply the same two-check strategy during offline validation:
public bool DetectTampering() { if (!_lastValidation.HasValue) { _lastValidation = DateTime.UtcNow; _lastTicks = Environment.TickCount64; // monotonic return false; } var now = DateTime.UtcNow; var currentTicks = Environment.TickCount64; // Check 1: time moved backward if (now < _lastValidation.Value) { Console.WriteLine("Clock tampering detected: Time moved backward"); return true; } // Check 2: wall clock jumped vs. monotonic elapsed time var elapsedMs = currentTicks - _lastTicks; var expectedNow = _lastValidation.Value.AddMilliseconds(elapsedMs); var difference = Math.Abs((now - expectedNow).TotalMilliseconds); if (difference > 60000) // > 60s unexplained drift { Console.WriteLine($"Clock tampering detected: Time jump of {difference}ms"); return true; } _lastValidation = now; _lastTicks = currentTicks; return false; }
When tampering is detected during offline validation, validation fails with a "Clock tampering detected" error instead of trusting the manipulated clock. The next successful online validation re-syncs trusted time from the server, so legitimate users who travel across time zones or fix a genuinely wrong BIOS clock recover automatically.
IntegrityGuard is a .NET-only runtime protection module. It runs five watchdog timers at randomized intervals that continuously re-check the process environment while your app runs. It is not available in the JavaScript, Python, or PHP SDKs — interpreted/web environments don't offer the process-level introspection it relies on.
| Timer | Check | Triggers failure when… |
|---|---|---|
| Timer A | Debugger detection | A native/managed debugger is attached to the process |
| Timer B | Process blacklist | Known RE tools are running (x64dbg, OllyDbg, WinDbg, IDA, Cheat Engine, Process Hacker, dnSpy, ILSpy, Reflector, Fiddler, Wireshark…) |
| Timer C | Fingerprint check | Hardware fingerprint drifted below 90% similarity vs. startup (VM migration, cloned disk) |
| Timer D | DLL integrity | The executing assembly's file was modified after deployment (write time > creation time) |
| Timer E | Hash validation | The stored integrity hash no longer matches computed state |
IntegrityGuard is opt-in (disabled by default) and configured through the standard config object — there is no separate global switch to disable it at runtime:
var config = new UnifiedLicenseConfig { VendorApiKey = "your-api-key", ProductKey = "your-product-key", // Protection features (all opt-in) EnableIntegrityGuard = true, EnableAntiDebug = true, EnableAntiTamper = true }; var manager = new UnifiedLicenseManager(config);
IntegrityGuard will flag your own debugger. Wrap the flags in #if DEBUG so Release builds are protected while you can still debug locally:
var config = new UnifiedLicenseConfig { VendorApiKey = "your-api-key", ProductKey = "your-product-key" #if DEBUG , EnableIntegrityGuard = false // allow debugging #endif };
They can try — and client-side patching is always theoretically possible. That's why the architecture assumes the client will be attacked and puts the decisive checks server-side:
machine_id; the server enforces activation limits independently of what the client reports.Cracking a UnifiedLicensing-protected app requires either breaking RSA-2048 (infeasible) or compromising your server/database (a very different, much harder attack than editing a local file).
A determined attacker with full offline access can patch out the client-side check itself (e.g., NOP the validation branch in a disassembler). No licensing SDK on the market prevents that. Your mitigations are server-side enforcement, heartbeats that re-validate periodically, and revocation — plus making the crack cost more than the license (see Q8).
Key sharing is the most common piracy pattern, and it's handled by four cooperating mechanisms:
machine_id. Every later validation presents the same fingerprint — a different machine doesn't match.max_activations. Once the limit is reached, additional machines are rejected at activation time. You control the limit per tier, and can reset activations for legitimate customers (new PC, reinstall) from the vendor dashboard.license_key + machine_id + fingerprint to the server on a schedule (daily / weekly / monthly, with 24-hour rate limiting built in). This gives you visibility into how many distinct machines are actually using a key — abnormal spread is visible in your dashboard.An app that never reconnects keeps running on a stale cache until its grace period expires (default 7 days, configurable via GracePeriodHours). Revocation is only as fast as the client's next contact with the server — that's inherent to any offline-tolerant licensing system.
Verify each layer independently, in a development environment with test keys — never against production licenses:
| # | Test | How | Expected result |
|---|---|---|---|
| 1 | Signature verification | Activate a valid license, then edit any field in the cached license file/blob (e.g., push the expiry date out) | Next validation fails: invalid signature |
| 2 | Forged license | Hand-craft a license payload without signing it (or sign with a self-made key) | Rejected — signature doesn't match your vendor public key |
| 3 | Clock rollback | Start a trial, close the app, set the system clock back several days, relaunch | Clock tampering detected; trial/expiry not extended |
| 4 | Clock skip-forward | Jump the system clock forward past the expiry date | License reported expired based on server-synced time on next online validation |
| 5 | Machine binding | Copy the app + cached license to a second machine (or VM) and validate | Activation/validation rejected: machine mismatch or activation limit reached |
| 6 | Revocation | Revoke a test key in the dashboard, then trigger a validation | Key rejected immediately online; cached usage dies at grace-period end |
| 7 | IntegrityGuard (.NET only) | Build Release with IntegrityGuard enabled, attach x64dbg / run under Cheat Engine | Guard triggers within one watchdog interval and fires the tamper response |
Repeat tests 1–6 on every platform you ship (JS, Python, PHP, .NET). Behavior differences usually come from storage locations and grace-period defaults, not from missing features.
Obfuscation complements licensing: the SDK protects the license, obfuscation makes the surrounding code harder to analyze and patch. Whether it's worth it depends heavily on platform:
| Platform | Typical tooling | Protection gained | Verdict |
|---|---|---|---|
| .NET | Control-flow obfuscation, string encryption, renaming (commercial obfuscators or ConfuserEx-class tools) | High — IL decompilers otherwise reconstruct near-source C# | Recommended for commercial desktop apps |
| JavaScript (browser) | Minification + mangling (bundler output) | Low — everything ships to the client; determined users can read it | Minify, don't over-invest |
| Node.js | Bundling/packaging into a single executable (e.g., pkg-style), minification | Low–medium — source is often recoverable from snapshots | Rely mainly on server-side checks |
| Python | Compile to bytecode/native (Nuitka, PyInstaller + Cython for hot paths) | Medium — plain .pyc decompiles easily; native compilation helps a lot |
Worth it if distributing compiled |
| PHP (server-side) | Not needed — your code never leaves your server | N/A — clients only talk to your API | Skip; server code isn't distributed |
Apply obfuscation as a post-build step after your licensing integration compiles and passes tests. Obfuscation rewrites symbols and control flow, so testing licensing on the obfuscated build (Q7) is part of your release checklist.
They're related but solve different problems, and UnifiedLicensing is a licensing system:
| Licensing (UnifiedLicensing) | DRM | |
|---|---|---|
| Goal | Control who may use your software and at what tier | Control access to content/media itself |
| Protects | Your revenue and business rules (tiers, seats, trials, expiry) | The media files — video, audio, ebooks — end-to-end |
| Mechanism | Key validation, signatures, machine binding, heartbeats, revocation | Content encryption at rest and in playback, licensed decoders, output controls |
| User friction | Activate once; works offline within grace period | Ongoing — every playback session touches the DRM layer |
| Typical stack | UnifiedLicensing SDK + your product logic | Widevine, FairPlay, PlayReady (or similar) |
| Good fit for | Desktop apps, SaaS clients, plugins, games, dev tools | Streaming media, published content distributions |
If you're shipping an application and want to enforce per-seat, per-tier, trial, and subscription rules — that's licensing, and it's exactly what these SDKs do. If you need to encrypt the media assets themselves so they're unusable outside an approved player, you need a DRM system alongside (or instead of) licensing.