Перейти к материалам
разбор

«Медуза» нашла уязвимость в системе интернет-голосования. Часть голосов можно расшифровать еще до официального подсчета

Источник: Meduza
Артем Геодакян / ТАСС / Scanpix / LETA

На общероссийском голосовании о внесении изменений в Конституцию РФ продолжился эксперимент с интернет-голосованием. Разработчики изменили систему голосования так, что избиратель теперь может гарантированно расшифровать собственный голос. С одной стороны, так легче принуждать к участию в голосовании. С другой — так можно отчасти проконтролировать честность подсчета голосов.

Департамент информационных технологий Москвы изменил схему шифрования голоса избирателя

В 2019 году департамент информационных технологий Москвы разработал систему дистанционного голосования с использованием блокчейна. Тогда голоса избирателей шифровали с помощью собственной реализации схемы Эль-Гамаля. Эксперты дважды находили в ней разного рода уязвимости.

Теперь в браузере избирателя его голос шифруется с помощью JavaScript-библиотеки TweetNaCl.js. Ее автор Дмитрий Честных узнал от «Медузы» об использовании своей программы разработчиками дистанционного электронного голосования.

Честных портировал на JavaScript программу TweetNaCl — компактную реализацию программы NaCl (Networking and Cryptography library), разработанную известными криптографами Дэниелом Бернштейном (Daniel J. Bernstein), Таней Ланге (Tanja Lange) и Питером Швабе (Peter Schwabe). Все эти программы используют эллиптическую кривую Curve25519 для согласования ключей, а алгоритмы Poly1305 для аутентификации сообщений и Salsa20 для шифрования.

Теперь до официального подсчета голосов (!) интернет-избиратель может сам расшифровать свой голос или разрешить это сделать посторонним

Предыдущая система со схемой Эль-Гамаля обеспечивала вероятностное шифрование голоса избирателя: при использовании одних и тех же параметров на практике всегда получался новый шифротекст. Сообщение нельзя было наверняка расшифровать, не раздобыв секретный ключ получателя (избиркома).

Новая система отличается детерминированным шифрованием: использование одних и тех же параметров приводит к формированию идентичных шифротекстов. Более того, отправитель и получатель формируют общий ключ (shared key), который пригоден как для шифрования сообщения, так и для его расшифровки.

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

Мы провели эксперимент, и оказалось, что раздобыть свой секретный ключ сравнительно легко.

Для того чтобы сохранить генерируемый в браузере секретный ключ, мы в Google Chrome получили электронный бюллетень, открыли «Инструменты разработки», выбрали вкладку Sources, отыскали библиотеку election.js, нашли там строку с генерацией секретного и публичного ключей, поставили после нее logpoint (точка, дойдя до которой браузер запишет в консоль требуемую отладочную информацию): 'voter secret key is', encryptor.keyPair.secretKey. И только после этого проголосовали.

Мы успешно расшифровали голоса избирателей, участвовавших в нашем эксперименте

Общие данные для всех избирателей

  • 1a434ceb91efb84f117e9a8103e2ce12c14f47797c58cb85bb8f142e978de707 (публичный ключ избиркома)
  • 83dcefb7 (так кодируется голос «за»)
  • 1ad5be0d (так кодируется голос «против»)

Уникальные данные первого избирателя

Общедоступные данные о голосовании избирателя

  • f7f4e6a567563e09052c2cb2c13bc81e98531424 (зашифрованное сообщение)
  • 39d48319e36fc40b30e9254c8441e071cff16cefdaf4f434 (nonce)
  • 76d57d4cd3b83d8897a74003bcbc1bd2ec1f107a286a407d27299aee36ceb37b (публичный ключ избирателя)

Секретный ключ избирателя из его браузера

  • cbaaa9d43a5ecdfd3a5f0882335801f50da6f988cf2c311fefb5481c69c0eefd

Уникальные данные второго избирателя

Общедоступные данные о голосовании избирателя

  • b685e869bb3af8ce294b788d135abe7c4e72acb7 (зашифрованное сообщение)
  • fc2fcb210d5ce41f3ec71915bdabcc7bda43f5a407959d6e (nonce)
  • 0a19b93335bff068021d5e6b10b09fe64f4504d29d5137d4ff125eeda75ebf05 (публичный ключ избирателя)

Секретный ключ избирателя из его браузера

  • 7df5ebfb215458153dd695b2f02a66c6895cf86e285c363d68a2a83a7fb11a6f

Теперь вы можете расшифровать эти голоса сами

Вот скрипт, позволяющий расшифровать голоса интернет-избирателей, сохранивших свои секретные ключи.

  1. Скачайте файл votes.js (там уже введены данные первого и второго избирателей)
  2. Положите его в какую-нибудь папку (директорию)
  3. Внутри этой папки в терминале наберите и запустите команду npm install tweetnacl (чтобы установить TweetNaCl.js)
  4. После это запустите node votes.js и проверьте, за что избиратели отдали свои голоса
  5. Если ЦИК опубликует официальные результаты, то можно будет перейти по ссылкам на транзакции с голосами двух избирателей и сравнить эту расшифровку с тем, что будет записано в блокчейне.
Если вы не сохранили свой секретный ключ, то вы не сможете расшифровать свой голос самостоятельно — до публикации секретного ключа избирательной комиссии.

Плохая новость: так можно принуждать к голосованию

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

Хорошая новость: так можно контролировать подсчет

Но эту же особенность можно использовать для контроля честности подсчета голосов, когда избирком отказывается обнародовать расшифровку каждого конкретного голоса (как это было в 2019 году). К примеру, сторонники одного из кандидатов могут договориться об установке такого же расширения для браузера. В этом случае прямо по ходу голосования они могут отслеживать минимум голосов, который точно должен получить их кандидат после подсчета.

Разработчики системы интернет-голосования могут запретить избирателям пользоваться одной и той же парой ключей, но это их не спасет. Дмитрий Честных предложил возможные пути обхода такого запрета: «Например, такое расширение может генерировать ключи детерминистически, взяв хэш от статичного секрета и имени (и какого-нибудь номера избирателя) — тогда это обнаружить будет сложно, потому что пары ключей будут разные, но тот, кто владеет секретом, может их заново сгенерировать». То есть для внешнего наблюдателя ключи, сгенерированные расширением, будут выглядеть случайными, но авторы этого расширения смогут восстановить ключи, зная определенные дополнительные параметры. Еще один вариант, предложенный автором TweetNaCl.js: «Расширение может просто писать ключи в центральную базу. Алгоритм Curve25519 очень быстрый, поэтому расшифровать миллионы голосов не составит труда».

«В любом случае это, конечно, полный бред, а не система электронного голосования», — резюмировал Дмитрий Честных.

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

Неожиданный бонус! Избиратели смогут оставлять сообщения в электронных бюллетенях — подобно надписям на бумажных

На странице электронного бюллетеня в браузере избирателя генерируется не только пара ключей, но и nonce — специальное число, которое должно меняться при создании нового шифротекста (number used only once).

Оно генерируется случайным образом, но теоретически его тоже можно подменить с помощью расширения. Это число достаточно длинное, чтобы персонализировать бюллетень. 24 байта позволяют записать пару слов на русском языке в кодировке UTF-8 (или целую фразу на английском), поставить несколько эмодзи или высказаться каким-то другим образом. На качество шифрования в данном случае это не повлияет.

Правда, чтобы прочитать такое сообщение, скорее всего, тоже нужно будет устанавливать специальное расширение или ждать подборок «расшифрованных» посланий от наблюдателей.

Денис Дмитриев

Автор благодарит за участие в эксперименте Михаила Зеленского, Евгению Давыдову и Дмитрия Карцева

«Медуза» — это вы! Уже три года мы работаем благодаря вам, и только для вас. Помогите нам прожить вместе с вами 2025 год!

Если вы находитесь не в России, оформите ежемесячный донат — а мы сделаем все, чтобы миллионы людей получали наши новости. Мы верим, что независимая информация помогает принимать правильные решения даже в самых сложных жизненных обстоятельствах. Берегите себя!