#辗转相除法化为连分数形式 deftransform(x, y): res = [] while y: res.append(x // y) x, y = y, x % y return res
# 实现连分数的逆向计算,将连分数序列转换为分数 defcontinued_fraction(sub_res): numerator, denominator = 1, 0 for i in sub_res[::-1]: denominator, numerator = numerator, i * numerator + denominator # 计算新的分子和分母 return numerator, denominator # 返回分数形式的结果
# 计算连分数 defsub_fraction(x, y): res = transform(x, y) # 获取 x 和 y 的连分数表示 res = list(map(continued_fraction, (res[0:i] for i inrange(1, len(res) + 1)))) # 将每一步的连分数转换为分数 return res # 返回连分数列表
# 根据韦达定理获取 p 和 q defget_pq(a, b, c): par = isqrt(b * b - 4 * a * c) x1, x2 = (-b + par) // (2 * a), (-b - par) // (2 * a) return x1, x2
defattack(e, n): for (k,d) in sub_fraction(e, n): if k == 0: continue if (e * d - 1) % k != 0: continue phi = (e * d - 1) // k x1, x2 = get_pq(1, n - phi + 1, n) if x1 * x2 == n: p, q = abs(int(x1)), abs(int(x2)) # 取 p 和 q 的绝对值 d = inverse_mod(e, (p - 1) * (q - 1)) print(f"p = {p}") print(f"q = {q}") print(f"d = {d}") return print("该方法不适用")
注意,在这一段代码中:
1 2 3 4 5
defcontinued_fraction(sub_res): numerator, denominator = 1, 0 for i in sub_res[::-1]: denominator, numerator = numerator, i * numerator + denominator # 计算新的分子和分母 return numerator, denominator # 返回分数形式的结果
和最后的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
defattack(e, n): for (k,d) in sub_fraction(e, n): if k == 0: continue if (e * d - 1) % k != 0: continue phi = (e * d - 1) // k x1, x2 = get_pq(1, n - phi + 1, n) if x1 * x2 == n: p, q = abs(int(x1)), abs(int(x2)) # 取 p 和 q 的绝对值 d = inverse_mod(e, (p - 1) * (q - 1)) print(f"p = {p}") print(f"q = {q}") print(f"d = {d}") return print("该方法不适用")
很多博客在for (k,d) in sub_fraction(e,n)这里会是(d,k),或者强调说是d是分子,但是仔细分析代码发现是continued_fraction(sub_res)这个函数的返回值不一样的问题,返回的numerator对应k,denominator对应d即可(需要注意numerator和denominator的初始值为1还是0)
from Crypto.Util.number import * from gmpy2 import * from secret import flag from random import *
gift = 0x98efa1cac6d4a1031759ddfb2cb2a1361b76a0327802e5b99e2f98a1a410705fe93f36979441c6b5eab2737bacc66565d425c56c434d04cbc2b3d756d264995f8b198d6887ec2dddfa640d88932604115d80a9f1f0d18538a738016292057518e02b8520d1322f2cc8c500438d24e041ef9d3e70244e327e28d03c371b7d119a387bf7dfaf7b1ad89ce68f0bdf5858d961b48a6080c589a7e5ac9505cb3893510670299d2f4570acca050e26f828056a4276387b69f64a1498552754ede89e21a1c4a5e0754b41aa2c17823b6d84666896d865c9627a3be5cb8ede76461b44f7ed2398cb29f52073f23c5b0b5ac1af048d310ddec9b683ae0535670195ea510012eb16fb60186a5c26f6c516addeade9bed3dea308fc9196de5b5e99b8f8354b9116995dffb350b5b71ee8ae21b776e122508bf4acd8c9c69bb67a8003291b9a217301656ff332d6802db63605aee2a881e0ddf08904e5c8ace0cd44bffdeee7b10e1b5d868b25ddb1248802c7341267f9862b9319cbaada6d7b557425273256505470d2d610232c00d53475693db249299594ee62271589ec4ebd92c0f37d05ca24c556948dd30b3e6b124f059e4776ef219766e805bf7b1003734172e8d2cda130966bd6c5643071efef3e39bc11f6bdfef4ba6e9fa450f7605bcf9ca22c5f12fdec2f8b3ead07a34a427e3602792939873a2481a8dd0e454305b5ce374a77
defmake_gift(p, q): n_bits = len(bin(p * q)) - 2 phi = (p - 1) * (q - 1) r = randint(11, 111) whileTrue: a = getPrime(n_bits // 4 - r) if gcd(a, phi) != 1: continue b = invert(a, phi) e = invert(b, gift) if gcd(e, phi) == 1: break d = invert(e, phi) return (e, d)
p = getPrime(2048) q = getPrime(2048) n = p * q e, d = make_gift(p, q) c = pow(bytes_to_long(flag), e, n)
from gmpy2 import * from Crypto.Util.number import * import random
defcontinuedFra(x, y): cf = [] while y: cf.append(x // y) x, y = y, x % y return cf
defgradualFra(sub_res): numerator, denominator = 1, 0 for i in sub_res[::-1]: denominator, numerator = numerator, i * numerator + denominator # 计算新的分子和分母 return numerator, denominator # 返回分数形式的结果
defgetGradualFra(cf): gf = [] for i inrange(1, len(cf) + 1): gf.append(gradualFra(cf[:i])) return gf
defwienerAttack(e, n): cf = continuedFra(e, n) gf = getGradualFra(cf) n_bits = len(bin(n)) - 2 for _,a in gf: if a.bit_length() < (n_bits // 4 - 11) and a.bit_length() > (n_bits // 4 - 111) and isPrime(a): return a
n=0xf5da802f4a0d148a957254c9287bf1515c81088416067574fb614342d15757b84014125fa9b0b2e8158a7321a0bcde32c6b98abede5da9e526dd2e67c148f89ac0787fa55dd2a2922bc0595e67cb347ab923ee251b1e7c395706a8956335032914f152fe30556feb48592be713c120186266a085a96dee08d86283362dd2593c0df06d83050ad7d3ce5a0ae482b32800a80f66f5d8bfa306b365faec72f4cfc02846c222602a660bd024c8b05055ee824a7a14d6c3d1227ecff1c5b95016ba4ac82f3d493c51ba5e07f3d220ec633358165c97062ffe35abba6745cb7e9182aade6f867fe1ade89515ef61e1c20f08b81b19afbc09be357b2cb328fbb341408bc2ac3fbd66ab7eb7470123e8bea12c3f46082c1f37dd9eb9716d2fe92c090b63f64b8fe3e456f08ced64068e9232309c1d71f9723a2cdf643aa3eca2c0d5fcb1ffe95f9c25bd090ea94f408411e1e030016a91b024eba077fd709d69feec798a86160b921fdc058a5d6b041997737789cd4afbab4a92a80f53152ef4c6cfed432de2bf5c1cb53e33cbed6776a1f7ea4b543f688f34c7765eb441246fdccd34f0c07dca305649375d59f62087d5b2bb863f1fc6d74fe47ab1e8cbf948473e7bc08d6bb8801518d908548624a6eea403ac7ec8531920bbb319681887e70fe1c67def9a431e3ed342fae3fe4bbed35f3081ffe54b8d41409a9d017963ceb1261745 e=0x324029b96d92446e3315b04d321db7228b30a3d0f0be3d16b7356b4259bf54e9203756fbb08713b88dbdc4986cc7ca676888f7b286b648028428af30175f4568d6443ba8f3a96a168fbe60a71addaf63b307e619c1047c24c88f2619c54b565a20fb066639c74bd7187f66e641384acca5dd59ae652873ebf715de7e1ccaa13187377e1a3c2f7ef2a3607a03bd216ef34ba3788bdb4a23b2a0ae158282c773e19635494907f65798e2a8927d6df96a4eb24ff3b40689d8ea4a82587d6dc7a268e5094c049e2321689c9d0f3fe6e261642970946d7454911518198b6e3cf7227a8e5467a6efa2ffff369307121216c65670e1319cfa20da72b4b5f5cd4a2115f360d9da94b84469466ca886d30184059dec26caca654e601c62c17b33dc30dcd66e1b89578267df7cbc4fe5270b72a23861d54426e86e3dfd7a6ae5a38168229d3f6352dfcd3d21674f349af741cc6a858a3e67c55329fb8c0fd21fb50fd2c3174b0ec2e365b0a0f444de1759ecb98a56dbd7830401e663782a564b4de2208606bee3aa98e0970d6f7cdf923c12852caaf86ef75ff438b1879da69b30564fcc7cc9aa38691ce1353fec995eaf4b8d97792b4f627bb7b631ec0dfcf8ee9333f592462ca6f16e99ef5ecece276c25ddb57b03f87266be0038bc78d374161bb8f558b8fca419a7716c984499bf17832ea2eb2e68fd4118fdb2e5a6d49d08dba0db69 c=0x5951976397efab4db75cecd1d669f64e31da28c82f383b920fe83a1b99a913d1cb60db9d5fc58795ae011a5c5949cc0b1f53ce28e1505aad93a5ffc9e71418f32aff300ff7d9d5de83c5f53535ea6f25bbc31b56bb7f785d95edf10672bb458f6dba81acc3fd9c2de79506ea7520068b17018359642f34c365580a8e200d411f5a80f38b673706b365f0e6d2e6fb3732208acc0ab64e6159310f8fe4076f9cff17192cb8cbf37c0278e5772c1ac7c80314fc8ec6eaa39852a8e67c5592a5d87dd406e189c19c8db635f8d50e48051dc6e29d1d52e233a490cb53e1d1a592fd3883ef25f02beaf90eb4323a6e3b37c814969689c11e696422125ccd7f8a2e4fcb5276784f1d2cb5aaa2b5a5944f6330684c1c9b9c8da6ca25b18b4024d6e859014ed488643193fe1f8a4b7fdc94ad59965e00cc6cfcbb123a04c13bacbfdf2a3fc240d08c416cbb0acfaa416c81aa351c43ab62020ab39ffa3d2ccde402cb7afbde6dcb61ad0270c44560dced8eb70ae6eeb4c3c092428e94fcf334afab39e10eb1a48a02444358d32ca2ebee3045b473c3b7f9629bbce56d599969c2e2e43d6c2d10079c0e7358f5e944020f77d5f79f6cf78952434cc038ffdadccc6ef1e88f0b8cf6cfe1a6b3f0f5ac1492b387c1dc29f6624f6b20fa86c0ed5d71296275df3388467680bf5208afbb39277045f0dd6a3230418e8220ee7a213888a712d682 gift = 0x98efa1cac6d4a1031759ddfb2cb2a1361b76a0327802e5b99e2f98a1a410705fe93f36979441c6b5eab2737bacc66565d425c56c434d04cbc2b3d756d264995f8b198d6887ec2dddfa640d88932604115d80a9f1f0d18538a738016292057518e02b8520d1322f2cc8c500438d24e041ef9d3e70244e327e28d03c371b7d119a387bf7dfaf7b1ad89ce68f0bdf5858d961b48a6080c589a7e5ac9505cb3893510670299d2f4570acca050e26f828056a4276387b69f64a1498552754ede89e21a1c4a5e0754b41aa2c17823b6d84666896d865c9627a3be5cb8ede76461b44f7ed2398cb29f52073f23c5b0b5ac1af048d310ddec9b683ae0535670195ea510012eb16fb60186a5c26f6c516addeade9bed3dea308fc9196de5b5e99b8f8354b9116995dffb350b5b71ee8ae21b776e122508bf4acd8c9c69bb67a8003291b9a217301656ff332d6802db63605aee2a881e0ddf08904e5c8ace0cd44bffdeee7b10e1b5d868b25ddb1248802c7341267f9862b9319cbaada6d7b557425273256505470d2d610232c00d53475693db249299594ee62271589ec4ebd92c0f37d05ca24c556948dd30b3e6b124f059e4776ef219766e805bf7b1003734172e8d2cda130966bd6c5643071efef3e39bc11f6bdfef4ba6e9fa450f7605bcf9ca22c5f12fdec2f8b3ead07a34a427e3602792939873a2481a8dd0e454305b5ce374a77
b = invert(e,gift)
a = wienerAttack(b,n)
defdivide_pq(e, d, n): k = e*d - 1 whileTrue: g = random.randint(2, n-1) t = k whileTrue: if t % 2 != 0: break t //= 2 x = pow(g, t, n) if x > 1and gcd(x-1, n) > 1: p = gcd(x-1, n) return (p, n//p)
p,q = divide_pq(a,b,n) d = inverse(e,(p-1)*(q-1)) print(long_to_bytes(pow(c,d,n))) # flag{W1nn3r_4tt4ck_1s_0k_!}
已知n,d,求e
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
from gmpy2 import invert from md5 import md5 from secret import p, q
e = ????? n = p*q phi = (p-1)*(q-1) d = invert(e, phi) ans = gcd(e,phi)
print n, e, d print"Flag: DASCTF{%s}" %md5(str(p + q)).hexdigest()
""" n = 80642592772746398646558097588687958541171131704233319344980232942965050635113860017117519166348100569115174644678997805783380130114530824798808098237628247236574959152847903491509751809336988273823686988619679739640305091291330211169194377552925908412183162787327977125388852329089751737463948165202565859373 d = 14218766449983537783699024084862960813708451888387858392014856544340557703876299258990323621963898510226357248200187173211121827541826897886277531706124228848229095880229718049075745233893843373402201077890407507625110061976931591596708901741146750809962128820611844426759462132623616118530705745098783140913 """
from gmpy2 import * from Crypto.Util.number import * import random
defcontinuedFra(x, y): cf = [] while y: cf.append(x // y) x, y = y, x % y return cf
defgradualFra(sub_res): numerator, denominator = 1, 0 for i in sub_res[::-1]: denominator, numerator = numerator, i * numerator + denominator # 计算新的分子和分母 return numerator, denominator # 返回分数形式的结果
defgetGradualFra(cf): gf = [] for i inrange(1, len(cf) + 1): gf.append(gradualFra(cf[:i])) return gf
defwienerAttack(d, n): cf = continuedFra(d, n) gf = getGradualFra(cf) for k,e in gf: if e == 1: continue if (e * d - 1) % k == 0: print(k) print(e) p_q = n + 1 - (e * d - 1) // k print('p + q =', p_q)
n = 80642592772746398646558097588687958541171131704233319344980232942965050635113860017117519166348100569115174644678997805783380130114530824798808098237628247236574959152847903491509751809336988273823686988619679739640305091291330211169194377552925908412183162787327977125388852329089751737463948165202565859373 d = 14218766449983537783699024084862960813708451888387858392014856544340557703876299258990323621963898510226357248200187173211121827541826897886277531706124228848229095880229718049075745233893843373402201077890407507625110061976931591596708901741146750809962128820611844426759462132623616118530705745098783140913 a = wienerAttack(d,n)
c = continued_fraction(data3) alist = c.convergents() for i in alist: a = str(i).split('/') if len(a)>1 and gcd(int(a[0]),int(a[1])) == 1 and is_prime(int(a[0])) and is_prime(int(a[1])) and int(a[0]).bit_length()==256 and int(a[1]).bit_length()==256: print(a) #['97093002077798295469816641595207740909547364338742117628537014186754830773717','67958620138887907577348085925738704755742144710390414146201367031822084270769']