Я, вероятно, немного опоздал, но я потратил немного времени, пытаясь разработать быстрый и эффективный метод защиты небольшого приложения на C #, и я хотел бы поделиться своими результатами.
Этокажется, что вы можете довольно легко создать свою собственную, достаточно безопасную систему лицензирования, используя RSA.
Очевидно, что нет ничего пуленепробиваемого, когда речь заходит о защите программного обеспечения (Это все равно, что защитить свой дом от грабителей: тревоги, лай собак и заборы создают больше проблем, чем оно того стоит, но они не остановят кого-то решительногочтобы войти)
Таким образом, ключевая фраза в защите программного обеспечения - создать больше проблем, чем того стоит: если вы предлагаете ERP-систему за 1 000 000 долларов, вы хотели бы иметь действительно хорошую защиту, разрешенную через веб-сайт.услуга (и пользователи, которые платят так много за систему, не будут иметь проблем с предоставлением этой системе постоянного доступа в Интернет)
Однако, если вы платите всего лишь 5-30 долларов за маленькое приложение, пользователи не собираются ставитьс очень тяжелой авторизацией.
Я думаю, что самая простая система для создания - это цифровая подпись файла лицензии, который содержит информацию о продукте, пользователе и его продолжительности.
Это означает, что любаяизменение файла лицензии делает цифровую подпись недействительной.
ДиЖитальная подпись может быть получена из класса DSACryptoServiceProvider с использованием метода SignData.
Для подписи данных требуется закрытый ключ, а открытая часть этого ключа может использоваться для проверки подписи: (таким образом, публичнаяключ должен быть доступен приложению)
DSAXCryptoServiceProvider имеет методы для создания и использования ключей:
DSACryptoServiceProvider.ToXMLString (bool includePrivate);
возвращает Public или Public & Public &Закрытые ключи в настоящее время в поставщике услуг представлены в виде строки XML.
DSACryptoServiceProvider.FromXMLString (String xmlString)
Этот метод устанавливает новый DSACryptoServiceProvider с существующими частными или открытыми ключами, полученными из DSACryptoServiceProvider.ToXString ()
Единственным недостатком в безопасности этой системы будет возможность взлома пользователем предоставления своего открытого ключа.Это позволило бы им создавать свои собственные файлы лицензий из собственного закрытого ключа.
Это можно обойти, дополнительно подписав требуемый ресурс для приложения (например, .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!");
}
Условия лицензии Class:
/// <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!");
}
}
}