---
# System prepended metadata

title: Bside Indore
tags: [DH_LCG]

---

# DiffieHellman
- DiffieHellman.py
```python=
from Crypto.Util.number import *
from secrets import randbelow

flag = b'BSidesIndore{?????????????????????????????????????????}'


p = getPrime(1024)
a = randbelow(p)
b = randbelow(p)
s = randbelow(p)

#private_key
na = randbelow(p)
nb = randbelow(p)

def f(z):
    return (a * z + b) % p

def compose_f(z , n):
    for _ in range(n):
        z = f(z)
    return z

#public_key
A = compose_f(s, na)
B = compose_f(s, nb)

shared_secret = compose_f(A, nb)
assert compose_f(B, na) == shared_secret

m = bytes_to_long(flag)
hint = (shared_secret * m) % p


print('p=' , p)
print('a=' , a)
print('b=' , b)
print('s=', s)
print('A=' , A)
print('B=' , B)
print('Hint=' , hint)
```
- output.txt
```
p= 177570430264404042586947209415361175829662877465021738163452003044204801236884005980142784114098378718171232421758262680024168974955507208327903586791589504974287563947107311706980541752128561476280897335081377540882450802053121704994636737618193754484639531123445136371629051163053932580571940280678765406507
a= 43956506117080063425552748919558963635605098605326775979012360863142443520592114771800350897421485025125720482734237579881628822814442838128036568093867197695237846018696049279357474258871874227658474923562729861151927356523476281314556495465881999078214836635672825087229897489780543610449600598310975845972
b= 174696548246270768822111154128350984851623375416115231737870633294112190977226571494266879050596220994493007232484609234595354342745045435123046789963360269847186352233769676144998148572751650872487364118516515673999802276136983028240521720649825627376559451556059366974145722267864743175103312487712498074749
s= 12434113186075391543764483911407788417903733970619704242876093325272607987251561194578833768854877839420807906348010197072863684238585629167767699669787141090172275735228322001099182693707345110444778401752303810786206722286874416348628222046081716777562273093345200683040455119310424421838556869940942435673
A= 136407737305511360356397851151387434747104130517942844746307421591300142246172197908094415745159427162154420196514774405243398839327050657296253147517687400701852380101057349604958670296473446404895687124842088949969419486055881611144671929238142825450181746276221000200846658169851653919504352250739069860730
B= 26467203262894711969159457169326125007000815712021405657352754729857627693311672965448787149024723113418146398326650495992712486220869311766554396353531102926524277200284073965641737905200427505698807999274743916487363108331073718034682818342814978156028844309220276666373635341609073539725142950450555754476
Hint= 111835764538968835283671465944316573442933510238606935593825235958809709981307851841392212790079210442271736305104653249935653746189422754282042111667903170916672655913492221169563628845786374370984595021502163203501215307272819616639858055813062468690363664768682360975293577533019188775265576784532652545007
```
- Đoạn code trên mô tả lại giao thức trao đổi khóa Diffie-Hellman (DH) để tạo ra một khóa chia sẻ (shared_secrets) giữa hai bên trao đổi thông tin (nếu bạn không rõ về nó thì có thể đọc thêm tại [đây](https://vi.wikipedia.org/wiki/Trao_%C4%91%E1%BB%95i_kh%C3%B3a_Diffie-Hellman)) 
- Bài này thay vì tính toán trong một multiplicative group như các bài DH thông thường thì họ sử dụng [LCG](https://en.wikipedia.org/wiki/Linear_congruential_generator) (Linear congruential generator). Qua đoạn code thì ta thấy:
    - Đề bài cho một hàm `f(x) = ax + b mod p`
    - Tính $A = f_{n_B}(s)$, $B = f_{n_A}(s)$ với $f_n(x) = f(f(..(f(x))))$ (n hàm f)
    - Tính shared_secret = $f_{n_B}(A)$ hoặc $f_{n_A}(B)$
    - Tính `hint = (shared_secret * m) mod p` với m là `bytes_to_long(flag)`
- Mấu chốt ở đây mình phải tìm được `shared_secret`. Dễ thấy shared_secret = $f_{n_A+n_B}(s)$ nên ý tưởng ban đầu là phải tìm bằng được 2 số n_A và n_B
- Mình sẽ thực hiện biến đổi một tí (lưu ý mình đang biến đổi trên Fp):
$f_1(x) = ax + b$ 
$f_2(x) = a(ax + b) + b = a^2x + ab + b$ 
$f_3(x) = a(a^2x+ab+b)+b = a^3x + a^2b + ab + b$ 
...
Ta có thể dự đoán: $f_n(x) = a^nx + a^{n-1}b + a^{n-2}b+ ... + ab + b$
Thực hiện biến đổi một tí cho gọn nào:
$(a-1).(f_n(x) - x) = (a-1)(a^nx -x + a^{n-1}b + a^{n-2}b+ ... + ab + b)$
$= (a-1).x(a^n-1) + b(a^n-1)$
$= (a^n-1)(b+x(a-1))$
Vì vậy, từ $A = f_{n_B}(s)$ suy ra $(a-1)(A-s) = (a^{n_B}-1)(s(a-1) + b)$ 
$\Rightarrow a^{n_B} = (a-1).(A-s).(s(a-1)+b)^{-1} + 1$
Mình cũng sẽ tìm được $a^{n_A}$ theo cách tương tự.
- Để tìm được $n_A, n_B$, mình phải giải bài toán [DLP](https://en.wikipedia.org/wiki/Discrete_logarithm) và tất nhiên nó là bài toán khó.Tuy nhiên để ý rằng:
shared_secret = $f_{n_A+n_B}(s) = (a^{n_A+n_B}-1)(s(a-1)+b).(a-1)^{-1}+s$
Dễ dàng tính được $a^{n_A+n_B} = a^{n_A}.a^{n_B}$, vì vậy mình có thể tìm shared_secret mà không cần tìm $n_A,n_B$.
- Vậy là xong phần ý tưởng rồi, code thôi ^^
```python=
p= 177570430264404042586947209415361175829662877465021738163452003044204801236884005980142784114098378718171232421758262680024168974955507208327903586791589504974287563947107311706980541752128561476280897335081377540882450802053121704994636737618193754484639531123445136371629051163053932580571940280678765406507
a= 43956506117080063425552748919558963635605098605326775979012360863142443520592114771800350897421485025125720482734237579881628822814442838128036568093867197695237846018696049279357474258871874227658474923562729861151927356523476281314556495465881999078214836635672825087229897489780543610449600598310975845972
b= 174696548246270768822111154128350984851623375416115231737870633294112190977226571494266879050596220994493007232484609234595354342745045435123046789963360269847186352233769676144998148572751650872487364118516515673999802276136983028240521720649825627376559451556059366974145722267864743175103312487712498074749
s= 12434113186075391543764483911407788417903733970619704242876093325272607987251561194578833768854877839420807906348010197072863684238585629167767699669787141090172275735228322001099182693707345110444778401752303810786206722286874416348628222046081716777562273093345200683040455119310424421838556869940942435673
A= 136407737305511360356397851151387434747104130517942844746307421591300142246172197908094415745159427162154420196514774405243398839327050657296253147517687400701852380101057349604958670296473446404895687124842088949969419486055881611144671929238142825450181746276221000200846658169851653919504352250739069860730
B= 26467203262894711969159457169326125007000815712021405657352754729857627693311672965448787149024723113418146398326650495992712486220869311766554396353531102926524277200284073965641737905200427505698807999274743916487363108331073718034682818342814978156028844309220276666373635341609073539725142950450555754476
Hint= 111835764538968835283671465944316573442933510238606935593825235958809709981307851841392212790079210442271736305104653249935653746189422754282042111667903170916672655913492221169563628845786374370984595021502163203501215307272819616639858055813062468690363664768682360975293577533019188775265576784532652545007

# from sympy.ntheory import discrete_log
from Crypto.Util.number import *
def decompose_f(C):
	ans = (C - s) % p
	ans = (ans * (a-1) * pow(b + (a-1)*s, -1,p) + 1) % p
	# assert (ans - 1) * (s*(a-1)+b) % p == (a-1)*(C - s) % p
	return ans

pow_nb = decompose_f(A)
pow_na = decompose_f(B)
shared_secret = ((pow_na * pow_nb - 1) * (s*(a-1) + b) * pow(a-1,-1,p) + s) % p
# assert (a-1)*(shared_secret - s)% p == (pow_nb * pow_na -1) * (s*(a-1) + b) % p
m = Hint * pow(shared_secret, -1, p) % p
print(long_to_bytes(m))
# BSidesIndore{yOu_5hou1D_7ry_S0M3ThIn9_elSe_o7h3r_TH4n_lcg}

```
- Flag: `BSidesIndore{yOu_5hou1D_7ry_S0M3ThIn9_elSe_o7h3r_TH4n_lcg}`