Покорение 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.

У меня еще была особенность в том, что я использую шестнадцатеричные значения чисел. Поэтому пришлось решать и эту проблему.

В итоге у меня получилось сделать первые шаги в декодировании закодированного ключа и я наполнился оптимизмом, что смогу решить эту задачу — основные препоны остались позади.