###### tags: `CTF` `ACSC2021` `crypto` # RSA stream Writer : [top](https://hackmd.io/S0VbDw_7RzyLCEr16S1Rxg) Problem --- I made a stream cipher out of RSA! But people say I made a huge mistake. Can you decrypt my cipher? `chal.py` ```=python import gmpy2 from Crypto.Util.number import long_to_bytes, bytes_to_long, getStrongPrime, inverse from Crypto.Util.Padding import pad from flag import m #m = b"ACSC{<REDACTED>}" # flag! f = open("chal.py","rb").read() # I'll encrypt myself! print("len:",len(f)) p = getStrongPrime(1024) q = getStrongPrime(1024) n = p * q e = 0x10001 print("n =",n) print("e =",e) print("# flag length:",len(m)) m = pad(m, 255) m = bytes_to_long(m) assert m < n stream = pow(m,e,n) cipher = b"" for a in range(0,len(f),256): q = f[a:a+256] if len(q) < 256:q = pad(q, 256) q = bytes_to_long(q) c = stream ^ q cipher += long_to_bytes(c,256) e = gmpy2.next_prime(e) stream = pow(m,e,n) open("chal.enc","wb").write(cipher) ``` Output --- `chal.enc` ```=txt m^�v�9����~�̲(�A�bCw8��vM[��;��\�;��S�G�6=֊�gO.p�]��`uV�~�}�nQ9U�j��<�^6B���2�P��!�7'>�,�;��]8H��GH\�hi���q<�s 7p����q�Κ �Hg*Z��}S��Q�c�r�� v�M�6���0�L8rü���BҗY�Nl-�Xb�w���S� �Bf+sU¤R&`�y;���E �{�1.���NW!X0��&�S퉦�ѡt<3���y0c��*�c�,/&p���� �����U�[�P�{׶ɪ(�v�V�iOz�S�p�w��>�o�/D(3�����Y� �+FEk����_����3��|0�vh��Ā*���g0��Ki%g+�V�>���z����z�/�Y��X�w�ޅ��Նp$a����e����&���M),��C��`�����ڧ����U2��\$�$��}f�N�Stp'�?`�W[u�(�v(�_Ρz���^5�� �b ����+�~�����_J��A��](=�d��U�%�7�sP�o�^X��1$4 G�ٜ��S�gY�m �y:L��.-F�:T>ٿ��ԧ]�ǖ+�PL �I��l]j��o<l�� ��$)"�� 7q:��N��wwoۑ�B��ǥ�c%#I��+��ط��Y��_���Ez�Bkl��g��XP�/�,<���F�eN�ܶ���^kD6�=�����H\J�w+mm0���gJ$Ft\���q�H,�����A�&b==�����R�}}�k ``` `output.txt` ```=txt len: 723 n = 30004084769852356813752671105440339608383648259855991408799224369989221653141334011858388637782175392790629156827256797420595802457583565986882788667881921499468599322171673433298609987641468458633972069634856384101309327514278697390639738321868622386439249269795058985584353709739777081110979765232599757976759602245965314332404529910828253037394397471102918877473504943490285635862702543408002577628022054766664695619542702081689509713681170425764579507127909155563775027797744930354455708003402706090094588522963730499563711811899945647475596034599946875728770617584380135377604299815872040514361551864698426189453 e = 65537 # flag length: 97 ``` Solve --- バカみたいなミスをして時間を取られてしまった問題 :-1: この問題は普通のRSA暗号をStream暗号っぽくしたもので、よく見るとRSA暗号の脆弱性の一つである**Common Modulus Attack**が適用できる. `chal.py`では`chal.py`自身を読み込み、それを256byteずつのブロック`q`にしている. また、1024bitの素数p,qを生成し、RSAの公開鍵を$n=p*q$と`e=0x10001`として、flagを平文として暗号化している. できた暗号文を`stream`として、`q`とXORをしたものを`cipher`に連結していく 次のブロックでは`stream`を生成する際に`0x10001`の次の素数を`e`として暗号化している. ここがポイントで、同じ平文、同じ法に対して異なる暗号化指数`e`で暗号化するというミスを犯している. このような場合は**Common Modulus Attack**が適用できてしまう. 下に上記のミスをした際にCommon Modulus Attackで`m`を復元できる証明を示す. --- ### Common Modulus Attack 同じ平文`m`を異なる暗号化指数`e1,e2`と,同じ法`n`で暗号化した暗号文が2つ入手可能とする. $$ c_1 = m^{e_1} \mod n\\ c_2 = m^{e_2} \mod n $$ ここで、$gcd(e_1,e_2)==1$を満たすので、拡張ユークリッドの互除法より $$ e_1s_1+e_2s_2=1 \leftarrow extgcd(e_1,e_2) $$ となる$(s1,s2)$がただ1つ見つかる. $$ \begin{eqnarray} c_1^{s_1}*c_2^{s_2} &=& m^{e_1s_1}*m^{e_2s_2}\mod n\\ &=&m^{(e_1s_1+e_2s_2)} \mod n\\ where, e_1&s_1&+e_2s_2=1 \\ &=&m^1 \mod n \\ &=&m \end{eqnarray} $$ 以上より$m$が求められる. --- 問題に戻り`cipher`の中身を考えると以下のようになっている. $$ \begin{eqnarray} cipher = c_1 \oplus q_1 | c_2 \oplus q_2 | c_3 \oplus q_3 \end{eqnarray} $$ ここで、$q_1,q_2,q_3$は既知なので、それぞれにもう一度`XOR`をしてあげることで $$ \begin{eqnarray} cipher = c_1 | c_2 | c_3 \end{eqnarray} $$ とすることができる. 暗号化指数`e`も最初の`0x10001`から次の素数を新たな`e`として選択しているので、それぞれの`e`を求めることができる. これで,同じ平文`m`を異なる暗号化指数$e_1,e_2,e_3$で暗号化している暗号文$c_1,c_2,c_3$が揃ったのでどれか2つに対して**Common Modulus Attack**を適用することで`flag`を得ることができる. ちなみにバカみたいなミスとは`XOR`の`^`を冪乗の記号だと勘違いしたことです。ありがとうございました :+1: --- :tada:`ACSC{changing_e_is_too_bad_idea_1119332842ed9c60c9917165c57dbd7072b016d5b683b67aba6a648456db189c}`