easymath
k
e
y
w
o
r
d
s
:
keywords:
keywords: 位移运算 ,模运算中逆元与模数非互质情况
D
e
s
c
r
i
p
t
i
o
n
Description
Description
assert(len(open('flag.txt', 'rb').read()) < 50)
assert(str(int.from_bytes(open('flag.txt', 'rb').read(), byteorder='big') << 10000).endswith(
'1862790884563160582365888530869690397667546628710795031544304378154769559410473276482265448754388655981091313419549689169381115573539422545933044902527020209259938095466283008'))
A
n
a
l
y
s
i
s
Analysis
Analysis
首先明确flag 长度小于
50
50
50,也就是说大概给出了flag 的数值范围
然后已知一个这样的式子
c
≡
f
l
a
g
?
2
10000
(
m
o
d
1
0
175
)
c\equiv flag\cdot 2^{10000}\pmod {10^{175}}
c≡flag?210000(mod10175)
为什么可以有这样一个式子呢?
首先位移运算就相当于乘以
2
n
2^n
2n;然后endwith() 函数给出数字末尾的数值,那么就相当于模掉这个数值的长度(是
10
10
10进制的长度)
可以看出我们只需要知道
2
10000
2^{10000}
210000对于模数
1
0
175
10^{175}
10175的逆元即可
而这两者是非互质的,所以不能直接求解,但是我们可以通过把模数进一步减小达到两者互质的条件
在原来式子的基础上再取模
5
175
5^{175}
5175,此时式子变为
c
≡
f
l
a
g
?
2
10000
(
m
o
d
5
175
)
c\equiv flag\cdot 2^{10000}\pmod{5^{175}}
c≡flag?210000(mod5175)
直接求逆元乘以
c
c
c解flag 即可
S
o
l
v
i
n
g
?
c
o
d
e
Solving~code
Solving?code
from Crypto.Util.number import *
import gmpy2
c = 1862790884563160582365888530869690397667546628710795031544304378154769559410473276482265448754388655981091313419549689169381115573539422545933044902527020209259938095466283008
flag = c * gmpy2.invert(2**10000,5**175) % pow(5,175)
print(long_to_bytes(flag))
let’s play with rsa~
k
e
y
w
o
r
d
s
:
keywords:
keywords: 毫无难点的rsa
D
e
s
c
r
i
p
t
i
o
n
Description
Description
from sympy import isprime,nextprime
from Crypto.Util.number import getPrime as getprime ,long_to_bytes,bytes_to_long,inverse
flag='flag{***************}'
def play():
p=getprime(1024)
q=getprime(1024)
n=p*q
e=65537
print "Hello,let's play rsa~\n"
print 'Now,I make some numbers,wait a second\n'
n1=getprime(200)
n2=getprime(200)
number=n1*n2
print "Ok,i will send two numbers to you,one of them was encoded.\n"
print "Encode n1:%d,\n"%(pow(n1,e,n))
print "And n2:%d.\n"%n2
print "Information that can now be made public:the public key (n,e):(%d,%d)\n"%(n,e)
while True:
try:
c=int(raw_input("ok,now,tell me the value of the number (encode it for safe):"))
except:
print "Sorry,the input is illeagal, and the integer is accept~"
else:
break
d=inverse(e,(p-1)*(q-1))
m=pow(c,d,n)
if m==number:
print "It's easy and interesting,didn't it?\n"
print "This is the gift for you :"+flag
else:
print "Emmmmm,there is something wrong, bye~\n"
if __name__ == '__main__':
play()
A
n
a
l
y
s
i
s
Analysis
Analysis
题目要求传递的是密文
c
c
c,只要该密文解密之后得到的明文等于
n
1
?
n
2
n_1\cdot n_2
n1??n2?即可
而我们已知
c
1
≡
n
1
e
(
m
o
d
n
)
c_1 \equiv n_1^{e}\pmod n
c1?≡n1e?(modn);以及
n
2
n_2
n2?
求
c
≡
(
n
1
?
n
2
)
e
(
m
o
d
n
)
c\equiv ({n_1\cdot n_2})^{e}\pmod n
c≡(n1??n2?)e(modn)
拆开也就是
c
≡
c
1
?
n
2
e
(
m
o
d
n
)
c\equiv c_1 \cdot n_2^e\pmod n
c≡c1??n2e?(modn)
同余式左边参数都已知,那么直接代入就好了
S
o
l
v
i
n
g
?
c
o
d
e
Solving~code
Solving?code
from Crypto.Util.number import *
import gmpy2
from pwn import *
io = remote("node4.buuoj.cn","27103")
io.recvuntil(b"n1:")
c1 = int(bytes.decode(io.recvuntil(b",")[:-1]))
io.recvuntil(b"n2:")
n2 = int(bytes.decode(io.recvuntil(b".")[:-1]))
io.recvuntil(b':')
temp = io.recvline()
temp2 = temp.split(b":")[1]
n, e = int(bytes.decode(temp2.split(b",")[0][1:])), int(bytes.decode(temp2.split(b",")[1][:-2]))
c = c1 * pow(n2,e,n) % n
io.recvuntil(b":")
io.sendline(str(c).encode())
io.interactive()
ezRSA
k
e
y
w
o
r
d
s
:
keywords:
keywords: 同余式的转换
D
e
s
c
r
i
p
t
i
o
n
Description
Description
from secret import flag
from Crypto.Util.number import *
from random import getrandbits
from hashlib import sha256
class EzRsa:
def __init__(self):
self.E = 0x10001
self.P = getPrime(1024)
self.Q = getPrime(1024)
while GCD((self.P-1)*(self.Q-1), self.E) != 1:
self.Q = getPrime(1024)
self.N = self.P*self.Q
def encrypt(self):
f = getrandbits(32)
c = pow(f, self.E, self.N)
return (f, c)
def encrypt_flag(self, flag):
f = bytes_to_long(flag)
c = pow(f, self.E, self.N)
return c
def proof():
seed = getrandbits(32)
print(seed)
sha = sha256(str(seed).encode()).hexdigest()
print(f"sha256({seed>>18}...).hexdigest() = {sha}")
sha_i = input("plz enter seed: ")
if sha256(sha_i.encode()).hexdigest() != sha:
exit(0)
if __name__ == "__main__":
proof()
print("welcome to EzRsa")
print("""
1. Get flag
2. Encrypt
3. Insert
4. Exit
""")
A = EzRsa()
coin = 5
while coin > 0:
choose = input("> ")
if choose == "1":
print(
f"pow(flag,e,n) = {A.encrypt_flag(flag)}\ne = 0x10001")
exit(0)
elif choose == "2":
f, c = A.encrypt()
print(f"plain = {f}\ncipher = {c}")
coin -= 1
elif choose == "3":
q = getrandbits(1024)
n = A.P*q
f = getrandbits(32)
c = pow(f, 0x10001, n)
print(f"plain = {f}\ncipher = {c}")
coin -= 1
elif choose == "4":
print("bye~")
else:
print("wrong input")
print("Now you get the flag right?")
A
n
a
l
y
s
i
s
Analysis
Analysis
proof 函数,从来没有遇到过这么无语的proof 函数
直接把程序打印出来的seed 再提交上去就好了
def proof():
seed = getrandbits(32)
print(seed)
然后分析主程序
分为三个功能:Get flag ,Encrypt ,Insert
分别是得到flag 的密文c_flag ;得到一组明文及密文plaint1,cipher1 (以
(
n
,
e
)
(n,e)
(n,e)作为公钥);得到一组明文及密文plaint2,cipher2 (以
(
p
?
q
o
t
h
e
r
,
e
)
(p*q_{other},e)
(p?qother?,e)作为公钥)
总共可以执行
5
5
5次上述功能;此时对于flag 的RSA加密,我们只知道
e
e
e的大小
很快分析出,Encrypt 一定是用来求得
n
n
n的,Insert 一定是用来求得
p
p
p从而把
n
n
n分解的
两个功能的加密过程是相似的,猜测两个功能都要分别执行两次
推导:Encrypt 功能
{
p
l
a
i
n
t
1
e
=
c
1
(
m
o
d
n
)
p
l
a
i
n
t
2
e
=
c
2
(
m
o
d
n
)
\begin{cases} plaint_1^e=c_1\pmod n\\ plaint_2^e=c_2\pmod n \end{cases}
{plaint1e?=c1?(modn)plaint2e?=c2?(modn)?
?
{
p
l
a
i
n
t
1
e
?
c
1
=
k
1
?
p
?
q
p
l
a
i
n
t
2
e
?
c
2
=
k
2
?
p
?
q
\Rightarrow \begin{cases} plaint_1^e - c_1 = k_1 \cdot p \cdot q \\ plaint_2^e - c_2 = k_2\cdot p \cdot q \end{cases}
?{plaint1e??c1?=k1??p?qplaint2e??c2?=k2??p?q?
同余式左侧的参数我们都已知,那么两者的最大公约数一定整除
n
n
n,因为可能
k
1
k_1
k1?和
k
2
k_2
k2?之间也有公约数,所以两者的最大公约数不直接等于
n
n
n
我们得到
n
∣
g
c
d
(
p
l
a
i
n
t
1
e
?
c
1
,
p
l
a
i
n
t
2
e
?
c
2
)
n \mid gcd(plaint_1^e -c_1,plaint_2^e - c_2)
n∣gcd(plaint1e??c1?,plaint2e??c2?) 而他们之间的倍数很小(等于
k
1
k_1
k1?和
k
2
k_2
k2?的最大公约数,所以可以直接爆破
1000
1000
1000以内的数作为倍数)
Insert 功能
{
p
l
a
i
n
t
3
e
≡
c
3
(
m
o
d
p
?
q
o
t
h
e
r
1
)
p
l
a
i
n
t
4
e
≡
c
4
(
m
o
d
p
?
q
o
t
h
e
r
2
)
\begin{cases} plaint_3^e \equiv c_3 \pmod {p\cdot q_{other1}}\\ plaint_4^e \equiv c_4 \pmod {p\cdot q_{other2}} \end{cases}
{plaint3e?≡c3?(modp?qother1?)plaint4e?≡c4?(modp?qother2?)?
?
{
p
l
a
i
n
t
3
e
?
c
3
=
k
3
?
p
?
q
o
t
h
e
r
3
p
a
l
i
n
t
4
e
?
c
4
=
k
4
?
p
?
q
o
t
h
e
r
4
\Rightarrow\begin{cases} plaint_3^e - c_3 = k_3 \cdot p\cdot q_{other3}\\ palint_4^e - c_4 = k_4 \cdot p \cdot q_{other4} \end{cases}
?{plaint3e??c3?=k3??p?qother3?palint4e??c4?=k4??p?qother4??
和Encrypt 的分析过程一致,可以得到
p
∣
g
c
d
(
p
l
a
i
n
t
3
e
?
c
3
,
p
l
a
i
n
t
4
e
?
c
4
)
p\mid gcd(plaint_3^e -c_3,plaint_4^e-c_4)
p∣gcd(plaint3e??c3?,plaint4e??c4?) 其中两者的倍数大小依然是等于
k
3
k_3
k3?和
k
4
k_4
k4?的最大公约数
S
o
l
v
i
n
g
?
c
o
d
e
Solving~code
Solving?code
from Crypto.Util.number import *
from pwn import *
import gmpy2
io = remote("node4.buuoj.cn","29721")
seed = int(bytes.decode(io.recvline()))
io.recvuntil(b":")
io.sendline(str(seed).encode())
e = 65537
plaint1 = []
cipher1 = []
for _ in range(2):
io.recvuntil(b">")
io.sendline(b"2")
io.recvuntil(b'=')
plaint1.append(int(bytes.decode(io.recvuntil(b"\n")[:-1])))
io.recvuntil(b"=")
cipher1.append(int(bytes.decode(io.recvuntil(b"\n")[:-1])))
n = gmpy2.gcd(plaint1[0]**e - cipher1[0],plaint1[1]**e - cipher1[1])
k = 2
while True:
if n % k == 0:
n = n // k
k = 2
continue
else:
k += 1
if k > 1000:
break
plaint2 = []
cipher2 = []
for _ in range(2):
io.recvuntil(b">")
io.sendline(b"3")
io.recvuntil(b'=')
plaint2.append(int(bytes.decode(io.recvuntil(b"\n")[:-1])))
io.recvuntil(b"=")
cipher2.append(int(bytes.decode(io.recvuntil(b"\n")[:-1])))
p = gmpy2.gcd(plaint2[0]**e - cipher2[0],plaint2[1]**e - cipher2[1])
k = 2
while True:
if p % k == 0:
p = p // k
k = 2
continue
else:
k += 1
if k > 1000:
break
assert n % p == 0
q = n // p
fai_n = (p-1)*(q-1)
d = gmpy2.invert(e,fai_n)
io.recvuntil(b">")
io.sendline(b'1')
io.recvuntil(b"=")
c_flag = int(bytes.decode(io.recvuntil(b"\n")[:-1]))
flag = pow(c_flag,d,n)
print(long_to_bytes(flag))
io.close()
|