
Всем привет.
Уже теперь в прошлом году в комментариях к очередной статье про безопасность аккаунтов и TOTP здесь, на Хабре, я спрашивал — а почему не очень распространены «hardware TOTP».
С одной стороны, оно и понятно — зачем нужно какое‑то еще одно отдельное устройство, если его вполне заменит любой смартфон, который и так всегда при себе. И этот подход, безусловно, имеет приоритетное право на жизнь. Но, с другой стороны, в той самой статье, с которой все и началось, как раз и обсуждался среди прочего «режим паранойи», когда пользователь не доверяет ни одному подходящему в данном случае устройству и хотел бы иметь свое устройство, которое будет показывать те самые TOTP коды, но работать будет автономно и не будет зависеть от конкретного приложения и конкретной ОС смартфона (которые, теоретически, могут сливать данные куда‑либо). Резюмируя — нужна некая «коробочка с экранчиком», которая умеет рассчитывать TOTP и отображать его.
Стоит признать, что подобные устройства, конечно, существуют, но готовое — это, во‑первых, не интересно, а во‑вторых — хочется же проверить, что можно сделать самому и сколько это может стоить. А поскольку я имел дело с микроконтроллерами и прочими связанными вещами (например, пайкой) только на уровне «я знаю, что они существуют», возникла мысль попробовать «смастерить» такое устройство с минимальной (а лучше — вообще без) пайкой/сборкой/подстройкой. В идеале, я хотел попытаться найти собранное устройство, которое нужно лишь запрограммировать нужным способом, и при этом которое не будет иметь какой‑то избыточной функциональности, влияющей на его конечную цену.
Не знаю уж, почему, но в первую очередь я подумал про Raspberry Pi (наверное, потому что на слуху + они позиционируют себя, как сборку чего‑то из готовых блоков, что соответствует моим вводным). И, конечно, у них достаточно много того, что с легкостью может решить такую задачу. Проблема только в том, что все это имеет кучу ненужного в данном случае функционала и, как следствие, высокую цену. Есть у них, конечно, и дешевые варианты плат, но там в комплекте только сама плата и если «добивать» комплект необходимым (например, экран), то цена уже не такая уж и дешевая получается.
Новый же поиск вывел на сборку LILYGO T‑PicoC3, которая показалась мне подходящей: небольшой размер, TFT‑экранчик, микроконтроллеры RP2040 и ESP32-C3 в связке, две готовые кнопки и развязка для аккумулятора — вроде то, что нужно. Порывшись на маркетплейсах, нашел такое устройство за приемлемые деньги (1500 руб) сразу в корпусе (но без аккумулятора) и заказал на «попробовать».
А пока устройство добиралось ко мне неизведанными путями Почты России, я начал изучать вопросы реализации задачи на этом устройстве.
В качестве языка был выбран MicroPython (потому что знаю немножко «большой» Python) и теперь оставалось просто найти реализацию нужных мне блоков, из которых потом получится прошивка для этого устройства.
Довольно быстро нашлись похожие зарубежные проекты, из которых впоследствии была взята реализация расчета TOTP (например, вот этот), а также почерпнута логика работы устройства в том виде, в котором ее видели авторы, что очень помогло в итоге. Однако, именно такого же проекта, из которого можно было бы «импортозаместить» весь функционал, не нашлось и стало ясно, что «колхозить» все‑таки придется и самому тоже.
Тем временем наступил Новый Год и заказанный в прошлом году «мелкий пакет из Китая» прибыл в отделение почты.
Вот так это устройство выглядит вживую:



Подключаем для проверки устройство к источнику питания — мигают огоньки, экран оживает, все работает — хорошо. Можно начинать.
Изначально концепт был выбран (и частично подсмотрен — да, каюсь) такой: при запуске устройство читает настройки TOTP из файла, далее рассчитывается и отображается сам TOTP. Кнопки устройства используются для переключения кодов по списку вверх или вниз (в файле может храниться несколько аккаунтов). А так как для генерации TOTP требуются дата и время, то их нужно настроить при первом после отключения питания запуске устройства.
В оригинальном проекте время и дата настраиваются на другой сборке, где есть аж 4 физических кнопки, что делает этот процесс более‑менее приемлемым (1 кнопка для переключения по сегментам даты и времени, 2 кнопки для увеличения/уменьшения значения в выбранном сегменте и 1 кнопка для подтверждения ввода). В моем же случае — есть только 2 физические кнопки и это делает аналогичный процесс крайне затруднительным (даже с учетом отлавливания двойных и долгих нажатий). И поэтому сразу же встал вопрос: как ввести дату и время в устройство?
К счастью, среда разработки (VS Code + расширения) умеет быстро синхронизировать время платы с временем хоста, а потому пока можно продолжать реализацию и проверку расчета TOTP, без которого все это не имеет никакого смысла.
Реализация получилась эдаким «франкенштейном» — кусочки реализации разных блоков, адаптированные (а иногда и, каюсь, полностью «импортозамещенные») под задачу. Это связано с тем, что у разработчика сборки почти нет примеров работы именно для MicroPython. И приходилось искать и адаптировать кое‑что самостоятельно, погружаясь все глубже в код. В итоге, когда TFT‑экранчик показал мне заветные 6 цифр TOTP и цифры эти совпали с тем же аккаунтом на смартфоне — радости не было предела. Вроде бы, ничего «эдакого», считай «помигал светодиодом», а все равно приятно.
Но осталось решить вопрос со временем. Собственно, получить актуальные дату и время можно только 2 путями: или внести вручную (отпадает) или получить автоматически. Но у RP2040 нет поддержки Wi‑Fi, зато такая поддержка есть у ESP32-C3, который, как мы помним, тоже есть на плате. И в документации даже есть примеры работы с Wi‑Fi, правда, увы, снова не для MicroPython. И все же, при более детальном изучении нашелся пример для работы и для него (если кратко, то там инициализируется UART на заведомо известных пинах, что знающий человек сразу увидит в распиновке и чего долго не видел я). И вот мы уже умеем подключаться к Wi‑Fi. И когда экранчик показал IP устройства в домашней сети — глаза загорелись еще больше.
Так, а что со временем? Честно признаюсь — на это ушло довольно много времени и все — по причине моей невнимательности и спешки (да‑да, спешка частенько приводит к дополнительным тратам времени, как это ни странно звучит). После сравнительно длительного изучения разной документации, оказалось, что ESP32-С3 умеет работать с NTP серверами и можно попросить его синхронизировать время, что и решило все проблемы (да, там есть свои нюансы, но разобраться получилось).
И когда, наконец, устройство включилось, подключилось к сети Wi‑Fi, синхронизировало время и отобразило корректный TOTP уже в автономном режиме — вот здесь я на радостях и посчитал задачу выполненной.
В итоге, на текущий момент, реализована такая схема:
При запуске устройство пытается подключиться к известным ему сетям Wi‑Fi (список сетей хранится в файле — например, туда можно внести сеть от смартфона, которую можно использовать в полевых условиях) и, если получается — синхронизирует время с NTP серверами.
Отображает TOTP для выбранного кнопками «аккаунта» (список аккаунтов хранится в файле).
Есть 2 «плюшки»: подсветка «уже почти истекшего» кода и «прогресс‑бар» истечения кода.
Посмотреть, как это все работает, можно здесь.
Но на радостях позабылся весьма важный вопрос — вопрос по питанию (и потреблению) устройства. А потому был быстренько заказан совместимый LiPo аккумулятор, который будет (на текущий момент еще нет) «приколхозен» (к слову, тоже тема — как его там разместить лучше) к этой коробочке с целью изучения этого вопроса.
Ну и, конечно, остался еще и вопрос добавления новых аккаунтов в список. С точки зрения системы это означает загрузку нового файла поверх старого, что выглядит не очень удобным, хотя и это можно попробовать упростить как‑то (может, есть идеи?).
А теперь о серьезном. Про безопасность.
Конечно, это совсем небезопасная схема, так как нет никакого шифрования, а файлы с настройками сетей и TOTP легко извлекаются из устройства (например, при его утере), но она имеет место быть. К тому же, если использовать, например, RP2350 вместо RP2040, то вроде как можно сделать эту схему более безопасной.
И, само собой, можно сделать устройство дешевле если применить правильные руки, а не покупать готовое. Повторюсь, здесь описан лишь мой дилетантский опыт от идеи до конкретной штуковины, которой я, кстати, собираюсь пользоваться, чтобы понять ее преимущества и недостатки лично для меня.
На этом все, спасибо, что дочитали! Всем добра!
P.S. Критика, вопросы и советы категорически приветствуются.
Комментарии (17)

xSVPx
12.01.2026 06:22Совершенно непонятно зачем там rp и вот это вот всё. Генерация ТОТР работает на кредитке, неужели она на esp32 работать не будет ?
Без хотя бы пина на вход это не очень полезное устройство.
Но направление правильное.

foxsoft2005 Автор
12.01.2026 06:22неужели она на esp32 работать не будет ?
думаю, без проблем будет. и если бы мне сразу попалась бы сборка чисто на esp32 с экранчиком, я бы взял бы ее (тем более, что по ощущениям она вышла бы дешевле).. но мне попалось то, что попалось - цель-то была - взять коробку и запрограммировать ее, без всякой умной схемотехники.

inkelyad
12.01.2026 06:22зачем там rp и вот это вот всё.
Ради защищенного хранилища ключа и прочих Secure Boot. Правда в контексте TOTP не очень очевидно, что оно нужно.

foxsoft2005 Автор
12.01.2026 06:22Кстати, да. Правда, в моем случае в rp2040 этого нет. А вот в rp2350 - есть и там это можно использовать.

xSVPx
12.01.2026 06:22Неужели извлечь что-нибудь из esp32 проще чем из rp с secure boot итп ? Ну т.е. я слабо себе представляю как извлечь штатно, а когда речь про "сфотографируем память в электронном микроскопе, там ячейки с единицами другого цвета получатся и потом сграбим данные с картинки" - тут уж никакие secure boot не помогут.
Только вот гораздо проще гаечным ключом по башке дать и сам всё расскажешь...

inkelyad
12.01.2026 06:22"сфотографируем память в электронном микроскопе, там ячейки с единицами другого цвета получатся и потом сграбим данные с картинки"
В 'правильных' защищенных хранилищах именно против такого и борются. Вот тут результаты про challenge по RP2350. Именно таким образом(одним из) их и сломали и для следующих поколений процессора они собираются меры принять, чтобы не получалось.

xSVPx
12.01.2026 06:22Ну вы же понимаете, что имея доступ к устройству получится в любом случае.
У меня только один вопрос: сколько стоит такая работа по взлому ? Не по взлому rp и его secure boot, который везде одинаковый, а по восстановлению неизвестно как работающей прошивки в esp32 неизвестно где гранящей ключ ?
Если эта работа стоит тысячу долларов - есть о чем подумать, если миллион, то я не среди целей, с меня миллион не отжать :).

inkelyad
12.01.2026 06:22Ну вы же понимаете, что имея доступ к устройству получится в любом случае.
Имея доступ к устройству его никто не будет ломать. Прямо им и будут пользоваться, чтобы коды генерировать. Потому и сомнительно, что для TOTP генератора оно надо.

inkelyad
12.01.2026 06:22Ну, собственно, статья - демонстрация того, что просто собрать TOTP генератор большой проблемы не составляет. Но тут - дорого. Я все еще надеюсь, что кто-нибудь на чем-нибудь похожем по цене на дешевые китайский "смарт-часы" (~200р vs 1500р) сумеет сделать.
Потому что за указанную цену(ну, чуть дороже) - можно вполне сертифицированный токен для входа по электронной подписи купить.
xSVPx
12.01.2026 06:22Знаете токены, которые могут хотя бы десяток разных ТОТР поддерживать ? И при этом показывают их на экране итп ?

inkelyad
12.01.2026 06:22хотя бы десяток разных ТОТР поддерживать
Тезис в том, что за эту цену можно перейти с TOTP на гораздо более надежный способ.
А так - любой старый смарт. В ту же стоимость на древнем 4.* андроиде выйдут. Если паранойя грызет насчет того что взломают - вскрыть и все антенны отодрать и выломать.
xSVPx
12.01.2026 06:22Более надежный - это какой?
Любой старый смарт не может быть надежным. Если мучает паранойа придется выломать всё включая экран :). Если ваш смарт уже скомпрометирован он сможет отправлять данные, к примеру меняя яркость подсветки :).
Смарт - это в первую очередь огромная ненужная дура требующая зарядки. Это очень неудобно.
Нормальный генератор ТОТР был раньше даже в кредитке, питание вероятно было в ней же. На весь срок службы...

inkelyad
12.01.2026 06:22Более надежный - это какой?
Уже сто раз объяснял. Тот, в котором злодею нельзя ничего сообщить (нормальным образом, без достаточно хитрых способов), что поможет ему в сервис войти. TOTP - костыль, хотя и удачный. Защищает только от подбора/угона паролей. Токен - от большего.
Если ваш смарт уже скомпрометирован он сможет отправлять данные, к примеру меняя яркость подсветки :).
У вас сценарии странные. Можно какой-нибудь не совсем шпионский?
У меня получается придумать только в духе: Evil Maid заражает смарт трояном(кстати, как, если мы все отодрали?), который при помощи мигания экрана отправляет ключики злодеям? А просто украсть железку нельзя, чтобы жертва не сменила токены входа?
kromwell_thct
2 кнопки запрограммированные на
1-ая перебор
2-ая сдвиг (десятки часов→часы →десятки минут→минуты)
Вполне эргономичный ввод. Зато не надо цепляться к сетям которые сами по себе уязвимость и дыра во внешний мир
foxsoft2005 Автор
В моей голове это прокрутилось как "неудобное", уж не знаю, почему - отсутствие опыта, наверное. Но сейчас выглядит вполне рабоче. Вопрос только - как подтверждать ввод в самом конце? Просто по таймеру ждать и если кнопок не нажато, то ок? Или типа двойное/длинное нажатие на одну из кнопок?
xSVPx
Из двух кнопок есть миллион вариантов.
Нажата одна кнопка. Нажата вторая. Нажаты две одновременно. Одна нажата и удерживается, вторая нажата и удерживается, две удерживаются, даблклик, трипл клик итд итп.
foxsoft2005 Автор
Логично. Надо будет попробовать что-то изобразить в этом направлении.
Правда, каждый раз после отключения питания вводить текущие дату и время... Хотя, не такая уж проблема, особенно если паранойя "зубстая"...