Для веб-приложения я хотел бы создать простую, но эффективную систему лицензирования. В C# это немного сложно, так как мой метод дешифрования может быть просмотрен любым, у кого установлен Reflector.
Какие методы шифрования файлов на C# достаточно защищены от несанкционированного доступа?





Зачем вам нужно его шифровать? Если вы боитесь, что это подделка (например, кто-то увеличивает количество пользователей), не могли бы вы просто подписать его, например, цифровой сертификат вашей организации?
или, возможно, вы хотите привязать лицензию к определенной машине, например, сгенерировав лицензионный ключ на основе значения md5 диска c компьютера. тогда ваша лицензия будет зависеть от машины.
Вы имеете в виду серийный номер диска C, верно? не содержание. И убедитесь, что вы не используете идентификатор тома, который можно легко скопировать.
Хеширование диска - плохая идея - слишком много данных. Лучше использовать DPAPI (машинная область) для защиты GUID (создавать только в том случае, если он еще не существует) в качестве «идентификатора машины». Используйте DPAPI пользовательской области для защиты «идентификатора пользователя».
Единственный способ обеспечить некоторую безопасность с лицензированием - это принудительно выполнить онлайн-вход в систему против учетных данных, которые вы держите (действительно абстрактно).
Все остальные методы требуют больше времени и, следовательно, больше денег для реализации, поскольку взламывают и злоупотребляют вашим программным обеспечением вместо покупки лицензии.
.NET имеет несколько хороших криптографических классов, но, как вы упомянули, если вы кодируете кодировку / дешифрование лицензии, каждый может легко ее декомпилировать.
Используйте подписанный XML-файл. Подпишите его с помощью части закрытого ключа пары ключей и проверьте ее с помощью части открытого ключа в своем программном обеспечении. Это дает вам возможность проверить, была ли изменена лицензия, а также проверить, действителен ли файл лицензии.
Подписание и проверка подписанного файла XML задокументированы в MSDN.
Конечно, логично, что вы подписываете файл лицензии в своей компании и отправляете файл лицензии клиенту, который затем помещает файл лицензии в папку, чтобы вы могли его прочитать.
Конечно, люди могут вырезать / взломать вашу распределенную сборку и вырвать проверку xml-знака, но, опять же, они всегда смогут это сделать, независимо от того, что вы делаете.
Я обнаружил, что материалы MSDN, о которых вы говорили, и подписывание XML выглядят достаточно просто. Однако не могли бы вы подробнее рассказать о части вашего ответа, связанной с открытым / закрытым ключом? Я ничего не видел об использовании двух разных ключей для подписи и проверки XML-файла.
используйте sn -k для создания пары ключей. Эта пара ключей используется для подписи XML. Чтобы проверить XML, вы используете публичную часть. Не включайте в свой код весь ключ. Используйте sn -p для извлечения публичной части в файл. Используйте это в своем коде, который вы распространяете, для проверки лицензии.
Похоже, вы хотите использовать публичную / частную криптографию для подписи токена лицензии (например, XML-фрагмента или файла), чтобы вы могли обнаружить подделку. Самый простой способ справиться с этим - выполнить следующие действия:
1) Создайте пару ключей для своей компании. Вы можете сделать это в командной строке Visual Studio с помощью инструмента SN. Синтаксис:
sn -k c:\keypair.snk
2) Используйте пару ключей, чтобы строго указать (т.е. подписать) ваше клиентское приложение. Вы можете установить это, используя вкладку подписи на странице свойств в вашем приложении.
3) Создайте лицензию для своего клиента, это должен быть документ XML, и подпишите его своим закрытым ключом. Это включает в себя простое вычисление цифровой подписи, и шаги по его выполнению можно найти по адресу:
http://msdn.microsoft.com/en-us/library/ms229745.aspx
4) На клиенте при проверке лицензии вы загружаете XmlDocument и используете свой открытый ключ для проверки подписи, чтобы доказать, что лицензия не была подделана. Подробности о том, как это сделать, можно найти по адресу:
http://msdn.microsoft.com/en-us/library/ms229950.aspx
Чтобы обойти распределение ключей (то есть убедиться, что ваш клиент использует правильный открытый ключ), вы можете фактически извлечь открытый ключ из самой подписанной сборки. Таким образом гарантируется, что у вас нет другого ключа для распространения, и даже если кто-то вмешается в сборку, .NET Framework умрет из-за исключения безопасности, потому что строгое имя больше не будет соответствовать самой сборке.
Чтобы получить открытый ключ из клиентской сборки, вы хотите использовать код, подобный следующему:
/// <summary>
/// Retrieves an RSA public key from a signed assembly
/// </summary>
/// <param name = "assembly">Signed assembly to retrieve the key from</param>
/// <returns>RSA Crypto Service Provider initialised with the key from the assembly</returns>
public static RSACryptoServiceProvider GetPublicKeyFromAssembly(Assembly assembly)
{
if (assembly == null)
throw new ArgumentNullException("assembly", "Assembly may not be null");
byte[] pubkey = assembly.GetName().GetPublicKey();
if (pubkey.Length == 0)
throw new ArgumentException("No public key in assembly.");
RSAParameters rsaParams = EncryptionUtils.GetRSAParameters(pubkey);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParams);
return rsa;
}
Я загрузил образец класса с множеством полезных утилит шифрования на Snipt по адресу: http://snipt.net/Wolfwyrd/encryption-utilities/, чтобы помочь вам встать на путь.
Я также включил образец программы по адресу: https://snipt.net/Wolfwyrd/sign-and-verify-example/. Пример требует, чтобы вы добавили его в решение с библиотекой утилит шифрования и предоставили тестовый файл XML и файл SNK для подписи. Проект должен быть подписан с помощью созданного вами SNK. Он демонстрирует, как подписать тестовый XML-файл с помощью закрытого ключа из SNK, а затем проверить с помощью открытого ключа сборки.
Обновлять
Добавлен последнее сообщение в блоге с красивым подробным прохождением файлов лицензий.
Чрезвычайно полезный код шифрования. Спасибо Wolfwyrd за то, что сделали его доступным.
@Wolfwyrd: Утилиты, которые вы сделали доступными, не могли бы вы дать краткие инструкции по их использованию?
@Wolfwyrd: ссылка на ваш класс больше не действительна. Мне очень хотелось увидеть процесс, который вы использовали для некоторых из этих функций. Есть шанс исправить ссылку?
@Molloch - Загрузил файлы в Snipt, где они должны пережить мою неуклюжую чистку сервера :)
Я нашел этот проект на GitHub, я посмотрел на метод EncryptionUtils.GetRSAParameters(key), он очень сложный ... не можем ли мы просто создать KeyContainerName из байтового массива открытого ключа сборки? cspParameters.KeyContainerName = FromArrayToString(pubKey);?
RE: Не включайте в свой код весь ключ. Используйте sn -p для извлечения публичной части в файл. Используйте это в своем коде, который вы распространяете, для проверки лицензии.
Используя код из статей MSDN, я создал небольшое приложение (LicMaker), чтобы облегчить это. Приложение подписано полной парой ключей. Входными данными является неподписанный файл лицензии в формате .XML. Результатом является исходная подпись XML + в подписанном файле .LIC. Мой продукт также подписан тем же файлом полной пары ключей. Продукт проверяет, не был ли изменен файл .LIC. Работает отлично. Я не использовал sn -p для этого решения.
Похоже, что в образцах MSDN используются параметры по умолчанию, и это приводит к подписанию для конкретной машины, так что вы не можете подписаться на одной машине и проверить на произвольной другой машине. Я изменил логику в этих примерах, чтобы использовать ключи в моем snk на подписывающей машине и ключи из моей сборки на проверяющей машине. Это было сделано с использованием логики из образца MSDN и подпрограмм из (очень хорошо выполненного) образца ExcryptionUtils.cs, ссылка на который приведена выше.
Для подписи файла я использовал это:
RSACryptoServiceProvider rsaKey = EncryptionUtils.GetRSAFromSnkFile(keyFilePath);
Для проверки файла я использовал это:
RSACryptoServiceProvider rsaKey = EncryptionUtils.GetPublicKeyFromAssembly
(System.Reflection.Assembly.GetExecutingAssembly());
Кстати: я заметил, что проверка подписи XML игнорирует комментарии XML.
Ответ Wolfwyrd превосходен, но я просто хотел предложить намного более простую версию метода Wolfwyrd GetPublicKeyFromAssembly (который использует множество вспомогательных методов из библиотеки, любезно предоставленной Wolfwyrd).
В этой версии это весь код, который вам нужен:
/// <summary>
/// Extracts an RSA public key from a signed assembly
/// </summary>
/// <param name = "assembly">Signed assembly to extract the key from</param>
/// <returns>RSA Crypto Service Provider initialised with the public key from the assembly</returns>
private RSACryptoServiceProvider GetPublicKeyFromAssembly(Assembly assembly)
{
// Extract public key - note that public key stored in assembly has an extra 3 headers
// (12 bytes) at the front that are not part of a CAPI public key blob, so they must be removed
byte[] rawPublicKeyData = assembly.GetName().GetPublicKey();
int extraHeadersLen = 12;
int bytesToRead = rawPublicKeyData.Length - extraHeadersLen;
byte[] publicKeyData = new byte[bytesToRead];
Buffer.BlockCopy(rawPublicKeyData, extraHeadersLen, publicKeyData, 0, bytesToRead);
RSACryptoServiceProvider publicKey = new RSACryptoServiceProvider();
publicKey.ImportCspBlob(publicKeyData);
return publicKey;
}
При реализации кода подписи / проверки будьте осторожны, чтобы не поместить его в отдельную сборку. Защита от несанкционированного доступа теперь очень легко обойти защиту от несанкционированного доступа, как описано в статье Защита от несанкционированного доступа CAS нарушена: последствия для лицензирования программного обеспечения.
Обязательный отказ от ответственности и заглушка: компания, которую я учредил, производит Решение для лицензирования OffByZero Cobalt.
Что бы вы ни пытались сделать, если вашему приложению необходимо расшифровать ваш файл лицензии, это может сделать каждый поощряемый пользователь. Подумайте о другом способе лицензирования вашего программного обеспечения.