# Bro-key-n
## Challenge Overview
We are given a **broken** private key file, which is encoded in Privacy-Enhanced Mail (PEM).
:::spoiler Key_Redacted.pem
```
-----BEGIN RSA PRIVATE KEY-----
MIIJJAIBAAKCAgASUWUVXgOvRLJkI77YJ6BlG5t6en55ysW40HpawMJb9bTyWMIn
NIkWpL7+swa+eddajk+sL32Fkdf38eUAbq/y0y6T/LGlDLW9RJqEhAxx+fC62Zmu
7tUA3DK3CS0LAhrd4oWdU8YE9LFhOID7StpmxaGdoFi8emZGuTXE0ooyG60KObs4
dGV3Xbwq1xhM4iG9Drw94PwOlXS5UqDNfCcY0GlrorKsUSJwjNlkPIoos5FtR7KP
Rsau1+kd8aeCeAObkZciPRqLDojy3cVXZqKO6qpXHk2qfyEy1AKAFaNyt4sEt3WY
ex9qQg9a2W0w12zD01QZnJaKhTkMhdThLHrrBQsbBPQwsjcl7FwT0DQBOPZsas+k
WUYbTr++WvKy1pB7j6eC4WUlFFKf3zQ2Z+aHXX0UmPPYDLdlJFgLbyrwEULxW7EO
kTZt2IL3c4+ywkK0F6Ty4M+lzW/Wtj0ZcpAd9pudXEgXeCSUMJ6AlU0ckOl1WSpH
zORHYZ9aPVt2Ertme7sU4XdJZLFOqXzqN1+Z96GdpUOptOmpeL2/sv/4816OlZdH
OIjLErLv73CNhxSJ592zymSZesb0rSnH4T01ResFai6HLOMvE99ezt0lt73XwyRk
MGRm0uW35Ir5rOioHkKVgas3dGjH8DED73WOrvt5p0BImSb9jyYzT9odZQIDAQAB
AoIB/0WfF5MewOJnN59kPPdRpU6kn0vkRtCg4N6PgntsJ0tdlV+F+mkIRALMJyHn
TrqmXNzSB/9ogKwqpa68tKXwDM______________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________YM4i/wJBudIGNGxwJRfOR9HUI2G/wchfC1772bxdFev5+0YM
PiuBRnypiaHcf2/AAOmDMZJFyrTqrfy8jmxfdwKCAQAMVay1pGR15Pyz/AEqJvO4
lrw09/BHA1xhDTc5uYzlChRuxJEn5ehmc1Lgbawr+jciSkfCnNkEueQYv0+EhPYF
lJBsztrCJX3hzcVEU7qJLR4aAP6Px+G0Fd/kxQVbyrCvCKM1ptmpNPqYZE2IR5Ri
Fzj4eD7rl1qEaBNIEdNs2VRMmsRwhrqIZcgRVbzcOf5cE3agelmTT/JeGFVFF+Ri
knxvhVcSScPKgsfdhpFwcYbeLqbLac7ZQcb1+Qz7XU______________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
________________________________________________________________
______________________________________________________
-----END RSA PRIVATE KEY-----
```
:::
About half of the file is redacted, and our goal is to recover the file. Then use it to connect the server and capture the flag.
## Solution
### Reveal Leakage
First of all, we need to investigate how the file is generated. The private key contains the information
```
RSAPrivateKey ::= SEQUENCE {
version Version,
modulus INTEGER, -- n
publicExponent INTEGER, -- e
privateExponent INTEGER, -- d
prime1 INTEGER, -- p
prime2 INTEGER, -- q
exponent1 INTEGER, -- d mod (p-1)
exponent2 INTEGER, -- d mod (q-1)
coefficient INTEGER, -- (inverse of q) mod p
otherPrimeInfos OtherPrimeInfos OPTIONAL
}
```
Then we apply Distinguished Encoding Rules (DER) to encode those info into binary data. Basically, all data will be encoded into following form
::: info
ASN.1 Tag + Length Octet + Data Content + End-of-Contents Octets
:::
Finally, PEM file is created by encoding DER with Base64. Let's use the broken file to explain the details. The first line is
`3082092402010002820200125165155e03af44b26423bed827a0651b9b7a7a7e79cac5b8d07a5ac0c25bf5b4f258c227`
The first byte is $0x30$ indicating the data is SEQUENCE, and it follows $0x82$, which means the length of data is given in the next $2$ bytes, say $0x0924$. Now, we move to the data wrapped in the SEQUENCE.
The next byte is $0x02$, which means the first data is an integer. The length is $0x01$ and the value is simply $0x00$. Note that it's a little different to what we do above.
:::warning
There are two forms for length octet:
1. Short form [One byte]. where the most significant bit (MSB) has value "0" and other bits give the length.
2. Long form [Two or more bytes (at most 127)]. MSB of first octet has value 1 and remaining bits give the number of additional octets. Second and following octets give the length.
:::
Keep doing, we will find the partial values! This is left as an exercise to the reader :P
:::spoiler Leakage
```
n = 0x125165155e03af44b26423bed827a0651b9b7a7a7e79cac5b8d07a5ac0c25bf5b4f258c227348916a4befeb306be79d75a8e4fac2f7d8591d7f7f1e5006eaff2d32e93fcb1a50cb5bd449a84840c71f9f0bad999aeeed500dc32b7092d0b021adde2859d53c604f4b1613880fb4ada66c5a19da058bc7a6646b935c4d28a321bad0a39bb387465775dbc2ad7184ce221bd0ebc3de0fc0e9574b952a0cd7c2718d0696ba2b2ac5122708cd9643c8a28b3916d47b28f46c6aed7e91df1a78278039b9197223d1a8b0e88f2ddc55766a28eeaaa571e4daa7f2132d4028015a372b78b04b775987b1f6a420f5ad96d30d76cc3d354199c968a85390c85d4e12c7aeb050b1b04f430b23725ec5c13d0340138f66c6acfa459461b4ebfbe5af2b2d6907b8fa782e1652514529fdf343667e6875d7d1498f3d80cb76524580b6f2af01142f15bb10e91366dd882f7738fb2c242b417a4f2e0cfa5cd6fd6b63d1972901df69b9d5c4817782494309e80954d1c90e975592a47cce447619f5a3d5b7612bb667bbb14e1774964b14ea97cea375f99f7a19da543a9b4e9a978bdbfb2fff8f35e8e9597473888cb12b2efef708d871489e7ddb3ca64997ac6f4ad29c7e13d3545eb056a2e872ce32f13df5ecedd25b7bdd7c32464306466d2e5b7e48af9ace8a81e429581ab377468c7f03103ef758eaefb79a740489926fd8f26334fda1d65
e = 0x010001
d_high_bits = 0x459f17931ec0e267379f643cf751a54ea49f4be446d0a0e0de8f827b6c274b5d955f85fa69084402cc2721e74ebaa65cdcd207ff6880ac2aa5aebcb4a5f00cc0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
q_low_bits = 0x60ce22ff0241b9d206346c702517ce47d1d42361bfc1c85f0b5efbd9bc5d15ebf9fb460c3e2b81467ca989a1dc7f6fc000e983319245cab4eaadfcbc8e6c5f77
dp_high_bits = 0x0c55acb5a46475e4fcb3fc012a26f3b896bc34f7f047035c610d3739b98ce50a146ec49127e5e8667352e06dac2bfa37224a47c29cd904b9e418bf4f8484f60594906ccedac2257de1cdc54453ba892d1e1a00fe8fc7e1b415dfe4c5055bcab0af08a335a6d9a934fa98644d884794621738f8783eeb975a8468134811d36cd9544c9ac47086ba8865c81155bcdc39fe5c1376a07a59934ff25e18554517e462927c6f85571249c3ca82c7dd8691707186de2ea6cb69ced941c6f5f90cfb5d4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
```
:::
Here, the unknown hex digits are replaced by $0$.
### Key Recovery
As we have low bits of the factor $q$, it's easy to find the low bits of $p$ as well.
```python
p_low_bits = (n % m) * pow(q_low_bits, -1, m) % m # m=2^512
```
On the other hand, by definition, $$dp \equiv d \pmod{p-1}$$ Multiply both sides by $e$, we get $$e \times dp \equiv e \times d \equiv 1 \pmod{p-1} $$ since $e$ is the multiplicative inverse of $d$ w.r.t to $(p-1)(q-1)$ Thus, there exists an integer $k$ less than $e$ so that $$e \times dp = k(p-1) + 1$$ Because we have partial values of $dp$ and $p$, we should rewrite the equation as $$ e \times (dp_{high\_bits} + j \times m + dp_{l}) = k(p_h + p_{low\_bits} - 1)+1 $$ for some $j < 16$ (Because there are $129$ zeros in the end, `dp_high_bits = dp % (4 * m)`. We need to add $j \times m$). Here $x_h, x_l$ represents high and low bits of $x$. In python,
```python
x_h = x - (x % m)
x_l = x % m
```
Take $\pmod{m}$, the equation becomes $$e \times dp_l \equiv k(p_l-1)+1 \pmod{m}$$ And we deduce the low bits value of $dp$: $$dp_l \equiv dp_l \equiv e^{-1} (k(p_l-1)+1) \pmod{m} $$
This give us one factor $$p = \frac{e \times dp - 1}{k}$$ We decide whether this is true $p$ by checking `n % p == 0`. For completeness, here is my script.
```python=
from output import * # store the leakage as output.py
from Crypto.Util.number import *
k = 512
m = 1 << k
p_low_bits = (n % m) * pow(q_low_bits, -1, m) % m
for i in range(1, e):
dp_low_bits = (i * (p_low_bits - 1) + 1) * pow(e, -1, m) % m
for j in range(16):
dp = dp_high_bits + j * m + dp_low_bits
p = ((dp * e - 1) // i) + 1
if isPrime(p):
if n % p == 0:
print(f"Found!")
print(p)
print(n // p)
exit()
```
### Capture The FLAG
Now, it suffices to recover the PEM file.
```python=
from output import *
from result import * # p = ...
from Crypto.PublicKey import RSA
q = n // p
phi = (p - 1) * (q - 1)
d = pow(e, -1, phi)
key = RSA.construct([n, e, d])
with open("key.pem", "wb") as f:
f.write(key.export_key('PEM'))
```
:::danger
Use the command `chmod 600 key.pem` to change permission! Or you may fail to connect to the server ...
:::
Finally, type `ssh user@bro-key-n.chal.uiuc.tf -p 1337 -i key.pem` on the terminal and press enter!
:::success
FLAG. uiuctf{hidden_in_plain_sight}
:::