Enigma.Licensing
1.0.0
See the version list below for details.
dotnet add package Enigma.Licensing --version 1.0.0
NuGet\Install-Package Enigma.Licensing -Version 1.0.0
<PackageReference Include="Enigma.Licensing" Version="1.0.0" />
<PackageVersion Include="Enigma.Licensing" Version="1.0.0" />
<PackageReference Include="Enigma.Licensing" />
paket add Enigma.Licensing --version 1.0.0
#r "nuget: Enigma.Licensing, 1.0.0"
#:package Enigma.Licensing@1.0.0
#addin nuget:?package=Enigma.Licensing&version=1.0.0
#tool nuget:?package=Enigma.Licensing&version=1.0.0
Enigma.Licensing
Enigma.Licensing generates signed software licenses and checks them. A license is a small JSON
envelope whose signature covers the stored payload bytes exactly — there is no canonicalization
step, no "build a string to sign" helper, and therefore no way for a signer and a verifier to
disagree about what was signed. That single idea shapes the whole surface: you sign a
LicenseRequest into a LicenseEnvelope with a private key, ship the public half inside your
application, and ask the validator for a verdict. Signing is classical RSA or post-quantum ML-DSA,
and all cryptography comes from Enigma.Core — whose
types never reach this library's public surface.
What's new in 1.0 — the first release: signed
enigma-license/1envelopes,enigma-key/1key files, six signature schemes, and a validator that returns a verdict instead of throwing. See RELEASENOTES.md.
Features
- License format —
enigma-license/1, a five-field JSON envelope carrying the format, the algorithm, the signing key's fingerprint, the base64 payload and its signature.ReadLicense()inspects an untrusted document without verifying it;SaveAsync/LoadAsyncmove one over any stream. - Keys —
enigma-key/1, one format for both algorithm families and both halves of a pair.IKeyServicegenerates, saves and loads them, optionally encrypting the private half with Argon2id + AES-256-GCM. Both halves share akeyIdfingerprint, which the generator stamps into every envelope it signs. - Signature schemes — RSA with SHA-256, SHA-384 or SHA-512 (2048–8192-bit moduli, 3072 by
default), and ML-DSA-44/65/87 (FIPS 204) for post-quantum signatures. The verifier is chosen from
the envelope's own
algorithmfield, so rewriting it makes the signature fail rather than downgrade. - Generating licenses —
ILicenseGeneratorsigns aLicenseRequestcarrying a product identifier, an owner, feature flags, arbitrary string claims, an optional validity window and an optional device binding. Identifier and creation time are defaulted per call; the one-call path overload loads the key, signs and writes the file. - Validating licenses —
ILicenseValidatorruns a fixed, documented check order and reports the first failing step as one of sevenLicenseFailurereasons, so an expired license and a forged one are never confused. Nothing a license can be makes it throw. Product identifiers may carry an anchored*wildcard, so one license can cover a version range.ILicenseStoreholds several licenses and re-validates on every query, caching nothing. - Device identity —
DeviceIdentifier.Generate()derives a best-effort machine identifier from the machine name and OS version, hashed so neither is readable in a license file. Any other scheme plugs in: the library only ever compares device identifiers ordinally.
Registration, trimming and AOT
All four services are sealed classes behind interfaces with a public parameterless constructor, so
new LicenseValidator() works anywhere; one call to AddEnigmaLicensing() registers all four as
singletons instead. Serialization is source-generated rather than reflection-based, and the library
is built with the trim and AOT analyzers enabled on its modern targets — so it stays usable in an
application published with PublishAot or with reflection-based JSON turned off.
Installation
dotnet add package Enigma.Licensing
Targets .NET Standard 2.0, .NET 8.0 and .NET 10.0; built on Enigma.Core 1.1.0.
Quick start
Generate a key pair, sign a license with the private half, and check it against the public half:
using System;
using System.Threading.Tasks;
using Enigma.Licensing;
using Enigma.Licensing.Keys;
// The issuer generates a pair once: the private half signs, the public half ships with the app.
var keyService = new KeyService();
LicensingKeyPair pair = keyService.GenerateKeyPair(LicenseSignatureAlgorithm.MLDsa65);
await keyService.SaveKeyPairAsync(pair, "signing.public.key.json", "signing.private.key.json");
// Sign a license. The path overload loads the key, signs and writes the file in one call.
LicenseEnvelope envelope = await new LicenseGenerator().GenerateAndSaveAsync(
new LicenseRequest { ProductId = "MyApp 2.0", Owner = "Acme GmbH" },
privateKeyPath: "signing.private.key.json",
password: null,
outputPath: "acme.license");
// The application checks it — a verdict, never an exception.
LicenseValidationResult result = await new LicenseValidator().ValidateAsync(
licensePath: "acme.license",
publicKeyPath: "signing.public.key.json",
productId: "MyApp 2.0");
Console.WriteLine(result.IsValid
? $"Licensed to {result.License?.Owner}, key {envelope.KeyId}."
: $"{result.Failure}: {result.Message}");
Documentation
Per-category guides — each with the supported algorithms and operations, the key types, and
copy-pasteable C# samples verified against the public API — live under docs/guides/ in the
repository, indexed by docs/guides/README.md. They cover the license format, keys, generating
licenses, validating licenses, and device identity. Every public member also carries XML
documentation, which ships inside the package.
Desktop application
The repository also contains Enigma.Licensing.Desktop, an Avalonia application for issuers: it generates key pairs, signs licenses from a form (with saveable profiles), and validates a license against a public key, reaching the same verdicts the library does. It is built on the library's public surface — exactly what a third-party consumer gets — and is distributed as a self-contained zip for Windows and Linux rather than through NuGet.
License
Enigma.Licensing is released under the MIT License.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. 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. 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 is compatible. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- DeviceId (>= 6.11.0)
- Enigma.Core (>= 1.1.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.18)
- System.Buffers (>= 4.6.1)
- System.Text.Json (>= 10.0.10)
- Ulid (>= 1.4.1)
-
net10.0
- DeviceId (>= 6.11.0)
- Enigma.Core (>= 1.1.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.18)
- Ulid (>= 1.4.1)
-
net8.0
- DeviceId (>= 6.11.0)
- Enigma.Core (>= 1.1.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.18)
- Ulid (>= 1.4.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
First public release. Generates and validates signed software licenses: enigma-license/1 envelopes whose signature covers the stored payload bytes exactly, with no canonicalization step; enigma-key/1 key files covering both algorithm families and both halves of a pair, with optional Argon2id + AES-256-GCM encryption of the private half; and six signature schemes — RSA with SHA-256/384/512 and post-quantum ML-DSA-44/65/87 (FIPS 204). A license carries feature flags, arbitrary claims, an optional validity window and an optional device binding. Validation returns a verdict rather than throwing, reports the first failing check of eight, and supports anchored wildcard product identifiers. Serialization is source-generated, so the library is trim- and AOT-safe. A clean break from Enigma.LicenseManager: its licenses and keys are deliberately not readable here. See RELEASENOTES.md for the full details.