如何向我的C#桌面应用程序添加许可证?我需要找到一种合适的免费方法来防止未经授权的用户安装我的软件。
.. NET有很多许可证管理系统(甚至有一个built-in for licensing controls)。快速搜索“ .NET许可证管理器”的Google推出了Open License系统,该系统是免费的。
我希望您可以轻松找到更多。
我可能有点晚了,但是我花了一些时间试图找到一种快速有效的方法来保护一个小的C#应用程序,我想分享我的结果。
似乎您可以相当容易地使用RSA构建自己的,相当安全的许可系统。
显然,在保护软件方面,没有什么是防弹的(就像保护您的房屋免遭窃贼的侵害:警报,吠叫的狗和篱笆使麻烦变得比其应有的要多,但它们并不能阻止决心进入的人)
因此,给它带来的麻烦多于其价值是软件保护的关键词:如果您提供的是价值$ 1,000,000的E.R.P.系统,您将希望获得通过Web服务授权的真正良好的保护(并且为该系统付费的用户在允许该系统持续访问Internet方面不会有问题)
但是,如果您为一个小应用程序只收取5至30美元的费用,则用户将不会承受非常繁重的授权。
我认为最简单的系统是对包含产品,用户及其使用期限的详细信息的许可证文件进行数字签名。
这意味着许可证文件的任何修改都会使数字签名无效。
可以使用SignData方法从DSACryptoServiceProvider类获得数字签名。
需要私钥对数据进行签名,并且可以使用该密钥的公共部分来验证签名:(因此,应用程序必须可以访问公共密钥)
DSAXCryptoServiceProvider具有创建和使用密钥的方法:
DSACryptoServiceProvider.ToXMLString(bool includePrivate);
[返回服务提供者中当前的公共或公共和私有密钥作为XML字符串。
DSACryptoServiceProvider.FromXMLString(String xmlString)
此方法使用从DSACryptoServiceProvider.ToXMLString()获得的现有私钥或公钥来设置新的DSACryptoServiceProvider。>
此系统的安全性的唯一缺陷是用户可能会破坏提供自己的公共密钥的可能性。这将使他们能够从自己的私钥中生成自己的许可证文件。
这可以通过为应用程序额外签名所需的资源来解决(例如,包含用于应用程序的基本逻辑的.dll,甚至是.exe本身)-因此,如果更改了公钥,则此附加(隐藏)签名将无效。
其他改进方法包括模糊许可条款(使用二进制格式化程序将包含许可条款的数据结构序列化为字节数组,然后使用Convert.ToBase64String()将相当有效地模糊许可条款,即使用户能够替换他们仍然需要计算出数据表示形式的公共密钥)
我有一个示例系统,但是它太大了,无法完全引用,但这是它的CreateLicense方法:
/// <summary> /// use a private key to generate a secure license file. the private key must match the public key accessible to /// the system validating the license. /// </summary> /// <param name="start">applicable start date for the license file.</param> /// <param name="end">applicable end date for the license file</param> /// <param name="productName">applicable product name</param> /// <param name="userName">user-name</param> /// <param name="privateKey">the private key (in XML form)</param> /// <returns>secure, public license, validated with the public part of the key</returns> public static License CreateLicense(DateTime start, DateTime end, String productName, String userName, String privateKey) { // create the licence terms: LicenseTerms terms = new LicenseTerms() { StartDate = start, EndDate = end, ProductName = productName, UserName = userName }; // create the crypto-service provider: DSACryptoServiceProvider dsa = new DSACryptoServiceProvider(); // setup the dsa from the private key: dsa.FromXmlString(privateKey); // get the byte-array of the licence terms: byte[] license = terms.GetLicenseData(); // get the signature: byte[] signature = dsa.SignData(license); // now create the license object: return new License() { LicenseTerms = Convert.ToBase64String(license), Signature = Convert.ToBase64String(signature) }; }
验证方法:
/// <summary> /// validate license file and return the license terms. /// </summary> /// <param name="license"></param> /// <param name="publicKey"></param> /// <returns></returns> internal static LicenseTerms GetValidTerms(License license, String publicKey) { // create the crypto-service provider: DSACryptoServiceProvider dsa = new DSACryptoServiceProvider(); // setup the provider from the public key: dsa.FromXmlString(publicKey); // get the license terms data: byte[] terms = Convert.FromBase64String(license.LicenseTerms); // get the signature data: byte[] signature = Convert.FromBase64String(license.Signature); // verify that the license-terms match the signature data if (dsa.VerifyData(terms, signature)) return LicenseTerms.FromString(license.LicenseTerms); else throw new SecurityException("Signature Not Verified!"); }
许可条款类别:
/// <summary>
/// terms of the license agreement: it's not encrypted (but is obscured)
/// </summary>
[Serializable]
internal class LicenseTerms
{
/// <summary>
/// start date of the license agreement.
/// </summary>
public DateTime StartDate { get; set; }
/// <summary>
/// registered user name for the license agreement.
/// </summary>
public String UserName { get; set; }
/// <summary>
/// the assembly name of the product that is licensed.
/// </summary>
public String ProductName { get; set; }
/// <summary>
/// the last date on which the software can be used on this license.
/// </summary>
public DateTime EndDate { get; set; }
/// <summary>
/// returns the license terms as an obscure (not human readable) string.
/// </summary>
/// <returns></returns>
public String GetLicenseString()
{
using (MemoryStream ms = new MemoryStream())
{
// create a binary formatter:
BinaryFormatter bnfmt = new BinaryFormatter();
// serialize the data to the memory-steam;
bnfmt.Serialize(ms, this);
// return a base64 string representation of the binary data:
return Convert.ToBase64String(ms.GetBuffer());
}
}
/// <summary>
/// returns a binary representation of the license terms.
/// </summary>
/// <returns></returns>
public byte[] GetLicenseData()
{
using (MemoryStream ms = new MemoryStream())
{
// create a binary formatter:
BinaryFormatter bnfmt = new BinaryFormatter();
// serialize the data to the memory-steam;
bnfmt.Serialize(ms, this);
// return a base64 string representation of the binary data:
return ms.GetBuffer();
}
}
/// <summary>
/// create a new license-terms object from a string-representation of the binary
/// serialization of the licence-terms.
/// </summary>
/// <param name="licenseTerms"></param>
/// <returns></returns>
internal static LicenseTerms FromString(String licenseTerms)
{
using (MemoryStream ms = new MemoryStream(Convert.FromBase64String(licenseTerms)))
{
// create a binary formatter:
BinaryFormatter bnfmt = new BinaryFormatter();
// serialize the data to the memory-steam;
object value = bnfmt.Deserialize(ms);
if (value is LicenseTerms)
return (LicenseTerms)value;
else
throw new ApplicationException("Invalid Type!");
}
}
}
从技术上讲,创建有效且安全的许可系统并非易事。如果您打算开发商业软件,我建议为其使用一些商业解决方案。定制编码的许可系统容易受到攻击。
一种方法是投放自己的partial key verification system。 Code Project上有一个VB.NET版本:
请注意您为保护应用程序付出了多少努力;如果密码很容易被破坏,可能会浪费时间;如果密码保护很强,可能会浪费时间(例如,每次运行时都必须输入密码)。
我认为应该为此添加另一个答案,因为公认的答案似乎是引用当前未维护的项目。