RSA高位攻击

RSA高位攻击

所谓高位攻击,就是已知部分二进制位,求剩余二进制位

1.coppersmith定理

高位攻击的核心定理就是coppersmith定理

只有未知的bit位满足以下结论(即coppersmith定理)时,才能通过small_roots()方法求出未知的bit位,进而求解flag

结论:unknown_bits / p_bits <= 0.44

含义:比如要求p,p未知的二进制位是unknown_bits,其原本的的bit位是p_bits

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

sagemath中的small_roots()函数应用了coppersmith定理

small_roots(X= ,beta= )的使用方法:

  • X代表所需要求解根的上限;虽然是根的上限,并不是说上限越高越好,当上限超过某个值的时候就会计算失效,即使已知二进制位数满足条件,也无法用此函数求得结果;所以一般来说X取在给定情况下的最大求解上限

  • beta即是前面提到的β ,当p,q二进制位数相同时一般只能取0.4 ;如果p,q二进制位数不同,就按照之前的方法具体问题具体分析

2.已知p高位(已知q高位,同理)

这是最简单的一种

解密脚本:

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

3.已知p高位,q低位

例题:

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)
c = pow(bytes_to_long(flag), e, n)
print(hint1)
print(hint2)
print(n)
print(c)

由题目,可知,hint1是p的高位,但p的未知二进制位有724位,无法单独求出

hint2是q的低265位,也无法单独求出

因此,我们将q的低265位转换成p的低265位

image-20250210142433059

等式两边同时模2 **265

image-20250210142533794

此时未知的二进制位数仍然有459位,但是要使用coppersmith定理需要满足未知bit位数小于等于454

剩下的5位,直接进行爆破

解密代码:724

from Crypto.Util.number import *
import gmpy2
p_high = 1514296530850131082973956029074258536069144071110652176122006763622293335057110441067910479
q_low = 40812438243894343296354573724131194431453023461572200856406939246297219541329623
n = 21815431662065695412834116602474344081782093119269423403335882867255834302242945742413692949886248581138784199165404321893594820375775454774521554409598568793217997859258282700084148322905405227238617443766062207618899209593375881728671746850745598576485323702483634599597393910908142659231071532803602701147251570567032402848145462183405098097523810358199597631612616833723150146418889589492395974359466777040500971885443881359700735149623177757865032984744576285054725506299888069904106805731600019058631951255795316571242969336763938805465676269140733371287244624066632153110685509892188900004952700111937292221969
c = 19073695285772829730103928222962723784199491145730661021332365516942301513989932980896145664842527253998170902799883262567366661277268801440634319694884564820420852947935710798269700777126717746701065483129644585829522353341718916661536894041337878440111845645200627940640539279744348235772441988748977191513786620459922039153862250137904894008551515928486867493608757307981955335488977402307933930592035163126858060189156114410872337004784951228340994743202032248681976932591575016798640429231399974090325134545852080425047146251781339862753527319093938929691759486362536986249207187765947926921267520150073408188188
e = 65537

mod = pow(2,265)
p0 = n * inverse_mod(q_low,mod) % mod
PR.<x> = PolynomialRing(Zmod(n))
for i in range(2^5):
    f = p_high * (2^724) + p0 + (x * 32 + i) * mod
    f = f.monic()
    out_p = f.small_roots(2^454,0.4)
    if len(out_p) != 0:
        print(out_p[0])
        break
p = (out_p[0] * 32 + i) * mod + p_high * (2^724) + p0
print(p)
p = 133637329398256221348922087205912367118213472434713498908220867690672019569057789598459580146410501473689139466275052698529257254973211963162087316149628000798221014338373126500646873612341158676084318494058522014519669302359038980726479317742766438142835169562422371156257894374341629012755597863752154328407
assert n % p == 0
q = n // p
fai_n = (p-1) * (q-1)
d = inverse_mod(e,fai_n)
m = pow(c,d,n)
print(bytes.decode(long_to_bytes(m)))

4.已知m高位

所有的m高位攻击中需要e =3(如果题目不给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

解密代码:

#sagemath
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)

#pycharm
from Crypto.Util.number import *
m = 1520800285708753284739523608878585974609134243280728660335545667177630830064371336150456537012842986526527904043383436211487979254140749228004148347597566264500276581990635110200009305900689510908049771218073767918907869112593870878204145615928290375086195098919355531430003571366638390993296583488184959318678321571278510231561645872308920917404996519309473979203661442792048291421574603018835698487725981963573816645574675640357569465990665689618997534740389987351864738104038598104713275375385003471306823348792559733393609593321367463114703873343853590413300366406780333184299791982772652326424221774382732443261
print(long_to_bytes(m))

5.已知d低位、高位

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

推导:
1

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^p_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())# 核心公式
        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
posted @ 2025-07-23 14:50  xiehou~  阅读(331)  评论(0)    收藏  举报