Задавались ли вы когда-нибудь вопросом, как работают QR-коды? Если да, то эта статья для вас. Здесь вас ждёт интерактивное объяснение*, которое мы составили для семинара, проводившегося в рамках Всемирного конгресса хакеров 37C3, но вы также можете использовать его самостоятельно.

Прочитав статью, вы узнаете:

  • Из чего состоят QR-коды.
  • Как декодировать QR-коды вручную (используя нашу шпаргалку).

*Прим. пер.: текст и приводимые в нём примеры соответствуют QR-коду, содержащему выражение «Hello world!» Полноценная интерактивная версия с возможностью использования собственных кодов и слов доступна в оригинале статьи.

▍ Содержание


  1. Анатомия QR-кода
  2. Шаблон маски
  3. Режим кодирования
  4. Порядок чтения
  5. Декодирование длины
  6. Декодирование содержимого
  7. Поздравления!

▍ Выберите QR-код


Для начала нам потребуется QR-код, с которым мы будем работать. И здесь у вас три варианта.

  1. Ввести любой текст, который обновит QR-код, объясняемый ниже.
  2. Отсканировать любой имеющийся QR-код с помощью камеры.
  3. Попрактиковаться на декодировании рандомных английских слов. В этом случае слово показано не будет, чтобы вы могли использовать его для обучения.

▍ Анатомия QR-кода


Вот QR-код для фразы «Hello world!»:


Размер этого кода 21×21 модуля (так в кодах называются пиксели).

QR-код может иметь разный размер, который иначе называется его версией. Самая маленькая версия имеет размер 21х21 модуль, и для каждой последующей этот размер увеличивается на 4. Выходит, что наш QR-код имеет версию 1. Вот его элементы наглядно:

▍ Опознавательные метки (finder pattern)


По опознавательным меткам сканеры распознают QR-коды.


▍ Разделители (separators)


Пустые строки вокруг опознавательных меток. При чтении содержимого кода их важно пропускать.


▍ Выравнивающие метки (alignment pattern)


Поскольку мы рассматриваем QR-код версии 1, выравнивающих меток у него нет (эти метки помогают сканерам правильно считывать QR-код).

▍ Метки тайминга (timing pattern)


Две всегда чередующиеся строки из чёрных/белых модулей — ещё один вспомогательный элемент для правильного считывания QR-кода.


▍ Информация о формате (format information)


Определяет шаблон маски и уровень коррекции ошибок.

Может быть представлена вертикально:


И горизонтально. Обратите внимание, что метка тайминга пересекает обе этих линии.


▍ Вот эти области вместе


Всё, что не выделено, является фактическим содержимым кода.


▍ Прочие области


Есть ещё один участок, который здесь не показан: тихая область — белая граница вокруг QR-кода. Она помогает сканерам определять его начало и конец.

▍ Шаблон маски


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

Вот место, где указывается использованный шаблон маски:



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



Ящерицы М. К. Эшера



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

▍ Режим кодирования


Приступим к расшифровке содержимого. Для начала нам нужно узнать используемую кодировку. Эта информация всегда указана в нижнем правом углу.


Но помните — первым делом нужно применить маску. Заглянем в нашу шпаргалку, чтобы понять как.


Нужно выполнить XOR для этих двух областей:



В случае нашего кода это будет режим Байтов (4).

Порядок чтения


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


▍ Байты


Первые четыре бита содержат информацию о режиме кодирования. Для режима ASCII следующие восемь битов указывают длину содержимого. Далее каждые восемь битов отражают байт содержимого.

И здесь снова нужно применить маску:


XOR


=


▍ Декодирование длины


Это информация о длине (без маски):


Это значение представляет общую длину содержимого в байтах.

▍ Декодирование содержимого


И, наконец, мы можем перейти к декодированию самого содержимого QR-кода.

Это первый байт (без маски):


Второй байт (без маски):


…И так далее. Декодирование остальных байтов оставим для вас в качестве практики. Вы можете остановиться, когда прочтёте столько символов, сколько было указано в поле длины ранее.

▍ Таблица ASCII



▍ Коррекция ошибок


Значит, всё остальное является содержимым? Не совсем. В QR-коде ещё есть коррекция ошибок, которая обеспечивает, чтобы его можно было прочитать даже в случае повреждения, размытости или отсутствия некоторых частей. Коррекция ошибок производится путём особых математических операций и в рамках процесса ручной расшифровки кода нас не интересует.

▍ Поздравляем!


Этого должно быть достаточно, чтобы самостоятельно декодировать простые QR-коды. Теперь вы можете либо нажать «Random code» в начале статьи (в оригинале, — прим. пер.), чтобы попрактиковаться на случайных английских словах, либо найти QR-код и просканировать его, нажав «Scan code».

▍ Нашли баг? Хотите внести свой вклад?


Исходный код лежит на Codeberg. Будем особенно благодарны за пул-реквесты с объяснением принципа работы режимов кодировки UTF-8.

Telegram-канал со скидками, розыгрышами призов и новостями IT ?

Комментарии (28)


  1. Number571
    11.10.2024 13:05

    Хаб криптография и тег шифрование - лишние.


    1. Bright_Translate Автор
      11.10.2024 13:05

      Спасибо, исправили. Сложно под эту тематику объективно подходящие хабы подобрать.


  1. Aelliari
    11.10.2024 13:05

    Что-то это мне напомнило:)


    1. grvelvet
      11.10.2024 13:05

      Скрижали древних


    1. malkovsky
      11.10.2024 13:05

      Ага, а еще вот это


    1. Wesha
      11.10.2024 13:05

      А если охота поиграть в камушки,

      то можно ещё вот так


  1. saag
    11.10.2024 13:05

    "Фельдфебель начал свертывать цигарку. Швейк между тем разглядывал номер винтовки и вдруг воскликнул:      - Четыре тысячи двести шестьдесят восемь! Такой номер был у одного паровоза в Печках. Этот паровоз стоял на шестнадцатом пути. Его собирались увести на ремонт в депо Лысую-на-Лабе, но не так-то это оказалось просто, господин фельдфебель, потому что у старшего машиниста, которому поручили его туда перегнать, была прескверная память на числа. Тогда начальник дистанции позвал его в свою канцелярию и говорит: "На шестнадцатом пути стоит паровоз номер четыре тысячи двести шестьдесят восемь. Я знаю, у вас плохая память на цифры, а если вам записать номер на бумаге, то вы бумагу эту также потеряете. Если у вас такая плохая память на цифры, послушайте меня повнимательней. Я вам докажу, что очень легко запомнить какой угодно номер. Так слушайте: номер паровоза, который нужно увести в депо в Лысую-на-Лабе,-- четыре тысячи двести шестьдесят восемь. Слушайте внимательно. Первая цифра - четыре, вторая - два. Теперь вы уже помните сорок два, то есть дважды два - четыре, это первая цифра, которая, разделенная на два, равняется двум, и рядом получается четыре и два. Теперь не пугайтесь! Сколько будет дважды четыре^ Восемь, так ведь? Так запомните, что восьмерка в номере четыре тысячи двести шестьдесят восемь будет по порядку последней. После того как вы запомнили, что первая цифра - четыре, вторая - два, четвертая - восемь, нужно ухитриться и запомнить эту самую шестерку, которая стоит перед восьмеркой, а это очень просто. Первая цифра-- четыре, вторая-два. а четыре плюс два - шесть. Теперь вы уже точно знаете, что вторая цифра от конца - шесть; и теперь у вас этот порядок цифр никогда не вылетит из головы. У вас в памяти засел номер четыре тысячи двести шестьдесят восемь. Но вы можете прийти к этому же результату еще проще......"


  1. mynameco
    11.10.2024 13:05

    Я думал там спец код, с переворотами, как в cd дисках и радипередачах и помоему в шинах данных. Чтобы не было длинных одинаковых последовательностей. Оказалось что нет. А потом подумал, что это работает в одном измерении, а в 2д могут соседнии ряды мешать и нужнл придумывать 2д коды, чтобы они не создавали острова одинаковых бит.


    1. tyomitch
      11.10.2024 13:05

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


  1. AlexanderS
    11.10.2024 13:05

    Вот место, где указывается использованный шаблон маски:

    Это место всегда фиксированное для данной версии кода?


    1. tyomitch
      11.10.2024 13:05

      Во-первых, оно фиксированное (возле опознавательных меток) вообще всегда, независимо от версии. Во-вторых, оно записывается в двух копиях -- горизонтально и вертикально. В-третьих, оно сопровождается кодом для коррекции ошибок, так что фактически от выбора шаблона маски и уровня коррекции ошибок (5 битов данных) зависят 30 ячеек QR: 15 в вертикальном ряду, и 15 в горизонтальном.