# CRYPTO-3
Оценка: 30
## Описание
В данном задании участнику необходимо найти секрет в уязвимой версии протокола.
## Решение
В данной задаче участнику необходимо найти секрет в уязвимой версии протокола Дифи-Хеллмана. По предположению протокола оба участника обмена не должны знать ключи друг друга. Уязвимость в данном задании заключается в том, что секрет постоянен. Участнику необходимо собрать достаточно дискретных логарифмов по подгруппам (по которым легко считать дискретный логарифм) и найти ответ при помощи китайской теоремы об остатках, взяв как остатки - дискретные логарифмы, а как модули — порядки подгрупп, по которым дискретный логарифм считался.
Участником предоставлялось множество уравнений:
```python3
pow(g,answer,p) == x
```
Где answer -- ответ на задачу, а g и p - разные в каждом уравнении.
Участнику необходимо модифицировать алгоритм Полига-Хеллмана для постоянного секрета и множества уравнений. Ниже представлена одна из возможных реализаций:
```python3
from sage.all import *
from factorize import factorize as ife
import math
from info import info as infos
from libnum import solve_crt
from Crypto.Util.number import *
import requests
import time
#main idea to find small factors of an order of element
#than take subgroup of order with small factor and compute discrete log
#than take crt and win
url = 'http://127.0.0.1:5000'
# Данная функция получает уравнение
def get_info(num):
anses = []
for _ in range(num):
anses.append(requests.get(f"{url}/shared_flag").json())
return anses
# Данная функция получает делитель числа number, находящийся в промежутке от 2^10 до 2^40
def find_convinient_factor(number, min=2**10, max=2**40):
factors = ife(number)
maxi = None
for i in range(len(factors)):
if min < factors[i] < max:
maxi = factors[i]
return maxi
# Данная функция находит маленький дискретный логарифм по подгруппе, порядка маленького множителя порядка группы.
def get_small_discrete_log(info):
p = info['p']
g = info['g']
order = p - 1
# Находим новый порядок подгруппы
_factor = find_convinient_factor(order)
if _factor is None:
return None, None
# Если смогли найти удобный для нас множитель
G = GF(p)
# Переходим в подгруппу порядка _factor
new_g = G(pow(g, order//_factor, p))
new_secret = G(pow(info['shared_flag'], order//_factor, p))
# Считаем дискретный логарифм по подгруппе маленького порядка
flag_part = discrete_log(new_secret, new_g, _factor)
# Возвращаем результат логарифмирования и порядок подгруппы
return flag_part, _factor
# Данная функция вызывает get_small_discrete_log пока не будет достаточно информации для получения ответа
def handle_info(infos):
orders = []
remainders = []
for info in infos:
parted = get_small_discrete_log(info)
if parted[1] is not None:
if parted[1] not in orders:
orders.append(parted[1])
remainders.append(parted[0])
print(f"{prod(orders).bit_length()}/180 of progress", end = '\r')
if prod(orders) > 2**180:
return orders, remainders
return orders, remainders
def solve():
ords, rems = handle_info(infos)# Находим результаты логарифмирования и порядки подгрупп, в которых эти логарифмы были найдены
# При помощи китайской теоремы об остатках находим ответ.
print(long_to_bytes(solve_crt(rems,ords )).decode())
if __name__ == "__main__":
solve()
```