1、题目
#!/usr/bin/python
from Crypto.Util.number import *
from Crypto.PublicKey import RSA
from secret import s, FLAG
def gen_prime(s):
while True:
r = getPrime(s) #生成一个素数r
R = [r] #将r转换为列表
t = int(5 * s / 2) + 1
for i in range(0, t):
R.append(r + getRandomRange(0, 4 * s ** 2))
#生成一个0~(4 * s ** 2)的随机数加上r的值并加到列表R里面
p = reduce(lambda a, b: a * b, R, 2) + 1
#reduce()函数会对参数序列中元素进行累积。
if isPrime(p):
if len(bin(p)[2:]) == 1024: #[2:]会截掉前面的'0b'
return p
while True:
p = gen_prime(s)
q = gen_prime(s)
n = p * q
e = 65537
d = inverse(e, (p-1)*(q-1))
if len(bin(n)[2:]) == 2048:
break
msg = FLAG
key = RSA.construct((long(n), long(e), long(d), long(p), long(q)))
for _ in xrange(s): #循环加密s次
enc = key.encrypt(msg, 0)[0]
msg = enc
print key.publickey().exportKey()
print '-' * 76
print enc.encode('base64')
print '-' * 76
题目除了给了以上加密算法,还给出了公钥文件和密文;加密算法的部分操作已写上注释。
二、分析
1、个人认为其中p、q的生成算法写得虽然详细,但是解题过程却用不上,因为n可以直接被分解(后面又发现即使不分解n也能解题:从公钥中可以提取出私钥,也就不需要p、q了)
2、公钥解析:首先将output.txt中的公钥部分复制出来保存为pubkey.pem,通过命令:
openssl rsa -pubin -text -modulus -in pubkey.pem
得到n和e。
3、私钥提取:找到d的方法有两种:
(1)简单暴力的, n可以通过大数分解得到p、q,再对e求逆即得到d。
(2)网上看到其他师傅的做法:从公钥文件中提取出私钥来,命令:
python3 RsaCtfTool.py --publickey pubkey.pem --private
关于RsaCtfTool使用,这里再记录几个常用命令:
用法一:已知公钥文件和加密文件进行解密
python3 RsaCtfTool.py --publickey 公钥文件 --uncipherfile 加密的文件
用法二:已知公钥求私钥
python3 RsaCtfTool.py --publickey 公钥文件 --private
用法三:密钥格式转换
把PEM格式的公钥转换为n,e
python3 RsaCtfTool.py --dumpkey --key 公钥文件
把n,e转换为PEM格式
python3 RsaCtfTool.py --createpub -n 782837482376192871287312987398172312837182 -e 65537
三、解密脚本
从加密脚本可以看出来,flag进行了循环多次加密,在解密脚本中我们可以试着循环一个较大的数来解密(最后发现其实加密了20次)
from Crypto.Util.number import *
from Crypto.PublicKey import RSA
import gmpy2
import base64
pub = RSA.importKey(open('E:/CTF/XCTF/Crypto/RSA/Handicraft_RSA/Handicraft_RSA/handicraft_rsa/pubkey.pem').read())
n = pub.n
e = pub.e
#print n:21702007965967851183912845012669844623756908507890324243024055496763943595946688940552416734878197459043831494232875785620294668737665396025897150541283087580428261036967329585399916163401369611036124501098728512558174430431806459204349427025717455575024289926516646738721697827263582054632714414433009171634156535642801472435174298248730890036345522414464312932752899972440365978028349224554681969090140541620264972373596402565696085035645624229615500129915303416150964709569033763686335344334340374467597281565279826664494938820964323794098815428802817709142950181265208976166531957235913949338642042322944000000001
p = 139457081371053313087662621808811891689477698775602541222732432884929677435971504758581219546068100871560676389156360422970589688848020499752936702307974617390996217688749392344211044595211963580524376876607487048719085184308509979502505202804812382023512342185380439620200563119485952705668730322944000000001
q = 155617827023249833340719354421664777126919280716316528121008762838820577123085292134385394346751341309377546683859340593439660968379640585296350265350950535158375685103003837903550191128377455111656903429282868722284520586387794090131818535032744071918282383650099890243578253423157468632973312000000000000001
d = gmpy2.invert(e,(p-1)*(q-1))
msg = base64.b64decode("eER0JNIcZYx/t+7lnRvv8s8zyMw8dYspZlne0MQUatQNcnDL/wnHtkAoNdCalQkpcbnZeAz4qeMX5GBmsO+BXyAKDueMA4uy3fw2k/dqFSsZFiB7I9M0oEkqUja52IMpkGDJ2eXGj9WHe4mqkniIayS42o4p9b0Qlz754qqRgkuaKzPWkZPKynULAtFXF39zm6dPI/jUA2BEo5WBoPzsCzwRmdr6QmJXTsau5BAQC5qdIkmCNq7+NLY1fjOmSEF/W+mdQvcwYPbe2zezroCiLiPNZnoABfmPbWAcASVU6M0YxvnXsh2YjkyLFf4cJSgroM3Aw4fVz3PPSsAQyCFKBA==")
key = RSA.construct((long(n),long(e),long(d),long(p),long(q)))
'''for i in range(20):
enc = key.decrypt(msg)
msg = enc
print(msg)
'''
msg = bytes_to_long(msg)
for i in range(20):
enc = pow(msg,d,n)
msg = enc
print(long_to_bytes(msg))
问题思考
以上代码中的16~19注释部分是其加密算法对应的解密算法,但是我运行出错了
错误提示:NotImplementedError: Use module Crypto.Cipher.PKCS1_OAEP instead
于是乎只能以21~25行所示代码解,如有师傅清楚问题所在,欢迎在评论区留下妙言。