Представитель Шуры Люберецкого в ЖЖ (brat_luber) wrote,
Представитель Шуры Люберецкого в ЖЖ
brat_luber

Categories:

Бесит, сука

Вот посмотрел я на то, из чего состоит rawStoreBallotTx, передающийся на сервер и сохраняющийся в блокчейн при электронном голосовании в Москве. Разбираться с обширным кодом клиента Exonum на Javascript я не стал, а просто глянул на сами данные.

58 1c c8 b3 ed 95 97 f3 f4 ab c7 76 1d 17 c3 02
a3 d5 3e 59 c8 c7 6c 55 04 4b f0 d3 91 e7 fc c1
00 00 e9 03 06 00 0a 40 64 61 38 35 66 61 66 38
34 66 61 65 62 30 65 39 30 65 66 33 31 61 32 65
37 32 35 32 34 31 35 31 66 62 61 63 30 65 32 66
36 65 36 63 34 39 38 33 36 30 31 33 64 36 34 35
32 39 34 36 39 38 38 64 10 4d 1a 56 0a 14 bc ef
fd 5e 5e a6 8a 6b b2 d9 04 31 dd 51 2e 11 5e 4c
44 e3 12 1a 0a 18 9b 37 cb a5 f0 26 25 ca 74 45
00 21 88 e1 59 ca 56 ee d5 24 dd 25 d3 26 1a 22
0a 20 57 1d b7 6c 24 f5 85 22 7e 75 4c ca e6 97
99 8f f6 22 6b 24 58 94 b9 0d 57 b0 f3 d5 9a 0c
16 01 9d c1 e2 eb 1d 8d 8a cf 12 60 27 3f f0 2e
cc ba 5d 9f 61 e0 ba 51 a7 d2 26 78 82 d1 05 6d
a5 92 93 75 7d 5a c5 23 e0 45 f7 f9 8d 6b ed 4f
33 fe d7 c2 e2 48 77 c6 61 9b 10 86 b3 c7 a7 73
3f 0d

Первые 32 байта – это некий идентификатор под названием accountAddressBlock; дальше начинается что-то непонятное – но резко выделяется довольно длинная последовательность из байт в диапазоне 30-39 и 60-66 – это цифры и буквы от a до f. Выпишем ее отдельно (справа – символы, которым эти байты соответствуют):

                        64 61 38 35 66 61 66 38            da85faf8
34 66 61 65 62 30 65 39 30 65 66 33 31 61 32 65    4faeb0e90ef31a2e
37 32 35 32 34 31 35 31 66 62 61 63 30 65 32 66    72524151fbac0e2f
36 65 36 63 34 39 38 33 36 30 31 33 64 36 34 35    6e6c49836013d645
32 39 34 36 39 38 38 64                            2946988d

Что это? А это как раз voting id, идентификатор голосования – только зачем-то переданный в виде текста. Сразу же хочется обратить внимание на байт 40, стоящий непосредственно перед voting id – да и вообще на всю последовательность 00 00 e9 03 06 00 0a 40 – хочется считать ее неким заголовком, а 40 – длиной поля. По аналогии находим еще три подобных последовательности – “заголовок” 10 4d 1a 56 0a 14 (в кавычках, и я сейчас объясню, почему) предшествует 20 байтам

                                          bc ef
fd 5e 5e a6 8a 6b b2 d9 04 31 dd 51 2e 11 5e 4c
44 e3

Заголовок 12 1a 0a 18 – последовательности из 24 байт:

                  9b 37 cb a5 f0 26 25 ca 74 45
00 21 88 e1 59 ca 56 ee d5 24 dd 25 d3 26

А заголовок 1a 22 0a 20 – 32 байтам:

      57 1d b7 6c 24 f5 85 22 7e 75 4c ca e6 97
99 8f f6 22 6b 24 58 94 b9 0d 57 b0 f3 d5 9a 0c
16 01

Казалось бы, это вся информация для записи в блокчейн? Но нет – не хватает district id, номера “участка” (здесь он принимал логичные значения 77 и 52 для Москвы и Нижнего Новгорода соответственно). Где он мог потеряться? Оказывается, первый “заголовок” из 6 байт – это на самом деле еще и поле с номером участка, 10 4d (4d в шестнадцатиричной системе – это как раз 77).

В оставшихся 64 байтах я какой-то структуры уже не увидел, но в целом для расшифровки голоса они нам уже не нужны. Вспоминаем структуру данных для передачи – это должны быть зашифрованный голос, nonce и публичный ключ пользователя; в используемой для голосования библиотеке NaCl длина nonce и публичного ключа как раз составляет 24 и 32 байта соответственно, 20 байт – это длина сообщения. Кажется, мы нашли все необходимое? Проверяем несложной программой:

unsigned char message[] = {
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0xbc, 0xef, 0xfd, 0x5e, 0x5e, 0xa6, 0x8a, 0x6b,
    0xb2, 0xd9, 0x04, 0x31, 0xdd, 0x51, 0x2e, 0x11,
    0x5e, 0x4c, 0x44, 0xe3
}; // first 16 bytes must be 0

unsigned char nonce[] = {
    0x9b, 0x37, 0xcb, 0xa5, 0xf0, 0x26, 0x25, 0xca,
    0x74, 0x45, 0x00, 0x21, 0x88, 0xe1, 0x59, 0xca,
    0x56, 0xee, 0xd5, 0x24, 0xdd, 0x25, 0xd3, 0x26
};

unsigned char public_key[] = {
    0x57, 0x1d, 0xb7, 0x6c, 0x24, 0xf5, 0x85, 0x22,
    0x7e, 0x75, 0x4c, 0xca, 0xe6, 0x97, 0x99, 0x8f,
    0xf6, 0x22, 0x6b, 0x24, 0x58, 0x94, 0xb9, 0x0d,
    0x57, 0xb0, 0xf3, 0xd5, 0x9a, 0x0c, 0x16, 0x01
};

unsigned char dit_private_key[] = {
    0xdb, 0x77, 0xd6, 0x2f, 0xc8, 0x87, 0x26, 0xf1,
    0xc5, 0xa6, 0xb7, 0x9b, 0x00, 0x3b, 0x3b, 0xca,
    0x83, 0x34, 0x9e, 0x33, 0x43, 0x37, 0xde, 0x84,
    0xbd, 0x17, 0x34, 0x4a, 0xb6, 0x01, 0xdb, 0x74
};

unsigned char buf[sizeof(message)] = { 0 };

int res, vote;

res = crypto_box_open(buf, message, sizeof(message), nonce, public_key, dit_private_key);
vote = *((int*)(buf + crypto_secretbox_ZEROBYTES));
printf("%x\r\n", vote);

И действительно – расшифрованное сообщение содержит 4 байта 1a d5 be 0d – голос “против” на этом голосовании.

Так вот, возвращаясь к тому, что бесит. Во-первых, бесят просранные талантливыми фронтендерами 32 байта – зачем засовывать voting id в виде строки? Во-вторых – бесит полное отсутствие описание формата передаваемых данных – вот я его разобрал довольно элементарным способом, но пока так и не знаю о назначении еще 64 байт в конце – похоже, что это как-то связано с блокчейном и криптографической подписью для него, но я не уверен.

Боженька, побей их всех по голове ЕСПД.

Запись опубликована в блоге Шуры Люберецкого. Вы можете оставлять свои комментарии там, используя свое имя пользователя из ЖЖ (вход по OpenID).

Subscribe

  • Two-pizza team

    Интересно, а «тупица-тим» я в этом выражении один вижу? Запись опубликована в блоге Шуры Люберецкого. Вы можете оставлять свои…

  • Я не эстонец, но торможу

    Спустя почти год после вынужденного перехода на удаленку решил проблему сосуществования на одном рабочем столе «рабочего» и…

  • А помните Альтависту?

    Пока писал в ЖЖ коммент — подумалось — вот помните такой древнючий поисковик Altavista? Времен «раннего интернета», когда еще…

  • Post a new comment

    Error

    default userpic

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 0 comments