# RSA stream

This is the first crypto challenge from ASCS 2021. It used Stream cipher with RSA to encrypt a message.

## Statement

I made a stream cipher out of RSA! But people say I made a huge mistake. Can you decrypt my cipher?

## Observation

The plaintext used for stream cipher is the file itself, which we already know.

Define $$f(m, e) = m^{e} \text{ mod } (N)$$

The OTP used for stream cipher are $$f(m, e_{1}), f(m, e_{2}), ..., f(m, e_{n})$$

where $$e_{i + 1} = \text{nextprime}(e_{i})$$

The objective is to find $$m$$

## Solution

Since the plaintext is known, it is easy to find out the OTP used by just xor the ciphertext with the plaintext.

$f(m, e_{i}) = c_{i} \oplus p_{i}$

Because $$e_{1}$$ and $$e_{2}$$ are coprime, by Bezout’s lemma

$a\cdot e_{1} + b\cdot e_{2} = 1$

where $$a$$ and $$b$$ are integers.

$$a$$ and $$b$$ can be found using extended euclidean algorithm.

$$m$$ is then revealed by

\begin{aligned} (m^{e_{1}})^{a} \cdot (m^{e_{2}})^{b} &\equiv m^{a\cdot e_{1}} \cdot m^{b\cdot e_{2}} \text{ mod} (N)\\ &\equiv m^{a\cdot e_{1} + b\cdot e_{2}} \text{ mod} (N)\\ &\equiv m^{1} \text{ mod} (N)\\ \end{aligned}

I used sage to do extended euclidean algorithm, the code is shown below.

from Crypto.Util.number import bytes_to_long, long_to_bytes

import gmpy2
from sage.all import *
from Crypto.Util.number import long_to_bytes

def xor(s1, s2):
return bytes([i ^ j for i,j in zip(s1,s2)])

f1 = open("chal.py","rb").read()
f2 = open("chal.enc","rb").read()

n = 30004084769852356813752671105440339608383648259855991408799224369989221653141334011858388637782175392790629156827256797420595802457583565986882788667881921499468599322171673433298609987641468458633972069634856384101309327514278697390639738321868622386439249269795058985584353709739777081110979765232599757976759602245965314332404529910828253037394397471102918877473504943490285635862702543408002577628022054766664695619542702081689509713681170425764579507127909155563775027797744930354455708003402706090094588522963730499563711811899945647475596034599946875728770617584380135377604299815872040514361551864698426189453
e = 65537
primes = []
res = []

for a in range(0,len(f1),256):
res.append(bytes_to_long(f1[a:a+256]) ^ bytes_to_long(f2[a:a+256]))
primes.append(e)
e = gmpy2.next_prime(e)

d,u,v = xgcd(primes[0],primes[1])
p1 = Zmod(n)(res[0])
p2 = Zmod(n)(res[1])
print(d, u, v)
print(long_to_bytes((p1**u) * (p2**v)))


flag : ACSC{changing_e_is_too_bad_idea_1119332842ed9c60c9917165c57dbd7072b016d5b683b67aba6a648456db189c}

Updated: