【无标题】

RSA_高位攻击

高位攻击就是,已知部分二进制位,通过coppersmith定理求得剩余的二进制位

注意,高位攻击需要构建环,需要使用sagemath进行解题,自行网上下载(下面的脚本不进行说明的都是sage)

coppersmith定理

RSA高位攻击的核心数学原理就是coppersmith定理,在此不多做介绍,直接上结论
u n k n o w n _ b i t s ÷ p _ b i t s ≤ 0.44 unknown\_bits÷p\_bits≤0.44 unknown_bits÷p_bits0.44
含义:比如要求p,p未知的二进制位是unknown_bits,其原本的的bit位是p_bits
原理文章
具体证明原理看这篇文章

比如最常见的p高位已知,bit位有1024,那么它最多未知位是454位(454/1024=0.44)

下面的kbits普遍为未知位

1.已知p高位

这是最简单的一种情况,p已知位数大于或等于454位,可以直接得出p,后面就直接可以用最为朴素的求flag方式求解m

解密脚本

p_high = 
n = 
c = 
pbits = 1024 # p原本位数
kbits = pbits - p_high.nbits() # p丢失位数
p_high = p_high << kbits
PR.<x> = PolynomialRing(Zmod(n))# 构建一个以x为符号模n的一元多项式环
f = x + p_high
p0 = f.small_roots(X = 2 ^ kbits,beta = 0.4)[0]# 多项式小值根求解及因子分解,其中X表示求解根的上界
print(p_high + p0)
得到p

2.已知p高位,q低位

这是鹤城杯2021,babyrsa,是p高位攻击的一种特殊题目

from Crypto.Util.number import getPrime, bytes_to_long
from secret import flag

p = getPrime(1024)
q = getPrime(1024)
n = p * q
e = 65537
hint1 = p >> 724
hint2 = q % (2 ** 265)
ct = pow(bytes_to_long(flag), e, n)
print(hint1)
print(hint2)
print(n)
print(ct)

这题就是将p的少部分高位给出,再将p的部分低位隐藏在q的低位中(算出来p的低位)

下面进行计算p的低位
q % 2 265 = q _ l o w q = k ∗ 2 265 + q _ l o w q\%2^{265}=q\_low\\ q=k*2^{265}+q\_low\\ q%2265=q_lowq=k2265+q_low
两边同时乘以p(引入p进行转换)
n = k ∗ 2 265 ∗ p + q _ l o w ∗ p n=k*2^{265}*p+q\_low*p n=k2265p+q_lowp
q_low,n是已知的,将等式两边分为已知数和未知数(同时除以q_low)
n ∗ q _ l o w − 1 = k ∗ 2 265 ∗ p ∗ q _ l o w − 1 + p n*q\_low^{-1}=k*2^{265}*p*q\_low^{-1}+p nq_low1=k2265pq_low1+p
下面这一项是2的256次方的倍数,所以整体模2的256次方后,这一项就消去了
k ∗ 2 265 ∗ p ∗ q _ l o w − 1 k*2^{265}*p*q\_low^{-1} k2265pq_low1
整体模2的256次方
p _ l o w = p % 2 265 = n ∗ q _ l o w − 1 % 2 265 p\_low=p\%2^{265}=n*q\_low^{-1}\%2^{265} p_low=p%2265=nq_low1%2265
现在的题目就是p的已知位数不连续,断开进行出题,中间位未知,给定p的高位和p的低位求p

简单来看,现在的p是这样的:
22321200000001212 22321200000001212 22321200000001212
中间的0是未知的数字,高位和低位都是已知的

hint1 = p >> 724 # 未知724
hint2 = q % (2 ** 265) # 未知724-265=459

那么我们最多的未知位是454位,但是现在有459位,采用爆破剩下的5位,2的5次方=32

from gmpy2 import *
from Crypto.Util.number import *
 
p1 = 1514296530850131082973956029074258536069144071110652176122006763622293335057110441067910479
q0 = 40812438243894343296354573724131194431453023461572200856406939246297219541329623
n = 21815431662065695412834116602474344081782093119269423403335882867255834302242945742413692949886248581138784199165404321893594820375775454774521554409598568793217997859258282700084148322905405227238617443766062207618899209593375881728671746850745598576485323702483634599597393910908142659231071532803602701147251570567032402848145462183405098097523810358199597631612616833723150146418889589492395974359466777040500971885443881359700735149623177757865032984744576285054725506299888069904106805731600019058631951255795316571242969336763938805465676269140733371287244624066632153110685509892188900004952700111937292221969
mod=pow(2,265)
p0=(n/q0)%mod
pbar=(p1<<724)+p0
PR.<x> = PolynomialRing(Zmod(n))# 构建以x为变量的一元多项式环
 
for i in range(32): # 循环爆破5位
    f=pbar+x*mod*32 # 构建多项式,pbar为已知的高位与低位,爆破较低的五位bit,剩下的直接套用前面脚本
    f=f.monic()# monic函数,将x的系数化为1,方便计算
    pp=f.small_roots(X=2^454,beta=0.4)
    if(pp):
        break
    pbar+=mod
 
p=pbar+pp[0]*32*mod # 得出p
assert n%p==0
print(p)

3.已知m高位

基本所以的m高位攻击中e需要e = 3,可以当作已知条件使用(如果题目不给的话)

普遍解密脚本:

def m_high(kbits,n,e,c):
    PR.<x> = PolynomialRing(Zmod(n))
    f = (m_high + x)^e - c
    x0 = f.small_roots(2^kbits,1)[0]
    m = m_high + x0
    print(m)

例题:

from Crypto.Util.number import getPrime,bytes_to_long,long_to_bytes
from random import randint

from secret import flag

p = getPrime(1024)
q = getPrime(1024)
n = p*q
print(n)

m = bytes_to_long(long_to_bytes(randint(0,30))*208+flag)
assert(m.bit_length()==2044)
print((m>>315)<<315)
c = pow(m,3,n)
print(c)

n = 14113948189208713011909396304970377626324044633561155020366406284451614054260708934598840781397326960921718892801653205159753091559901114082556464576477585198060530094478860626532455065960136263963965819002575418616768412539016154873800614138683106056209070597212668250136909436974469812231498651367459717175769611385545792201291192023843434476550550829737236225181770896867698281325858412643953550465132756142888893550007041167700300621499970661661288422834479368072744930285128061160879720771910458653611076539210357701565156322144818787619821653007453741709031635862923191561438148729294430924288173571196757351837
m_high = 1520800285708753284739523608878585974609134243280728660335545667177630830064371336150456537012842986526527904043383436211487979254140749228004148347597566264500276581990635110200009305900689510908049771218073767918907869112593870878204145615928290375086195098919355531430003571366638390993296583488184959318678321571278510231561645872308920917404996519309473979203661442792048291421574603018835698487725981963573816645574675640357569465990665689618997534740389987351864738104038598104713275375385003471306823348792559733332094774873827383320058176803218213042061965933143968710199376164960850951030741280074168795136
c = 6635663565033382363211849843446648120305449056573116171933923595209656581213410699649926913276685818674688954045817246263487415328838542489103709103428412175252447323358040041217431171817865818374522191881448865227314554997131690963910348820833080760482835650538394814181656599175839964284713498394589419605748581347163389157651739759144560719049281761889094518791244702056048080280278984031050608249265997808217512349309696532160108250480622956599732443714546043439089844571655280770141647694859907985919056009576606333143546094941635324929407538860140272562570973340199814409134962729885962133342668270226853146819

例题解密脚本:

from Crypto.Util.number import *
n = 14113948189208713011909396304970377626324044633561155020366406284451614054260708934598840781397326960921718892801653205159753091559901114082556464576477585198060530094478860626532455065960136263963965819002575418616768412539016154873800614138683106056209070597212668250136909436974469812231498651367459717175769611385545792201291192023843434476550550829737236225181770896867698281325858412643953550465132756142888893550007041167700300621499970661661288422834479368072744930285128061160879720771910458653611076539210357701565156322144818787619821653007453741709031635862923191561438148729294430924288173571196757351837
m_high = 1520800285708753284739523608878585974609134243280728660335545667177630830064371336150456537012842986526527904043383436211487979254140749228004148347597566264500276581990635110200009305900689510908049771218073767918907869112593870878204145615928290375086195098919355531430003571366638390993296583488184959318678321571278510231561645872308920917404996519309473979203661442792048291421574603018835698487725981963573816645574675640357569465990665689618997534740389987351864738104038598104713275375385003471306823348792559733332094774873827383320058176803218213042061965933143968710199376164960850951030741280074168795136
c = 6635663565033382363211849843446648120305449056573116171933923595209656581213410699649926913276685818674688954045817246263487415328838542489103709103428412175252447323358040041217431171817865818374522191881448865227314554997131690963910348820833080760482835650538394814181656599175839964284713498394589419605748581347163389157651739759144560719049281761889094518791244702056048080280278984031050608249265997808217512349309696532160108250480622956599732443714546043439089844571655280770141647694859907985919056009576606333143546094941635324929407538860140272562570973340199814409134962729885962133342668270226853146819
e = 3
kbits = 315
PR.<x> = PolynomialRing(Zmod(n))
f = (m_high + x)^e - c
x0 = f.small_roots(2^kbits,1)[0]
m = m_high + x0
print(m)
# 使用python,这里的Crypto.Util.number无法在sage中使用
from Crypto.Util.number import *
m = 1520800285708753284739523608878585974609134243280728660335545667177630830064371336150456537012842986526527904043383436211487979254140749228004148347597566264500276581990635110200009305900689510908049771218073767918907869112593870878204145615928290375086195098919355531430003571366638390993296583488184959318678321571278510231561645872308920917404996519309473979203661442792048291421574603018835698487725981963573816645574675640357569465990665689618997534740389987351864738104038598104713275375385003471306823348792559733393609593321367463114703873343853590413300366406780333184299791982772652326424221774382732443261
print(long_to_bytes(m))

4.已知d高位、低位

总之就根据d来求p,进而使用p高位或低位知识进行求解p

大佬链接

具体公式推导可以看师傅的图片:

在这里插入图片描述

这里只进行脚本小子操作,大佬的文章中有详细的解释。

d低位

def get_full_p(p_low, n,d_low):
    PR.<x> = PolynomialRing(Zmod(n))
    d_lowbits = d_low.nbits()
    nbits = n.nbits()
    p_lowbits = p_low.nbits()
    f = 2^p_lowbits*x + p_low
    f = f.monic()
    roots = f.small_roots(X=2^(nbits//2-p_lowbits), beta=0.4)  
    if roots:
        x0 = roots[0]
        p = gcd(2^d_lowbits*x0 + p_low, n)
        return ZZ(p)


def find_p_low(d_low, e, n):
    X = var('X')
    for k in range(1, e+1):
        results = solve_mod([e*d_low*X == k*n*X + k*X + X-k*X**2 - k*n], 2^d_low.nbits())# 核心公式//d_low的bit位和n的一半bit位等价这里也可以替换为2^(n.nbits()//2)
        for x in results:
            p_low = ZZ(x[0])
            p = get_full_p(p_low, n,d_low)
            if p and p != 1:
                return p
find_p_low(d_low, e, n)

d高位

from Crypto.Util.number import *
def get_full_p(p_high, n,d_high,kbits):
    PR.<x> = PolynomialRing(Zmod(n))    
    f = x + p_high
    f = f.monic()
    roots = f.small_roots(X=2^(kbits + 4), beta=0.4)  
    if roots:
        x0 = roots[0]
        p = gcd(x0 + p_high, n)
        return ZZ(p)


def find_p_high(d_high, e, n,kbits):
    PR.<X> = PolynomialRing(RealField(1000))
    for k in tqdm(range(1, e+1)):
        f=e * d_high * X - (k*n*X + k*X + X-k*X**2 - k*n)# 核心公式
        results = f.roots()
        if results:
            for x in results:
                p_high = int(x[0])
                p = get_full_p(p_high, n,d_high,kbits)
                if p and p != 1:
                    return p
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值