feat: initial LicenseGenerator -- keygen, fingerprint, sign commands
Standalone .NET 4.7.2 console tool for NcProgramManager offline licensing. - keygen: RSA 2048-bit key pair generation - fingerprint: WMI machine fingerprint (Windows only) - sign: RSA-SHA256 sign fingerprint, write .lic file Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
commit
2ef68dd477
10 changed files with 284 additions and 0 deletions
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
bin/
|
||||
obj/
|
||||
.vs/
|
||||
*.user
|
||||
private.key.xml
|
||||
*.lic
|
||||
packages/
|
||||
44
Commands/FingerprintCommand.cs
Normal file
44
Commands/FingerprintCommand.cs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
using System;
|
||||
using System.Management;
|
||||
|
||||
namespace LicenseGenerator.Commands
|
||||
{
|
||||
internal static class FingerprintCommand
|
||||
{
|
||||
// Windows + WMI only. Matches MachineFingerprint.GetFingerprint() logic.
|
||||
internal static void Execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
string pcInfo = string.Empty;
|
||||
|
||||
using (var mc = new ManagementClass("win32_processor"))
|
||||
using (ManagementObjectCollection moc = mc.GetInstances())
|
||||
{
|
||||
foreach (ManagementObject mo in moc)
|
||||
{
|
||||
pcInfo = mo.Properties["processorID"].Value.ToString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
using (var searcher = new ManagementObjectSearcher(
|
||||
"root\\CIMV2", "SELECT * FROM Win32_BaseBoard"))
|
||||
{
|
||||
foreach (ManagementObject obj in searcher.Get())
|
||||
{
|
||||
pcInfo += obj["SerialNumber"].ToString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine(pcInfo);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine("Error reading fingerprint (Windows + WMI required): " + ex.Message);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
24
Commands/KeygenCommand.cs
Normal file
24
Commands/KeygenCommand.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace LicenseGenerator.Commands
|
||||
{
|
||||
internal static class KeygenCommand
|
||||
{
|
||||
internal static void Execute()
|
||||
{
|
||||
using (var rsa = new RSACryptoServiceProvider(2048))
|
||||
{
|
||||
string privateXml = rsa.ToXmlString(true);
|
||||
string publicXml = rsa.ToXmlString(false);
|
||||
File.WriteAllText("private.key.xml", privateXml);
|
||||
Console.WriteLine("=== PUBLIC KEY XML -- paste into LicenseValidator.cs ===");
|
||||
Console.WriteLine(publicXml);
|
||||
Console.WriteLine("========================================================");
|
||||
Console.WriteLine("Private key saved: private.key.xml");
|
||||
Console.WriteLine("KEEP private.key.xml SECRET -- never distribute it.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
36
Commands/SignCommand.cs
Normal file
36
Commands/SignCommand.cs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace LicenseGenerator.Commands
|
||||
{
|
||||
internal static class SignCommand
|
||||
{
|
||||
internal static void Execute(InputArgs args)
|
||||
{
|
||||
if (string.IsNullOrEmpty(args.KeyPath))
|
||||
{
|
||||
Console.Error.WriteLine("Missing: -key=<path-to-private.key.xml>");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
if (string.IsNullOrEmpty(args.Fingerprint))
|
||||
{
|
||||
Console.Error.WriteLine("Missing: -fingerprint=<machine-fingerprint>");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
string privateXml = File.ReadAllText(args.KeyPath);
|
||||
byte[] data = Encoding.UTF8.GetBytes(args.Fingerprint);
|
||||
|
||||
using (var rsa = new RSACryptoServiceProvider())
|
||||
{
|
||||
rsa.FromXmlString(privateXml);
|
||||
byte[] signature = rsa.SignData(data, new SHA256CryptoServiceProvider());
|
||||
string base64 = Convert.ToBase64String(signature);
|
||||
File.WriteAllText(args.OutPath, base64);
|
||||
Console.WriteLine("License written: " + args.OutPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
Dockerfile.build
Normal file
8
Dockerfile.build
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
FROM mono:6.12
|
||||
WORKDIR /build
|
||||
RUN cert-sync /etc/ssl/certs/ca-certificates.crt
|
||||
COPY LicenseGenerator.csproj ./
|
||||
RUN nuget restore LicenseGenerator.csproj -NonInteractive 2>/dev/null || true
|
||||
COPY . .
|
||||
RUN msbuild LicenseGenerator.csproj /p:Configuration=Release /p:Platform=AnyCPU /v:minimal /nologo
|
||||
CMD mono bin/Release/LicenseGenerator.exe keygen
|
||||
38
InputArgs.cs
Normal file
38
InputArgs.cs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
namespace LicenseGenerator
|
||||
{
|
||||
internal class InputArgs
|
||||
{
|
||||
internal string Command { get; private set; }
|
||||
internal string KeyPath { get; private set; }
|
||||
internal string Fingerprint { get; private set; }
|
||||
internal string OutPath { get; private set; }
|
||||
|
||||
private InputArgs() { }
|
||||
|
||||
internal static InputArgs Parse(string[] args)
|
||||
{
|
||||
var result = new InputArgs
|
||||
{
|
||||
Command = args.Length > 0 ? args[0].ToLowerInvariant() : string.Empty,
|
||||
OutPath = "license.lic"
|
||||
};
|
||||
|
||||
for (int i = 1; i < args.Length; i++)
|
||||
{
|
||||
string arg = args[i];
|
||||
int eq = arg.IndexOf('=');
|
||||
if (eq < 0) continue;
|
||||
string key = arg.Substring(0, eq).TrimStart('-').ToLowerInvariant();
|
||||
string val = arg.Substring(eq + 1);
|
||||
switch (key)
|
||||
{
|
||||
case "key": result.KeyPath = val; break;
|
||||
case "fingerprint": result.Fingerprint = val; break;
|
||||
case "out": result.OutPath = val; break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
49
LicenseGenerator.csproj
Normal file
49
LicenseGenerator.csproj
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{A7B3C4D5-E6F7-4801-9ABC-DEF012345678}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>LicenseGenerator</RootNamespace>
|
||||
<AssemblyName>LicenseGenerator</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Management" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="InputArgs.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Commands\KeygenCommand.cs" />
|
||||
<Compile Include="Commands\FingerprintCommand.cs" />
|
||||
<Compile Include="Commands\SignCommand.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
22
LicenseGenerator.sln
Normal file
22
LicenseGenerator.sln
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.28701.123
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LicenseGenerator", "LicenseGenerator.csproj", "{A7B3C4D5-E6F7-4801-9ABC-DEF012345678}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{A7B3C4D5-E6F7-4801-9ABC-DEF012345678}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A7B3C4D5-E6F7-4801-9ABC-DEF012345678}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A7B3C4D5-E6F7-4801-9ABC-DEF012345678}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A7B3C4D5-E6F7-4801-9ABC-DEF012345678}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
46
Program.cs
Normal file
46
Program.cs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
using System;
|
||||
using LicenseGenerator.Commands;
|
||||
|
||||
namespace LicenseGenerator
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
var input = InputArgs.Parse(args);
|
||||
switch (input.Command)
|
||||
{
|
||||
case "keygen":
|
||||
KeygenCommand.Execute();
|
||||
break;
|
||||
case "fingerprint":
|
||||
FingerprintCommand.Execute();
|
||||
break;
|
||||
case "sign":
|
||||
SignCommand.Execute(input);
|
||||
break;
|
||||
default:
|
||||
PrintUsage();
|
||||
Environment.Exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void PrintUsage()
|
||||
{
|
||||
Console.WriteLine("LicenseGenerator — NcProgramManager license tool");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Commands:");
|
||||
Console.WriteLine(" keygen");
|
||||
Console.WriteLine(" Generate RSA 2048-bit key pair.");
|
||||
Console.WriteLine(" Writes private.key.xml to current dir.");
|
||||
Console.WriteLine(" Prints public key XML to stdout.");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(" fingerprint");
|
||||
Console.WriteLine(" Print machine fingerprint (Windows + WMI required).");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(" sign -key=<private.key.xml> -fingerprint=<fp> [-out=<license.lic>]");
|
||||
Console.WriteLine(" Sign machine fingerprint, write .lic file.");
|
||||
}
|
||||
}
|
||||
}
|
||||
10
Properties/AssemblyInfo.cs
Normal file
10
Properties/AssemblyInfo.cs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[assembly: AssemblyTitle("LicenseGenerator")]
|
||||
[assembly: AssemblyDescription("NcProgramManager license generator tool")]
|
||||
[assembly: AssemblyProduct("LicenseGenerator")]
|
||||
[assembly: AssemblyCopyright("")]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
Loading…
Add table
Reference in a new issue