RSA oracle
RSA Oracle
看了几天格人给整傻了,还是学习点简单的RSA缓一缓
主要是弄明白几种oracle的利用方法但都是大同小异了
RSA Byte Oracle
假设存在一个预言机,能够对给定密文进行解密,并且返回明文的最后一个字节,那么给定一个加密后的密文,我们log256n次操作即可还原明文
操作过程如下
首先会给出明文的加密结果,我们通过一下步骤还原
记明文为P,密文为C
将256eC传给oracle,返回256P(modn)的最低比特结果
∵256P(modn)=256P-kn
=>\(\frac{kn}{256}≤P<\frac{(k+1)n}{256}\)
故最终返回的最低有效位为kn(mod256)
易知in(i=0,1,···,255)构成模256的完系,由此我们在已知n的情况下可以构建in(i=0,1,···,255)与lsb之间的双射
我们接下来证明这种操作最终能够成功约束P的范围
利用数学归纳法,
假设我们已知了\(\frac{xn}{256^i}≤P<\frac{(x+1)n}{256^i}\)
现在我们向oracle传递256e(i+1)C得到(256i+1Pmod(n))mod(256)的反馈
不妨设256i+1Pmod(n)=256i+1P-(256y+r)n
通过反馈我们能知道r的取值
于是我们得到P的约束:\(\frac{(256y+r)n}{256^{i+1}}≤P<\frac{(256y+r+1)n}{256^{i+1}}\)
已知可改写为\(\frac{256xn}{256^{i+1}}≤P<\frac{256(x+1)n}{256^{i+1}}\)
由两个范围必有交集我们可知x=y
=>\(\frac{(256x+r)n}{256^{i+1}}≤P<\frac{(256x+r+1)n}{256^{i+1}}\)
由归纳假设我们可知每一次操作都能缩小P的约束范围,
由约束式log256n的操作次数是显然的
示例
Lost Key[2018 hitcon]
#!/usr/bin/python
from Crypto.Util.number import *
from gmpy import *
import os,sys
sys.stdin = os.fdopen(sys.stdin.fileno(), 'r', 0)
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
def genKey():
p = getPrime(512)
q = getPrime(512)
n = p*q
phi = (p-1)*(q-1)
while True:
e = getRandomInteger(40)
if gcd(e,phi) == 1:
d = int(invert(e,phi))
return n,e,d
def calc(n,p,data):
num = bytes_to_long(data)
res = pow(num,p,n)
return long_to_bytes(res).encode('hex')
def readFlag():
flag = open('flag').read()
assert len(flag) >= 40
assert len(flag) <= 50
prefix = os.urandom(68)
return prefix+flag
if __name__ == '__main__':
n,e,d = genKey()
flag = calc(n,e,readFlag())
print 'Here is the flag!'
print flag
for i in xrange(150):
msg = raw_input('cmd: ')
if msg[0] == 'A':
m = raw_input('input: ')
try:
m = m.decode('hex')
print calc(n,e,m)
except:
print 'no'
exit(0)
elif msg[0] == 'B':
m = raw_input('input: ')
try:
m = m.decode('hex')
print calc(n,d,m)[-2:]
except:
print 'no'
exit(0)
此处未给出n,需要加密x=c1mod(n)和x2=c2mod(n)=>c12-c2=kn,多取几组数据gcd即可
代码一小时,查代码查了一天😢,最后问学长告诉我循环开始整位置取错了,。。。,希望以后写代码的时候长点心吧
from pwn import *
import gmpy2
from tqdm import tqdm
p=remote('redirect.do-not-trust.hacking.run',10478)
#------
p.recvuntil('Here is the flag!\n')
c=p.recvuntil('\n')
c=int(c[:-1],16)
#------
kn=[]
for i in range(4):
p.recvuntil(': ')
p.sendline('A')
p.recvuntil('input: ')
pay=pow(2,2022*i)
mess=hex(pay)[2:]
if len(mess)%2==1:
mess='0'+mess
p.sendline(mess)
re1=int(p.recvuntil('\n')[:-1],16)
p.recvuntil(': ')
p.sendline('A')
p.recvuntil('input: ')
pay=pay**2
mess=hex(pay)[2:]
if len(mess)%2==1:
mess='0'+mess
p.sendline(mess)
re2=int(p.recvuntil('\n')[:-1],16)
s=re1**2-re2
kn.append(s)
nn=[]
for i in range(3):
nn.append(gmpy2.gcd(kn[i],kn[i+1]))
n=gmpy2.gcd(gmpy2.gcd(nn[0],nn[1]),gmpy2.gcd(nn[1],nn[2]))
#------
p.recvuntil(': ')
p.sendline('A')
pay=256
mess=hex(pay)[2:]
if len(mess)%2==1:
mess='0'+mess
p.recvuntil('input: ')
p.sendline(mess)
padding=int(p.recvuntil('\n')[:-1],16)
#------
bound=[0,0,0]
for i in tqdm(range(1,135)):
pay=c*pow(padding,i,n)
p.recvuntil(': ')
p.sendline('B')
p.recvuntil('input: ')
mess=hex(pay)[2:]
if len(mess)%2==1:
mess='0'+mess
p.sendline(mess)
re=int(p.recvuntil('\n')[:-1],16)
for j in range(256):
if -j*n%256==re:
print(j)
bound[0]=256*bound[0]+j*n
bound[1]=bound[0]+n
bound[2]=i
print(bound[1]//pow(256,bound[2]))
print(bound[0]//pow(256,bound[2]))
p.interactive()
RSA parity oracle
假设存在一个预言机,会对给定的密文进行解密,并且检查解密后明文的奇偶性,并通过奇偶性返回值,1->奇,0->偶。那么在给定一个加密后的密文,我们只需log2(N)次即可恢复明文
奇偶预言机和之前的lsb预言机的情况是类似的,都是通过选择密文攻击用反馈对明文进行约束
操作过程如下:
假设明文为P,密文为C
我们发送2eC,得到(2Pmod(N))mod(2)的结果
不妨设2Pmod(N)=2P-kN(∵P<N=>k=0 or 1)
=>\(\frac{kN}{2}≤P<\frac{(k+1)N}{2}\)
如果返回值为0说明k为偶数,返回值为1说明k为奇数
我们对此过程进行归纳,
假设已得到\(\frac{xN}{2^i}≤P<\frac{(x+1)N}{2^i}\)
我们发送2e(i+1)C给服务器,得到(2i+1Pmod(N))mod(2)的结果
设2i+1Pmod(N)=2i+1P-(2y+r)N
于是我们可以根据反馈得到r的值
=>\(\frac{(2y+r)N}{2^{i+1}}≤P<\frac{(2y+r+1)N}{2^{i+1}}\)
条件可化为\(\frac{2xN}{2^{i+1}}≤P<\frac{2(x+1)N}{2^{i+1}}\)
由于两范围必有交集,我们可知y=x
=>\(\frac{(2x+r)N}{2^{i+1}}≤P<\frac{(2x+r+1)N}{2^{i+1}}\)
由归纳假设每一次操作都能够缩小P的范围
故我们可知在log2(N)次操作内我们能够还原P
示例
wait for update