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
,可以求出P
的16
~32
位,以此类推来恢复P
,Q
但是我们也可以用剪枝做法:
已知条件:
N = P * Q
gift = P ^ (Q >> 16)
搜索方式:
- 从高位向低位搜索
- 这种情况,
p
的高kbits
位已知,与xor
的高kbits
位相同,那搜索就从xor
的kbits
位开始,即p
的第kbits
位,q
的第1
位 - 若
xor
当前位为1
,则可能为两种情况:p
为1
,q
为0
或者p
为0
,q
为1
;反之xor
当前位为0
,则p
为1
,q
为1
或者p
为0
,q
为0
(这里的p
或者q
为1
指的都是xor
当前位对应的p
和q
的位置)
剪枝条件:
- 将
p
和q
剩下位全部填充为1
,需要满足p*q > n
- 将
p
和q
剩下位全部填充为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