Skip to content

C# SDK

Signox.Sdk — the official SDK for C# (.NET, Unity). It targets netstandard2.0 only, so it runs as-is on .NET Framework 4.6.1+, .NET 5/6/7/8+, and Unity 2019+ (including IL2CPP).

  • Every server response is trusted only after its Ed25519 signature is verified with the product public key (tampering/replay defense).
  • The hardware ID (hwid) is generated internally by the SDK — callers never deal with it.
  • Verdicts are delivered as LicenseResult values, not exceptions. Exceptions occur only on invalid arguments (empty key, etc.).
  • The only runtime dependency is BouncyCastle.Cryptography (for Ed25519 verification, MIT).
Terminal window
dotnet add package Signox.Sdk

Or in .csproj:

<PackageReference Include="Signox.Sdk" Version="0.1.0" />
  1. Drop the DLLs in directly (recommended, simplest) — copy Signox.Sdk.dll and BouncyCastle.Cryptography.dll into Assets/Plugins/. Both are pure managed code, so no extra setup is needed even on the IL2CPP backend. Get BouncyCastle.Cryptography.dll from your NuGet cache or nuget.org.
  2. NuGetForUnity — installing Signox.Sdk via NuGetForUnity pulls in the dependency automatically.

In Unity, hwid collection attempts external process execution or system file reads; in restricted environments it safely falls back to a low-confidence identifier (weak_hwid).

using Signox.Sdk;
var client = new SignoxClient(new SignoxOptions
{
// Embed the product public key (SPKI PEM) in your app. See "Embedding the public key" below.
ProductPublicKey = @"-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEA... (per-product public key)
-----END PUBLIC KEY-----",
// BaseUrl defaults to https://api.signox.kr
// With CacheDir set, the offline-fallback cache is stored on disk
CacheDir = System.IO.Path.Combine(
System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData),
"MyApp", "signox-cache"),
});
// 1) Activate (register this device) — once, idempotent
LicenseResult act = client.Activate("S4K2MB-7IWQ3F-...", new ActivateOptions
{
Name = "John's laptop", // shown in the dashboard (optional)
});
if (!act.Valid)
{
// act.Code: DEVICE_LIMIT_REACHED / VM_NOT_ALLOWED / NOT_FOUND ...
return;
}
// 2) Validate — on every app run. The cache (cache.ttl) skips redundant re-validation
LicenseResult v = client.Validate("S4K2MB-7IWQ3F-...");
if (v.Valid)
{
bool proExport = v.Features.TryGetValue("pro_export", out var pe) && pe is bool b && b;
// v.Code == VALID | IN_GRACE_PERIOD
}
else if (v.Code == ValidationCode.NETWORK_ERROR)
{
// Network failure + no valid cache — handle distinctly from "invalid" in your UX
}
Method Purpose
Validate(licenseKey) Validate license + device (includes cache/offline fallback)
Activate(licenseKey[, opts]) Activate this device (hwid/anomalies attached automatically)
Deactivate(licenseKey) Deactivate (returns the slot)
Heartbeat(licenseKey) Liveness signal + lightweight re-validation
ReportUsage(licenseKey, feature[, value]) Report metered usage
RequestOfflineFile(licenseKey) Issue a .lic file (content via File.Content)
ValidateOffline(licContent) Fully local .lic verification (no network)
GetHwid() Diagnostic — this device’s hwid
Group Codes
Valid VALID, IN_GRACE_PERIOD
Invalid (state) SUSPENDED, REVOKED, EXPIRED
Invalid (request/device) NOT_FOUND, PRODUCT_INACTIVE, HWID_REQUIRED, DEVICE_NOT_ACTIVATED, DEVICE_LIMIT_REACHED, VM_NOT_ALLOWED, FEATURE_NOT_FOUND, USAGE_LIMIT_REACHED
SDK-local SIGNATURE_INVALID, NONCE_MISMATCH, OFFLINE_FILE_INVALID, HWID_MISMATCH, NETWORK_ERROR

NETWORK_ERROR means no verdict is possible (network failure + no valid cache) — it does not mean the license is invalid. On network failure, a cache within SignoxOptions.OfflineGraceDays (default 7 days counted from when the cache was stored, 0 = no fallback) is used as the verdict with Stale=true. See the online activation guide for the recommended UX per code.

Machines without internet access use a .lic file issued from the portal/dashboard or an online device. See offline activation for the full flow.

// (Online) issue a .lic — on success the file body is in result.File.Content
LicenseResult issued = client.RequestOfflineFile("S4K2MB-7IWQ3F-...");
if (issued.Code == ValidationCode.VALID && issued.File != null)
System.IO.File.WriteAllText("license.lic", issued.File.Content);
// (Offline) fully local verification — no network; the SDK matches the hwid locally
string lic = System.IO.File.ReadAllText("license.lic");
LicenseResult offline = client.ValidateOffline(lic);
// offline.Code: VALID | IN_GRACE_PERIOD | EXPIRED | HWID_MISMATCH | SIGNATURE_INVALID | OFFLINE_FILE_INVALID

SignoxClient is built from immutable options and is safe to call concurrently from multiple threads. Create one instance for the app’s lifetime and reuse it (hwid and cache are memoized).

Always embed ProductPublicKey in your app. The SDK does not fetch the public key from the server — receiving it over the network would let a man-in-the-middle inject a forged key. The public key is not a secret, but swap prevention is the point. Never put the private key in a client (it exists only on the server).