###### tags: `Computer Security`
# HW0x01 Writeup (Crypto)
[TOC]
## 1. nLFSR
先建出Companion Matrix:
```python=
poly = 0xaa0d3a677e1be0bf
binpoly = str(poly.binary())
F.<x> = PolynomialRing(GF(2))
pList = []
for i in range(len(binpoly)):
pList.append(-int(binpoly[i]))
pList.append(1)
C = companion_matrix(pList, format = 'bottom')
```
C是64x64的矩陣,所以我們會需要64個bits來解出key,可以先隨便輸出,用一開始給的1.2$得到這些bits(可能錢會不夠但機率不大)
```python=
out = []
previous = 1.2
for i in range(64):
r.sendline(b'0')
line = r.recvline().decode()
money = float(line.split('> ')[1].split('\n')[0])
if (money > previous): #correct ansewr
out.append(0)
else: #wrong answer
out.append(1)
previous = money
print(out)
```
又,從server code可以看出output每過43次step會output一次,不是連續的,所以C不能直接拿來用
可以用課程說的方式把真正拿來解key時要用的Matrix建出來
```python=
m = matrix(GF(2), 64)
A = C^42
unit = C^43
for i in range(64):
row = A * (unit^(i))
m[i] = row[0]
# m * key = out
b = vector(out)
kl= m^-1 * b
```
有了key就可以讓它生成一串output,再丟回去給server,拿到flag。
```python=
ans = []
for i in range(64, 64+121):
outputrow = A * (unit^(i)) * kl
output = outputrow[0]
ans.append(output)
print(ans)
```
:::success
:triangular_flag_on_post: FLAG{2iroO742LwA2ES1Cwewx}
:::
---
## 2. Single
題目給了兩個橢圓曲線上的點,可以先用這兩個點把曲線的係數a、b求出來:
```python=
numerator = (((A.y ** 2) % p) - ((B.y ** 2) % p) -
(((A.x ** 3) % p) - ((B.x ** 3) % p))) % p
denominator = (A.x - B.x) % p
a = numerator * inverse(denominator, p) % p
b = (((A.y ** 2) % p) - ((A.x ** 3) % p) - ((a * A.x) % p)) % p
```
求出來後就可以發現4a^3^+27b^2^=0(mod p)
:::info
a =
9605275265879631008726467740646537125692167794341640822702313056611938432994
b = 7839838607707494463758049830515369383778931948114955676985180993569200375480
4a^3 + 27b^2 = 0
:::
為了得知該Singular曲線是Node型還是Cusp型,可以用Sage的roots()來找根:
```python=
a = 9605275265879631008726467740646537125692167794341640822702313056611938432994
b = 7839838607707494463758049830515369383778931948114955676985180993569200375480
x = PolynomialRing(GF(p), 'x').gen()
eq = x^3 + a * x + b
roots = eq.roots()
```
:::info
[(7925182757193285961316626419940151258451119718064102936455321651294650340555,
1),
(853242911173207820721903052331400912971957115055181874915218687301323932414,
2)]
:::
有一根及一二重根,故為Node型。
從講義得知,Node型的曲線可以藉由定義$φ(P(x,y))=\dfrac{y+\sqrt{α-β}(x-α)}{y-\sqrt{α-β}(x-α)}$
來得到φ(dP)=φ(P\)^d^,接著可以用Pohlig-Hellmen把d求出。
```python=
alpha = roots[1][0]
beta = roots[0][0]
t = GF(p)(alpha - beta).square_root()
def phi(P):
numer = P.y + t * (P.x - alpha)
denom = P.y - t * (P.x - alpha)
return (numer / denom) % p
# phi(A) = phi(G)^dA
ca = phi(A)
cb = phi(B)
g = phi(G)
p = 9631668579539701602760432524602953084395033948174466686285759025897298205383
n = factor(p-1)
def pohel(g, c, n):
f = [fi[0] for fi in n]
x = []
for fi in f:
gi = pow(g, (p-1)//fi, p)
hi = pow(c, (p-1)//fi, p)
xi = bsgs(gi, hi, (0, fi))
x.append(xi)
k = crt(x, f)
#pow(g, k, n) == c
return k
dA = pohel(g, ca, n)
dB = pohel(g, cb, n)
dA, dB
```
:::info
(1532487521612462894579517163606359285989568203515734083099567402780433190052,
3812736493733305483749266829321957602546252009705107605004286667532073783392)
:::
有了dA、dB後就可以把flag解出來了。
```python=
dA = 1532487521612462894579517163606359285989568203515734083099567402780433190052
dB = 3812736493733305483749266829321957602546252009705107605004286667532073783392
#Decryption
k = point_multiply(B, dA).x
k = hashlib.sha512(str(k).encode('ascii')).digest()
flag = bytes(ci ^ ki for ci, ki in zip(enc.ljust(len(k), b'\0'), k))
flag
```
:::success
:triangular_flag_on_post: FLAG{adbffefdb46a99fad0042dd3c10fdc414fadd25c}
:::
---
## 3. HNP-rev
解法與講義上的方法類似,差別在於k多了一項常數md5(b'secret').hexdigest()
令這個常數為α(轉成數字後要再乘2^128^,這邊不小心踩到坑qq),講義式子的k~1~、k~2~換成k~1~+α、k~2~+α並代入可以得到如下的結果:
$k_1+α-s_1^{-1}h_1-s_1^{-1}r_1s_2r_2^{-1}k_2-s_1^{-1}r_1s_2r_2^{-1}α+s_1r_1r_2^{-1}h_2\equiv0\ (mod\ n)$
只要改令v、u為:
$v=-s_1^{-1}r_1s_2r_2^{-1}k_2$ , $u=α-s_1^{-1}h_1-s_1^{-1}r_1s_2r_2^{-1}α+s_1r_1r_2^{-1}h_2$
就可以用跟講義一樣的方法解了。
```python=
K = 2^127
L = matrix(ZZ, [[n, 0, 0] ,[t, 1, 0], [u, 0, K]])
v = L.LLL()
k1 = -v[0][0]
v, K
```
LLL之後會有一個vector v在解出的3個vector內,我是利用解出的vector反推回d,再計算dG看看是否與Public Key給出的座標一樣
```python=
crack_k1 = k1 + alpha
d1 = ((s1 * crack_k1 - h1) * inverse_mod(r1, n)) % n
(d1*G).x() == pubkey_x
```
應該是因為上界的問題,不是每次嘗試都會成功,但多試幾次找到dG出來跟公鑰一樣的結果後,就可以用這個d去做簽章得到r、s
```python=
d = d1
k1_real = (inverse_mod(s1, n) * (h1 + d * r1)) % n
k2_real = (inverse_mod(s2, n) * (h2 + d * r2)) % n
pubkey = Public_key(G, d1*G)
prikey = Private_key(pubkey, d1)
h = 'Kuruwa'
h = sha256(h.encode()).digest()
k = int(md5(b'secret').hexdigest() + md5(long_to_bytes(prikey.secret_multiplier) + h).hexdigest(), 16)
sig = prikey.sign(bytes_to_long(h), k)
print(f'sig = ({sig.r}, {sig.s})')
```
:::success
:triangular_flag_on_post: FLAG{adfc9b68bd6ec6dbf6b3c9ddd46aafaea06a97ee}
:::