Проверка серийника устройства Anviz через RSA в C#

Для своей компоненты взаимодействия с биометрическими устройствами Anviz я хочу, чтобы она работала только с определенными устройствами, на серийники которых я выдал лицензию.

Делюсь небольшим участком кода компоненты, который я написал на C# для этого и расскажу немного о том, как я отлаживал и разрабатывал этот код:

check_serial:
//Check serial with cryptography
Boolean serial_ok = false;
AddLog("Get serial of device: " + serial_number);
if (serial_number == "")
    AddLog("Serial is empty");
else {
    Int64 serial_number_long = Convert.ToInt64(serial_number);
    string serial_number_hex = Convert.ToString(serial_number_long, 16).ToUpper();
    string serial_number_dec = Convert.ToString(serial_number_long, 10).ToUpper();
    AddLog("Serial of device in 16 system: " + serial_number_hex);
    AddLog("Serial of device in 10 system: " + serial_number_dec);
 
    foreach (string currLic in SerialsLicens) {
        //Проверяем лицензию
        TwoWords twLic = SplitByColon(currLic);
        string currSerial = twLic.First.ToUpper().TrimStart('0'); //Remove leading zeroes
        AddLog("Curr serial from Licenses: " + currSerial);
        if ((currSerial != serial_number_hex) & (currSerial != serial_number_dec)) 
            continue; //skip if not our serial
        TwoWords twRSA = SplitByColon(public_key);
        string DecodedSerial = myRSA.RSA_Decode(twLic.Second, twRSA.First, twRSA.Second);
        AddLog("Restored serial by RSA: " + DecodedSerial);
        if (DecodedSerial == currSerial) { //Here hex
            serial_ok = true;
            AddLog("Serial OK restored by RSA");
        }
        else
            AddLog("Serial BAD restored by RSA");
        break;
    }

Клиенту выдается публичный ключ в виде строки: 1001:ABDFCD10….
Где первая часть — экспонента, а вторая — модуль алгоритма RSA.

Клиенту также на каждое устройство выдается ключ в виде строки: 0123456789:BBEDF203….
Первая часть этой строки — серийный номер устройства. Вторая — закодированный через RSA серийный номер.

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

Для ускорения в списке лицензий ищется серийный номер, соответствующий текущему и для него выполняется декодирование зашифрованного серийника. Если в результате расшифровки получаем нужный нам серийник, то все ок, лицензия имеется. Можно было бы перебирать все лицензии, но это долго, т.к. декодирование — не самый быстрый процесс. Поэтому используется небольшое ускорение в виде явного указания серийника в списке лицензий.

Как видите, везде в алгоритме я использую по максимуму логирование через AddLog. Если логирование в моей компоненте выключено, то этот метод ничего не делает, если включено, то пишет в лог, что полезно, если нужно понять причины ошибки.

И вот клиент прислал мне лог, что его серийный номер не проходит проверку RSA.

Я начал разбираться и понял, что у меня проверяется только шестнадцатеричный номер серийника, хотя лицензия выдается на десятичный номер. Видимо, когда я отлаживал, я получил с устройства номер в шестнадцатеричном формате и так и оставил, забыв, что лицензии выдаются на десятичные номера.

Я решил оставить оба формата — 16 и 10, объединил проверку через логическое И. И добавил преобразование к верхнему регистру на всякий случай (для букв шестнадцатиричной системы).

Однако и тут не проходила проверку. Анализ показал, что строка серийника в список лицензий выдается с лидирующими нулями, хотя расшифровывается он без лидирующих нулей (т.к. получаем просто число).

Поэтому в сравнение я еще добавил убирать лидирующие нули.

В итоге сравнение и декодирование заработало.

В коде вы можете увидеть метку check_serial, да, я использовал тестовый код, чтобы сразу переходить на эту метку с нужным мне серийником:

После завершения отладки я закомментировал этот код.

Весь код не очень профессиональный, написал с помощью Google, но работает. Дело в том, что я лишь начинающий программист в C#.

fixin

Программирую на 1С с 1999 года. В 1С просто Гений. В 2020 году ушел из офиса на вольные хлеба фриланса. Принимаю заказы.

Читайте также:

комментария 4

  1. bob:

    Писать основную логику в else-бранче — признак плохого стиля. Использовать метки когда не надо — так же.
    Бессмысленные конверсии туда-сюда не нужны. Если подумаешь над сутью операций, сможешь сделать все проще и лаконичней.

    • метки я использовал для отладки.
      насчет else не совсем понял.
      но в целом, претензии возможны, т.к. C# — не мой основной язык. Использую по крайней необходимости.

  2. bob:

    Обычно пишут if (condition) { /* основная логика */ } else { /*альтернатива*/}. У тебя вынесена логика в else-ветку (branch)

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *