---
# System prepended metadata

title: HW 0x0A Write Up
tags: [Course, CS, NCTU, SecureProgramming]

---

###### tags: `NCTU` `CS` `Course` `SecureProgramming`

HW 0x0A Write Up
==
yysung

## [Lab 10-1] Crypto Lab 1

題目給定 RSA 的公鑰 (n, e) 和以 flag 加密的加密文字 c

並且提供可以解密任意密文並回傳明文 least significant bit (LSB) 的功能

可以建構 c * 2^e = m^e * 2^e = (2m)^e 也就是 2m 的密文並傳送給 server 得到明文的 LSB

假設 0 < m < n/2 可以得知  2m < n

2m % n % 2 = 2m % 2 = 0

假設 n/2 <= m < n 可以得知 2n > 2m >= n

2m % n % 2 = (2m - n) % 2 = (偶 - 奇) % 2 = 1

就可以知道 m 的範圍是 [0, 2/n) 還是 [2/n, n)

接下來可以推廣 c * 2^(ke) = (2^k m)^e

假設 tn / 2^k < m < (t+1)n / 2^k 且 t % 2 == 0

2^k m % n % 2 = 2^k m - tn % 2 = (偶 - 偶) % 2 = 0

假設 tn / 2^k < m < (t+1)n / 2^k 且 t % 2 == 1

2^k m % n % 2 = 2^k m - tn % 2 = (偶 - 奇) % 2 = 1

可以迭代的將 m 的範圍縮小，每代都可以將範圍減少一半，做 1024 次後就會非常接近 m 的值，就可以得到 flag 了

## [Lab 10-2] Crypto Lab 2

題目是將 一段已知的文字 + 未知的 flag 作加密， flag 長度給定 17bytes

可以建構方程式
```
f(x) = (message * 2 ^ (8 * 17) + x) ^ e - c
```

並使用 sage 解方程式

解出來的根就是 flag

## [HW 0x0A] Can You Decrypt?

題目先生成三個質數 (p, q1, q2)

p 是隨機選擇數個 3~1024 之間的質數相乘再乘以 2 加 1，並且生成至質數為止

q1 和 q2 是隨機 r = 100 ~ 2^512

並以 (next_prime(r), next_prime(3 * next_prime(r))) 作為兩質數

再用 4 * randint(10, 100) 生成 e 並確保 gcd(e, phi) = 4

用 n = p * q1 * q2 和 e 作為公鑰並加密 flag 為 c

只能拿到 (n, e, c)

需要先將 p, q1, q2 解出

p 的生成方式符合 Pollard's p-1 algorithm 能解的質數

剩下的 q1, q2 可以用二分搜 100 ~ 2^512 來找出

接下來就可以開始還原 m^e

e = 388 = 4 * 97

m^e = (m\^4)^97

可以先對三個質數分別將 m^4 解出

解法是
```
對於質數 p
m ^ (p-1) % p == 1 (根據費馬小定理)
m ^ x % p == m when x % (p - 1) == 1

設 t = m^4
(t^97)^(invert(97, p - 1)) % p
= t^(97 * invert(97, p - 1)) % p
= t^(k(p - 1) + 1) % p (k > 0)
= (t^(k(p - 1)) % p) * (t % p) 
= t % p
= m^4 % p
```

接下對三個質數將 m^4 做兩次 modular_sqrt

用 Chinese Remainder Theorem 對 64 種四次方值求解

就可以在其中一種組合中還原出 flag 了

## [HW 0x0A] Yet Another Oracle

這題和 Lab 10-1 很像，只是解密時會提供到 4 bits，並且只能與程式互動 1024 / 4 + 5 次

可以建構 q[-n * t % 16] = t 的值 (0 <= t < 16)

就可以在 16^k m % 16 == -n * t % 16 將回傳值放入 q 確定 t 的值

也就可以知道這次縮小的範圍

從原本的 L, R

到 L = L + (R - L) * k / 16, R = L + (R - L) * (k + 1) / 16

並且每次都縮小 1/16，所以只要 250 次就可以得到 flag 了
