p^(q>>nbits)

题目:

from Crypto.Util.number import getPrime

P = getPrime(512)
Q = getPrime(512)
print(f'P=', P)
print(f'Q=', Q)
N = P * Q
gift = P ^ (Q >> 16)
print(f'N=', N)
print(f'gift=', gift)
'''
P= 11481612532689135862501805996842831673107792613792055252512715623753544233802562308026426490828415603111152533790119282435578802048988109663823935868709469
Q= 9692252381448626601112664259476245824049031300920876447302512902241423303744427463471331538152609906597730047920241633860373212038891843226251416518424467
N= 111282686412826674201998513574910007138527547638030117720977198675060472749776265556690826259176810825199693619362958921994099597675484062874277983151898203734769433073133775041506030856215078997362438937560880592493899592780603947746558190195946567691428693508993737133339899140963387755547588435992444178023
gift= 11481477468553644543362409746875077840801283571135996438866581579956742344184253395877980560572002496249698639314769718613889234053482044504336948594567411
'''

解题思路:

P = getPrime(512)
Q = getPrime(512)
N = P * Q
gift = P ^ (Q >> 16)

这个其实并不算剪枝了,因为gift的高16位就是P的高16位,用N除以P后得到的就是Q的高位,再次利用Q的高位和 gift,可以求出P1632位,以此类推来恢复P,Q

但是我们也可以用剪枝做法:

已知条件:

  • N = P * Q
  • gift = P ^ (Q >> 16)

搜索方式:

  • 从高位向低位搜索
  • 这种情况,p的高kbits位已知,与xor的高kbits位相同,那搜索就从xorkbits位开始,即p的第kbits位,q的第1
  • xor当前位为1,则可能为两种情况:p1,q0或者p0,q1;反之xor当前位为0,则p1,q1或者p0,q0(这里的p或者q1指的都是xor当前位对应的pq的位置)

剪枝条件:

  • pq剩下位全部填充为1,需要满足p*q > n
  • pq剩下位全部填充为0,需要满足p*q < n
  • 这里要注意把p的已知的高kbits位加上

结束条件:

  • n mod p = 0

解答:

N= 111282686412826674201998513574910007138527547638030117720977198675060472749776265556690826259176810825199693619362958921994099597675484062874277983151898203734769433073133775041506030856215078997362438937560880592493899592780603947746558190195946567691428693508993737133339899140963387755547588435992444178023
gift= 11481477468553644543362409746875077840801283571135996438866581579956742344184253395877980560572002496249698639314769718613889234053482044504336948594567411

pbar = gift >>(512-16)

while True:
    try:
        qbar = (N>>(1024 - pbar.bit_length()*2))//pbar
        qbar = qbar>>6
        gifts = gift^(qbar<<(512-16-qbar.bit_length()))
        pbar = gifts >> (512-16-qbar.bit_length())
    except:
        break

for i in range(64):
    if N%((pbar<<6)+i) == 0:
        p = (pbar<<6)+i
        q = N//p
        print("[+] p =",p)
        print("[+] q =",q)
        break
#[+] p = 11481612532689135862501805996842831673107792613792055252512715623753544233802562308026426490828415603111152533790119282435578802048988109663823935868709469
#[+] q = 9692252381448626601112664259476245824049031300920876447302512902241423303744427463471331538152609906597730047920241633860373212038891843226251416518424467
n = 111282686412826674201998513574910007138527547638030117720977198675060472749776265556690826259176810825199693619362958921994099597675484062874277983151898203734769433073133775041506030856215078997362438937560880592493899592780603947746558190195946567691428693508993737133339899140963387755547588435992444178023
xor = 11481477468553644543362409746875077840801283571135996438866581579956742344184253395877980560572002496249698639314769718613889234053482044504336948594567411
kbits = 16
pbits = 512
xor = str(bin(xor)[2:])
ph = xor[:kbits]
qh = ''
xor = xor[kbits:]
qh = ''

def find(ph, qh):
    l0 = len(ph)
    l1 = len(qh)
    tmp0 = ph + '0' * (pbits - l0)
    tmp1 = ph + '1' * (pbits - l0)
    tmq0 = qh + '0' * (pbits - l1)
    tmq1 = qh + '1' * (pbits - l1)
    if int(tmp0, 2) * int(tmq0, 2) > n:  # 剪枝条件1
        return
    if int(tmp1, 2) * int(tmq1, 2) < n:  # 剪枝条件2
        return

    if l0 == pbits:  # 结束条件
        if n % int(ph, 2) == 0:
            print(f'p = {int(ph, 2)}')
            return

    else:
        if xor[l1] == '1':
            find(ph + '0', qh + '1')
            find(ph + '1', qh + '0')
        else:
            find(ph + '1', qh + '1')
            find(ph + '0', qh + '0')

find(ph, qh)
p1 = 11481612532689135862501805996842831673107792613792055252512715623753544233802562308026426490828415603111152533790119282435578802048988109663823935868709469
#p = 11481612532689135862501805996842831673107792613792055252512715623753544233802562308026426490828415603111152533790119282435578802048988109663823935868709469
print(f'q =', n//p1)
#q = 9692252381448626601112664259476245824049031300920876447302512902241423303744427463471331538152609906597730047920241633860373212038891843226251416518424467

假设我们不知道<font style="color:#DF2A3F;">kbits</font>是多少,一样可以求,无非就是爆破

已知 p⊕(q>>kbits) 但前kbits位未知

题目:

from Crypto.Util.number import *
p = getPrime(128)
q = getPrime(128)
n = p*q
kbits = 16
_q = q>>kbits
xor = p^_q
xor = int(bin(xor)[2:][kbits:],2)
print(f"n = {n}")
print(f"xor = {xor}")

#n = 67993063298729224384929426280013061841686812014564261424956366758045322225691
#xor = 4614553526345165212539618883307366

解答:

n = 67993063298729224384929426280013061841686812014564261424956366758045322225691
xor = 4614553526345165212539618883307366
kbits = 16
pbits = 128
xor = str(bin(xor)[2:])

def find(ph,qh):
    l0 = len(ph)
    l1 = len(qh)
    tmp0 = ph + '0' * (pbits-l0)
    tmp1 = ph + '1' * (pbits-l0)
    tmq0 = qh + '0' * (pbits-l1)
    tmq1 = qh + '1' * (pbits-l1)
    if int(tmp0,2) * int(tmq0,2) > n:#剪枝条件1
        return
    if int(tmp1,2) * int(tmq1,2) < n:#剪枝条件2
        return
    
    if l0 == pbits:#结束条件
        if n % int(ph,2) == 0:
            print(f'p = {int(ph,2)}')
            return
    
    else:
        if xor[l1] == '1':
            find(ph+'0',qh+'1')
            find(ph + '1',qh+'0') 
        else:
            find(ph+'1',qh+'1')
            find(ph + '0',qh+'0')    

for i in  range(2**kbits):
    ph = bin(i)[2:].zfill(kbits)
    qh = ''            
    find(ph,qh)
#p = 252330886747767934000827792522692714557
posted @ 2025-03-11 22:11  sevensnight  阅读(24)  评论(0)    收藏  举报