ARSoft.WinFormsLicensing
1.5.2
dotnet add package ARSoft.WinFormsLicensing --version 1.5.2
NuGet\Install-Package ARSoft.WinFormsLicensing -Version 1.5.2
<PackageReference Include="ARSoft.WinFormsLicensing" Version="1.5.2" />
<PackageVersion Include="ARSoft.WinFormsLicensing" Version="1.5.2" />
<PackageReference Include="ARSoft.WinFormsLicensing" />
paket add ARSoft.WinFormsLicensing --version 1.5.2
#r "nuget: ARSoft.WinFormsLicensing, 1.5.2"
#:package ARSoft.WinFormsLicensing@1.5.2
#addin nuget:?package=ARSoft.WinFormsLicensing&version=1.5.2
#tool nuget:?package=ARSoft.WinFormsLicensing&version=1.5.2
ARSoft WinForms Licensing
A robust time-based licensing library for Windows Forms applications that provides secure license management with encryption, dual storage, and comprehensive validation.
π Features
- Time-based Licensing: Create licenses with configurable expiration periods
- Dual Storage with Self-Healing: Stores licenses in both local files and Windows Registry for redundancy with automatic repair
- Encryption: AES encryption with PBKDF2 key derivation for secure license storage
- Tamper Protection: SHA256 checksums prevent license modification
- Flexible Distribution: Support for direct license data registration or .lic file import
- Optional Logging: Built-in silent logger with optional custom logging support
- Dual Usage Patterns: Separate factory methods for creation (with logging) and validation (silent)
- Extended Default License: 366-day default validity period
- License Detection: Built-in methods to check license presence and load valid licenses
- Automatic Recovery: Self-healing validation automatically repairs corrupted or missing license copies
π¦ Installation
NuGet Package Manager
Install-Package ARSoft.WinFormsLicensing
.NET CLI
dotnet add package ARSoft.WinFormsLicensing
Package Manager Console
PM> Install-Package ARSoft.WinFormsLicensing
Note: As of v1.5.0, providing a logger is now optional. The library includes a built-in silent logger by default.
π§ How It Works
Core Concepts
- Dual Usage Patterns:
ForCreation(): Full-featured manager with custom logging for license generation tools and vendor operationsForValidation(): Silent manager for client applications (no logging overhead)
- License Creation: Generate time-bound licenses for specific clients (default 366 days)
- Dual Storage with Self-Healing: Automatically saves to both AppData file and Windows Registry with automatic repair if one becomes corrupted
- Encryption: All license data is encrypted using AES with derived keys
- Validation: Multi-layer validation including checksum verification, expiration checks, and dual-source verification
- Flexible Distribution: Support for both direct license registration and .lic file import
- License Detection: Check for license presence before validation
- Unified Encryption: Both creation and validation modes use the same encryption parameters for consistency
Security Features
- PBKDF2 Key Derivation: Uses 100,000 iterations with SHA256
- AES Encryption: Industry-standard encryption for license data
- SHA256 Checksums: Prevents tampering with license data
- Client Hashing: Secure client identification without storing sensitive info
- Dual-Source Validation: Validates both file and registry copies with automatic repair
Self-Healing License Validation
The library implements a robust self-healing mechanism during license validation:
- Dual-Source Check: Validates licenses from both file storage and Windows Registry
- Automatic Repair: If one source is missing or corrupted, it's automatically restored from the valid source
- Most Recent Selection: When both sources are valid, the most recently issued license is used
- Transparent Recovery: Self-healing happens automatically without user intervention
This ensures maximum license integrity and protects against:
- Accidental file deletion
- Registry corruption
- Storage media failures
- Tampering attempts
π οΈ Basic Implementation
1. Setup and Initialization
The library provides two factory methods for different use cases:
For License Creation (Vendor Tools with Logging)
using ARSoft.WinFormsLicensing;
using Microsoft.Extensions.Logging;
using System.Text;
// Option 1: Without logger (uses built-in silent logger - recommended for production)
var licenseManager = LicenseManager.ForCreation(
logger: null, // Pass null to use built-in silent logger
keyPassword: "YourSecurePassword123!", // Use a strong password
keySalt: Encoding.UTF8.GetBytes("YourUniqueSalt12345"), // At least 8 bytes
appName: "MyApplication",
settingsFile: "license.json",
registryKeyPath: "SOFTWARE\\MyCompany\\MyApp\\License"
);
// Option 2: With custom logger (for debugging/monitoring)
var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
var customLogger = loggerFactory.CreateLogger<LicenseManager>();
var licenseManagerWithLogging = LicenseManager.ForCreation(
logger: customLogger,
keyPassword: "YourSecurePassword123!",
keySalt: Encoding.UTF8.GetBytes("YourUniqueSalt12345"),
appName: "MyApplication",
settingsFile: "license.json",
registryKeyPath: "SOFTWARE\\MyCompany\\MyApp\\License"
);
// Option 3: Toggle logging on/off at runtime
licenseManager.LoggerEnabled = true; // Enable logging
licenseManager.LoggerEnabled = false; // Disable logging (default)
For License Validation (Client Applications - Silent Mode)
using ARSoft.WinFormsLicensing;
using System.Text;
// Initialize LicenseManager for validation (no logging, same encryption parameters)
var licenseManager = LicenseManager.ForValidation(
password: "YourSecurePassword123!", // Same password as ForCreation
salt: Encoding.UTF8.GetBytes("YourUniqueSalt12345"), // Same salt as ForCreation
appName: "MyApplication",
settingsFile: "license.json",
registryKeyPath: "SOFTWARE\\MyCompany\\MyApp\\License"
);
Important: The password and salt used in ForValidation() must match those used in ForCreation() and LicenseGenerator.GenerateLicenseFile(). These are your application's encryption credentials.
2. License Distribution Workflows
The library supports two main distribution patterns:
Workflow A: Direct License Registration
- Vendor: Creates license using
CreateLicense()method - Vendor: Provides license data to customer (via secure channel)
- Customer: Enters license data in your registration window
- Customer App: Uses
RenewLicense()or similar to register the license
Workflow B: License File Distribution
- Vendor: Generates .lic file using
LicenseGenerator.GenerateLicenseFile() - Vendor: Sends .lic file to customer (via secure channel)
- Customer: Receives .lic file
- Customer App: Uses
ImportLicenseFile()to import and register the license
3. Creating Licenses (Vendor/Generator Tools)
Direct License Creation
// Use ForCreation() for vendor tools
var licenseManager = LicenseManager.ForCreation(
logger: null,
keyPassword: "YourSecurePassword123!",
keySalt: Encoding.UTF8.GetBytes("YourUniqueSalt12345"),
appName: "MyApplication",
settingsFile: "license.json",
registryKeyPath: "SOFTWARE\\MyCompany\\MyApp\\License"
);
// Create a 366-day license for a client (default validity)
bool success = licenseManager.CreateLicense(
clientName: "John Doe Company",
licensedDate: DateTime.Now,
validityDays: 366 // Optional: defaults to 366 days
);
if (success)
{
Console.WriteLine("License created and registered successfully!");
}
Generating License Files (.lic)
using ARSoft.WinFormsLicensing.Service.Helpers;
// Generate encrypted .lic file for distribution
// IMPORTANT: Use the SAME password and salt as your application
bool fileGenerated = LicenseGenerator.GenerateLicenseFile(
clientName: "John Doe Company",
password: "YourSecurePassword123!",
salt: Encoding.UTF8.GetBytes("YourUniqueSalt12345"),
outputFile: @"C:\licenses\client-license.lic",
validityDays: 366,
startDate: DateTime.Now
);
if (fileGenerated)
{
Console.WriteLine("License file generated successfully!");
// Send client-license.lic to customer via secure channel
}
4. License Registration (Customer Applications)
// Initialize with ForValidation() for silent operation
var licenseManager = LicenseManager.ForValidation(
password: "YourSecurePassword123!",
salt: Encoding.UTF8.GetBytes("YourUniqueSalt12345"),
appName: "MyApplication",
settingsFile: "license.json",
registryKeyPath: "SOFTWARE\\MyCompany\\MyApp\\License"
);
// Import License from File
bool imported = licenseManager.ImportLicenseFile(@"C:\path\to\received-license.lic");
if (imported)
{
MessageBox.Show("License imported and registered successfully!", "Success");
}
else
{
MessageBox.Show("Failed to import license file.", "Error");
}
// Or Register License from Data
var licenseData = new LicenseData
{
Client = hashedClientName, // This should come from vendor
Licensed = licensedDate,
Expires = expirationDate,
Version = "1.0",
Checksum = providedChecksum
};
bool registered = licenseManager.RenewLicense(licenseData);
if (registered)
{
MessageBox.Show("License registered successfully!", "Success");
}
5. License Validation (Client Applications)
// Check if license exists before validation
if (!licenseManager.IsLicensePresent())
{
MessageBox.Show("No license found. Please register your software.", "License Missing",
MessageBoxButtons.OK, MessageBoxIcon.Error);
// Show registration form or exit
return;
}
// Validate license on application startup
// The validation method automatically repairs corrupted or missing licenses
var (isValid, message, daysRemaining) = licenseManager.ValidateLicense();
if (!isValid)
{
MessageBox.Show($"License Error: {message}", "License Validation",
MessageBoxButtons.OK, MessageBoxIcon.Error);
Application.Exit();
return;
}
// Show expiration warning if needed
if (daysRemaining <= 30 && !string.IsNullOrEmpty(message))
{
MessageBox.Show(message, "License Expiration Warning",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
Note: The ValidateLicense() method automatically performs self-healing. If the license file is corrupted but the registry copy is valid (or vice versa), the corrupted copy will be automatically restored. This happens transparently without any user intervention.
6. Working with License Data
// Load valid license data for inspection
var licenseData = licenseManager.LoadValidLicense();
if (licenseData != null)
{
Console.WriteLine($"Licensed to: {licenseData.Client}"); // Note: This is a hashed value
Console.WriteLine($"Expires on: {licenseData.Expires:yyyy-MM-dd}");
Console.WriteLine($"Version: {licenseData.Version}");
}
πΌ Business Workflows
Workflow A: Direct License Registration
Vendor Side:
- Uses
ForCreation()instance to create licenses - Generates license data using
CreateLicense() - Provides license details to customer (securely)
- Uses
Customer Side:
- Application has registration form/window
- Customer enters provided license data
- Application uses
ForValidation()instance withRenewLicense()to register - Application validates license on startup using
ValidateLicense() - Self-healing ensures license integrity automatically
Workflow B: License File Distribution
Vendor Side:
- Creates license generator tool using this library
- Uses
LicenseGenerator.GenerateLicenseFile()to create .lic files - Sends .lic files to customers via secure channels
Customer Side:
- Receives .lic file from vendor
- Application uses
ForValidation()instance withImportLicenseFile() - Application validates license on startup using
ValidateLicense() - Self-healing protects against storage corruption
Workflow C: Hybrid Approach
- Initial Registration: Customer registers using direct license data
- Renewals: Vendor sends .lic files for license renewals
- Updates: Customer imports new .lic files without reinstalling application
- Automatic Recovery: License automatically repairs if one storage location fails
π Security Best Practices
- Use Strong Passwords: Use complex passwords for key derivation
- Unique Salt: Use a unique salt for each application (minimum 8 bytes)
- Consistent Credentials: Use identical password and salt across all vendor tools and customer applications
- Secure Distribution: Distribute license files/data securely (encrypted email, secure download)
- Regular Validation: Validate license on application startup and periodically during runtime
- Error Handling: Implement proper error handling for license validation failures
- Registry Path Validation: Use valid registry paths starting with "SOFTWARE\" and containing only alphanumeric characters, backslashes, underscores, or hyphens
- Silent Operation in Production: Use
ForValidation()in client applications to avoid logging overhead - Trust Self-Healing: The dual-storage system with automatic repair provides robust protection against data corruption
π Configuration Options
Factory Methods
LicenseManager.ForCreation()
For license generation tools and vendor operations with optional logging:
| Parameter | Type | Required | Description |
|---|---|---|---|
logger |
ILogger<LicenseManager> |
No | Logger instance for tracking events. Pass null to use built-in silent logger (recommended for production). |
keyPassword |
string |
Yes | Password for encryption key derivation. Must match across all instances. |
keySalt |
byte[] |
Yes | Salt for key derivation (min 8 bytes). Must match across all instances. |
appName |
string |
Yes | Application name for storage paths |
settingsFile |
string |
Yes | License file name |
registryKeyPath |
string |
Yes | Registry key path for license storage |
Logging Control:
- Pass
nullfor logger parameter to use built-in silent logger (no output) - Pass a custom logger when you need debugging/monitoring capabilities
- Set
LoggerEnabled = trueto enable logging with your custom logger - Set
LoggerEnabled = falseto disable logging (reverts to silent logger)
LicenseManager.ForValidation()
For client applications with silent operation (no logging):
| Parameter | Type | Required | Description |
|---|---|---|---|
password |
string |
Yes | Password for encryption key derivation. Must match ForCreation() password. |
salt |
byte[] |
Yes | Salt for key derivation (min 8 bytes). Must match ForCreation() salt. |
appName |
string |
Yes | Application name for storage paths |
settingsFile |
string |
Yes | License file name |
registryKeyPath |
string |
Yes | Registry key path for license storage |
Important: The password and salt must be identical to those used in ForCreation() and LicenseGenerator.GenerateLicenseFile().
Key Methods
| Method | Description | Available In |
|---|---|---|
CreateLicense() |
Creates and saves a new license | Both (ForCreation recommended) |
ValidateLicense() |
Validates existing license with automatic self-healing | Both |
IsLicensePresent() |
Checks if license exists in either storage location | Both |
LoadValidLicense() |
Loads license data if valid | Both |
RenewLicense() |
Registers license from data object | Both |
RenewLicenseFromString() |
Registers from encrypted string | Both |
RenewLicenseFromFile() |
Registers from license file | Both |
ImportLicenseFile() |
Imports and registers .lic file | Both |
Properties
| Property | Type | Description |
|---|---|---|
LoggerEnabled |
bool |
Gets or sets whether logging is enabled. Only affects ForCreation() instances with custom loggers. |
Utility Classes
| Class/Method | Description |
|---|---|
LicenseGenerator.GenerateLicenseFile() |
Creates encrypted .lic files. Must use same password/salt as your application. |
Storage Locations
- File Storage:
%AppData%\[AppName]\[SettingsFile] - Registry Storage:
HKEY_CURRENT_USER\[RegistryKeyPath]
Both locations are validated and automatically synchronized during license validation.
Validation Messages
The library returns Portuguese validation messages:
- "LicenΓ§a nΓ£o encontrada ou corrompida." - License not found or corrupted
- "LicenΓ§a expirada." - License expired
- Expiration warnings are generated automatically for licenses with 31 days or fewer remaining
π§ͺ Example Application Structure
MyApplication/
βββ VendorTools/ // Vendor-side tools
β βββ LicenseGenerator/ // Tool for generating .lic files
β β βββ GeneratorForm.cs // UI for license generation
β β βββ Program.cs // Uses LicenseGenerator helper
β βββ LicenseCreator/ // Tool for direct license creation
β βββ CreatorForm.cs // UI for license creation
β βββ Program.cs // Uses ForCreation()
βββ ClientApp/ // Customer application
β βββ Program.cs // Application entry with validation
β βββ MainForm.cs // Main application form
β βββ LicenseRegistrationForm.cs // Customer registration UI
β βββ LicenseService.cs // Service layer (uses ForValidation)
βββ Models/
β βββ AppConfig.cs // Application configuration
βββ Shared/
βββ LicenseConstants.cs // Shared configuration constants (password/salt)
Example Usage Patterns
Vendor License Generator Tool
// Tool for generating .lic files (no logger needed in production)
// Note: This doesn't require LicenseManager, just the helper class
bool success = LicenseGenerator.GenerateLicenseFile(
clientName: "Customer ABC Corp",
password: "YourSecurePassword123!",
salt: Encoding.UTF8.GetBytes("YourUniqueSalt12345"),
outputFile: @"C:\licenses\customer-abc.lic",
validityDays: 366
);
Customer Registration Window
// Customer app registration form (silent mode)
var licenseManager = LicenseManager.ForValidation(
password: "YourSecurePassword123!",
salt: Encoding.UTF8.GetBytes("YourUniqueSalt12345"),
appName: "MyApplication",
settingsFile: "license.json",
registryKeyPath: "SOFTWARE\\MyCompany\\MyApp\\License"
);
// Import .lic file received from vendor
bool imported = licenseManager.ImportLicenseFile(licenseFilePath);
// Or register direct license data
bool registered = licenseManager.RenewLicense(licenseData);
Client Application Validation
// Main application startup validation (silent mode with auto-healing)
var licenseManager = LicenseManager.ForValidation(
password: "YourSecurePassword123!",
salt: Encoding.UTF8.GetBytes("YourUniqueSalt12345"),
appName: "MyApplication",
settingsFile: "license.json",
registryKeyPath: "SOFTWARE\\MyCompany\\MyApp\\License"
);
if (!licenseManager.IsLicensePresent())
{
ShowRegistrationDialog();
return;
}
// ValidateLicense() automatically repairs corrupted licenses
var (isValid, message, daysRemaining) = licenseManager.ValidateLicense();
if (!isValid)
{
ShowLicenseErrorDialog(message);
return;
}
π License Data Structure
public class LicenseData
{
public string Client { get; init; } // Hashed client identifier (SHA256)
public DateTime Licensed { get; init; } // License issue date
public DateTime Expires { get; init; } // License expiration date
public string Version { get; init; } // License version
public string Checksum { get; set; } // SHA256 tamper protection checksum
}
Important Notes:
- The
Clientfield stores a SHA256 hash of the client name, not the actual name - The
Checksumis automatically generated and validated to prevent tampering - All dates are handled as
DateTimeobjects
π Error Handling
The library provides comprehensive error handling with detailed logging (when enabled):
- Invalid license format
- Corrupted license data (checksum validation with automatic repair)
- Expired licenses
- Missing license files (with automatic restoration from registry)
- Registry access issues (with automatic restoration from file)
- Encryption/decryption errors
- Invalid registry paths
- File system access errors
- Base64 decoding errors
- Invalid .lic file format
All errors are logged appropriately (when logging is enabled) and methods return boolean success indicators or tuples with validation results. The self-healing mechanism automatically attempts to recover from storage corruption.
π Requirements
- .NET 6.0 or higher
- Windows OS (uses Windows Registry)
- Microsoft.Extensions.Logging (for custom logging in ForCreation - optional)
- Newtonsoft.Json (for JSON serialization)
π¨ Important Limitations
- Encryption Consistency: Password and salt must be identical across all tools and applications
- Registry Path Validation: Registry paths must start with "SOFTWARE\" and contain only valid characters
- Salt Requirements: Encryption salt must be at least 8 bytes
- Both Methods Full-Featured: Both
ForCreation()andForValidation()support all operations (create, renew, import, validate). The distinction is primarily about logging. - Self-Healing Requirements: Both storage locations must be accessible for self-healing to work properly
π€ Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
π License
This project is licensed under the MIT License - see the LICENSE file for details.
π Support
For support, feature requests, or bug reports, please create an issue on GitHub.
π Version History
v1.5.2
- Self-Healing License Validation:
ValidateLicense()now validates both file and registry copies - Automatic Repair: Corrupted or missing licenses are automatically restored from the valid source
- Most Recent Selection: When both copies are valid, the most recently issued license is used
- Enhanced Reliability: Improved protection against storage corruption and data loss
- Updated Validation Messages: Combined "not found" and "corrupted" into single message for cleaner UX
v1.5.1
- Breaking Change: Removed parameterless
ForValidation()method - ForValidation() now requires password and salt: Client applications must provide encryption credentials to decrypt licenses
- Unified encryption: Both
ForCreation()andForValidation()now use the same encryption parameters for consistency - Simplified architecture: The distinction between creation and validation is now primarily about logging, not functionality
v1.5.0
- Logger now optional: The
loggerparameter inForCreation()can now benull, which uses a built-in silent logger - Runtime logging control: Added
LoggerEnabledproperty to toggle logging on/off at runtime - Improved flexibility: Applications no longer need to set up logging infrastructure if they don't need it
- Backward compatible: Existing code with custom loggers continues to work without changes
v1.4.0
- Breaking Changes: LicenseUtils was made public
- Added
ImportLicenseFile()method for .lic file import - Added
LicenseGeneratorutility class for creating .lic files
v1.3.0
- Breaking Changes: LicenseUtils was made public
- Improved error handling and validation
- Enhanced security with better registry path validation
v1.2.0
- Breaking Changes: Introduced factory methods pattern
- Added
ForCreation()andForValidation()factory methods - Added
IsLicensePresent()method for license detection - Added
LoadValidLicense()method for license data access - Improved separation of concerns between license creation and validation
v1.0.0
- Initial release
- Time-based licensing
- Dual storage (file + registry)
- AES encryption with PBKDF2
- License renewal capabilities
- Comprehensive logging
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0-windows10.0.17763 is compatible. net9.0-windows was computed. net10.0-windows was computed. |
-
net8.0-windows10.0.17763
- Microsoft.Extensions.Logging (>= 9.0.9)
- Newtonsoft.Json (>= 13.0.4)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.