528 lines
18 KiB
C#
528 lines
18 KiB
C#
using Org.BouncyCastle.Crypto;
|
||
using Org.BouncyCastle.Security;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Management;
|
||
using System.Security.Cryptography;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
|
||
namespace CapMachine.Wpf.SoftAuthorizeCore
|
||
{
|
||
/// <summary>
|
||
/// Lience客户端
|
||
/// </summary>
|
||
public class LicenseClient
|
||
{
|
||
/// <summary>
|
||
/// 根据硬件信息生成机器序列号
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public static string GenSerialNo()
|
||
{
|
||
try
|
||
{
|
||
//获取硬件信息
|
||
string info = string.Empty;
|
||
string cpu = GetCPUInfo();
|
||
string gpu = GetGPUInfo();
|
||
string baseBoard = GetBaseBoardInfo();
|
||
string bios = GetBIOSInfo();
|
||
string mac = GetMACInfo();
|
||
info = string.Concat(cpu, gpu, baseBoard, bios, "mac");
|
||
|
||
//AES加密
|
||
using (Aes tempAES = Aes.Create())
|
||
{
|
||
byte[] encrypted = EncryptStringToBytes(info, tempAES.Key, tempAES.IV);
|
||
byte[] dataCnt = BitConverter.GetBytes(Convert.ToInt16(encrypted.Length));
|
||
|
||
byte[] res = new byte[tempAES.Key.Length
|
||
+ tempAES.IV.Length
|
||
+ dataCnt.Length
|
||
+ encrypted.Length];
|
||
|
||
//拼接AES密钥 32+16 bytes
|
||
Buffer.BlockCopy(tempAES.Key, 0, res, 0, tempAES.Key.Length);
|
||
Buffer.BlockCopy(tempAES.IV, 0, res, tempAES.Key.Length, tempAES.IV.Length);
|
||
//拼接加密数据
|
||
Buffer.BlockCopy(dataCnt, 0, res, tempAES.Key.Length + tempAES.IV.Length, dataCnt.Length);
|
||
Buffer.BlockCopy(encrypted, 0, res, tempAES.Key.Length + tempAES.IV.Length + dataCnt.Length, encrypted.Length);
|
||
|
||
//生成机器序列号
|
||
info = Convert.ToBase64String(res);
|
||
}
|
||
return info;
|
||
}
|
||
catch (Exception)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 校验授权文件
|
||
/// </summary>
|
||
/// <param name="license"></param>
|
||
/// <param name="publicKey"></param>
|
||
/// <returns></returns>
|
||
public static bool VerifyLicense(string license, string publicKey)
|
||
{
|
||
try
|
||
{
|
||
byte[] lic = Convert.FromBase64String(license);
|
||
|
||
//获取AES密钥信息
|
||
byte[] aesKey = lic.Skip(0).Take(32).ToArray();
|
||
byte[] aesIV = lic.Skip(32).Take(16).ToArray();
|
||
|
||
//获取加密数据长度
|
||
int dataCnt = BitConverter.ToInt16(lic, 48);
|
||
|
||
//获取加密数据
|
||
byte[] data = lic.Skip(50).Take(dataCnt).ToArray();
|
||
|
||
//获取签名
|
||
byte[] sign = lic.Skip(50 + dataCnt).Take(128).ToArray();
|
||
string signStr = Convert.ToBase64String(sign);
|
||
//Console.WriteLine("get sign: " + signStr);
|
||
|
||
//获取时间
|
||
byte[] times = lic.Skip(48 + 2 + dataCnt + 128).ToArray();
|
||
string[] timeStrs = DecryptStringFromBytes(times, aesKey, aesIV).Split('|');
|
||
//byte[] start = lic.Skip(50 + dataCnt+128).Take(8).ToArray();
|
||
//byte[] end = lic.Skip(50 + dataCnt + 128+8).Take(8).ToArray();
|
||
//byte[] last = lic.Skip(50 + dataCnt + 128+16).Take(8).ToArray();
|
||
|
||
|
||
//获取签名的对象
|
||
byte[] sn = lic.Skip(0).Take(50 + dataCnt).ToArray();
|
||
string snStr = Convert.ToBase64String(sn);
|
||
//Console.WriteLine("get sn: " + snStr);
|
||
|
||
//验签
|
||
if (VerifySign(snStr, signStr, publicKey) == false)
|
||
return false;
|
||
|
||
//校验机器序列号
|
||
if (CheckHardware(snStr, aesKey, aesIV) == false)
|
||
return false;
|
||
|
||
//校验授权时间
|
||
if (CheckTime(timeStrs[0], timeStrs[1], timeStrs[2]) == false)
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
catch (Exception)
|
||
{
|
||
|
||
return false;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 更新登录时间
|
||
/// </summary>
|
||
/// <param name="license"></param>
|
||
/// <param name="path"></param>
|
||
/// <returns></returns>
|
||
public static bool UpdateVerifyTime(string license, string path)
|
||
{
|
||
try
|
||
{
|
||
byte[] lic = Convert.FromBase64String(license);
|
||
|
||
byte[] now = BitConverter.GetBytes(new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds());
|
||
int dataCnt = BitConverter.ToInt16(lic, 48);
|
||
byte[] aesKey = lic.Skip(0).Take(32).ToArray();
|
||
byte[] aesIV = lic.Skip(32).Take(16).ToArray();
|
||
byte[] times = lic.Skip(48 + 2 + dataCnt + 128).ToArray();
|
||
string[] timeStr = DecryptStringFromBytes(times, aesKey, aesIV).Split('|');
|
||
|
||
long nowTime = BitConverter.ToInt64(now, 0);
|
||
long lastTime = Convert.ToInt64(timeStr[2]);
|
||
|
||
//时间只能递增
|
||
if (lastTime >= nowTime)
|
||
return true;
|
||
|
||
|
||
timeStr[2] = nowTime.ToString();
|
||
byte[] newtimes = EncryptStringToBytes(timeStr[0] + "|" + timeStr[1] + "|" + timeStr[2], aesKey, aesIV);
|
||
byte[] newlic = new byte[48 + 2 + dataCnt + 128 + newtimes.Length];
|
||
Buffer.BlockCopy(lic, 0, newlic, 0, 48 + 2 + dataCnt + 128);
|
||
Buffer.BlockCopy(newtimes, 0, newlic, 48 + 2 + dataCnt + 128, newtimes.Length);
|
||
|
||
license = Convert.ToBase64String(newlic);
|
||
using (StreamWriter writer = new StreamWriter(path))
|
||
{
|
||
writer.WriteLine(license);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
catch (Exception)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
#region private methods
|
||
|
||
/// <summary>
|
||
/// 检查硬件信息
|
||
/// </summary>
|
||
/// <param name="sn"></param>
|
||
/// <param name="key"></param>
|
||
/// <param name="Iv"></param>
|
||
/// <returns></returns>
|
||
private static bool CheckHardware(string sn, byte[] key, byte[] Iv)
|
||
{
|
||
//获取硬件信息
|
||
string info = string.Empty;
|
||
string cpu = GetCPUInfo();
|
||
string gpu = GetGPUInfo();
|
||
string baseBoard = GetBaseBoardInfo();
|
||
string bios = GetBIOSInfo();
|
||
string mac = GetMACInfo();
|
||
info = string.Concat(cpu, gpu, baseBoard, bios, "mac");
|
||
|
||
//AES加密
|
||
byte[] encrypted = EncryptStringToBytes(info, key, Iv);
|
||
byte[] dataCnt = BitConverter.GetBytes(Convert.ToInt16(encrypted.Length));
|
||
|
||
byte[] res = new byte[key.Length
|
||
+ Iv.Length
|
||
+ dataCnt.Length
|
||
+ encrypted.Length];
|
||
|
||
//拼接AES密钥 32+16 bytes
|
||
Buffer.BlockCopy(key, 0, res, 0, key.Length);
|
||
Buffer.BlockCopy(Iv, 0, res, key.Length, Iv.Length);
|
||
//拼接加密数据
|
||
Buffer.BlockCopy(dataCnt, 0, res, key.Length + Iv.Length, dataCnt.Length);
|
||
Buffer.BlockCopy(encrypted, 0, res, key.Length + Iv.Length + dataCnt.Length, encrypted.Length);
|
||
|
||
//生成机器序列号
|
||
info = Convert.ToBase64String(res);
|
||
|
||
if (info != sn)
|
||
return false;
|
||
return true;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 检查授权时间
|
||
/// </summary>
|
||
/// <param name="start"></param>
|
||
/// <param name="end"></param>
|
||
/// <param name="last"></param>
|
||
/// <returns></returns>
|
||
private static bool CheckTime(string startTime, string endTime, string lastTime)
|
||
{
|
||
long now = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds();
|
||
long start = Convert.ToInt64(startTime);
|
||
long end = Convert.ToInt64(endTime);
|
||
long last = Convert.ToInt64(lastTime);
|
||
|
||
if (end <= start)
|
||
return false;
|
||
if (now < start || now >= end)
|
||
return false;
|
||
if (now <= last)
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 最大解密长度
|
||
/// </summary>
|
||
private const int MAX_DECRYPT_BLOCK = 256;
|
||
|
||
|
||
/// <summary>
|
||
/// 公钥解密
|
||
/// </summary>
|
||
/// <param name="xmlPublicKey"></param>
|
||
/// <param name="content"></param>
|
||
/// <returns></returns>
|
||
private static string Decrypt(string xmlPublicKey, string content)
|
||
{
|
||
//加载公钥
|
||
RSACryptoServiceProvider publicRsa = new RSACryptoServiceProvider();
|
||
publicRsa.FromXmlString(xmlPublicKey);
|
||
RSAParameters rp = publicRsa.ExportParameters(false);
|
||
|
||
//转换密钥
|
||
AsymmetricKeyParameter pbk = DotNetUtilities.GetRsaPublicKey(rp);
|
||
|
||
IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");
|
||
//第一个参数为true表示加密,为false表示解密;第二个参数表示密钥
|
||
c.Init(false, pbk);
|
||
|
||
byte[] DataToDecrypt = Convert.FromBase64String(content);
|
||
|
||
byte[] cache;
|
||
int time = 0;//次数
|
||
int inputLen = DataToDecrypt.Length;
|
||
int offSet = 0;
|
||
MemoryStream outStream = new MemoryStream();
|
||
while (inputLen - offSet > 0)
|
||
{
|
||
if (inputLen - offSet > MAX_DECRYPT_BLOCK)
|
||
{
|
||
cache = c.DoFinal(DataToDecrypt, offSet, MAX_DECRYPT_BLOCK);
|
||
}
|
||
else
|
||
{
|
||
cache = c.DoFinal(DataToDecrypt, offSet, inputLen - offSet);
|
||
}
|
||
//写入
|
||
outStream.Write(cache, 0, cache.Length);
|
||
|
||
time++;
|
||
offSet = time * MAX_DECRYPT_BLOCK;
|
||
}
|
||
byte[] resData = outStream.ToArray();
|
||
|
||
string strDec = Encoding.UTF8.GetString(resData);
|
||
return strDec;
|
||
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 公钥验签
|
||
/// </summary>
|
||
/// <param name="str">待验证的字符串</param>
|
||
/// <param name="sign">加签之后的字符串</param>
|
||
/// <returns>签名是否符合</returns>
|
||
private static bool VerifySign(string str, string sign, string publicKey)
|
||
{
|
||
|
||
byte[] bt = Convert.FromBase64String(str);
|
||
byte[] rgbHash = null;
|
||
|
||
var csp = new SHA256CryptoServiceProvider();
|
||
rgbHash = csp.ComputeHash(bt);
|
||
|
||
RSACryptoServiceProvider key = new RSACryptoServiceProvider();
|
||
key.FromXmlString(publicKey);
|
||
RSAPKCS1SignatureDeformatter deformatter = new RSAPKCS1SignatureDeformatter(key);
|
||
deformatter.SetHashAlgorithm("SHA256");
|
||
byte[] rgbSignature = Convert.FromBase64String(sign);
|
||
if (deformatter.VerifySignature(rgbHash, rgbSignature))
|
||
return true;
|
||
return false;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// AES加密
|
||
/// </summary>
|
||
/// <param name="plainText"></param>
|
||
/// <param name="Key"></param>
|
||
/// <param name="IV"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="ArgumentNullException"></exception>
|
||
static byte[] EncryptStringToBytes(string plainText, byte[] Key, byte[] IV)
|
||
{
|
||
// Check arguments.
|
||
if (plainText == null || plainText.Length <= 0)
|
||
throw new ArgumentNullException("plainText");
|
||
if (Key == null || Key.Length <= 0)
|
||
throw new ArgumentNullException("Key");
|
||
if (IV == null || IV.Length <= 0)
|
||
throw new ArgumentNullException("IV");
|
||
byte[] encrypted;
|
||
|
||
// Create an Aes object
|
||
// with the specified key and IV.
|
||
using (Aes aesAlg = Aes.Create())
|
||
{
|
||
aesAlg.Key = Key;
|
||
aesAlg.IV = IV;
|
||
|
||
// Create an encryptor to perform the stream transform.
|
||
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
|
||
|
||
// Create the streams used for encryption.
|
||
using (MemoryStream msEncrypt = new MemoryStream())
|
||
{
|
||
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
|
||
{
|
||
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
|
||
{
|
||
//Write all data to the stream.
|
||
swEncrypt.Write(plainText);
|
||
}
|
||
encrypted = msEncrypt.ToArray();
|
||
}
|
||
}
|
||
}
|
||
|
||
// Return the encrypted bytes from the memory stream.
|
||
return encrypted;
|
||
}
|
||
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// AES解密
|
||
/// </summary>
|
||
/// <param name="cipherText"></param>
|
||
/// <param name="Key"></param>
|
||
/// <param name="IV"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="ArgumentNullException"></exception>
|
||
static string DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
|
||
{
|
||
// Check arguments.
|
||
if (cipherText == null || cipherText.Length <= 0)
|
||
throw new ArgumentNullException("cipherText");
|
||
if (Key == null || Key.Length <= 0)
|
||
throw new ArgumentNullException("Key");
|
||
if (IV == null || IV.Length <= 0)
|
||
throw new ArgumentNullException("IV");
|
||
|
||
// Declare the string used to hold
|
||
// the decrypted text.
|
||
string plaintext = null;
|
||
|
||
// Create an Aes object
|
||
// with the specified key and IV.
|
||
using (Aes aesAlg = Aes.Create())
|
||
{
|
||
aesAlg.Key = Key;
|
||
aesAlg.IV = IV;
|
||
|
||
// Create a decryptor to perform the stream transform.
|
||
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
|
||
|
||
// Create the streams used for decryption.
|
||
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
|
||
{
|
||
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
|
||
{
|
||
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
|
||
{
|
||
|
||
// Read the decrypted bytes from the decrypting stream
|
||
// and place them in a string.
|
||
plaintext = srDecrypt.ReadToEnd();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return plaintext;
|
||
}
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 获取CPU序列号
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private static string GetCPUInfo()
|
||
{
|
||
var info = string.Empty;
|
||
var mc = new ManagementClass("Win32_Processor");
|
||
var moc = mc.GetInstances();
|
||
foreach (var o in moc)
|
||
{
|
||
var mo = (ManagementObject)o;
|
||
info = mo.Properties["ProcessorId"].Value.ToString();
|
||
}
|
||
return info;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取显卡序列号
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private static string GetGPUInfo()
|
||
{
|
||
var info = "";
|
||
var mos = new ManagementObjectSearcher("Select * from Win32_VideoController");
|
||
foreach (var o in mos.Get())
|
||
{
|
||
var mo = (ManagementObject)o;
|
||
info = mo["PNPDeviceID"].ToString();
|
||
}
|
||
return info;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取主板序列号
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private static string GetBaseBoardInfo()
|
||
{
|
||
var info = string.Empty;
|
||
var mos = new ManagementObjectSearcher("Select * from Win32_BaseBoard");
|
||
foreach (var o in mos.Get())
|
||
{
|
||
var mo = (ManagementObject)o;
|
||
info = mo["SerialNumber"].ToString();
|
||
}
|
||
return info;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取BIOS序列号
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private static string GetBIOSInfo()
|
||
{
|
||
var info = string.Empty;
|
||
var mos = new ManagementObjectSearcher("Select * from Win32_BIOS");
|
||
foreach (var o in mos.Get())
|
||
{
|
||
var mo = (ManagementObject)o;
|
||
info = mo["SerialNumber"].ToString();
|
||
}
|
||
return info;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 获取MAC地址
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private static string GetMACInfo()
|
||
{
|
||
var info = string.Empty;
|
||
var mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
|
||
var moc = mc.GetInstances();
|
||
foreach (var o in moc)
|
||
{
|
||
var mo = (ManagementObject)o;
|
||
if (!(bool)mo["IPEnabled"]) continue;
|
||
info = mo["MacAddress"].ToString();
|
||
break;
|
||
}
|
||
return info;
|
||
}
|
||
|
||
#endregion
|
||
|
||
|
||
}
|
||
}
|