Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Цикл разрывает логику в grasshopper_decrypt_block #408

Open
marcfedorow opened this issue Jul 14, 2022 · 5 comments
Open

Comments

@marcfedorow
Copy link
Contributor

Есть такой фрагмент кода:

    grasshopper_append128multi(buffer, target, grasshopper_l_dec128);

    for (i = 9; i > 1; i--) {
        grasshopper_append128(target, &subkeys->k[i]);
        grasshopper_append128multi(buffer, target, grasshopper_pil_dec128);
    }

    grasshopper_append128(target, &subkeys->k[1]);
    grasshopper_convert128(target, grasshopper_pi_inv);

На самом деле это ничто иное как

    grasshopper_append128(target, &subkeys->k[9]);
    for (i = 9; i > 0; i--) {
        grasshopper_append128multi(buffer, target, grasshopper_lipi_dec128);
        grasshopper_append128(target, &subkeys->k[i-1]);
    }

, где grasshopper_lipi_dec128 -- несуществующая таблица.
grasshopper_pil_dec128 делает сперва pi, а потом l (аналогично случаю для зашифрования). Проблема в том, что для расшифрования это надо делать в обратном порядке (сперва l_dec, а потом pi_inv).

Я предлагаю предвычислить таблицу, которая нужна для этой задачи, и использовать её (а grasshopper_pi_inv и grasshopper_pil_dec128 удалить, потому что они больше нигде не нужны).

У меня нет генераторов для этих таблиц. Если они у кого-то есть, наверное, будет лучше если это сделает человек с генераторами.
Если такого человека нет, но моё предложение сочтут хорошим, я готов попытаться сделать это сам.

@beldmit
Copy link
Contributor

beldmit commented Jul 14, 2022

Можете дать ссылку на кусок кода, чтобы я контекст увидел?

@marcfedorow
Copy link
Contributor Author

void grasshopper_encrypt_block(grasshopper_round_keys_t* subkeys, grasshopper_w128_t* source,
grasshopper_w128_t* target, grasshopper_w128_t* buffer) {
int i;
grasshopper_copy128(target, source);
for (i = 0; i < 9; i++) {
grasshopper_append128(target, &subkeys->k[i]);
grasshopper_append128multi(buffer, target, grasshopper_pil_enc128);
}
grasshopper_append128(target, &subkeys->k[9]);
}
void grasshopper_decrypt_block(grasshopper_round_keys_t* subkeys, grasshopper_w128_t* source,
grasshopper_w128_t* target, grasshopper_w128_t* buffer) {
int i;
grasshopper_copy128(target, source);
grasshopper_append128multi(buffer, target, grasshopper_l_dec128);
for (i = 9; i > 1; i--) {
grasshopper_append128(target, &subkeys->k[i]);
grasshopper_append128multi(buffer, target, grasshopper_pil_dec128);
}
grasshopper_append128(target, &subkeys->k[1]);
grasshopper_convert128(target, grasshopper_pi_inv);
grasshopper_append128(target, &subkeys->k[0]);
}

@beldmit
Copy link
Contributor

beldmit commented Jul 14, 2022

Расшифрование на практике нам нужно только в CBC, я правильно помню?

Вообще оптимизацию Кузнечика надо начинать не с этого.

@vt-alt
Copy link
Member

vt-alt commented Jul 14, 2022

Проблема в том, что для расшифрования это надо делать в обратном порядке (сперва l_dec, а потом pi_inv).

Ошибка в расшифровке или просто "код не в том порядке", а результат правильный? Не помню, чтоб у нас были ошибки с расшифровке Кузнечика. А если всё работает правильно, то в чем проблема?

@marcfedorow
Copy link
Contributor Author

marcfedorow commented Jul 14, 2022

Код работает верно (результат правильный).
Попытаюсь объяснить, почему я считаю, что код "не в том порядке".

Функция делает следующее:

void grasshopper_decrypt_block(grasshopper_round_keys_t* subkeys, grasshopper_w128_t* source, 
                                grasshopper_w128_t* target, grasshopper_w128_t* buffer) { 
     int i; 
     grasshopper_copy128(target, source);
     L_INV // одна таблица
     for (i = 9; i > 1; i--) { 
         XOR с ключом расшифрования
         PI_INV; L_INV // вторая таблица
     } 
     XOR
     PI_INV // третья таблица
     XOR
 } 

Столько таблиц не нужно.
Если просто развернуть PI_INV+ L_INV в две функции, будет видно, что цикл преобразуется в

void grasshopper_decrypt_block(grasshopper_round_keys_t* subkeys, grasshopper_w128_t* source, 
                                grasshopper_w128_t* target, grasshopper_w128_t* buffer) { 
     int i; 
     grasshopper_copy128(target, source);
     for (i = 9; i > 0; i--) {  //  добавили итерацию
         L_INV // одна таблица
         XOR с ключом расшифрования
         PI_INV // вторая таблица
     } 
     XOR
 } 

Разумеется, мы не хотим оставлять две таблицы (для зашифрования же нужна всего одна).
Для этого надо вспомнить, что

  1. L_INV(a) xor L_INV(b) = L_INV(a xor b)
  2. В функции вычисления раундовых ключей зашифрования мы уже сделали L_INV над всеми ключами.

Если мы не будем делать действие из (2), то мы сможем поменять XOR и L_INV:

void grasshopper_decrypt_block(grasshopper_round_keys_t* subkeys, grasshopper_w128_t* source, 
                                grasshopper_w128_t* target, grasshopper_w128_t* buffer) { 
     int i; 
     grasshopper_copy128(target, source);
     for (i = 9; i > 0; i--) { 
         XOR с ключом
         L_INV // здесь происходит линейное преобразования и ключа, и текста
         PI_INV
     } 
     XOR
 } 

В этот момент мы видим, что L_INV и PI_INV находятся друг рядом с другом, а значит для их вычисления нужна только одна таблица. Это позволит избавиться от двух других ненужных таблиц: PI_INV вообще больше нигде не использовался, а L_INV использовался только в действии из (2), которое мы решили не делать.

В качестве финальной версии я предлагаю

void grasshopper_decrypt_block(grasshopper_round_keys_t* subkeys, grasshopper_w128_t* source, 
                                grasshopper_w128_t* target, grasshopper_w128_t* buffer) { 
     int i; 
     grasshopper_copy128(target, source);
         XOR с ключом[9]
     for (i = 9; i > 0; i--) { 
         L_INV // здесь происходит линейное преобразования и ключа, и текста
         PI_INV
         XOR с ключом[i - 1]
     } 
 } 

, или если писать на языке тех функций, которые там реально есть,

 void grasshopper_decrypt_block(grasshopper_round_keys_t* subkeys, grasshopper_w128_t* source, 
                                grasshopper_w128_t* target, grasshopper_w128_t* buffer) { 
     int i; 
     grasshopper_copy128(target, source); 
     grasshopper_append128(target, &subkeys->k[9]); 
     for (i = 9; i > 0; i--) {  
         grasshopper_append128multi(buffer, target, grasshopper_lpi_dec128); 
         grasshopper_append128(target, &subkeys->k[i-1]);
     } 
 } 

, где grasshopper_lpi_dec128 -- новая таблица, которую надо вычислить, которая по мсмыслу сперва делает L_INV, а потом делает PI_INV.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants