Enigma.LicenseManager
1.1.0
dotnet add package Enigma.LicenseManager --version 1.1.0
NuGet\Install-Package Enigma.LicenseManager -Version 1.1.0
<PackageReference Include="Enigma.LicenseManager" Version="1.1.0" />
<PackageVersion Include="Enigma.LicenseManager" Version="1.1.0" />
<PackageReference Include="Enigma.LicenseManager" />
paket add Enigma.LicenseManager --version 1.1.0
#r "nuget: Enigma.LicenseManager, 1.1.0"
#:package Enigma.LicenseManager@1.1.0
#addin nuget:?package=Enigma.LicenseManager&version=1.1.0
#tool nuget:?package=Enigma.LicenseManager&version=1.1.0
Enigma.LicenseManager
Enigma.LicenseManager is a comprehensive .NET library designed for secure license management in applications. It provides robust cryptographic protection using both traditional RSA and modern ML-DSA (FIPS 204) digital signature algorithms, ensuring your software licensing is both secure and future-proof.
Features
- Dual Cryptographic Support: Choose between RSA and ML-DSA (post-quantum) signatures
- Flexible License Management: Create, validate, and manage licenses with customizable properties
- Device Binding: Lock licenses to specific machines using hardware-derived device identifiers
- Cross-Platform Compatibility: Supports .NET Standard 2.0 and .NET 8.0+
- JSON Serialization: Easy license storage and distribution in JSON format
- Product Version Matching: Support for wildcard patterns in product IDs (e.g.,
MyApp 1.*) - Expiration Handling: Built-in support for time-based license expiration
- Thread-Safe Service:
LicenseServiceis fully thread-safe for concurrent access
Installation
dotnet add package Enigma.LicenseManager
License Creation
Create an RSA-Signed License
Generate a license with RSA digital signature for traditional cryptographic security:
await using var privateKeyFile = new FileStream("<YourKeyFile.pem>", FileMode.Open, FileAccess.Read);
var privateKey = PemUtils.LoadPrivateKey(privateKeyFile, "<KeyPassword>");
var license = new LicenseBuilder()
.SetProductId("MyApp 1.*")
.SetExpirationDate(DateTime.UtcNow.AddDays(365))
.SetOwner("Acme Corp")
.SignWithRsa(privateKey)
.Build();
Create an ML-DSA-Signed License
Generate a license with ML-DSA (post-quantum) signature for enhanced future security:
await using var privateKeyFile = new FileStream("<YourKeyFile.pem>", FileMode.Open, FileAccess.Read);
var privateKey = PemUtils.LoadPrivateKey(privateKeyFile, "<KeyPassword>");
var license = new LicenseBuilder()
.SetProductId("MyApp")
.SignWithMlDsa(privateKey)
.Build();
Create a Device-Bound License
Bind a license to a specific machine so it cannot be used elsewhere:
// On the target machine, generate the device ID
var deviceId = LicenseUtils.GenerateDeviceId();
// When creating the license, bind it to that device
var license = new LicenseBuilder()
.SetProductId("MyApp 1.*")
.SetDeviceId(deviceId)
.SetExpirationDate(DateTime.UtcNow.AddDays(365))
.SignWithRsa(privateKey)
.Build();
Iddefaults to a ULID andCreationDatedefaults toDateTime.UtcNowwhen not explicitly set.
License Persistence
Save License to JSON
Export your generated license to a JSON file for distribution:
await using var fs = new FileStream("<DestinationPath>", FileMode.Create, FileAccess.Write);
await license.SaveAsync(fs);
Load License from JSON
Import a license from a JSON file for validation:
await using var fs = new FileStream("<LicenseFilePath>", FileMode.Open, FileAccess.Read);
var license = await License.LoadAsync(fs);
Both SaveAsync and LoadAsync accept an optional CancellationToken parameter.
License Validation
Verify a Single License
Validate a license against its public key. IsValid returns a (bool, string?) tuple with an error message on failure:
await using var publicKeyFile = new FileStream("<YourKeyFile.pem>", FileMode.Open, FileAccess.Read);
var publicKey = PemUtils.LoadKey(publicKeyFile);
var service = new LicenseService();
var (isValid, errorMessage) = service.IsValid(license, publicKey, "MyApp 1.0");
if (!isValid)
Console.WriteLine($"License rejected: {errorMessage}");
For device-bound licenses, pass the device ID:
var deviceId = LicenseUtils.GenerateDeviceId();
var (isValid, errorMessage) = service.IsValid(license, publicKey, "MyApp 1.0", deviceId);
Using LicenseService
LicenseService maintains an in-memory, thread-safe collection of licenses. Register licenses once, then check validity by product ID throughout your application:
var service = new LicenseService();
// Register licenses with their public keys
service.AddLicense(license, publicKey);
// Check if any registered license is valid for a product
if (service.HasValidLicense("MyApp 1.0"))
{
// Feature is licensed
}
// For device-bound licenses
var deviceId = LicenseUtils.GenerateDeviceId();
if (service.HasValidLicense("MyApp 1.0", deviceId))
{
// Feature is licensed for this device
}
// Remove a license when no longer needed
service.RemoveLicense(license);
Project Structure
| Path | Description |
|---|---|
src/Enigma.LicenseManager/ |
Core library |
src/UnitTests/ |
Unit tests |
src/ConsoleApp1/ |
Example console application |
| 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 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. |
| .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.Cryptography (>= 4.2.1)
- Newtonsoft.Json (>= 13.0.4)
- Ulid (>= 1.4.1)
-
net8.0
- DeviceId (>= 6.11.0)
- Enigma.Cryptography (>= 4.2.1)
- Newtonsoft.Json (>= 13.0.4)
- 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.