Покорение RSA на C#
Ранее я разработал компоненту на C# для подключения терминала с биометрией Anviz к 1С. Но я сделал ее для единственного клиента. А для того, чтобы ее можно было использовать для большого количества клиентов, нужно сделать проверку серийного номера.
Для проверки я ранее использовал RSA, но это было на Visual Basic. Код проверки выглядел примерно так:
Function CheckLicense(Serial) Dim i As Long Dim CurrLic As String Dim CurrSerial As String Dim CurrMask As String Dim strDeCrypt As String CheckLicense = False 'By default On Error GoTo errtrap For i = LBound(SerialsLicens) To UBound(SerialsLicens) CurrLic = SerialsLicens(i) CurrSerial = Left(CurrLic, 16) 'Seek for serial 'MsgBox "Curr serial: " & CurrSerial If CurrSerial = Serial Then CurrMask = Mid(CurrLic, 18) 'MsgBox "Curr mask: " & CurrMask 'if already checked before If CurrMask = "+" Then CheckLicense = True Exit Function Else strDeCrypt = mpModExp(CurrMask, PublicKeyExp, PublicKeyModulus) 'MsgBox "Decrypt: " & strDeCrypt If Val(strDeCrypt) = Val(CurrSerial) Then CheckLicense = True SerialsLicens(i) = CurrSerial & ":+" 'MsgBox "Memory for serial: " & SerialsLicens(i) Exit Function Else Exit Function End If End If End If Next Exit Function errtrap: MsgBox "Error CheckLicense:" & err.Description & " " & err.HelpContext End Function
Публичный ключ состоял из степени PublicKeyExp и модуля PublicKeyModulus. Предварительно я проверял корректность самого публичного ключа. И потом восстанавливал публичным ключом зашифрованную лицензию. Если восстанавливался серийный номер, равный текущему, значит проверка прошла.
Мои первые шаги в C# в RSA были неуклюжими.
Конечно в Microsoft есть готовый RSA-класс для шифрования, но он очень усложнен, я не понял, как им пользоваться.
Поэтому я нашел готовый пример программы RSA-шифрования, использующую класс Biginteger.

Сначала я перенес свой проект в другой каталог и не мог найти, где указать, какой из двух проектов сборки должен запускаться (один проект — библиотека, другой — тестовая форма). В итоге нашел:

Следующей проблемой оказалось то, что C# ругался на Biginteger. Я нашел, что нужно подключить библиотеку Numeric. Но она не подключалась. Нашел, что потому, что у меня сборка под Net 2.0, а надо под Net 4.0. Поменял целевую платформу, все заработало:

Возникла очередная проблема — я не знал, как в C# добавлять модули для библиотечных функций. Но примерно понимал, что их можно заменить static-классами. Нашел пример static-классов. Сделал по аналогии:
using System; using System.Collections.Generic; using System.Numerics; using System.Text; namespace AnvizCCH { static public class myRSA { static public string RSA_Decode(string input, long d, long n) { string result = ""; //About hex: https://stackoverflow.com/questions/30119174/converting-a-hex-string-to-its-biginteger-equivalent-negates-the-value BigInteger bi = BigInteger.Parse("0" + input, System.Globalization.NumberStyles.AllowHexSpecifier); bi = BigInteger.Pow(bi, (int) d); BigInteger n_ = new BigInteger((int)n); bi = bi % n_; result = bi.ToString(); return result; } } }
Нашел один небольшой нюанс, что в начало числа надо добавлять ноль, чтобы не получать отрицательных значений Biginteger.
У меня еще была особенность в том, что я использую шестнадцатеричные значения чисел. Поэтому пришлось решать и эту проблему.
В итоге у меня получилось сделать первые шаги в декодировании закодированного ключа и я наполнился оптимизмом, что смогу решить эту задачу — основные препоны остались позади.
