Как расшифровать коды ключей Proximity в базе Орион Про Болид

В этом посте я хочу поделиться с вами информацией о том как расшифровать коды ключей Proximity карт в базе Орион Про Болид. Может возникнуть вопрос: «Зачем это нужно, ведь есть же генератор отчетов который предоставляет данную информацию?». Возможно я странный человек, но я считаю что пользоваться разного рода надстройками над СУБД если имеешь опыт работы с нею это несколько странно. Работать с базой напрямую гораздо интереснее и веселее чем изучать чужие костыли. Коды карточек PROXIMITY в базе хранятся в базе в таблице pMark с столбце CodeP. Зачем-то разработчики ПО Орион Про их зашифровали… Но на наше счастье не очень серьезно. О связях между таблицами в БД Орион Про я уже делал короткую заметку в посте Связи между таблицами в базе данных MS SQL Orion Pro Болид, поэтому сейчас на этом останавливаться не будем. Вообще если кого-то интересует аналитика — пишите в комментах, присылайте дампы базы — будем посмотреть.
У меня есть файл в формате excel — экспорт открытых ключей из базы Орион Про. На его примере мы посмотрим как легко расшифровываются ключи карточек. Вот скрин:

Дамп ключей из БД Орион Про
Дамп ключей из БД Орион Про в формате Excel

Возьмем в работу 3х человек, да простят меня эти люди. Участниками эксперимента назначим номера 10239 Меднов, 10297 Дербенева и 10308 Лапынин.
Теперь напишем простенький запрос к БД:

  1. SELECT 
  2. TabNumber
  3. ,Name
  4. ,FirstName
  5. ,MidName
  6. ,CodeP
  7.  FROM pList INNER JOIN pMark 
  8. ON pList.ID = pMark.Owner
  9. WHERE pList.TabNumber IN ('10239', '10297', '10308')

На скрине виден результат. Ключи, как мы видим спрятаны.

Запрос к БД Орион Про для получения кодов ключей
Запрос к БД Орион Про для получения кодов ключей

Давайте скопируем крокозябры из столбца codeP и вставим в какой-нибудь двоичный редактор. Что получилось — видно на скринах ниже:

Код ключа из базы Орион Про в редакторе WinHex
Код ключа из базы Орион Про в редакторе WinHex

Код ключа из базы Орион Про в редакторе WinHex
Код ключа из базы Орион Про в редакторе WinHex
Таким образом мы выяснили что ключ представляет 12 байтное слово. На самом деле это кодировка ASCII. Теперь давайте для наглядности впишем полученные данные в нашу таблицу. Вот что получается:
Сырой код ключа из БД Орион Про
Сырой код ключа из БД Орион Про

Прелестно… Теперь откинем первый байт и заменим все пары байт FE01 на 00, вот что получилось:

Ну и напоследок: осталось переписать байты задом наперед и ключик наш! Делаем.

Расшифрованный ключ карты Proximity из БД Орион Про
Расшифрованный ключ карты Proximity из БД Орион Про

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

Оцените пожалуйста статью:

ПечальноТак себеНе плохоХорошоОтличная статья! 7 оценок.
Загрузка...

29 Replies to “Как расшифровать коды ключей Proximity в базе Орион Про Болид

  1. Эта схема преобразования старая как мир, но работает не во всех версиях Орион ПРО.
    Сейчас пытаюсь реверсировать для версии 1.20.2 и пока без результата.

    Вот пара примеров карт и базы:
    Карта: 62 00 04 00 AF CE DE 01
    в Базе: 08 01 D0 AE D0 9E D0 87 D1 8E 01 04 D1 8E 01 62

    Карта: 8A 00 00 00 34 7C FA 01
    в Базе: 08 01 D1 8A 7C 34 D1 8E 01 D1 8E 01 D1 8E 01 D0 89

  2. SQl Server 2014

    ALTER FUNCTION [dbo].[fсGetCodeStr] (@pCode varchar(50), @pCodeAdd varchar(50))
    RETURNS varchar(50) AS
    BEGIN
    DECLARE @Result varchar(50) ;
    IF @pCode IS NOT NULL
    BEGIN
    SET @Result = UPPER(REPLACE(sys.fn_varbintohexsubstring(0, CONVERT(varbinary(max), REVERSE(@pCode)), 1, 0)
    , sys.fn_varbintohexsubstring(0, CONVERT(varbinary(max), REVERSE(@pCodeAdd)), 1, 0)
    ,’00’));
    IF RIGHT(@Result, 2) = ’08’
    SET @Result =LEFT(@Result, LEN(@Result)-2) ;
    END
    Return(@Result)
    END

    1. Спасибо тебе добрый человек.

      Используя данное знание перевел из SQL в PHP функцию:
      —- INFO —-
      @info_1 как показали тесты, значение из поля `CodePAdd` не участвует в образовании хранимого в `CodeP` кода, поэтому `01fe` является постоянным значением заменяемым на `00`.
      @info_2 `mb_convert_encoding` потребовалось в нашем случае, т.к. результат выборки из базы данных приходил в `UTF-8` кодировке.
      —- SAMPLE —
      <?php
      // php 7.2
      function decode_bolid_card ( $code_from_pMark_CodeP )
      {
      $code = mb_convert_encoding( $code_from_pMark_CodeP, 'cp1251' );
      $code = strrev( $code );
      $code = unpack( 'H*', $code );
      $code = str_replace( '01fe', '00', array_pop( $code ) );
      $code = substr( $code, 0, 16 );
      return $code;
      }

  3. Тоже сильно раздражали костыли классического интерфейса. Делаю альтернативный веб интерфейс для добавления пользователей и карт, с картами возник затык c расшифровкой.
    Для примера что получилось при использовании функции(версия орион про 1.12)
    4D00370086FE6F01
    4D00370086023F6F01

    3F0009002246B101
    BD0009002246B101

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

  4. // Если кому понадобится на javascript
    function convertBolid(str) {
    var arr = [];
    for (var i = 0, l = str.length; i < l; i ++) {
    var hex = Number(str.charCodeAt(i)).toString(16);
    if(hex.length == 1 ) {
    hex = '0'+hex
    }
    arr.push(hex);
    }
    return arr.slice(1).reverse().join('').replace(/01fe/g,'00');
    }

  5. Эм. Я тут свои пять копеек оставлю.

    В дистребутиве АРМ 1.12.2 есть файлик, выше его уже упоминали, «C:\BOLID\ARM_ORION_PRO1_12_2\Data\LibraryDBEditor\OrionDBEditor.dll». А в нем функция DecodePassword которая расшифровывает все пароли в CodeP.

    В 1.20.3 тоже работает.

    1. Можно, например, с помощью Microsoft SQL Server Management Studio.

      • Соединяетесь с сервером;
      • Выбираете нужную БД;
      • Выполняете запрос SELECT * from pMark;
      • Внизу, в таблице результата, выделяете все;
      • ПКМ;
      • Сохранить результаты как… ;
      • Выбираете csv.
      1. Спасибо, сделал с помощью орионовского експлорера. Но из-за проблем с кодировкой не получается адекватно расшифровать коды. Ввожу в HEX редактор значения сначала адекватно конвертирует, но после 3-4 ввода Совсем другой результат. Целый день потратил и так не разобрался в чём проблема. Может вы мне поможете, я вам скину csv а вы расшифруете коды в нём? Разумеется не бесплатно. Времени очень мало на то чтобы разбираться с этим.

  6. Данные карт в базе никак не шифруются. Они хранятся в двоичном виде.
    При запросе к базе используйте CAST в varbinary для поля CodeP.
    Получится как то так «select id, cast(codep as varbinary), owner, ownername from pMark»
    К примеру, возьмем одну из карт из базы 0x0801B97A73FE0108FE012A из запроса выше.
    0х08 префикс. Меняем все FE01 на 00 (почему так еще не выяснил, скорее всего что то связанное с хранением во флэш памяти контроллеров или еще что то).
    Получится 01B97A730008002A — как раз те данные карты которые отображаются в АБД (нужно только перевернуть в правильную сторону — 2A000800737AB901).

    Для формирования кода из карт используется алгоритм CRC-8/maxim dallas.

    Получить код карты тоже просто. Убираем младший байт 01 (он всегда имеет такое значение), и старший байт 2A (это контрольная сумма).
    Получаем код карты B97A730008

  7. Нет никакого шифрования в поле с кодом карт. Они хранятся в двоичном виде.
    формат 0х0801хххххххххххх
    Для формирования кода из карт используется алгоритм CRC-8/Dallas

      1. Небольшое дополнение.
        Стало понятно почему в базе хранится ключ с FE 01 вместо 00.
        Очевидно же почему так реализовано. Но не догнал сразу.
        Формат поля в БД — varchar, а сохраняются данные в это поле в двоичном виде. Но в строку нельзя записать символ с кодом 00.
        Поэтому и используется такое кодирование — вместо 00, пишется FE 01.

  8. Описанное в статье на SQL можно реализовать так:

    select

    replace(convert(varchar(max), cast(reverse(substring(pm.CodeP, 2, len(pm.CodeP) — 1)) as varbinary(max)), 2), ’01FE’, ’00’)

    from
    pMark pm

  9. У нас не сработал алгоритм с заменой FE01, FE02 и т.д.
    Вернее сказать на большинство карт сработал, около 7 карт остались анонимными. Таких карт я не нашёл в БД.

  10. Здравствуйте. Есть CSV файл с номерами карт в формате болида. 8B004100412D2F01, 8D004100635FEF01, 30003A003DA7E301, CB00270060822101, F900270060A96B01 и т.п. Нам нужно их конвертировать в десятеричную систему (или в любую другую, которую можно потом конвертировать в десятеричную) чтобы не собирать карты у всех сотрудников для модернизации системы. Можете помочь? разумеется не бесплатно!

    1. Иван, не буду спрашивать зачем вам это, но если напрямую конвертировать 8-байтное слово в 10-чную ССч — числа получатся огромные. Данную операцию может проделать даже калькулятор винды. Просто переключите его в режим «программист» во вкладке Вид. Если вам не хочется этим заниматься — сообщите мне, пришлёте файл, я вам сконвертирую каким-нибудь автоматическим способом.

  11. Public Function mark(str As Variant, gtype As Byte) As String
    Dim ab() As Byte

    If IsNull(str) Then
    mark = «»
    Exit Function
    End If

    ab = StrConv(str, vbFromUnicode) ‘ &H75)

    Select Case gtype
    Case 1
    mark = Password(ab()) ‘password1(str) ‘
    Case 3, 4
    mark = prox(ab)
    Case Else
    mark = «??»
    End Select
    End Function

    Private Function prox(ab As Variant) As String
    Dim l As Byte, i As Byte, b As Byte

    l = UBound(ab)
    For i = 1 To l
    b = ab(i)
    If b = &HFE Then
    Select Case ab(i + 1)
    Case 1
    b = 0
    Case 2
    b = &HFE
    End Select
    i = i + 1
    End If
    If b < 16 Then
    prox = "0" & Hex(b) & prox
    Else
    prox = Hex(b) & prox
    End If
    Next i
    End Function

  12. Обновленная PHP функция декодирования карт из значения «CodeP», для Болида v1.20.2.
    Изменения не значительные, теперь кроме «01fe» нужно так же заменять еще несколько значений.
    — PHP Code —
    function decode_bolid_card ( $code )
    {
    $code = mb_convert_encoding( $code, ‘CP1251’ );
    $code = strrev( $code );
    $code = unpack( ‘H*’, $code );
    $code = array_pop( $code );
    $code = str_replace( ’01fe’, ’00’, $code );
    $code = str_replace( ’01fe’, ‘fe’, $code );
    $code = str_replace( ’02fe’, ‘fe’, $code );
    $code = str_replace( ’03fe’, ’20’, $code );
    $code = str_replace( ’04fe’, ‘cc’, $code );
    $code = str_replace( ’05fe’, ‘0a’, $code );
    $code = str_replace( ’00fe’, ‘0001FE’, $code );
    $code = substr( $code, 0, 16 );
    return $code;
    }
    — — — — — —

  13. Кому надо выкладываю код ЛаоСана но в Python вариации.
    Я переводил-переводил… и что-то осознал что зря делала :))) с usb proxy считывателя совсем другой код приходит. ха)

    — Python Code —
    import binascii

    def decodingCard(self, code) -> str:
    __result = code.encode(«CP1251»)
    __result = binascii.hexlify(__result[::-1])
    __result = __result[::-1].decode()
    __result = __result[::-1].replace(’01fe’, ’00’)
    __result = __result[::-1].replace(’01fe’, ‘fe’)
    __result = __result[::-1].replace(’02fe’, ‘fe’)
    __result = __result[::-1].replace(’03fe’, ’20’)
    __result = __result[::-1].replace(’04fe’, ‘cc’)
    __result = __result[::-1].replace(’05fe’, ‘0a’)
    __result = __result[::-1].replace(’00fe’, ‘0001FE’)
    return __result[0:16]
    ————

  14. Некрокоммент с вопросами к ЛаоСан и MeGaX5.
    1. На кой нужна строка
    $code = str_replace( ’01fe’, ‘fe’, $code );
    , когда предыдущей строкой мы уже поменяли все ’01fe’?
    2. Как мы можем получить в выхлопе («расшифрованной» строке) последовательность ’00fe’? (ну или зачем нужна последняя замена)

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