[ad_1]
有没有办法在静态类的每个方法中自动调用 CheckLicence() 方法?
我有几个带有数百个方法的静态类。
因此,全局许可证检查比在每个类方法中调用 CheckLicence() 方法更舒服。
示例说明:
licenceKey 由应用程序在启动时设置。
所以许可证在整个生命周期都是可以的。
我想摆脱 AddMethod() 中的 CheckLicence() 调用。
背景:
我有一个大型工具库,用于多个项目。 该库部署在我的项目(网站、桌面应用程序)中。 我想要有一个基本的保护,让DLL不能被客户在自己的内部项目中直接使用。
我尝试过的:
public static class LicensedClass { public static string licenceKey = ""; public static bool IsLicensed { get { return (licenceKey == "ABC123"); } } public static void CheckLicence() { if (!IsLicensed) throw new System.ArgumentException("Wrong licence key.", licenceKey); } public static double AddMethod(double number1, double number2) { CheckLicence(); return number1 + number2; } }
解决方案1
不。
C# 不会自动为您调用任何内容 – 您必须明确告诉它您想要调用什么以及何时调用。
您总是可以添加一个辅助线程任务来定期检查它,并使用它可以处理的“失败”指示器来响应主线程?
解决方案2
你可以看看 奥普 (面向方面编程): NConsern,NConsern .NET AOP 框架,下载NConsern的源码_GitHub_酷徒[^]
但你可能会发现它对于你想要的东西来说太复杂了……
另一种选择是使用众所周知的 后锐利 扩大: PostSharp – Visual Studio 市场[^]
解决方案3
通过静态类构造函数中的许可证检查来解决。
这是一个非常基本的解决方案,可以防止我的 dll 被公司其他人重复使用。
如果某些方法有效,而另一些方法未经“许可”则无效,人们可能会觉得很烦人,所以这就足够了。
如果该方法是如此改变世界的重要,那么可以轻松地从 dll 中恢复原始代码,因此在 .net 中,如果没有第 3 方工具,就没有代码保护……
用法:
DllClassLibrary.License.SetLicense("ABC123"); var result = DllClassLibrary.Foo.DoSomething();
带有简单许可证检查的 DLL 类库:
namespace DllClassLibrary { public static class License { private static bool isLicensed = false; public static bool SetLicense(string licenseKey) { isLicensed = (licenseKey == "ABC123"); return isLicensed; } public static void CheckLicense() { if (!isLicensed) throw new Exception("License not set."); } } public static class Foo { static Foo() { License.CheckLicense(); } public static string DoSomething() { return $"[{DateTime.Now.ToString()}] DoFoo()"; } } }
解决方案4
激活码
这是激活密钥的简单结构:
<code>class ActivationKey { public byte[] Data { get; set; } // Encrypted part. public byte[] Hash { get; set; } // Hashed part. public byte[] Tail { get; set; } // Initialization vector. } </code> <p>This tool will use cryptographic transformations to generate the key.</p> <h2>Generating</h2> <p>The algorithm for obtaining a unique activation key for a data set consists of several steps:</p> <ul> <li>data collection,</li> <li>getting the hash and data encryption,</li> <li>converting activation key to string.</li> </ul> <h3>Data collection</h3> <p>At this step, you need to get an array of data such as serial number, device ID, expiration date, etc. This purpose can be achieved using the following method:</p> <pre class="lang-cs prettyprint-override"><code>unsafe byte[] Serialize(params object[] objects) { using (MemoryStream memory = new MemoryStream()) using (BinaryWriter writer = new BinaryWriter(memory)) { foreach (object obj in objects) { if (obj == null) continue; switch (obj) { case string str: if (str.Length > 0) writer.Write(str.ToCharArray()); continue; case DateTime date: writer.Write(date.Ticks); continue; case bool @bool: writer.Write(@bool); continue; case short @short: writer.Write(@short); continue; case ushort @ushort: writer.Write(@ushort); continue; case int @int: writer.Write(@int); continue; case uint @uint: writer.Write(@uint); continue; case long @long: writer.Write(@long); continue; case ulong @ulong: writer.Write(@ulong); continue; case float @float: writer.Write(@float); continue; case double @double: writer.Write(@double); continue; case decimal @decimal: writer.Write(@decimal); continue; case byte[] buffer: if (buffer.Length > 0) writer.Write(buffer); continue; case Array array: if (array.Length > 0) foreach (var a in array) writer.Write(Serialize(a)); continue; case IConvertible conv: writer.Write(conv.ToString(CultureInfo.InvariantCulture)); continue; case IFormattable frm: writer.Write(frm.ToString(null, CultureInfo.InvariantCulture)); continue; case Stream stream: stream.CopyTo(stream); continue; default: try { int rawsize = Marshal.SizeOf(obj); byte[] rawdata = new byte[rawsize]; GCHandle handle = GCHandle.Alloc(rawdata, GCHandleType.Pinned); Marshal.StructureToPtr(obj, handle.AddrOfPinnedObject(), false); writer.Write(rawdata); handle.Free(); } catch(Exception e) { // Place debugging tools here. } continue; } } writer.Flush(); byte[] bytes = memory.ToArray(); return bytes; } } </code>
获取哈希值和数据加密
该步骤包含以下子步骤:
- 使用密码创建加密引擎并将初始化向量存储在 尾巴 财产。
- 下一步,对到期日期和选项进行加密,并将加密数据保存到 数据 财产。
- 最后,哈希引擎根据过期日期、密码、选项和环境计算哈希值并将其放入 哈希值 财产。
ActivationKey Create<TAlg, THash>(DateTime expirationDate, object password, object options = null, params object[] environment) where TAlg : SymmetricAlgorithm where THash : HashAlgorithm { ActivationKey activationKey = new ActivationKey(); using (SymmetricAlgorithm cryptoAlg = Activator.CreateInstance<TAlg>()) { if (password == null) { password = new byte[0]; } activationKey.Tail = cryptoAlg.IV; using (DeriveBytes deriveBytes = new PasswordDeriveBytes(Serialize(password), activationKey.Tail)) { cryptoAlg.Key = deriveBytes.GetBytes(cryptoAlg.KeySize / 8); } expirationDate = expirationDate.Date; long expirationDateStamp = expirationDate.ToBinary(); using (ICryptoTransform transform = cryptoAlg.CreateEncryptor()) { byte[] data2 = Serialize(expirationDateStamp, options); activationKey.Data = transform.TransformFinalBlock(data2, 0, data2.Length); } using (HashAlgorithm hashAlg = Activator.CreateInstance<THash>()) { byte[] data = Serialize(expirationDateStamp, cryptoAlg.Key, options, environment, activationKey.Tail); activationKey.Hash = hashAlg.ComputeHash(data); } } return activationKey; }
转换为字符串
使用 ToString 方法获取包含关键文本的字符串,准备传输给最终用户。
基于 N 的编码(其中 N 是数字系统的基数)通常用于将二进制数据转换为人类可读的文本。 激活密钥中最常用的是base32。 这种编码的优点是由数字和字母组成的大字母表,不区分大小写。 缺点是这种编码没有在 .NET 标准库中实现,您应该自己实现。 该站点上有许多 Base32 实现的示例。 您还可以使用 mscorlib 内置的十六进制编码和 base64。 在我的例子中 32进制 用来。
string ToString(ActivationKey activationKey) { if (activationKey.Data == null || activationKey.Hash == null || activationKey.Tail == null) { return string.Empty; } using (Base32 base32 = new Base32()) { return base32.Encode(Data) + "-" + base32.Encode(Hash) + "-" + base32.Encode(Tail); } }
检查
密钥验证是使用方法GetOptions 和Verify 进行的。
- 获取选项 检查密钥并将嵌入数据恢复为字节数组,如果密钥无效,则将嵌入数据恢复为 null。
- 核实 只是检查密钥。
byte[] GetOptions<TAlg, THash>(object password = null, params object[] environment) where TAlg : SymmetricAlgorithm where THash : HashAlgorithm { if (Data == null || Hash == null || Tail == null) { return null; } try { using (SymmetricAlgorithm cryptoAlg = Activator.CreateInstance<TAlg>()) { cryptoAlg.IV = Tail; using (DeriveBytes deriveBytes = new PasswordDeriveBytes(Serialize(password), Tail)) { cryptoAlg.Key = deriveBytes.GetBytes(cryptoAlg.KeySize / 8); } using (ICryptoTransform transform = cryptoAlg.CreateDecryptor()) { byte[] data = transform.TransformFinalBlock(Data, 0, Data.Length); int optionsLength = data.Length - 8; if (optionsLength < 0) { return null; } byte[] options; if (optionsLength > 0) { options = new byte[optionsLength]; Buffer.BlockCopy(data, 8, options, 0, optionsLength); } else { options = new byte[0]; } long expirationDateStamp = BitConverter.ToInt64(data, 0); DateTime expirationDate = DateTime.FromBinary(expirationDateStamp); if (expirationDate < DateTime.Today) { return null; } using (HashAlgorithm hashAlg = Activator.CreateInstance<THash>()) { byte[] hash = hashAlg.ComputeHash( Serialize(expirationDateStamp, cryptoAlg.Key, options, environment, Tail)); return ByteArrayEquals(Hash, hash) ? options : null; } } } } catch { return null; } } bool Verify<TAlg, THash>(object password = null, params object[] environment) where TAlg : SymmetricAlgorithm where THash : HashAlgorithm { try { byte[] key = Serialize(password); return Verify<TAlg, THash>(key, environment); } catch { return false; } }
例子
这里 是使用您自己的任意数据量(文本、字符串、数字、字节等)组合生成激活密钥的完整示例。
使用示例:
string serialNumber = "0123456789"; // The serial number. const string appName = "myAppName"; // The application name. // Generating the key. All the parameters passed to the costructor can be omitted. ActivationKey activationKey = new ActivationKey( //expirationDate: DateTime.Now.AddMonths(1), // Expiration date 1 month later. // Pass DateTime.Max for unlimited use. //password: null, // Password protection; // this parameter can be null. //options: null // Pass here numbers, flags, text or other // that you want to restore // or null if no necessary. //environment: appName, serialNumber // Application name and serial number. ); // Thus, a simple check of the key for validity is carried out. bool checkKey = activationKey.Verify((byte[])null, appName, serialNumber); if (!checkKey) { MessageBox.Show("Your copy is not activated! Please get a valid activation key."); Application.Exit(); }
Activation-Key,代表用于保护 C# 应用程序的激活密钥,下载Activation-Key的源码_GitHub_帮酷[^]
[ad_2]
コメント