Keygen.Net
0.2.0
See the version list below for details.
dotnet add package Keygen.Net --version 0.2.0
NuGet\Install-Package Keygen.Net -Version 0.2.0
<PackageReference Include="Keygen.Net" Version="0.2.0" />
<PackageVersion Include="Keygen.Net" Version="0.2.0" />
<PackageReference Include="Keygen.Net" />
paket add Keygen.Net --version 0.2.0
#r "nuget: Keygen.Net, 0.2.0"
#:package Keygen.Net@0.2.0
#addin nuget:?package=Keygen.Net&version=0.2.0
#tool nuget:?package=Keygen.Net&version=0.2.0
Keygen.Net
dotnet add package Keygen.Net
A .NET client for the Keygen software licensing API: license validation, machine activation and heartbeats, certificate checkout, offline verification of cryptographic license and machine files, and a client for Keygen Relay.
MIT licensed, by Santiago Saavedra info@ssaavedra.eu.
This is a community-supported SDK. It is not affiliated with, endorsed by, or supported by Keygen LLC. Keygen maintains first-party SDKs for Go, Node, Rust, C++, Java, Swift and Python, but none for .NET — this exists to fill that gap.
We would be glad to see it become the official one. If Keygen would like to adopt, fork or take over maintenance of this package, that is welcome and no strings are attached: open a PR or an issue here and we will work out the handover, including transferring the NuGet package owner and this repository. Until then it is maintained on a best-effort basis by its contributors.
No dependencies on any target. The cryptography is entirely System.Security.Cryptography.
Two assets ship:
| Target | Contents |
|---|---|
net8.0 |
Portable. No Windows APIs, nothing platform-specific. |
net8.0-windows |
Adds Fingerprint.WindowsMachineGuid(), which reads the registry. |
Registry types come from the Windows targeting pack, so the Windows asset needs no package
reference either. Target net8.0 and you download nothing extra and reference nothing
Windows-specific; target net8.0-windows and you get the machine GUID as well.
Verifying a license file offline
This is the part that matters: it needs no network, so a licensing outage can never reach your users.
using Keygen;
var verifier = new KeygenVerifier(
publicKey: MyAccountPublicKeyPem,
expectedAlgorithm: new KeygenAlgorithm(PayloadEncoding.Base64, SignatureScheme.EcdsaP256));
var file = verifier.VerifyLicenseFile(certificate); // throws on anything untrustworthy
using var payload = file.ParsePayload();
var status = payload.RootElement
.GetProperty("data").GetProperty("attributes").GetProperty("status").GetString();
Encrypted files need the license key, and machine files additionally need the fingerprint:
var file = verifier.VerifyLicenseFile(certificate, licenseKey);
var machine = verifier.VerifyMachineFile(certificate, licenseKey, fingerprint);
Choose your algorithm, and say so
expectedAlgorithm is asserted against every certificate. This is deliberate: trusting the
alg field inside the file would let an attacker downgrade you to whichever scheme they can
forge. Set it to whatever your Keygen policy's scheme is, and never derive it from input.
Ed25519
Keygen signs with Ed25519 when a policy sets no scheme, and .NET has no Ed25519 primitive. Either:
- set the policy's scheme to ECDSA P-256, which this library verifies with no extra dependency — recommended; or
- plug in an implementation:
KeygenVerifier.Ed25519Verifier = (publicKey, data, signature) =>
/* libsodium, BouncyCastle, … */;
What the exceptions mean
| Exception | Meaning | Reasonable response |
|---|---|---|
KeygenSignatureException |
Bad signature, or the algorithm was not the one demanded | Treat as hostile. Alarm. |
KeygenFileExpiredException |
The certificate's TTL has elapsed | Routine. Check out a fresh one. |
KeygenDecryptionException |
Wrong license key or machine fingerprint | Ask the user to re-check |
KeygenFormatException |
Not a well-formed certificate | Reject the input |
They are distinct so an expired snapshot never looks like an attack, and an attack never looks routine.
Fingerprinting
var fingerprint = await Fingerprint.KubernetesClusterUidAsync(httpClient) // clustered installs
?? Fingerprint.MachineId();
string?[] components =
[
Fingerprint.MachineId(),
Fingerprint.PrimaryMacAddress(),
Fingerprint.BoardSerial(),
];
Every collector returns null rather than throwing when an identifier cannot be read — a
container with no DMI access, a host with no active NIC. Absent components are expected and
fine: pair this with Keygen's MATCH_MOST component matching strategy so that replacing a
NIC or migrating a VM does not invalidate a license, while cloning a whole install still
fails to match.
On the portable net8.0 asset, MachineId() returns null when running on Windows — the
machine GUID needs registry access. If your application runs on Windows and wants that
component, target net8.0-windows:
var guid = Fingerprint.WindowsMachineGuid(); // net8.0-windows asset only
Hash before sending. A fingerprint should identify a host, not inventory it:
components.Where(c => c is not null).Select(Fingerprint.Hash!);
KubernetesClusterUidAsync needs the pod's service account to hold get on namespaces;
without that RBAC it returns null.
Keygen Relay
Relay is a separate API, not a variant of the main one: no JSON:API envelope, no account in the path, and a lease model instead of machine activation. It is what makes air-gapped sites work.
var relay = new RelayClient(httpClient, new Uri("http://relay.plant.local:6349"));
var lease = await relay.ClaimAsync(fingerprint); // PUT /v1/nodes/{fingerprint}
// lease.Certificate, lease.LicenseKey, lease.ExpiresAt, lease.Extended
await relay.ReleaseAsync(fingerprint); // DELETE, returns the licence to the pool
Re-claiming extends the lease when the server has heartbeats enabled; lease.Extended reports
whether Relay renewed an existing lease (202) or granted a new one (201). Two refusals are worth
telling apart, and have their own exception types: RelayPoolExhaustedException (410, no licence
left) and RelayLeaseHeldException (409, this node holds one and heartbeats are off).
Verify the leased certificate exactly as any other — Relay distributes certificates, it does not vouch for them.
keygen-cli
A small tool for support calls and for trying the library without a Keygen instance.
dotnet run --project tools/keygen-cli -- fingerprint
dotnet run --project tools/keygen-cli -- demo-cert --out /tmp/demo
dotnet run --project tools/keygen-cli -- verify --cert /tmp/demo/demo.lic --pubkey /tmp/demo/demo-public-key.pem
fingerprint prints this host's components, raw and hashed, and says how many are readable —
useful for judging whether MATCH_MOST has enough to work with before issuing anything.
verify works against real Keygen certificates and exits 0 valid, 2 stale, 3 bad
signature, 4 cannot decrypt, 5 malformed — so it drops into a health check or a support
script without parsing output.
demo-cert writes a throwaway certificate signed by an ephemeral key. It is not an issuer:
minting real licences belongs in Keygen, and a second signing implementation is the thing
that drifts.
Licence
MIT. See LICENSE.
Contributing
Issues and pull requests are welcome, from users and from Keygen alike — see the note at the top about adoption.
Releases publish to NuGet through GitHub Actions using NuGet Trusted Publishing (OIDC), so no long-lived API key is stored in this repository. Publishing runs on a published GitHub release.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net8.0-windows7.0 is compatible. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- No dependencies.
-
net8.0-windows7.0
- No dependencies.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Keygen.Net:
| Package | Downloads |
|---|---|
|
Keygen.Net.Ed25519
Ed25519 signature verification for Keygen.Net. .NET has no Ed25519 primitive, and Ed25519 is Keygen's default signing scheme, so this adds it through BouncyCastle. Kept in a separate package so applications using ECDSA P-256 or RSA policies take no dependency at all. |
GitHub repositories
This package is not used by any popular GitHub repositories.