<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>Заметки Lizard'а</title><subtitle>Криптография, RFID, Sub-GHz и прочее...

TG - https://t.me/li0ard_notes</subtitle><author><name>Заметки Lizard'а</name></author><id>https://teletype.in/atom/li0ard</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/li0ard?offset=0"></link><link rel="alternate" type="text/html" href="https://blog.li0ard.rest/?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=li0ard"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/li0ard?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-06-07T19:05:48.861Z</updated><entry><id>li0ard:ecb_penguin</id><link rel="alternate" type="text/html" href="https://blog.li0ard.rest/ecb_penguin?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=li0ard"></link><title>The ECB Penguin</title><published>2026-05-30T16:20:02.832Z</published><updated>2026-05-30T16:20:02.832Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img3.teletype.in/files/2f/f9/2ff92101-2982-4849-98e8-3e9ac1c45315.png"></media:thumbnail><category term="kriptografiya" label="Криптография"></category><summary type="html">&lt;img src=&quot;https://img4.teletype.in/files/f9/ee/f9ee0f21-be77-469f-a996-928267976916.png&quot;&gt;Данное изображение стало культовым в криптографическом и InfoSec сообществе. Речь идёт о картинке маскота Linux - пингвине Tux, которую зашифровали с помощью блочного шифра в ECB режиме (&quot;Режим простой замены&quot; в терминологии ГОСТ), однако контуры оригинального изображения остались видны...</summary><content type="html">
  &lt;figure id=&quot;0Yr1&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/f9/ee/f9ee0f21-be77-469f-a996-928267976916.png&quot; width=&quot;196&quot; /&gt;
    &lt;figcaption&gt;Суть такова&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Jg4y&quot;&gt;Данное изображение стало культовым в криптографическом и InfoSec сообществе. Речь идёт о картинке маскота Linux - пингвине Tux, которую зашифровали с помощью блочного шифра в &lt;a href=&quot;https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_.28ECB.29&quot; target=&quot;_blank&quot;&gt;ECB режиме&lt;/a&gt; (&amp;quot;Режим простой замены&amp;quot; в терминологии ГОСТ), однако контуры оригинального изображения остались видны. История этого изображения описана в &lt;a href=&quot;https://words.filippo.io/the-ecb-penguin/&quot; target=&quot;_blank&quot;&gt;статье Filippo Valsorda&lt;/a&gt;, в данной же статье будут результаты моего повторения данного эксперимента, но с разными блочными шифрами&lt;/p&gt;
  &lt;h2 id=&quot;JzRF&quot;&gt;Эксперимент&lt;/h2&gt;
  &lt;p id=&quot;VgRk&quot;&gt;Для начала эксперимента нам понадобится изображение маскота, но поскольку оригинальное изображение с Википедии очень низкого разрешения, то я решил использовать картинку, найденную на просторах интернета, с разрешением 823x823.&lt;/p&gt;
  &lt;figure id=&quot;TWZ7&quot; class=&quot;m_retina&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/72/af/72afad24-8b25-4ec9-904c-a74a4b923fb6.png&quot; width=&quot;411.5&quot; /&gt;
    &lt;figcaption&gt;Исходное изображение&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;NbIk&quot;&gt;Теперь определимся с шифрами:&lt;/p&gt;
  &lt;ul id=&quot;6xJ7&quot;&gt;
    &lt;li id=&quot;8VKy&quot;&gt;AES&lt;/li&gt;
    &lt;li id=&quot;73CY&quot;&gt;BelT - белорусский стандарт шифрования (описан в СТБ 34.101.31)&lt;/li&gt;
    &lt;li id=&quot;17gP&quot;&gt;DES&lt;/li&gt;
    &lt;li id=&quot;HXoD&quot;&gt;Калина - украинский стандарт шифрования (описан в ДСТУ 7624:2014)&lt;/li&gt;
    &lt;li id=&quot;LwrA&quot;&gt;Кузнечик - российский стандарт шифрования (описан в ГОСТ Р 34.12-2015)&lt;/li&gt;
    &lt;li id=&quot;xE68&quot;&gt;Магма - российский и советский стандарт шифрования (описан в ГОСТ Р 34.12-2015, а также ГОСТ 28147-89)&lt;/li&gt;
    &lt;li id=&quot;gNqn&quot;&gt;SM4 - китайский стандарт шифрования (описан GB/T 32907-2016)&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;OllV&quot;&gt;А также определим дополнительные условия:&lt;/p&gt;
  &lt;ol id=&quot;BtwW&quot;&gt;
    &lt;li id=&quot;RxHz&quot;&gt;Ключ - &lt;code&gt;00112233445566778899AABBCCDDEEFF&lt;/code&gt; , при необходимости уменьшается или расширяется дублированием до нужной длины блока&lt;/li&gt;
    &lt;li id=&quot;tmtY&quot;&gt;Padding - Заполнение нулями, пока буфер не будет кратен длине блока (это условие ECB)&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;q0K6&quot;&gt;Теперь необходимо перевести изображение из PNG в PPM (Формат представляет из себя ASCII заголовок и последовательность из трёхбайтовых RGB пикселей), сделано это было с помощью ImageMagick (с помощью команды &lt;code&gt;convert&lt;/code&gt;)&lt;/p&gt;
  &lt;p id=&quot;7PFv&quot;&gt;Далее с помощью hex-редактора отделяем ASCII заголовок от самого изображения и сохраняем обе части по отдельности:&lt;/p&gt;
  &lt;figure id=&quot;lSBe&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/ab/8f/ab8f0572-abee-44a3-bcee-088fd48fc09b.png&quot; width=&quot;706&quot; /&gt;
    &lt;figcaption&gt;Файл .ppm в hex-редакторе&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;r5Jo&quot;&gt;Далее порядок действий таков:&lt;/p&gt;
  &lt;ol id=&quot;hSDa&quot;&gt;
    &lt;li id=&quot;sqn0&quot;&gt;Шифруем изображение с помощью одного из алгоритмов&lt;/li&gt;
    &lt;li id=&quot;sQmd&quot;&gt;Присоединяем заголовок к шифрованному изображению&lt;/li&gt;
    &lt;li id=&quot;43Bi&quot;&gt;Переводим PPM в PNG&lt;/li&gt;
  &lt;/ol&gt;
  &lt;h3 id=&quot;eFaX&quot;&gt;Результаты&lt;/h3&gt;
  &lt;p id=&quot;bjpn&quot;&gt;В результате &amp;quot;прогона&amp;quot; изображения через все алгоритмы я получил, следующие изображения:&lt;/p&gt;
  &lt;p id=&quot;p12U&quot; data-align=&quot;center&quot;&gt;&lt;strong&gt;AES:&lt;/strong&gt;&lt;/p&gt;
  &lt;figure id=&quot;e310&quot; class=&quot;m_retina&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/88/71/88713cc2-da85-4425-8517-aff95359be0c.png&quot; width=&quot;411.5&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;DVSv&quot; data-align=&quot;center&quot;&gt;&lt;strong&gt;BelT:&lt;/strong&gt;&lt;/p&gt;
  &lt;figure id=&quot;CHZ7&quot; class=&quot;m_retina&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e9/f4/e9f457bb-a668-4b4f-83af-c91a9ae05a54.png&quot; width=&quot;411.5&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;2NIt&quot; data-align=&quot;center&quot;&gt;&lt;strong&gt;DES:&lt;/strong&gt;&lt;/p&gt;
  &lt;figure id=&quot;QtSB&quot; class=&quot;m_retina&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/26/34/26344ddc-d7ac-4ec9-b65e-f467bebb102b.png&quot; width=&quot;411.5&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;UxVl&quot; data-align=&quot;center&quot;&gt;&lt;strong&gt;Калина:&lt;/strong&gt;&lt;/p&gt;
  &lt;figure id=&quot;QlA3&quot; class=&quot;m_retina&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/97/b9/97b9d86f-6be3-4a62-bd02-e58697be0ed0.png&quot; width=&quot;411.5&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;mvd9&quot; data-align=&quot;center&quot;&gt;&lt;strong&gt;Кузнечик:&lt;/strong&gt;&lt;/p&gt;
  &lt;figure id=&quot;CU7N&quot; class=&quot;m_retina&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/d1/bc/d1bccaf3-3ad3-45fa-bad9-b52b1ab66bb9.png&quot; width=&quot;411.5&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;gMaJ&quot; data-align=&quot;center&quot;&gt;&lt;strong&gt;Магма:&lt;/strong&gt;&lt;/p&gt;
  &lt;figure id=&quot;kiqh&quot; class=&quot;m_retina&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/13/dd/13dd6111-6042-4ede-8ba5-a67628b634b8.png&quot; width=&quot;411.5&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;6Ae7&quot; data-align=&quot;center&quot;&gt;&lt;strong&gt;SM4:&lt;/strong&gt;&lt;/p&gt;
  &lt;figure id=&quot;W1ob&quot; class=&quot;m_retina&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/eb/5c/eb5ccc2f-0402-4948-81c8-46b6c0ef3f7d.png&quot; width=&quot;411.5&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;RGKX&quot;&gt;Эксперимент наглядно подтвердил, почему от режима ECB стоит полностью отказаться. Этот режим допускает утечку паттернов (статистических особенностей) исходных данных, позволяя распознать структуру сообщения даже в зашифрованном виде&lt;/p&gt;

</content></entry><entry><id>li0ard:anticryptopro_p4</id><link rel="alternate" type="text/html" href="https://blog.li0ard.rest/anticryptopro_p4?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=li0ard"></link><title>Побег из КриптоПро (ч.4, final?)</title><published>2026-05-06T12:46:14.864Z</published><updated>2026-05-06T12:46:14.864Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img4.teletype.in/files/be/54/be543906-4c1f-4d20-912a-bd51c223449c.png"></media:thumbnail><category term="anticryptopro" label="Побег из КриптоПро"></category><summary type="html">&lt;img src=&quot;https://img2.teletype.in/files/97/e1/97e146cd-9301-41fc-a30b-ec1b2467a348.png&quot;&gt;В третьей части цикла статей &quot;Побег из КриптоПро&quot; был разобран экспорт приватного ключа из проприетарного формата ключевого контейнера (те самые 6 файлов .key), а в цикле &quot;Тащим ключи с Рутокен Lite&quot; собственно был разобран экспорт самого контейнера с токена. Однако остался главный нерешённый вопрос, из-за которого экспорт контейнера штатными средствами &quot;Панели администрирования Рутокен&quot; и КриптоПро был невозможен - флаг экспортируемости контейнера.</summary><content type="html">
  &lt;nav&gt;
    &lt;ul&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#O70F&quot;&gt;Его величество - флаг...&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#92jH&quot;&gt;А если подробнее?&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#j4y9&quot;&gt;Пересчитываем MAC контейнера&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#39WK&quot;&gt;Бонус. Как вычисляются остальные MAC&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#8lPh&quot;&gt;MAC маски и соли&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#4aIv&quot;&gt;MAC пароля&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/nav&gt;
  &lt;p id=&quot;iMhc&quot;&gt;В &lt;a href=&quot;https://teletype.in/@li0ard/anticryptopro_p3&quot; target=&quot;_blank&quot;&gt;третьей части&lt;/a&gt; цикла статей &amp;quot;&lt;a href=&quot;https://blog.li0ard.rest/+anticryptopro&quot; target=&quot;_blank&quot;&gt;Побег из КриптоПро&lt;/a&gt;&amp;quot; был разобран экспорт приватного ключа из проприетарного формата ключевого контейнера (те самые 6 файлов .key), а в цикле &amp;quot;&lt;a href=&quot;https://blog.li0ard.rest/+rutoken_export&quot; target=&quot;_blank&quot;&gt;Тащим ключи с Рутокен Lite&lt;/a&gt;&amp;quot; собственно был разобран экспорт самого контейнера с токена. Однако остался главный нерешённый вопрос, из-за которого экспорт контейнера штатными средствами &amp;quot;Панели администрирования Рутокен&amp;quot; и КриптоПро был невозможен - флаг экспортируемости контейнера.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0, 0%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;T4Di&quot;&gt;&lt;strong&gt;Важно&lt;/strong&gt;: не следует путать понятие &lt;u&gt;неэкспортируемости&lt;/u&gt; и &lt;u&gt;неизвлекаемости&lt;/u&gt;. &lt;u&gt;Неэкспортируемый&lt;/u&gt; контейнер - контейнер, на который наложено &lt;u&gt;софтовое ограничение&lt;/u&gt; на экспорт, т.е если программа проигнорирует этот флаг, то она сможет произвести экспорт. Понятие &lt;u&gt;неизвлекаемости&lt;/u&gt; относится к токенам с механизмом ФКН (Функциональный ключевой носитель, аля PKCS#11), где &lt;u&gt;сам ключ генерируется на токене и никогда не покидает его&lt;/u&gt; (такая возможность попросту отсутствует), все операции вплоть до вычисления хэшей выполняются на самом токене.&lt;/p&gt;
  &lt;/section&gt;
  &lt;h2 id=&quot;O70F&quot;&gt;Его величество - флаг...&lt;/h2&gt;
  &lt;p id=&quot;KpLs&quot;&gt;Почему флаг? - Потому, что как оказалась всё софтовое ограничение, запрещающее экспорт, представляет из себя значение в 1 бит. Т.е &amp;quot;1&amp;quot; - экспорт разрешён, а &amp;quot;0&amp;quot; - экспорт запрещён. Такие дела...&lt;/p&gt;
  &lt;h3 id=&quot;92jH&quot;&gt;А если подробнее?&lt;/h3&gt;
  &lt;p id=&quot;T6C2&quot;&gt;Давайте взглянем на файл &lt;code&gt;header.key&lt;/code&gt; с помощью декодера ASN.1:&lt;/p&gt;
  &lt;figure id=&quot;EUax&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/97/e1/97e146cd-9301-41fc-a30b-ec1b2467a348.png&quot; width=&quot;935&quot; /&gt;
    &lt;figcaption&gt;Размеченное содержимое header.key&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;VKSf&quot;&gt;Мы видим всю открытую информацию о контейнере, например байты сертификата под тегом 5, или кусочек публичного ключа под тегом 8, или HMAC для проверки пароля контейнера под тегом 2. Но в данном случае нас интересуют другие данные, а именно 2 SEQUENCE (выделены оранжевым и зелёным). В одном из них мы можем заметить BIT STRING с 3 битами (выделены жёлтым). Данные биты - это параметры приватного ключа. Собственно первый бит и есть флаг экспортируемости. Вообще вся структура там следующая:&lt;/p&gt;
  &lt;figure id=&quot;POOj&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/04/64/0464e8d1-4586-43d5-b4b0-5323e715a782.png&quot; width=&quot;347&quot; /&gt;
    &lt;figcaption&gt;Структура битов для параметров приватного ключа&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;oZuT&quot;&gt;Однако, что за значение выделенное красным? - Это MAC всего контейнера, если мы просто изменим флаг, но не пересчитаем MAC, то КриптоПро такой контейнер не примет. (Кстати подобная схема используется и в экспортном представлении приватного ключа)&lt;/p&gt;
  &lt;h2 id=&quot;j4y9&quot;&gt;Пересчитываем MAC контейнера&lt;/h2&gt;
  &lt;p id=&quot;sAPP&quot;&gt;Сам алгоритм вычисления MAC довольно прост:&lt;/p&gt;
  &lt;ol id=&quot;zh52&quot;&gt;
    &lt;li id=&quot;vvnl&quot;&gt;Берём SEQUENCE выделенный оранжевым и сериализуем его в байты;&lt;/li&gt;
    &lt;li id=&quot;p84i&quot;&gt;Вычисляем MAC с помощью шифра Магма (ГОСТ 28147-89) со следующими параметрами:&lt;br /&gt;- Ключ: 32 нулевых байта&lt;br /&gt;- IV/Соль: 8 нулевых байт&lt;br /&gt;- Данные: сериализованый ранее SEQUENCE&lt;br /&gt;- Набор параметров (SBox) - &lt;code&gt;ID_TC26_GOST_28147_PARAM_Z&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;K5U1&quot;&gt;Подставляем получившейся в MAC (&lt;u&gt;если MAC больше 4 байт то берём только первые 4 байта&lt;/u&gt;) в ASN.1 структуру, сериализуем в байты и записываем их в файл&lt;/li&gt;
    &lt;li id=&quot;s2lq&quot;&gt;Profit!&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;TPm7&quot;&gt;В результате изменения бита в параметрах приватного ключа и применения алгоритма вычисления MAC контейнера мы смогли успешно &amp;quot;пролечить&amp;quot; контейнер разрешив экспорт.&lt;/p&gt;
  &lt;h2 id=&quot;39WK&quot;&gt;Бонус. Как вычисляются остальные MAC&lt;/h2&gt;
  &lt;h3 id=&quot;8lPh&quot;&gt;MAC маски и соли&lt;/h3&gt;
  &lt;figure id=&quot;N8QO&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/a8/ed/a8eda366-2a42-462b-9308-2f2788779dd5.png&quot; width=&quot;757&quot; /&gt;
    &lt;figcaption&gt;Размеченное содержимое masks.key&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;gnjx&quot;&gt;Вычисляем MAC с помощью шифра Магма (ГОСТ 28147-89) со следующими параметрами:&lt;br /&gt;- Ключ: Значение маски (выделено жёлтым, если больше 32 байтов, то берём последние 32 байта)&lt;br /&gt;- IV/Соль: 8 нулевых байт&lt;br /&gt;- Данные: Значение соли (выделено оранжевым)&lt;br /&gt;- Набор параметров (SBox) - &lt;code&gt;ID_TC26_GOST_28147_PARAM_Z&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;8evR&quot;&gt;&lt;u&gt;Если MAC больше 4 байт то берём только первые 4 байта&lt;/u&gt;&lt;/p&gt;
  &lt;h3 id=&quot;4aIv&quot;&gt;MAC пароля&lt;/h3&gt;
  &lt;figure id=&quot;30Rj&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/40/65/40650a4c-0600-4b26-999c-4cf0f337f8af.png&quot; width=&quot;933&quot; /&gt;
    &lt;figcaption&gt;Размеченное содержимое masks.key&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;ol id=&quot;5kJL&quot;&gt;
    &lt;li id=&quot;Pwhc&quot;&gt;Прогоняем через CPKDF (CryptoPro Key derivation function) пароль (в качестве соли для CPKDF берём 8 байт куска публичного ключа (в ASN.1 под тегом 10, на рисунке выделено жёлтым)&lt;/li&gt;
    &lt;li id=&quot;hNu5&quot;&gt;Вычисляем MAC с помощью шифра Магма (ГОСТ 28147-89) со следующими параметрами:&lt;br /&gt;- Ключ: Результат из п.1&lt;br /&gt;- IV/Соль: 8 нулевых байт&lt;br /&gt;- Данные: 16 нулевых байт&lt;br /&gt;- Набор параметров (SBox) - &lt;code&gt;ID_TC26_GOST_28147_PARAM_Z&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;2ZmH&quot;&gt;&lt;u&gt;Если MAC больше 4 байт то берём только первые 4 байта&lt;/u&gt;&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;4KDj&quot;&gt;На этом у меня всё, все ASN.1 схемы, а также практические реализации алгоритмов вычисления MAC вы можете найти в исходном коде &lt;a href=&quot;https://github.com/li0ard/cpfx_ts/tree/main/src/ckey&quot; target=&quot;_blank&quot;&gt;@li0ard/cpfx&lt;/a&gt;. Также туда в скором времени выйдет обновление добавляющее автоматическое изменение флага экспортируемости с пересчётом MAC.&lt;/p&gt;

</content></entry><entry><id>li0ard:blazorpack</id><link rel="alternate" type="text/html" href="https://blog.li0ard.rest/blazorpack?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=li0ard"></link><title>Получаем HTML из Blazorpack</title><published>2025-10-25T09:46:31.526Z</published><updated>2025-11-08T18:40:39.533Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img1.teletype.in/files/46/26/46267e9f-f5bf-408d-ace8-9f195a9ff832.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://img1.teletype.in/files/c0/8f/c08f94dc-2250-453f-bd1e-03dbff72cbe7.png&quot;&gt;Одним вечером у меня появилась необходимость написать парсер HTML одного сайта, но при просмотре содержимого страницы вместо нужных мне данных я увидел данный комментарий:</summary><content type="html">
  &lt;nav&gt;
    &lt;ul&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#bljn&quot;&gt;Как это работает?&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#UIKA&quot;&gt;Установка соединения&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#1qWH&quot;&gt;Обмен данными (BlazorPack)&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#Vo1f&quot;&gt;Получаем HTML&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#lWZX&quot;&gt;Формат DOM&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#hMRf&quot;&gt;Таблица строк&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#txRS&quot;&gt;Процесс восстановления HTML&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/nav&gt;
  &lt;p id=&quot;kjrt&quot;&gt;Одним вечером у меня появилась необходимость написать парсер HTML одного сайта, но при просмотре содержимого страницы вместо нужных мне данных я увидел данный комментарий:&lt;/p&gt;
  &lt;figure id=&quot;snJc&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c0/8f/c08f94dc-2250-453f-bd1e-03dbff72cbe7.png&quot; width=&quot;632&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;HY4h&quot;&gt;Я подумал: &amp;quot;Ага, значит данные подгружаются динамически, следовательно должен быть запрос на сервер&amp;quot;, однако открыв DevTools я увидел WebSocket, который судя по всему получал HTML от сервера&lt;/p&gt;
  &lt;figure id=&quot;VEMg&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/ac/c0/acc00ff7-88a0-4ee3-a064-006989514529.png&quot; width=&quot;532&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;bljn&quot;&gt;Как это работает?&lt;/h2&gt;
  &lt;figure id=&quot;QgFt&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/27/f9/27f9e8af-d348-4cc4-82ea-0f5c29af3c16.png&quot; width=&quot;1838&quot; /&gt;
    &lt;figcaption&gt;Полная схема установки соединения и согласования протоколов&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;vCDi&quot;&gt;Делать полный разбор протокола я не буду, поэтому кратко пройдёмся по основным этапам:&lt;/p&gt;
  &lt;h3 id=&quot;UIKA&quot;&gt;Установка соединения&lt;/h3&gt;
  &lt;p id=&quot;yoFt&quot;&gt;После того как браузер загрузил страницу происходит POST запрос на &lt;code&gt;/_blazor/negotiate&lt;/code&gt;, который возвращает:&lt;/p&gt;
  &lt;ul id=&quot;Wza4&quot;&gt;
    &lt;li id=&quot;x26V&quot;&gt;список поддерживаемых транспортных протоколов (WebSockets, Server-Sent Events, Long Polling);&lt;/li&gt;
    &lt;li id=&quot;6Qig&quot;&gt;ID соединения (&lt;code&gt;connectionId&lt;/code&gt;);&lt;/li&gt;
    &lt;li id=&quot;Gapb&quot;&gt;Токен доступа (&lt;code&gt;connectionToken&lt;/code&gt;).&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;HOTV&quot;&gt;Браузер перебирает список протоколов, и пытается установить соединение.&lt;br /&gt;Если первый вариант не удался, то пробуется следующий и так далее.&lt;/p&gt;
  &lt;h3 id=&quot;1qWH&quot;&gt;Обмен данными (BlazorPack)&lt;/h3&gt;
  &lt;p id=&quot;WCCk&quot;&gt;В качестве протокола обмена сообщениями между сервером и браузером используется протокол &lt;strong&gt;SignalR&lt;/strong&gt;, который в свою очередь использует &lt;strong&gt;MessagePack&lt;/strong&gt; (бинарный формат сериализации)&lt;/p&gt;
  &lt;p id=&quot;bOye&quot;&gt;Также поверх этого используется ещё 1 слой - &lt;strong&gt;Binary Message Format (BMF)&lt;/strong&gt;.&lt;br /&gt;К данным добавляются префикс длины, что позволяет передать несколько сообщений за один раз.&lt;/p&gt;
  &lt;p id=&quot;XsTV&quot;&gt;Получается такая &amp;quot;матрёшка&amp;quot; из кодировок:&lt;/p&gt;
  &lt;p id=&quot;Lpl4&quot; data-align=&quot;center&quot;&gt;&lt;code&gt;BMF -&amp;gt; SignalR -&amp;gt; MessagePack&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;iFxl&quot;&gt;Каждый слой решает свою задачу:&lt;/p&gt;
  &lt;ul id=&quot;BSBV&quot;&gt;
    &lt;li id=&quot;QWAF&quot;&gt;&lt;strong&gt;MessagePack&lt;/strong&gt; - компактное представление данных;&lt;/li&gt;
    &lt;li id=&quot;3nuw&quot;&gt;&lt;strong&gt;SignalR&lt;/strong&gt; - вызов методов и маршрутизация сообщений (Ядро BlazorPack);&lt;/li&gt;
    &lt;li id=&quot;QolB&quot;&gt;&lt;strong&gt;Binary Message Format (BMF)&lt;/strong&gt; - framing сообщений (Передача нескольких сообщений за раз)&lt;/li&gt;
  &lt;/ul&gt;
  &lt;figure id=&quot;62wq&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/f7/d4/f7d474fd-f177-4797-b509-3a4e03cde1d3.png&quot; width=&quot;807&quot; /&gt;
    &lt;figcaption&gt;Пример сообщения&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;Vo1f&quot;&gt;Получаем HTML&lt;/h2&gt;
  &lt;p id=&quot;ub9u&quot;&gt;Данный этап можно назвать самым сложным, так как Blazor &lt;u&gt;не отдаёт HTML в &amp;quot;голом&amp;quot; виде&lt;/u&gt; , вместо этого &lt;u&gt;он отдаёт представление DOM в бинарном пакете&lt;/u&gt; (&lt;code&gt;RenderBatch&lt;/code&gt;) разделённым на секции:&lt;/p&gt;
  &lt;ul id=&quot;5I1K&quot;&gt;
    &lt;li id=&quot;kbt3&quot;&gt;&lt;code&gt;UpdatedComponents&lt;/code&gt; (&lt;code&gt;ArrayRange&amp;lt;Diff&amp;gt;&lt;/code&gt;);&lt;/li&gt;
    &lt;li id=&quot;OqOJ&quot;&gt;&lt;code&gt;ReferenceFrames&lt;/code&gt; (&lt;code&gt;ArrayRange&amp;lt;Frame&amp;gt;&lt;/code&gt;);&lt;/li&gt;
    &lt;li id=&quot;vbap&quot;&gt;&lt;code&gt;DisposedComponentIds&lt;/code&gt; (&lt;code&gt;ArrayRange&amp;lt;int&amp;gt;&lt;/code&gt;);&lt;/li&gt;
    &lt;li id=&quot;Bqcy&quot;&gt;&lt;code&gt;DisposedEventHandlerIds&lt;/code&gt; (&lt;code&gt;ArrayRange&amp;lt;long&amp;gt;&lt;/code&gt;);&lt;/li&gt;
    &lt;li id=&quot;Ysgc&quot;&gt;&lt;code&gt;StringTable&lt;/code&gt; (&lt;code&gt;ArrayRange&amp;lt;string offsets&amp;gt;&lt;/code&gt;).&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;i66J&quot;&gt;В конце пакета находятся 5 чисел (&lt;code&gt;int32&lt;/code&gt;) — это смещения каждой секции в байтах (от начала массива).&lt;/p&gt;
  &lt;h3 id=&quot;lWZX&quot;&gt;Формат DOM&lt;/h3&gt;
  &lt;p id=&quot;YbF7&quot;&gt;Сами узлы DOM хранятся в структуре под названием &lt;code&gt;RenderTreeFrame&lt;/code&gt;, одна структура может описывать:&lt;/p&gt;
  &lt;ul id=&quot;fvVX&quot;&gt;
    &lt;li id=&quot;Xzar&quot;&gt;HTML-тег;&lt;/li&gt;
    &lt;li id=&quot;vwKA&quot;&gt;текстовое значение;&lt;/li&gt;
    &lt;li id=&quot;wtOv&quot;&gt;атрибут;&lt;/li&gt;
    &lt;li id=&quot;02CK&quot;&gt;компонент Blazor;&lt;/li&gt;
    &lt;li id=&quot;rjgc&quot;&gt;&amp;quot;голый&amp;quot; HTML-фрагмент.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;lXmG&quot;&gt;Сам &lt;code&gt;RenderTreeFrame&lt;/code&gt; выглядит так:&lt;/p&gt;
  &lt;pre id=&quot;ZmRh&quot;&gt;[Тип фрейма][Параметр 1][Параметр 2][Параметр 3][Параметр 4]&lt;/pre&gt;
  &lt;p id=&quot;Y8AP&quot;&gt;Тип фрейма определяет, что это за узел:&lt;/p&gt;
  &lt;ul id=&quot;XuGh&quot;&gt;
    &lt;li id=&quot;AwWs&quot;&gt;1 - HTML-тег (&lt;code&gt;Element&lt;/code&gt;);&lt;/li&gt;
    &lt;li id=&quot;eCKh&quot;&gt;2 - текст (&lt;code&gt;Text&lt;/code&gt;);&lt;/li&gt;
    &lt;li id=&quot;7s2a&quot;&gt;3 - атрибут (&lt;code&gt;Attribute&lt;/code&gt;);&lt;/li&gt;
    &lt;li id=&quot;VqoK&quot;&gt;4 - Компонент Blazor (&lt;code&gt;Component&lt;/code&gt;);&lt;/li&gt;
    &lt;li id=&quot;Rc5z&quot;&gt;5 - Регион (Служебные данные) (&lt;code&gt;Region&lt;/code&gt;);&lt;/li&gt;
    &lt;li id=&quot;psSN&quot;&gt;8 - &amp;quot;Голый&amp;quot; HTML (&lt;code&gt;Markup&lt;/code&gt;).&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h3 id=&quot;hMRf&quot;&gt;Таблица строк&lt;/h3&gt;
  &lt;p id=&quot;iyB3&quot;&gt;Чтобы не дублировать текст, все строки (имена тегов, атрибуты, значения, текст)&lt;br /&gt;хранятся в конце пакета в таблице строк.&lt;/p&gt;
  &lt;p id=&quot;tqT0&quot;&gt;Каждая запись содержит смещение на строку, а сами строки записаны как:&lt;/p&gt;
  &lt;pre id=&quot;C2yU&quot;&gt;[LEB128-длина][UTF-8 байты строки]&lt;/pre&gt;
  &lt;h3 id=&quot;txRS&quot;&gt;Процесс восстановления HTML&lt;/h3&gt;
  &lt;ol id=&quot;13xH&quot;&gt;
    &lt;li id=&quot;DcYH&quot;&gt;Берём &lt;code&gt;RenderBatch&lt;/code&gt; полученный от SignalR&lt;/li&gt;
    &lt;li id=&quot;tjGq&quot;&gt;Читаем 5 чисел в конце файла - получаем смещение секций&lt;/li&gt;
    &lt;li id=&quot;MufW&quot;&gt;Переходим в секцию &lt;code&gt;ReferenceFrames&lt;/code&gt; - получаем все узлы дерева (&lt;code&gt;RenderTreeFrame&lt;/code&gt;)&lt;/li&gt;
    &lt;li id=&quot;hY2k&quot;&gt;Последовательно читаем фреймы:&lt;br /&gt;- если &lt;code&gt;Element&lt;/code&gt; - создаём элемент;&lt;br /&gt;- если &lt;code&gt;Attribute&lt;/code&gt; - добавляем к предыдущему тегу;&lt;br /&gt;- если &lt;code&gt;Text&lt;/code&gt; - вставляем текстовое содержимое в предыдущий тег;&lt;br /&gt;- если &lt;code&gt;Markup&lt;/code&gt; - вставляем HTML как есть;&lt;br /&gt;- если &lt;code&gt;Region&lt;/code&gt; - рекурсивно обрабатываем последующие фреймы;&lt;/li&gt;
    &lt;li id=&quot;UQD3&quot;&gt;Используем свойство subtreeLength, чтобы понять, где заканчивается элемент;&lt;/li&gt;
    &lt;li id=&quot;HI3g&quot;&gt;Склеиваем всё в строку и получаем HTML.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;i6lS&quot;&gt;&lt;strong&gt;P.S Реализация TS библиотеки доступна &lt;a href=&quot;https://github.com/li0ard/renderbatch&quot; target=&quot;_blank&quot;&gt;здесь&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

</content></entry><entry><id>li0ard:rutoken_export_p2</id><link rel="alternate" type="text/html" href="https://blog.li0ard.rest/rutoken_export_p2?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=li0ard"></link><title>Тащим ключи с Рутокен Lite (ч.2)</title><published>2025-08-09T16:59:07.277Z</published><updated>2026-05-06T16:05:48.951Z</updated><category term="rutoken_export" label="Тащим ключи с Рутокен Lite"></category><summary type="html">&lt;img src=&quot;https://img2.teletype.in/files/1b/40/1b40aa91-6c20-4034-a705-f1fcf4d68cf9.png&quot;&gt;В предыдущей статье, я описал способ экспорта ключей с Рутокен Lite вручную, в этой же статье будет инструкция по экспорту автоматизированным способом.</summary><content type="html">
  &lt;p id=&quot;AkKu&quot;&gt;В &lt;a href=&quot;https://teletype.in/@li0ard/rutoken_export&quot; target=&quot;_blank&quot;&gt;предыдущей статье&lt;/a&gt;, я описал способ экспорта ключей из Рутокен Lite вручную, в этой же статье будет инструкция по экспорту автоматизированным способом.&lt;/p&gt;
  &lt;p id=&quot;O7zM&quot;&gt;Нам понадобится:&lt;/p&gt;
  &lt;ol id=&quot;NQkI&quot;&gt;
    &lt;li id=&quot;F1Ed&quot;&gt;&lt;a href=&quot;https://github.com/li0ard/rutoken_export&quot; target=&quot;_blank&quot;&gt;Моя утилита&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;4VqY&quot;&gt;Сам Рутокен Lite и PIN-код пользователя&lt;/li&gt;
  &lt;/ol&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0, 0%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;1btQ&quot;&gt;&lt;strong&gt;Важно&lt;/strong&gt;: Данная статья предполагает, что у вас уже установлен компилятор Go&lt;/p&gt;
  &lt;/section&gt;
  &lt;ol id=&quot;OTJu&quot;&gt;
    &lt;li id=&quot;CuSn&quot;&gt;Клонируем репозиторий и переходим в папку с кодом&lt;/li&gt;
    &lt;li id=&quot;zsTS&quot;&gt;Собираем утилиту с помощью &lt;code&gt;go build&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;qjyh&quot;&gt;Запускаем утилиту, вводим PIN-код пользователя, и вводим метку (см. ниже) нужного контейнера&lt;/li&gt;
  &lt;/ol&gt;
  &lt;figure id=&quot;qa7l&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/1b/40/1b40aa91-6c20-4034-a705-f1fcf4d68cf9.png&quot; width=&quot;593&quot; /&gt;
    &lt;figcaption&gt;Пример работы&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;QFf5&quot;&gt;В указанной утилитой папке будет лежать экспортированный контейнер&lt;/p&gt;
  &lt;figure id=&quot;mWmC&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/0c/b2/0cb28bae-f772-41ef-98a3-d60c71834c66.png&quot; width=&quot;618&quot; /&gt;
  &lt;/figure&gt;

</content></entry><entry><id>li0ard:rutoken_export</id><link rel="alternate" type="text/html" href="https://blog.li0ard.rest/rutoken_export?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=li0ard"></link><title>Тащим ключи с Рутокен Lite</title><published>2025-08-03T17:23:14.015Z</published><updated>2026-05-06T11:45:33.666Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img2.teletype.in/files/98/bc/98bc0167-357c-4188-b336-7b6de337e139.png"></media:thumbnail><category term="rutoken_export" label="Тащим ключи с Рутокен Lite"></category><summary type="html">&lt;img src=&quot;https://img4.teletype.in/files/b8/8b/b88b54ca-631e-4511-887e-f583e59a7d39.png&quot;&gt;Думаю многим знакома ситуация, когда ФНС (или любой другой УЦ) записывает контейнер с ЭЦП на Рутокен, а в процессе использования возникает необходимость использования ЭЦП без самого Рутокена (например из файловой системы) и т.д.</summary><content type="html">
  &lt;figure id=&quot;AaR9&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b8/8b/b88b54ca-631e-4511-887e-f583e59a7d39.png&quot; width=&quot;1280&quot; /&gt;
    &lt;figcaption&gt;Суть такова&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;tEny&quot;&gt;Думаю многим знакома ситуация, когда ФНС (или любой другой УЦ) записывает контейнер с ЭЦП на Рутокен, а в процессе использования возникает необходимость использования ЭЦП без самого Рутокена (например из файловой системы) и т.д.&lt;/p&gt;
  &lt;p id=&quot;yaXO&quot;&gt;Однако та же ФНС &lt;strong&gt;&amp;quot;отключает&amp;quot; флаг экспортируемости&lt;/strong&gt; контейнера и при попытке экспорта ключа мы получаем ошибку, а в Центре управления Рутокен&amp;#x27;ом есть возможность только экспортировать сертификат.&lt;/p&gt;
  &lt;figure id=&quot;gDcM&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/79/7c/797c65f7-1f7f-4990-acbd-19014118a520.png&quot; width=&quot;1019&quot; /&gt;
    &lt;figcaption&gt;Скриншот из Центре управления Рутокен&amp;#x27;ом&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;6SJl&quot;&gt;Также следует упомянуть, что существует популярная утилита Tokens.exe от СКБ Контур, однако у неё есть ряд недостатков:&lt;/p&gt;
  &lt;ol id=&quot;OCrr&quot;&gt;
    &lt;li id=&quot;jLy2&quot;&gt;Утилита работает только на Windows&lt;/li&gt;
    &lt;li id=&quot;b6BM&quot;&gt;Написана на HTML с использованием устаревшего ActiveXObject с связке с DLL&lt;/li&gt;
    &lt;li id=&quot;N26s&quot;&gt;Утилиту благополучно &amp;quot;выпилили&amp;quot; с сайта, поэтому приходится искать по всему интернету&lt;/li&gt;
  &lt;/ol&gt;
  &lt;h2 id=&quot;IlRW&quot;&gt;Тащим ключи&lt;/h2&gt;
  &lt;h3 id=&quot;Byue&quot;&gt;1. Ищем контейнер&lt;/h3&gt;
  &lt;p id=&quot;fFlw&quot;&gt;Рутокен Lite - не совсем флешка в привычном понимании, у него максимально облегченная файловая система, поэтому просто открыть его в проводнике не получится&lt;/p&gt;
  &lt;p id=&quot;cWsB&quot;&gt;Однако для этих целей можно воспользоваться утилитами от проекта &lt;a href=&quot;https://github.com/OpenSC/OpenSC&quot; target=&quot;_blank&quot;&gt;OpenSC&lt;/a&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0, 0%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;lOiM&quot;&gt;&lt;strong&gt;Важно&lt;/strong&gt;: Данная статья предполагает, что у вас уже установлены &lt;code&gt;opensc-tool&lt;/code&gt; и &lt;code&gt;opensc-explorer&lt;/code&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;Z50H&quot;&gt;Поэтому подключаем Рутокен, открываем консоль и вводим &lt;code&gt;opensc-tool --list-files&lt;/code&gt;&lt;/p&gt;
  &lt;figure id=&quot;2JAE&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/49/41/49411806-5802-4a2c-b4c5-fa5e01e54a8d.png&quot; width=&quot;815&quot; /&gt;
    &lt;figcaption&gt;Файловая система Рутокена&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;tMMJ&quot;&gt;Среди всего списка необходимо найти директорию с 6 файлами, часть из которых доступна для чтения только после авторизации (&lt;code&gt;read[CHV2]&lt;/code&gt;). Сделать это легче всего по имени контейнера в КриптоПро, поскольку &lt;code&gt;opensc-tool&lt;/code&gt; декодирует ASCII текст:&lt;/p&gt;
  &lt;figure id=&quot;aGlN&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/21/1d/211de796-f6e7-4ba2-8ae7-ffb7b5ad25c3.png&quot; width=&quot;1366&quot; /&gt;
    &lt;figcaption&gt;Совпадение имени контейнера с содержимым файла на Рутокене&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;zCiG&quot;&gt;Файл на скриншоте это &lt;code&gt;name.key&lt;/code&gt;, а директория с контейнером (выделена жёлтым) в нашем случае будет &lt;code&gt;3f00100010030a00&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;9R9N&quot;&gt;&lt;strong&gt;UPD от 05.08&lt;/strong&gt;: Вероятнее всего все контейнеры действительно лежат по пути &lt;code&gt;1000/1003&lt;/code&gt;. Соответственно при помощи команды asn1 искать по имени контейнера:&lt;/p&gt;
  &lt;figure id=&quot;aHQk&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/d2/ee/d2ee69b4-f56d-4cbb-9d23-fe171bf9f709.png&quot; width=&quot;809&quot; /&gt;
    &lt;figcaption&gt;name.key и header.key второго контейнера на Рутокене&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h3 id=&quot;3San&quot;&gt;2. Выгрузка&lt;/h3&gt;
  &lt;p id=&quot;3k7m&quot;&gt;Запускаем &lt;code&gt;opensc-explorer&lt;/code&gt; и переходим в директорию контейнера с помощью команды &lt;code&gt;cd &amp;lt;путь&amp;gt;&lt;/code&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0, 0%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;Yzxm&quot;&gt;&lt;strong&gt;Важно&lt;/strong&gt;: Необходимо разделить путь директории на группы по 4 символа и убрать &lt;code&gt;3f00&lt;/code&gt;, в нашем случае это будет &lt;code&gt;1000&lt;/code&gt;, &lt;code&gt;1003&lt;/code&gt;, &lt;code&gt;0a00&lt;/code&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;figure id=&quot;dGCj&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/7e/bd/7ebd7d39-532a-4133-af66-95cf2bc5ac2f.png&quot; width=&quot;457&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;hV8A&quot;&gt;В директории файлы лежат в следующем порядке: &lt;code&gt;name.key&lt;/code&gt;, &lt;code&gt;header.key&lt;/code&gt;, &lt;code&gt;primary.key&lt;/code&gt;, &lt;code&gt;masks.key&lt;/code&gt;, &lt;code&gt;primary2.key&lt;/code&gt;, &lt;code&gt;masks2.key&lt;/code&gt;&lt;/p&gt;
  &lt;figure id=&quot;wQ2G&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/a3/72/a3728a84-797b-4b8a-af1d-808bbd4f3bcf.png&quot; width=&quot;357&quot; /&gt;
    &lt;figcaption&gt;Файлы контейнера&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;PMVf&quot;&gt;Теперь самый важный пункт - необходимо авторизоваться по PIN-коду пользователя (в противном случае Рутокен даст выгрузить только &lt;code&gt;name.key&lt;/code&gt; и &lt;code&gt;header.key&lt;/code&gt;). Сделать это можно с помощью команды &lt;code&gt;verify CHV2 &amp;quot;PIN-код&amp;quot;&lt;/code&gt;&lt;/p&gt;
  &lt;figure id=&quot;Inqq&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/24/6c/246c2b0d-8fc6-4df7-8a1c-cece3675eab1.png&quot; width=&quot;438&quot; /&gt;
    &lt;figcaption&gt;Успешная авторизация&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;dIOi&quot;&gt;Теперь же просто копируем файлы контейнера в память компьютера с помощью команды &lt;code&gt;get File_ID путь_назначения&lt;/code&gt;&lt;/p&gt;
  &lt;figure id=&quot;8fHq&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c6/df/c6dfa3e9-8ad7-4ae5-8ef0-b4e351dac4a8.png&quot; width=&quot;609&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;JpuC&quot;&gt;На этом всё, мы успешно скопировали контейнер с Рутокен Lite в память нашего компьютера. Далее желательно &amp;quot;пролечить&amp;quot; контейнер, чтобы &amp;quot;включить&amp;quot; флаг экспортируемости, но на текущий момент решение ещё в разработке (оповещение о релизе будет в Telegram канале). &lt;em&gt;To be continued...&lt;/em&gt;&lt;/p&gt;
  &lt;h2 id=&quot;Hybq&quot;&gt;Бонус. Экспорт приватного ключа&lt;/h2&gt;
  &lt;p id=&quot;l7us&quot;&gt;Для удобства использования ключа подписи, его можно экспортировать в формат &lt;code&gt;.pem&lt;/code&gt; (с которым умеет работать OpenSSL и прочие утилиты) с помощью моей онлайн-утилиты&lt;br /&gt;В утилиту загружаем файлы &lt;code&gt;header.key&lt;/code&gt;, &lt;code&gt;masks.key&lt;/code&gt; и &lt;code&gt;primary.key&lt;/code&gt;, поле &amp;quot;Пароль&amp;quot; оставляем пустым (поскольку контейнеры на Рутокенах не имеют пароля т.к происходит авторизация по PIN-коду) и нажимаем &amp;quot;Извлечь&amp;quot;, через несколько секунд скачается &lt;code&gt;.pem&lt;/code&gt; файл с приватным ключом.&lt;/p&gt;
  &lt;figure id=&quot;qvCN&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/0c/7c/0c7ce9c1-2f98-4f27-b65c-7bd45e5d62a2.png&quot; width=&quot;1344&quot; /&gt;
  &lt;/figure&gt;

</content></entry><entry><id>li0ard:wtfiskeeloq</id><link rel="alternate" type="text/html" href="https://blog.li0ard.rest/wtfiskeeloq?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=li0ard"></link><title>KeeLoq и с чем его едят</title><published>2025-05-27T20:27:42.908Z</published><updated>2025-07-08T06:50:33.706Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img2.teletype.in/files/d2/31/d231606d-6bef-4de9-9ebc-c2d8b9f57b54.png"></media:thumbnail><category term="kriptografiya" label="Криптография"></category><summary type="html">&lt;img src=&quot;https://img3.teletype.in/files/e4/f3/e4f33756-7577-44fd-9681-ecc6ab3684e8.png&quot;&gt;KeeLoq - блочный шифр, основанный на NLFSR...</summary><content type="html">
  &lt;nav&gt;
    &lt;ul&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#XZoD&quot;&gt;Принцип работы&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#iRjJ&quot;&gt;Режимы безопасности&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#kATQ&quot;&gt;Теоретические атаки&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#LK6k&quot;&gt;Слайд-атака&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#xUzg&quot;&gt;Корреляционный подход&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#UXF8&quot;&gt;Линейный шаг&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#MlSn&quot;&gt;Практические атаки&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#QeWA&quot;&gt;Replay-атака&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#hrtX&quot;&gt;Клонирование пульта&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#EVpD&quot;&gt;Future-атака&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#tacj&quot;&gt;Rollback-атака&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#jCpe&quot;&gt;Rolljam-атака&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#ckqu&quot;&gt;Атака на мануфактурные ключи (KGB attack)&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#tLCW&quot;&gt;Enc00-атака&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#wSBY&quot;&gt;Unknown-атака&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_1&quot;&gt;&lt;a href=&quot;#5cd7&quot;&gt;Заключение&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;m_level_2&quot;&gt;&lt;a href=&quot;#34Ux&quot;&gt;Использованные материалы&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/nav&gt;
  &lt;p id=&quot;kioG&quot;&gt;Итак, начнём с выдержки из Википедии:&lt;/p&gt;
  &lt;blockquote id=&quot;zIMz&quot;&gt;&lt;strong&gt;KeeLoq&lt;/strong&gt; - блочный шифр, основанный на NLFSR (регистр сдвига с нелинейной обратной связью), разработан компанией Nanoteq Pty Ltd. и продан компании Microchip Technology Inc. Шифрование происходит блоками по 32 бита с помощью 64 битного ключа за 528 итераций. Ранее использовался в автомобильных сигнализациях, а ныне используется в автоматических воротах, гаражных дверях и т.п&lt;/blockquote&gt;
  &lt;figure id=&quot;j3FI&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e4/f3/e4f33756-7577-44fd-9681-ecc6ab3684e8.png&quot; width=&quot;675&quot; /&gt;
    &lt;figcaption&gt;Картинка для привлечения внимания &lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;XZoD&quot;&gt;Принцип работы&lt;/h2&gt;
  &lt;p id=&quot;96Cs&quot;&gt;KeeLoq реализует так называемый &lt;em&gt;code hopping&lt;/em&gt; (переключение кода), то есть генерирует уникальный пакет данных для каждой передачи.&lt;/p&gt;
  &lt;figure id=&quot;ZBv5&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/8e/87/8e8716b1-06de-449b-aca1-f2847a954798.png&quot; width=&quot;1050&quot; /&gt;
    &lt;figcaption&gt;Структура пакета данных&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Pfu4&quot;&gt;Разберём на примере:&lt;/p&gt;
  &lt;p id=&quot;T1Gp&quot; data-align=&quot;center&quot;&gt;&lt;code&gt;&lt;strong&gt;239B3DEB&lt;/strong&gt;F16C47A6&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;Gmjp&quot;&gt;Первые 4 байта - это фиксированная часть (т.н &lt;code&gt;fix&lt;/code&gt;), содержит в себе ID нажатой кнопки на пульте (в нашем случае &lt;code&gt;2&lt;/code&gt;) и 28&amp;#x27;ми битный серийный номер пульта (&lt;code&gt;&lt;strong&gt;39B3DEB&lt;/strong&gt;&lt;/code&gt;)&lt;/p&gt;
  &lt;p id=&quot;3RFP&quot;&gt;Следующие 4 байта - динамическая часть (т.н &lt;code&gt;hop&lt;/code&gt;), зашифрована мануфактурным ключом (ключом производителя). В расшифрованном виде выглядит так:&lt;/p&gt;
  &lt;p id=&quot;CuTc&quot; data-align=&quot;center&quot;&gt;&lt;code&gt;21EB000A&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;xhAC&quot;&gt;Здесь мы видим всё тот же ID нажатой кнопки (&lt;code&gt;2&lt;/code&gt;), 12 бит дополнительной информации (зачастую это &lt;code&gt;serial &amp;amp; 0x3FF&lt;/code&gt;) и сам 16 битный счётчик нажатий (&lt;code&gt;000A&lt;/code&gt;)&lt;/p&gt;
  &lt;p id=&quot;Sa0P&quot;&gt;Логика работы счётчика такая:&lt;/p&gt;
  &lt;ul id=&quot;O522&quot;&gt;
    &lt;li id=&quot;nH51&quot;&gt;Если переданное значение счётчика соответствует значению в EEPROM приёмника то приёмник подаёт сигнал контроллеру, что всё хорошо (и контроллер например открывает ворота)&lt;/li&gt;
  &lt;/ul&gt;
  &lt;figure id=&quot;lA81&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/07/44/07446e47-580e-4043-a0c0-37b32b7283f7.png&quot; width=&quot;796&quot; /&gt;
    &lt;figcaption&gt;Штатная работа приёмника&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;ul id=&quot;kL84&quot;&gt;
    &lt;li id=&quot;iVC0&quot;&gt;Если переданное значение больше значения в EEPROM то приёмник синхронизируется с переданным значением и соответственно после следующей передачи значения начнёт работать штатно&lt;/li&gt;
  &lt;/ul&gt;
  &lt;figure id=&quot;fd8Y&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/59/66/5966eef6-7b9d-4930-ab26-e9e21b95497c.png&quot; width=&quot;784&quot; /&gt;
    &lt;figcaption&gt;Процесс сихронизации приёмника&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;ul id=&quot;Q5S6&quot;&gt;
    &lt;li id=&quot;sY2m&quot;&gt;Если переданное значение меньше значения в EEPROM то приёмник игнорирует переданную команду, а в некоторых случаях после нескольких отправок &amp;quot;устаревшего&amp;quot; значения и вовсе отвязывает пульт. (Собственно говоря это и есть опасность при экспериментах с KeeLoq)&lt;/li&gt;
  &lt;/ul&gt;
  &lt;figure id=&quot;vsj9&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/6b/9c/6b9c0e69-07be-4a82-a569-4ecb7ecb1dcc.png&quot; width=&quot;860&quot; /&gt;
    &lt;figcaption&gt;Реакция на устаревшее значение счётчика и отвязка пульта&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;iRjJ&quot;&gt;Режимы безопасности&lt;/h2&gt;
  &lt;p id=&quot;S5EC&quot;&gt;В стандарте KeeLoq есть 3 режима безопасности (также известны как KDF, learnings):&lt;/p&gt;
  &lt;ul id=&quot;gAD1&quot;&gt;
    &lt;li id=&quot;AWTH&quot;&gt;&lt;strong&gt;Простой режим (Simple learning)&lt;/strong&gt;&lt;br /&gt;Наименее защищённый режим, при котором мануфактурный ключ никак не преобразуется и используется в шифровании as is.&lt;/li&gt;
    &lt;li id=&quot;O4Oo&quot;&gt;&lt;strong&gt;Классический режим (Normal learning)&lt;/strong&gt;&lt;br /&gt;Улучшенная версия, где мануфактурный ключ изменяется с помощью серийного номера пульта с помощью побитовых операций&lt;/li&gt;
  &lt;/ul&gt;
  &lt;figure id=&quot;kanv&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e6/56/e656f372-c5a5-4c28-ab78-1bb3a872f9fe.png&quot; width=&quot;525&quot; /&gt;
    &lt;figcaption&gt;Примерная запись алгоритма&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;ul id=&quot;qKp3&quot;&gt;
    &lt;li id=&quot;C09x&quot;&gt;&lt;strong&gt;Безопасный режим (Secure learning)&lt;/strong&gt;&lt;br /&gt;Модифицированная версия классического режима, использующая вместо побитовых операций над серийным номером, дополнительное значение (он же seed), уникальное для каждого пульта и передающееся при первоначальной привязке пульта к приёмнику. На данный момент самый защищённых режим из представленных в стандарте&lt;/li&gt;
  &lt;/ul&gt;
  &lt;figure id=&quot;jZiQ&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/4a/55/4a5598d6-fbf5-4438-b411-f3f1b0d80c3f.png&quot; width=&quot;496&quot; /&gt;
    &lt;figcaption&gt;Примерная запись алгоритма&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;N8p0&quot;&gt;Однако некоторые производители отклоняются от стандартных режимов безопасности и реализуют свои собственные, давайте рассмотрим некоторые из них:&lt;/p&gt;
  &lt;ul id=&quot;nUV6&quot;&gt;
    &lt;li id=&quot;YvOw&quot;&gt;&lt;strong&gt;Magic XOR Type-1 learning&lt;/strong&gt;&lt;br /&gt;Используется производителем Beninca, представляет из себя XOR серийного номера пульта на мануфактурный ключ&lt;/li&gt;
  &lt;/ul&gt;
  &lt;figure id=&quot;0wgO&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/d8/8a/d88a7eb1-9a74-4566-8aa7-0f3984286a8e.png&quot; width=&quot;357&quot; /&gt;
    &lt;figcaption&gt;Примерная запись алгоритма&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;ul id=&quot;gLs7&quot;&gt;
    &lt;li id=&quot;lKNt&quot;&gt;&lt;strong&gt;FAAC SLH (SPA) learning&lt;/strong&gt;&lt;br /&gt;Как понятно из названия, данный алгоритм используется производителем FAAC и по моему мнению является самым продуманным. Представляет из себя серию побитовых операций и шифрования&lt;/li&gt;
  &lt;/ul&gt;
  &lt;figure id=&quot;RRK3&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/eb/26/eb26511a-62ba-4234-9467-15d55ee36454.png&quot; width=&quot;360&quot; /&gt;
    &lt;figcaption&gt;Примерная запись алгоритма&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;kATQ&quot;&gt;Теоретические атаки&lt;/h2&gt;
  &lt;h3 id=&quot;LK6k&quot;&gt;Слайд-атака&lt;/h3&gt;
  &lt;p id=&quot;bolB&quot;&gt;Атака применима, преимущественно, к многораундовым кодам, каждый раунд которых представляет собой несложное преобразование исходного блока с использованием лишь одного ключа.&lt;/p&gt;
  &lt;p id=&quot;H8XD&quot;&gt;На первом этапе набрать порядка 2^32 пар открытый-зашифрованный текст&lt;br /&gt;Далее &lt;code&gt;(M,C)&lt;/code&gt; - одна из таких пар, &lt;code&gt;F&lt;/code&gt; - функция преобразования. Суть такова:&lt;br /&gt;если &lt;code&gt;(M’,C’)&lt;/code&gt; такая, что &lt;code&gt;P’= F(K,M)&lt;/code&gt; и &lt;code&gt;C’= F(K,C)&lt;/code&gt;, то &lt;code&gt;K&lt;/code&gt; и есть искомый ключ.&lt;/p&gt;
  &lt;p id=&quot;xXtN&quot;&gt;В теории данная атака позволяет получить первые 32 бита ключа.&lt;/p&gt;
  &lt;h3 id=&quot;xUzg&quot;&gt;Корреляционный подход&lt;/h3&gt;
  &lt;p id=&quot;pbUD&quot;&gt;Атака базируется на свойстве NLFSR - &lt;code&gt;Cor(F) = 1&lt;/code&gt;&lt;br /&gt;Оказывается, что для равномерно распределенных &lt;code&gt;x2,x3,x4&lt;/code&gt; имеет место следующее:&lt;/p&gt;
  &lt;ul id=&quot;FylO&quot;&gt;
    &lt;li id=&quot;jusg&quot;&gt;&lt;code&gt;{NLFSR(x4, x3, x2, x1, x0) = 0 | x0 ^ x1 = 0} = 5/8&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;DHFP&quot;&gt;&lt;code&gt;{NLFSR(x4, x3, x2, x1, x0) = 1 | x0 ^ x1 = 1} = 5/8&lt;/code&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;50G9&quot;&gt;Используя это и аппроксимируя NLFSR вероятности, можно добиться определения очередной части ключа.&lt;/p&gt;
  &lt;h3 id=&quot;UXF8&quot;&gt;Линейный шаг&lt;/h3&gt;
  &lt;p id=&quot;DRsM&quot;&gt;Последние 16 бит ключа определяются, если известны все предыдущие. Основываясь на том, что если мы знаем полностью 48 состояние в цикле,то можем записать:&lt;/p&gt;
  &lt;figure id=&quot;d9uN&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/4b/c1/4bc11943-61af-4270-8db5-855441752ef3.png&quot; width=&quot;499&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;QhAw&quot;&gt;Отсюда находим &lt;code&gt;key^48&lt;/code&gt; и аналогично &lt;code&gt;key^49 ... key^63&lt;/code&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;GNb7&quot;&gt;Общая сложность всех теоретических атак - ≈2^52 (≈4503599627370496)&lt;/p&gt;
  &lt;h2 id=&quot;MlSn&quot;&gt;Практические атаки&lt;/h2&gt;
  &lt;p id=&quot;N1Bb&quot;&gt;Здесь я хочу поблагодарить &lt;a href=&quot;https://github.com/jamisonderek&quot; target=&quot;_blank&quot;&gt;Derek Jamison&lt;/a&gt; за прекрасные материалы по практическим атакам на KeeLoq&lt;/p&gt;
  &lt;h3 id=&quot;QeWA&quot;&gt;Replay-атака&lt;/h3&gt;
  &lt;figure id=&quot;VXZr&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/f1/49/f149c351-07ba-4de2-ad91-7b1c8a2f9661.png&quot; width=&quot;1236&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;SjbV&quot;&gt;Очень распространённая атака работающая, преимущественно, для статических кодов, и для уявизмых приёмников, которые не проверяют значение счётчика&lt;/p&gt;
  &lt;h3 id=&quot;hrtX&quot;&gt;Клонирование пульта&lt;/h3&gt;
  &lt;figure id=&quot;qYAy&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/5a/2f/5a2f5185-87fd-4498-b619-680a4da622fc.png&quot; width=&quot;1200&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;esSo&quot;&gt;Если мы знаем мануфактурный ключ пульта то без проблем можем сделать копию, которая будет работать, однако делать так не рекомендуется т.к будет конфликт значения счётчика у оригинального пульта и у копии, и в результате при использования двух пультов (оригинального и копии) приёмник может просто отвязать ваш пульт&lt;/p&gt;
  &lt;h3 id=&quot;EVpD&quot;&gt;Future-атака&lt;/h3&gt;
  &lt;figure id=&quot;IDuB&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/6f/47/6f478059-d942-4e1a-abaf-e7f14b29efd1.png&quot; width=&quot;1216&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;LebV&quot;&gt;Если мы знаем мануфактурный ключ пульта то можно воспользоваться логикой работы счётчика и отправить &amp;quot;будущее&amp;quot; значение счётчика (было &lt;code&gt;0001&lt;/code&gt; - стало &lt;code&gt;3E91&lt;/code&gt;), приёмник может подумать, что пульт &amp;quot;убежал&amp;quot; далеко вперёд и синхронизироваться с переданным значением и штатно работать со следующими значениями (&lt;code&gt;3E92&lt;/code&gt;, &lt;code&gt;3E93&lt;/code&gt; и т.п). При данной атаке оригинальный пульт полностью рассинхронизируется и дальнейшее его использования не рекомендуется &lt;a href=&quot;#esSo&quot;&gt;по описанным выше причинам&lt;/a&gt;. &lt;/p&gt;
  &lt;h3 id=&quot;tacj&quot;&gt;Rollback-атака&lt;/h3&gt;
  &lt;figure id=&quot;aopX&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/dc/8a/dc8ada19-3fb1-4e2a-83fc-4364837e1689.png&quot; width=&quot;1233&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;FJ7C&quot;&gt;Данная атака весьма редкая, однако всё же возможна с некоторыми приёмниками. Она похожа на Future-атаку, однако вместо последующих значений, мы откатываем состояние счётчика после нескольких использований и приёмник может заново синхронизироваться с этими значениями.&lt;/p&gt;
  &lt;h3 id=&quot;jCpe&quot;&gt;Rolljam-атака&lt;/h3&gt;
  &lt;figure id=&quot;66PT&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/0e/89/0e89ffba-3d7d-4ee7-9c34-4172190432d0.png&quot; width=&quot;1231&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;KfTJ&quot;&gt;Вся суть атаки в том, что вы записываете сигналы с оригинального пульта и не даёте приёмнику получить их (например создавая помехи рядом с приёмником), после чего вы можете использовать записанные сигналы.&lt;/p&gt;
  &lt;p id=&quot;Ok8c&quot;&gt;Однако следует учесть, что почти во всех странах (&lt;a href=&quot;https://www.fcc.gov/general/jammer-enforcement&quot; target=&quot;_blank&quot;&gt;например в США&lt;/a&gt;, странах ЕС, &lt;a href=&quot;https://www.consultant.ru/document/cons_doc_LAW_34661/acaefaec257669702f20b2a36e96381e17d50f52/&quot; target=&quot;_blank&quot;&gt;РФ&lt;/a&gt;) глушение сигналов является незаконным.&lt;/p&gt;
  &lt;h3 id=&quot;ckqu&quot;&gt;Атака на мануфактурные ключи (KGB attack)&lt;/h3&gt;
  &lt;figure id=&quot;pPGX&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/ff/f5/fff5633b-1266-47a8-98ac-9a313ce4db9f.png&quot; width=&quot;1218&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Q0cY&quot;&gt;Идея заключается в том, что, возможно, приёмник умеет работать с несколькими мануфактурными ключами, а не только с одним. Если мы отправим &lt;code&gt;fix&lt;/code&gt; от оригинального пульта, но закодируем счётчик с помощью другого мануфактурного ключа, то, возможно, оно откроется (обычно эту атаку комбинируют с Future-атакой, потому что вы не знаете, каким должно быть значение счётчика).&lt;/p&gt;
  &lt;h3 id=&quot;tLCW&quot;&gt;Enc00-атака&lt;/h3&gt;
  &lt;figure id=&quot;me8y&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/a2/d2/a2d2f01c-d90c-437a-abb8-579a9f901322.png&quot; width=&quot;1408&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;GkM9&quot;&gt;Атака представляет собой подмену &lt;code&gt;fix&lt;/code&gt; оригинального пульта на &lt;code&gt;fix&lt;/code&gt; другого пульта (также привязанного к приёмнику) и использование &lt;code&gt;hop&lt;/code&gt; с оригинального пульта. &lt;/p&gt;
  &lt;p id=&quot;4hTT&quot;&gt;&lt;strong&gt;Важно, что после подмены, пульт, &lt;code&gt;fix&lt;/code&gt; которого использовали, рассинхронизируется и перестаёт работать&lt;/strong&gt;&lt;/p&gt;
  &lt;h3 id=&quot;wSBY&quot;&gt;Unknown-атака&lt;/h3&gt;
  &lt;figure id=&quot;BxwY&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/1b/99/1b9931cd-d718-4d16-8d36-ac5238574bfc.png&quot; width=&quot;1216&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;da9s&quot;&gt;Суть в том, что, когда приёмник не может декодировать &lt;code&gt;hop&lt;/code&gt;, он использует значение 0. Для универсальных приёмников есть вероятность, что они откроются при значении 0.&lt;/p&gt;
  &lt;h2 id=&quot;5cd7&quot;&gt;Заключение&lt;/h2&gt;
  &lt;p id=&quot;LRM8&quot;&gt;Не смотря на все описанные выше уязвимости, KeeLoq, также как и Mifare Classic (чей шифр Crypto-1 был взломан в далёких 2000x) остаётся популярным выбором для бюджетных систем безопасности (автоматические ворота, гаражные двери и т.п). Возможно в будущем все производители перейдут на более стойкие алгоритмы шифрования (например на AES), как это сделали Beninca и Hormann&lt;/p&gt;
  &lt;p id=&quot;3kdg&quot;&gt;Кстати, имея на руках мануфактурный ключ вы можете &amp;quot;поиграться&amp;quot; с KeeLoq онлайн в &lt;a href=&quot;http://li0ard.rest/apps/keeloq&quot; target=&quot;_blank&quot;&gt;моём мини-приложении&lt;/a&gt;.&lt;/p&gt;
  &lt;h3 id=&quot;34Ux&quot;&gt;Использованные материалы&lt;/h3&gt;
  &lt;ol id=&quot;k2eR&quot;&gt;
    &lt;li id=&quot;4Jp7&quot;&gt;&lt;a href=&quot;https://github.com/li0ard/keeloq/&quot; target=&quot;_blank&quot;&gt;Моя собственная библиотека для работы с KeeLoq&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;vDmX&quot;&gt;&lt;a href=&quot;https://github.com/DarkFlippers/unleashed-firmware/&quot; target=&quot;_blank&quot;&gt;Исходный код Unleashed Firmware для Flipper Zero&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;oj28&quot;&gt;&lt;a href=&quot;https://github.com/jamisonderek/flipper-zero-tutorials/tree/main/subghz/apps/rolling-flaws&quot; target=&quot;_blank&quot;&gt;Материалы Derek Jamison по KeeLoq и его приложение &amp;quot;SubGHZ Rolling Flaws&amp;quot;&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;

</content></entry><entry><id>li0ard:reviving_t5577</id><link rel="alternate" type="text/html" href="https://blog.li0ard.rest/reviving_t5577?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=li0ard"></link><title>Чиним T5577 с помощью proxmark3</title><published>2025-04-09T21:27:32.942Z</published><updated>2025-04-26T19:25:14.219Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img1.teletype.in/files/42/99/429977fd-5669-48e4-bde1-b429a5eac76c.png"></media:thumbnail><category term="proxmark-3" label="proxmark3"></category><summary type="html">&lt;img src=&quot;https://img4.teletype.in/files/77/8c/778c5307-c3eb-4b33-ab76-bef2cb61069c.png&quot;&gt;Однажды экспериментировав с конфигурацией метки T5577, я получил в результате метку (даже две), которая нормально не определялась через lf search, либо определялась как Valid Indala ID found!.</summary><content type="html">
  &lt;p id=&quot;6PXB&quot;&gt;Однажды экспериментировав с конфигурацией метки T5577, я получил в результате метку (даже две), которая нормально не определялась через &lt;code&gt;lf search&lt;/code&gt;, либо определялась как &lt;code&gt;Valid Indala ID found!&lt;/code&gt;.&lt;/p&gt;
  &lt;figure id=&quot;j9qu&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/77/8c/778c5307-c3eb-4b33-ab76-bef2cb61069c.png&quot; width=&quot;678&quot; /&gt;
    &lt;figcaption&gt;Valid Indala ID found!, а ведь метка была EM-Marine....&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;bxEK&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b5/97/b5977b3a-c02b-4835-ad66-11eb4dda1698.png&quot; width=&quot;1041&quot; /&gt;
    &lt;figcaption&gt;А теперь определяется как ASK и PSK одновременно...&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;lNf3&quot;&gt;Скорее жив чем мёртв?&lt;/h2&gt;
  &lt;p id=&quot;4tlB&quot;&gt;Учитывая, что метка всё-таки как-то определялась, то необходимость использования команды &lt;code&gt;lf tune&lt;/code&gt; отпадала сама собой.&lt;/p&gt;
  &lt;p id=&quot;UwNK&quot;&gt;Поэтому необходимо было определить, может ли proxmark3 считать конфигурацию чипа через &lt;code&gt;lf t55xx [detect / p1detect]&lt;/code&gt;. Введя команду, я получил следующий ответ:&lt;/p&gt;
  &lt;pre id=&quot;lnnA&quot;&gt;[!] Could not detect modulation automatically. Try setting it manually with &amp;#x27;lf t55xx config&amp;#x27;&lt;/pre&gt;
  &lt;p id=&quot;jqyi&quot;&gt;Что ж, ещё не всё потеряно...&lt;/p&gt;
  &lt;h2 id=&quot;zqOZ&quot;&gt;Принудительное оживление&lt;/h2&gt;
  &lt;p id=&quot;9g9H&quot;&gt;Следующим шагом была попытка перезаписать нулевой блок метки, отвечающий за конфигурацию. Я делал это следующими командами:&lt;/p&gt;
  &lt;pre id=&quot;iDxQ&quot;&gt;lf t55xx write -b 0 -d 000880E0 -t
lf t55xx write -b 0 -d 000880E0 --r0 -t
lf t55xx write -b 0 -d 000880E0 --r1 -t
lf t55xx write -b 0 -d 000880E0 --r2 -t
lf t55xx write -b 0 -d 000880E0 --r3 -t&lt;/pre&gt;
  &lt;p id=&quot;3L7P&quot;&gt;После чего я проверил метку командой &lt;code&gt;lf t55xx detect&lt;/code&gt; и... видимо, одна из команд сработала:&lt;/p&gt;
  &lt;figure id=&quot;XJp7&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/a9/f4/a9f49b9a-bbc3-4a61-8a0e-be40e6e6155b.png&quot; width=&quot;402&quot; /&gt;
    &lt;figcaption&gt;Метку удалось вернуть к работе на конфигурации по умолчанию&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;VPXN&quot;&gt;После чего я попробовал записать на метку какой нибудь рандомный EM-Marine ID и считать его, это сработало!&lt;/p&gt;
  &lt;figure id=&quot;V1GQ&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/3a/fb/3afb5452-b162-49c7-b6c7-71f2952fec5b.png&quot; width=&quot;635&quot; /&gt;
    &lt;figcaption&gt;Метка заработала в стандарте EM-Marine&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;QRWu&quot;&gt;Заключение&lt;/h2&gt;
  &lt;p id=&quot;9a3T&quot;&gt;Получилась весьма короткая статья, но я думаю, она кому-нибудь да пригодится.&lt;/p&gt;
  &lt;p id=&quot;8uxe&quot;&gt;Вообще, восстановление работоспособности T5577 - это довольно-таки индивидуальная тема. То, что работает в одних случаях, может не работать в других.&lt;/p&gt;
  &lt;figure id=&quot;MIwg&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/78/62/78621bca-cc25-443c-a549-36d4ce69c489.png&quot; width=&quot;764&quot; /&gt;
    &lt;figcaption&gt;Многообразие решений на форуме Dangerous Things :)&lt;/figcaption&gt;
  &lt;/figure&gt;

</content></entry><entry><id>li0ard:blindedid</id><link rel="alternate" type="text/html" href="https://blog.li0ard.rest/blindedid?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=li0ard"></link><title>Blinded ID в Session и что с ними не так</title><published>2024-08-20T10:30:28.968Z</published><updated>2025-06-29T21:47:51.111Z</updated><category term="kriptografiya" label="Криптография"></category><summary type="html">Blinded ID (aka &quot;слепые&quot; айди и т.п) - алгоритм деривации публичного ключа (ID) пользователя для открытых групп в Session, для того чтобы скрыть настоящий ID пользователя, тем самым обеспечить некую приватность.</summary><content type="html">
  &lt;p id=&quot;fqfi&quot;&gt;Blinded ID (aka &amp;quot;слепые&amp;quot; айди и т.п) - алгоритм деривации ID пользователя, который является публичным ключом Curve25519, для открытых групп в &lt;a href=&quot;http://getsession.org&quot; target=&quot;_blank&quot;&gt;Session&lt;/a&gt;, для того чтобы скрыть настоящий ID пользователя.&lt;/p&gt;
  &lt;p id=&quot;8uQF&quot;&gt;Всего существует две версии данного алгоритма:&lt;/p&gt;
  &lt;ol id=&quot;6jQf&quot;&gt;
    &lt;li id=&quot;ugY5&quot;&gt;Legacy версия (ID начинается с префикса 15)&lt;/li&gt;
    &lt;li id=&quot;PKVB&quot;&gt;Новая версия (ID начинается с префикса 25)&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;dMlP&quot;&gt;На данный момент полностью реализованной является legacy версия, а поддержка новой версии есть только в &lt;a href=&quot;https://github.com/oxen-io/libsession-util/blob/dev/src/blinding.cpp&quot; target=&quot;_blank&quot;&gt;libsession&lt;/a&gt; и вроде как планируется в &lt;a href=&quot;https://github.com/oxen-io/session-pysogs/pull/220&quot; target=&quot;_blank&quot;&gt;pysogs&lt;/a&gt;.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;jNcZ&quot;&gt;&lt;strong&gt;Важно&lt;/strong&gt;: Все математические операции выполняются в поле &lt;em&gt;F&lt;/em&gt;p кривой ed25519, манипуляции со скалярами (редуцирование, инвертирование) выполняются в поле &lt;em&gt;F&lt;/em&gt;n (order field)&lt;/p&gt;
  &lt;/section&gt;
  &lt;h2 id=&quot;EQRZ&quot;&gt;Один ключ -&amp;gt; два ключа. Legacy версия.&lt;/h2&gt;
  &lt;h3 id=&quot;4Id9&quot;&gt;Алгоритм&lt;/h3&gt;
  &lt;p id=&quot;751h&quot;&gt;Для работы алгоритма нам понадобится:&lt;/p&gt;
  &lt;ul id=&quot;JwS8&quot;&gt;
    &lt;li id=&quot;FDkU&quot;&gt;ID пользователя&lt;/li&gt;
    &lt;li id=&quot;m5M4&quot;&gt;Публичный ключ сервера&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;mV2l&quot;&gt;Сам алгоритм:&lt;/p&gt;
  &lt;ol id=&quot;f5SJ&quot;&gt;
    &lt;li id=&quot;BCUN&quot;&gt;Генерируем т.н &amp;quot;blinding factor&amp;quot;: хэшируем с помощью Blake2B публичный ключ сервера и редуцируем результат.&lt;br /&gt;Обозначим, как &lt;code&gt;k&lt;/code&gt;.&lt;/li&gt;
    &lt;li id=&quot;Njow&quot;&gt;Из ID пользователя убираем префикс 05 и переводим его в ed25519.&lt;br /&gt;Обозначим, как &lt;code&gt;A&lt;/code&gt;.&lt;/li&gt;
    &lt;li id=&quot;8RHt&quot;&gt;Умножаем &lt;code&gt;k&lt;/code&gt; на &lt;code&gt;A&lt;/code&gt; и получаем ключ ed25519, который является одним из возможных &amp;quot;слепых&amp;quot; id.&lt;br /&gt;Обозначим, как &lt;code&gt;kA&lt;/code&gt;.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;figure id=&quot;1mos&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/78/69/78693505-fa28-4cc3-852c-418b9b00d683.png&quot; width=&quot;661&quot; /&gt;
    &lt;figcaption&gt;Примерная запись алгоритма&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h3 id=&quot;uY6p&quot;&gt;Сломанное условие&lt;/h3&gt;
  &lt;p id=&quot;eCpq&quot;&gt;Как следует из заголовка, legacy версия генерирует 2 возможных &amp;quot;слепых&amp;quot; ID.&lt;/p&gt;
  &lt;p id=&quot;Bgil&quot;&gt;Второй возможный ID (&lt;code&gt;kA2&lt;/code&gt;) генерируется на основе &lt;code&gt;kA&lt;/code&gt;, только с &lt;a href=&quot;https://github.com/theinfinityway/session_id/blob/main/src/index.ts#L98&quot; target=&quot;_blank&quot;&gt;изменённым&lt;/a&gt; (XOR на 128) sign битом.&lt;/p&gt;
  &lt;p id=&quot;T5D0&quot;&gt;И для того чтобы выяснить какой из двух ключей следует использовать, pysogs &lt;a href=&quot;https://github.com/oxen-io/session-pysogs/blob/dev/sogs/crypto.py#L101-L117&quot; target=&quot;_blank&quot;&gt;предлагает&lt;/a&gt; следующий код:&lt;/p&gt;
  &lt;pre id=&quot;sU4t&quot; data-lang=&quot;python&quot;&gt;if kA[31] &amp;amp; 0x80:
    return kA[0:31] + bytes([kA[31] &amp;amp; 0x80])&lt;/pre&gt;
  &lt;p id=&quot;O6vu&quot;&gt;Однако это условие &lt;a href=&quot;https://github.com/oxen-io/session-pysogs/issues/221&quot; target=&quot;_blank&quot;&gt;совершенно не работает&lt;/a&gt;, поэтому в реализации клиентов пошли другим путём - &lt;a href=&quot;https://github.com/oxen-io/session-desktop/blob/eb463a49baa79ffcb6a54362d34860f7fc358e11/ts/session/apis/open_group_api/sogsv3/sogsBlinding.ts#L161-L190&quot; target=&quot;_blank&quot;&gt;получение&lt;/a&gt; &amp;quot;слепого&amp;quot; id из приватного ключа, вместо того чтобы получать его из публичного ключа. Таким образом сервер не знает наверняка, какой ключ из двух следует использовать, и надеется на клиент в результате чего в теории может произойти раздвоение пользователя.&lt;/p&gt;
  &lt;figure id=&quot;Q2Qv&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/91/04/91042e9b-b7d9-4a6b-a68a-734b943df30a.png&quot; width=&quot;683&quot; /&gt;
    &lt;figcaption&gt;Примерная запись условия&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h3 id=&quot;nIr1&quot;&gt;Обратимая необратимость&lt;/h3&gt;
  &lt;p id=&quot;hhGD&quot;&gt;Так же немало важным является то, что legacy версия (а фактически единственная версия на момент написания статьи) является обратимой вопреки всем заявлениям.&lt;/p&gt;
  &lt;p id=&quot;C1xo&quot;&gt;Для этого достаточно инвертировать полученный ранее &amp;quot;blinding factor&amp;quot;, умножить его на слепой id, полученный ключ перевести в Curve25519 и в результате мы имеем ID пользователя.&lt;/p&gt;
  &lt;figure id=&quot;4HQ6&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/20/fd/20fd6a13-f4fb-4996-bd6a-677ab853c674.png&quot; width=&quot;670&quot; /&gt;
    &lt;figcaption&gt;Примерная запись алгоритма&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;4XKD&quot;&gt;Один ключ -&amp;gt; один ключ. Новая версия&lt;/h2&gt;
  &lt;p id=&quot;Rc2T&quot;&gt;На момент написания статьи эта версия реализована только в libsession, и поэтому может поменяться.&lt;/p&gt;
  &lt;p id=&quot;gYKy&quot;&gt;Самое главное отличие этой версии от legacy в том, что в процессе генерации &amp;quot;blinding factor&amp;quot; принимает участие ID пользователя вместе с публичным ключом сервера, что, в свою очередь, исключает возможность обратимости, как это было с legacy версией.&lt;/p&gt;
  &lt;p id=&quot;E64O&quot;&gt;Т.е алгоритм следующий:&lt;/p&gt;
  &lt;ol id=&quot;pZRm&quot;&gt;
    &lt;li id=&quot;4AOy&quot;&gt;Генерируем &amp;quot;blinding factor&amp;quot;: хэшируем с помощью Blake2B ID пользователя (вместе с префиксом) и публичный ключ сервера и редуцируем результат.&lt;br /&gt;Обозначим, как &lt;code&gt;k&lt;/code&gt;.&lt;/li&gt;
    &lt;li id=&quot;uYJ3&quot;&gt;Переводим ID пользователя из Curve25519 в ed25519.&lt;br /&gt;Обозначим, как &lt;code&gt;A&lt;/code&gt;.&lt;/li&gt;
    &lt;li id=&quot;3yYP&quot;&gt;Умножаем скаляр &lt;code&gt;k&lt;/code&gt; на &lt;code&gt;A&lt;/code&gt; &lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;DnGh&quot;&gt;На выходе получаем единственный Blinded ID для конкретного пользователя на конкретном сервере.&lt;/p&gt;
  &lt;figure id=&quot;e2eb&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b2/12/b212990b-309b-41a2-b944-bc9c45a51a9e.png&quot; width=&quot;677&quot; /&gt;
    &lt;figcaption&gt;Примерная запись алгоритма&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;1g9d&quot;&gt;Ссылки&lt;/h2&gt;
  &lt;p id=&quot;MsGC&quot;&gt;&lt;a href=&quot;https://github.com/theinfinityway/session_id&quot; target=&quot;_blank&quot;&gt;Моя библиотека &amp;quot;Session ID&amp;quot;&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;MZUq&quot;&gt;&lt;a href=&quot;https://github.com/sessionjs&quot; target=&quot;_blank&quot;&gt;Проект Session.js&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;DAGm&quot;&gt;&lt;a href=&quot;https://github.com/VityaSchel/bunsogs&quot; target=&quot;_blank&quot;&gt;Проект bunsogs&lt;/a&gt;&lt;/p&gt;

</content></entry><entry><id>li0ard:findkey</id><link rel="alternate" type="text/html" href="https://blog.li0ard.rest/findkey?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=li0ard"></link><title>Расчёт параметров МСК</title><published>2024-07-26T06:31:02.435Z</published><updated>2024-08-19T13:54:02.776Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img1.teletype.in/files/c7/f3/c7f349bb-bfdf-4d23-871f-a079a0eca839.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://img3.teletype.in/files/a6/98/a698fc32-0b84-4d31-bed8-f5976aebc4ee.png&quot;&gt;Под МСК (Местная система координат) подразумевается система координат построенная независимо от государственной системы координат (чаще всего на основе СК-42 или СК-63) и для конкретного субъекта Российской Федерации.</summary><content type="html">
  &lt;p id=&quot;Aw6b&quot;&gt;Под МСК (Местная система координат) подразумевается система координат построенная независимо от государственной системы координат (чаще всего на основе СК-42 или СК-63) и для конкретного субъекта Российской Федерации.&lt;/p&gt;
  &lt;blockquote id=&quot;MwJ3&quot;&gt;Многие программы ГИС позволяют реализовать работу в МСК непосредственно. Так, в QGIS и в MapInfo Pro любая проекция может быть дополнена аффинным преобразованием, а в Global Mapper конформные проекции дополняются разворотом.&lt;/blockquote&gt;
  &lt;h2 id=&quot;lR1F&quot;&gt;Постановка задачи&lt;/h2&gt;
  &lt;p id=&quot;yafh&quot;&gt;Имеется 6-7 пунктов, для которых известны координат X и Y в ГСК и в МСК. Необходимо подобрать параметры проекции представляющую МСК в ГИС.&lt;/p&gt;
  &lt;blockquote id=&quot;dQzV&quot;&gt;При подборе параметров предполагается использовать один из пунктов в качестве центральной точки преобразования.&lt;/blockquote&gt;
  &lt;h2 id=&quot;oAb7&quot;&gt;Подготовка данных&lt;/h2&gt;
  &lt;p id=&quot;0W1q&quot;&gt;Имеем 2 каталога координат. Один содержит координаты пунктов в государственной системе, а именно в СК-42, 4 зона (EPSG:28404) в формате &lt;code&gt;Y X&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;f8wC&quot;&gt;4645997.49 5768521.60
4661392.15 5770068.91
4650059.09 5783332.41
4634241.37 5778952.22
4631481.69 5764570.61
4642125.18 5754643.12
4655952.19 5757337.28&lt;/pre&gt;
  &lt;p id=&quot;bBPW&quot;&gt;А второй координаты в местной системе:&lt;/p&gt;
  &lt;pre id=&quot;bv3g&quot;&gt;67266.64 30088.40
82697.29 31184.27
71759.40 44771.50
55822.67 40857.06
52643.65 26564.42
62990.64 16331.35
76888.20 18619.57&lt;/pre&gt;
  &lt;p id=&quot;i43U&quot;&gt;Каждая строка в обоих файлах соответствует одному и тому же пункту. В первой строке центральный пункт системы.&lt;/p&gt;
  &lt;blockquote id=&quot;xBbz&quot;&gt;Очень важно помнить, что с точки зрения математической картографии МСК остаётся проекцией Гаусса-Крюгера и наследует её искажения. Поэтому важно знать, на какой именно ГСК основана МСК. Зачастую это заранее неизвестно, и приходится проводить предварительное исследование для выяснения этого вопроса.&lt;/blockquote&gt;
  &lt;p id=&quot;yjkL&quot;&gt;В нашем примере мы предполагаем, что это либо СК-42, 4 зона, либо СК-63, район C. Создадим также каталог в СК-63:&lt;/p&gt;
  &lt;figure id=&quot;yAdU&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/a6/98/a698fc32-0b84-4d31-bed8-f5976aebc4ee.png&quot; width=&quot;1191&quot; /&gt;
    &lt;figcaption&gt;cs2cs online by MyGeodata Cloud&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;pre id=&quot;nka5&quot;&gt;330797.453706 5755981.4752
346208.044264 5757327.09534
335051.738244 5770735.14419
319180.795365 5766563.18288
316233.724465 5752221.19702
326744.900981 5742157.23182
340603.316544 5744670.19105&lt;/pre&gt;
  &lt;h2 id=&quot;Q4vH&quot;&gt;Получение параметров&lt;/h2&gt;
  &lt;p id=&quot;I2Jt&quot;&gt;Для вычислений воспользуемся моей &lt;a href=&quot;https://geo.li0ard.rest/keys&quot; target=&quot;_blank&quot;&gt;утилитой&lt;/a&gt;.&lt;/p&gt;
  &lt;p id=&quot;RKDq&quot;&gt;Для начала необходимо определить базовую ГСК, сделаем это с помощью координатных невязок.&lt;/p&gt;
  &lt;p id=&quot;I64Q&quot;&gt;Загружаем каталог в СК-42 и в МСК в утилиту, и получаем значение невязок:&lt;/p&gt;
  &lt;figure id=&quot;UaNY&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/5d/6c/5d6cb960-ef51-47d1-acf3-9663cabbcacd.png&quot; width=&quot;553&quot; /&gt;
    &lt;figcaption&gt;Невязки для СК-42&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;6wRz&quot;&gt;Теперь вычислим невязки аналогичным способом для СК-63:&lt;/p&gt;
  &lt;figure id=&quot;31Tt&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/9f/a1/9fa1830a-5eef-4dcb-b3ba-68fcbd7d8a4e.png&quot; width=&quot;562&quot; /&gt;
    &lt;figcaption&gt;Невязки для СК-63&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;aYAm&quot;&gt;Сравнив невязки мы понимаем, что базовая ГСК - СК-63&lt;/p&gt;
  &lt;p id=&quot;Ho4F&quot;&gt;Получаем параметры 2D преобразования Гельмерта:&lt;/p&gt;
  &lt;figure id=&quot;wkIL&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/7b/8e/7b8e85ad-b303-4c69-9679-979e5bd22b97.png&quot; width=&quot;564&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;RfmG&quot;&gt;А также параметры Аффинного параметрического преобразования:&lt;/p&gt;
  &lt;figure id=&quot;BeQr&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/87/c3/87c3aab6-23ac-4af7-9f55-127a0215b17d.png&quot; width=&quot;550&quot; /&gt;
  &lt;/figure&gt;

</content></entry><entry><id>li0ard:anticryptopro_p3</id><link rel="alternate" type="text/html" href="https://blog.li0ard.rest/anticryptopro_p3?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=li0ard"></link><title>Побег из КриптоПро (ч.3)</title><published>2024-06-23T12:06:45.108Z</published><updated>2026-05-06T11:47:55.891Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img2.teletype.in/files/56/b9/56b95756-5be1-44d6-be7a-8b423726351e.png"></media:thumbnail><category term="anticryptopro" label="Побег из КриптоПро"></category><summary type="html">&lt;img src=&quot;https://img2.teletype.in/files/9d/d5/9dd5b7e8-5018-4f4b-bfdc-c2b32875e02b.png&quot;&gt;В прошлых частях я разбирался с транспортным ключевым контейнером от КриптоПро (он же PFX, PKCS12, P12). В этой статье пойдёт речь о собственном формате ключевого контейнера КриптоПро (те самые 6 файлов .key)</summary><content type="html">
  &lt;p id=&quot;7ST7&quot;&gt;В прошлых частях (&lt;a href=&quot;/anticryptopro&quot;&gt;клик&lt;/a&gt;, &lt;a href=&quot;/anticryptopro_p2&quot;&gt;клик&lt;/a&gt;) я разбирался с транспортным ключевым контейнером от КриптоПро (он же PFX, PKCS12, P12). В этой статье пойдёт речь о собственном формате ключевого контейнера КриптоПро (те самые 6 файлов .key)&lt;/p&gt;
  &lt;figure id=&quot;GY2O&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/9d/d5/9dd5b7e8-5018-4f4b-bfdc-c2b32875e02b.png&quot; width=&quot;598&quot; /&gt;
    &lt;figcaption&gt;Проприетарный контейнер КриптоПро&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;cZkW&quot;&gt;Вообще тема данной статьи не нова, ещё в далёком 2016 года Михаил Куликов (он же shukan) написал &lt;a href=&quot;https://habr.com/ru/articles/275039/&quot; target=&quot;_blank&quot;&gt;статью&lt;/a&gt; на Хабре в которой он предоставил программу на C, которая вытаскивала ключ для ГОСТ 34.10-2001. Чуть позже благодаря сообществу появилась версия и для ГОСТ 34.10-2012. Однако пробуя запустить все эти утилиты для контейнера ГОСТ 34.10-2012 512 бит сгенерированного в КриптоПро CSP 5.0, утилиты выдавали ошибку. Собственно это и стало мотивацией разобраться как там всё устроено и написать свою программу.&lt;/p&gt;
  &lt;h2 id=&quot;bApX&quot;&gt;Как там всё устроено&lt;/h2&gt;
  &lt;h3 id=&quot;naQk&quot;&gt;Файл masks.key&lt;/h3&gt;
  &lt;figure id=&quot;GQHb&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/58/86/58863e2a-852e-432a-a347-ccb0a4fdd410.png&quot; width=&quot;812&quot; /&gt;
    &lt;figcaption&gt;Содержимое masks.key&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;MkTb&quot;&gt;Содержит в себе три Octet String, которые в свою очередь являются маской ключа (32 байта для 256 бит, 64 для 512), солью для деривации пароля и контрольной суммы маски соответственно.&lt;/p&gt;
  &lt;h3 id=&quot;vjGc&quot;&gt;Файл primary.key&lt;/h3&gt;
  &lt;figure id=&quot;qmTL&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/19/b7/19b7ab2d-7ea5-42dc-9f32-49447d9dfef1.png&quot; width=&quot;822&quot; /&gt;
    &lt;figcaption&gt;Содержимое primary.key&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;MEyb&quot;&gt;Содержит зашифрованный приватный ключ (32 байта для 256 бит, 64 для 512), который после расшифровки надо разделить по модулю на поле Q эллиптической кривой ключа.&lt;/p&gt;
  &lt;h3 id=&quot;auGh&quot;&gt;Файл header.key&lt;/h3&gt;
  &lt;figure id=&quot;3mQn&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/91/6a/916ad450-13e0-4c25-8b99-72ad41482b51.png&quot; width=&quot;848&quot; /&gt;
    &lt;figcaption&gt;Содержимое header.key&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;7Y70&quot;&gt;Содержит всю информацию о контейнере: Сертификат, свойства ключа, параметры эллиптической кривой и алгоритма хэширования, первые 8 байт публичного ключа, а также контрольные суммы.&lt;/p&gt;
  &lt;h2 id=&quot;XLcJ&quot;&gt;Получаем приватный ключ&lt;/h2&gt;
  &lt;p id=&quot;Mvlh&quot;&gt;Для получения приватного ключа необходимо выполнить следующие шаги:&lt;/p&gt;
  &lt;ol id=&quot;FOPy&quot;&gt;
    &lt;li id=&quot;yeOC&quot;&gt;Получение так ключа хранения с помощью CPKDF (CryptoPro Key Derivation Function) в которую передаётся пароль и соль из файла masks.key.&lt;/li&gt;
    &lt;li id=&quot;PJTR&quot;&gt;Расшифровка основного ключа с помощью ГОСТ 28147-89 (Магма) в ECB режиме с параметрами набора Z от ТК-26&lt;/li&gt;
    &lt;li id=&quot;bZZo&quot;&gt;Деление по модулю расшифрованного ключа на маску&lt;/li&gt;
    &lt;li id=&quot;9u5A&quot;&gt;Подстановка результата в ASN.1 конструкцию приватного ключа&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;csSv&quot;&gt;Подводя итоги могу сказать, что это была достаточно сложная работа, отнявшая у меня годовой запас кофе и не только :) Однако я полностью доволен результатом.&lt;/p&gt;
  &lt;p id=&quot;UHAM&quot;&gt;Также хочу выразить благодарность Савелию Красовскому за его утилиту go-decrypto-pro, которая стала основной для моей программы, и VovkaTM за консультации и прочую помощь.&lt;/p&gt;
  &lt;h2 id=&quot;0Kh6&quot;&gt;Ссылки&lt;/h2&gt;
  &lt;p id=&quot;uTre&quot;&gt;Программа - &lt;a href=&quot;https://github.com/li0ard/ckey&quot; target=&quot;_blank&quot;&gt;https://github.com/li0ard/ckey&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;8yLV&quot;&gt;Утилита go-decrypto-pro - &lt;a href=&quot;https://github.com/savely-krasovsky/go-decrypto-pro&quot; target=&quot;_blank&quot;&gt;https://github.com/savely-krasovsky/go-decrypto-pro&lt;/a&gt;&lt;/p&gt;

</content></entry></feed>