├── README.md ├── exp1.py ├── exp2.py ├── exp3.py ├── exp4.py ├── exp5.sage ├── exp6.sage ├── exp7.sage ├── exp8.sage ├── exp9.sage ├── expa.py └── expb.py /README.md: -------------------------------------------------------------------------------- 1 | # CTF中RSA的一些攻击思路 2 | 3 | > 本项目收集了一些RSA的攻击脚本,并将其中一部分用python3重构 4 | > 5 | > 参考文章: 6 | > 7 | > https://www.tr0y.wang/2017/11/06/CTFRSA/index.html 8 | > 9 | > http://inaz2.hatenablog.com/entry/2016/01/20/022936 10 | 11 | ## 关于RSA算法 12 | 13 | > **RSA加密算法**是一种非对称加密算法,1977年由Ron Rivest、Adi Shamir和Leonard Adleman一起提出的,算法安全性依赖于极大整数做因数分解的难度 14 | 15 | ## RSA算法加解密实现 16 | 17 | 1.随意选择两个大素数*p*和*q*,且*p不等于q*,计算*N=p***q* 18 | 19 | 2.计算*n*的欧拉函数*φ(n) = (p-1)(q-1)*(常用*phi(n)*表示*φ(n)*) 20 | 21 | 3.选择一个整数*e*,满足*1< e < φ(n)*,且*e与φ(n)* 互质(e通常取65537) 22 | 23 | 4.计算模反元素*d*,*ed ≡ 1 (mod φ(n))* 即求解*ex + φ(n)y = 1*方程组(利用扩展欧几里得算法可以求出*d*) 24 | 25 | ```d = gmpy2.invert(e, (p-1)*(q-1))``` 26 | 27 | 5.得到公钥*(N,e)*私钥*(N,d)* 28 | 29 | 6.加密 *c = pow(m,e,N)* 30 | 31 | 7.解密 *m = pow(c,d,N)* 32 | 33 | ## RSA在CTF中的攻击方法 34 | 35 | >gmpy2 安装 36 | > 37 | >sudo apt install libmpc-dev 38 | > 39 | >pip/pip3 install gmpy2 40 | > 41 | >sage安装 42 | > 43 | >https://mirrors.tuna.tsinghua.edu.cn/sagemath/linux/64bit/index.html 44 | 45 | ### 明文解密 46 | 47 | #### **模互素** 48 | 49 | d = gmpy2.invert(e,(p-1) * (q-1)) 50 | 51 | m = gmpy2.powmod(c,d,n) 52 | 53 | #### **模不互素** 54 | 55 | 第一种情况 56 | 57 | 给出 p,q,c,e且gcd(e, (p-1)*(q-1))非常小(可能为3) 58 | 59 | example: 60 | 61 | p,q = 3881, 885445853681787330351086884500131209939 62 | 63 | c = 1926041757553905692219721422025224638913707 64 | 65 | e = 33 66 | 67 | 第二种情况 68 | 69 | 给出n1,n2,e1,e2,c1,c2求满足以下式子 70 | 71 | assert p = gcd(n1,n2) 72 | 73 | assert pow(flag,e1,n1)==c1 74 | 75 | assert pow(flag,e2,n2)==c2 76 | 77 | assert gcd(e1,(p1-1) * (q1-1))==gcd(e2,(p2-1) * (q2-1)) 78 | 79 | 80 | 81 | ### 低加密指数攻击 82 | 83 | m ^ e = kn + c 其中一般 e = 3,k比较小(k小于10亿爆破时间一般小于半小时) 84 | 85 | ### 低加密指数广播攻击 86 | 87 | c1 ≡ m^e mod n1 88 | 89 | c2 ≡ m^e mod n2 90 | 91 | …… 92 | 93 | ce ≡ m^e mod ne 94 | 95 | 如以上所示,e比较小,题目给出n[e]和c[e],且m相同,利用中国剩余定理可以求m 96 | 97 | ### 低解密指数攻击 98 | 99 | 与低加密指数攻击相反,需要满足e非常大,接近于N 100 | 101 | ### 共模攻击 102 | 103 | c1 ≡ m^e1 mod n 104 | 105 | c2 ≡ m^e2 mod n 106 | 107 | 如以上使用了相同的模数N对相同的明文进行加密 108 | 109 | ### Boneh and Durfee attack 110 | 111 | e 非常大接近于N,跟低解密指数攻击类似,比低解密指数攻击更强,可以解决d= modulus: 43 | nothelpful += 1 44 | 45 | print nothelpful, "/", BB.dimensions()[0], " vectors are not helpful" 46 | 47 | # display matrix picture with 0 and X 48 | def matrix_overview(BB, bound): 49 | for ii in range(BB.dimensions()[0]): 50 | a = ('%02d ' % ii) 51 | for jj in range(BB.dimensions()[1]): 52 | a += '0' if BB[ii,jj] == 0 else 'X' 53 | if BB.dimensions()[0] < 60: 54 | a += ' ' 55 | if BB[ii, ii] >= bound: 56 | a += '~' 57 | print a 58 | 59 | # tries to remove unhelpful vectors 60 | # we start at current = n-1 (last vector) 61 | def remove_unhelpful(BB, monomials, bound, current): 62 | # end of our recursive function 63 | if current == -1 or BB.dimensions()[0] <= dimension_min: 64 | return BB 65 | 66 | # we start by checking from the end 67 | for ii in range(current, -1, -1): 68 | # if it is unhelpful: 69 | if BB[ii, ii] >= bound: 70 | affected_vectors = 0 71 | affected_vector_index = 0 72 | # let's check if it affects other vectors 73 | for jj in range(ii + 1, BB.dimensions()[0]): 74 | # if another vector is affected: 75 | # we increase the count 76 | if BB[jj, ii] != 0: 77 | affected_vectors += 1 78 | affected_vector_index = jj 79 | 80 | # level:0 81 | # if no other vectors end up affected 82 | # we remove it 83 | if affected_vectors == 0: 84 | print "* removing unhelpful vector", ii 85 | BB = BB.delete_columns([ii]) 86 | BB = BB.delete_rows([ii]) 87 | monomials.pop(ii) 88 | BB = remove_unhelpful(BB, monomials, bound, ii-1) 89 | return BB 90 | 91 | # level:1 92 | # if just one was affected we check 93 | # if it is affecting someone else 94 | elif affected_vectors == 1: 95 | affected_deeper = True 96 | for kk in range(affected_vector_index + 1, BB.dimensions()[0]): 97 | # if it is affecting even one vector 98 | # we give up on this one 99 | if BB[kk, affected_vector_index] != 0: 100 | affected_deeper = False 101 | # remove both it if no other vector was affected and 102 | # this helpful vector is not helpful enough 103 | # compared to our unhelpful one 104 | if affected_deeper and abs(bound - BB[affected_vector_index, affected_vector_index]) < abs(bound - BB[ii, ii]): 105 | print "* removing unhelpful vectors", ii, "and", affected_vector_index 106 | BB = BB.delete_columns([affected_vector_index, ii]) 107 | BB = BB.delete_rows([affected_vector_index, ii]) 108 | monomials.pop(affected_vector_index) 109 | monomials.pop(ii) 110 | BB = remove_unhelpful(BB, monomials, bound, ii-1) 111 | return BB 112 | # nothing happened 113 | return BB 114 | 115 | """ 116 | Returns: 117 | * 0,0 if it fails 118 | * -1,-1 if `strict=true`, and determinant doesn't bound 119 | * x0,y0 the solutions of `pol` 120 | """ 121 | def boneh_durfee(pol, modulus, mm, tt, XX, YY): 122 | """ 123 | Boneh and Durfee revisited by Herrmann and May 124 | 125 | finds a solution if: 126 | * d < N^delta 127 | * |x| < e^delta 128 | * |y| < e^0.5 129 | whenever delta < 1 - sqrt(2)/2 ~ 0.292 130 | """ 131 | 132 | # substitution (Herrman and May) 133 | PR. = PolynomialRing(ZZ) 134 | Q = PR.quotient(x*y + 1 - u) # u = xy + 1 135 | polZ = Q(pol).lift() 136 | 137 | UU = XX*YY + 1 138 | 139 | # x-shifts 140 | gg = [] 141 | for kk in range(mm + 1): 142 | for ii in range(mm - kk + 1): 143 | xshift = x^ii * modulus^(mm - kk) * polZ(u, x, y)^kk 144 | gg.append(xshift) 145 | gg.sort() 146 | 147 | # x-shifts list of monomials 148 | monomials = [] 149 | for polynomial in gg: 150 | for monomial in polynomial.monomials(): 151 | if monomial not in monomials: 152 | monomials.append(monomial) 153 | monomials.sort() 154 | 155 | # y-shifts (selected by Herrman and May) 156 | for jj in range(1, tt + 1): 157 | for kk in range(floor(mm/tt) * jj, mm + 1): 158 | yshift = y^jj * polZ(u, x, y)^kk * modulus^(mm - kk) 159 | yshift = Q(yshift).lift() 160 | gg.append(yshift) # substitution 161 | 162 | # y-shifts list of monomials 163 | for jj in range(1, tt + 1): 164 | for kk in range(floor(mm/tt) * jj, mm + 1): 165 | monomials.append(u^kk * y^jj) 166 | 167 | # construct lattice B 168 | nn = len(monomials) 169 | BB = Matrix(ZZ, nn) 170 | for ii in range(nn): 171 | BB[ii, 0] = gg[ii](0, 0, 0) 172 | for jj in range(1, ii + 1): 173 | if monomials[jj] in gg[ii].monomials(): 174 | BB[ii, jj] = gg[ii].monomial_coefficient(monomials[jj]) * monomials[jj](UU,XX,YY) 175 | 176 | # Prototype to reduce the lattice 177 | if helpful_only: 178 | # automatically remove 179 | BB = remove_unhelpful(BB, monomials, modulus^mm, nn-1) 180 | # reset dimension 181 | nn = BB.dimensions()[0] 182 | if nn == 0: 183 | print "failure" 184 | return 0,0 185 | 186 | # check if vectors are helpful 187 | if debug: 188 | helpful_vectors(BB, modulus^mm) 189 | 190 | # check if determinant is correctly bounded 191 | det = BB.det() 192 | bound = modulus^(mm*nn) 193 | if det >= bound: 194 | print "We do not have det < bound. Solutions might not be found." 195 | print "Try with highers m and t." 196 | if debug: 197 | diff = (log(det) - log(bound)) / log(2) 198 | print "size det(L) - size e^(m*n) = ", floor(diff) 199 | if strict: 200 | return -1, -1 201 | else: 202 | print "det(L) < e^(m*n) (good! If a solution exists < N^delta, it will be found)" 203 | 204 | # display the lattice basis 205 | if debug: 206 | matrix_overview(BB, modulus^mm) 207 | 208 | # LLL 209 | if debug: 210 | print "optimizing basis of the lattice via LLL, this can take a long time" 211 | 212 | BB = BB.LLL() 213 | 214 | if debug: 215 | print "LLL is done!" 216 | 217 | # transform vector i & j -> polynomials 1 & 2 218 | if debug: 219 | print "looking for independent vectors in the lattice" 220 | found_polynomials = False 221 | 222 | for pol1_idx in range(nn - 1): 223 | for pol2_idx in range(pol1_idx + 1, nn): 224 | # for i and j, create the two polynomials 225 | PR. = PolynomialRing(ZZ) 226 | pol1 = pol2 = 0 227 | for jj in range(nn): 228 | pol1 += monomials[jj](w*z+1,w,z) * BB[pol1_idx, jj] / monomials[jj](UU,XX,YY) 229 | pol2 += monomials[jj](w*z+1,w,z) * BB[pol2_idx, jj] / monomials[jj](UU,XX,YY) 230 | 231 | # resultant 232 | PR. = PolynomialRing(ZZ) 233 | rr = pol1.resultant(pol2) 234 | 235 | # are these good polynomials? 236 | if rr.is_zero() or rr.monomials() == [1]: 237 | continue 238 | else: 239 | print "found them, using vectors", pol1_idx, "and", pol2_idx 240 | found_polynomials = True 241 | break 242 | if found_polynomials: 243 | break 244 | 245 | if not found_polynomials: 246 | print "no independant vectors could be found. This should very rarely happen..." 247 | return 0, 0 248 | 249 | rr = rr(q, q) 250 | 251 | # solutions 252 | soly = rr.roots() 253 | 254 | if len(soly) == 0: 255 | print "Your prediction (delta) is too small" 256 | return 0, 0 257 | 258 | soly = soly[0][0] 259 | ss = pol1(q, soly) 260 | solx = ss.roots()[0][0] 261 | 262 | # 263 | return solx, soly 264 | 265 | def example(): 266 | ############################################ 267 | # How To Use This Script 268 | ########################################## 269 | 270 | # 271 | # The problem to solve (edit the following values) 272 | # 273 | 274 | # the modulus 275 | N = 0xbadd260d14ea665b62e7d2e634f20a6382ac369cd44017305b69cf3a2694667ee651acded7085e0757d169b090f29f3f86fec255746674ffa8a6a3e1c9e1861003eb39f82cf74d84cc18e345f60865f998b33fc182a1a4ffa71f5ae48a1b5cb4c5f154b0997dc9b001e441815ce59c6c825f064fdca678858758dc2cebbc4d27L 276 | # the public exponent 277 | e = 0x11722b54dd6f3ad9ce81da6f6ecb0acaf2cbc3885841d08b32abc0672d1a7293f9856db8f9407dc05f6f373a2d9246752a7cc7b1b6923f1827adfaeefc811e6e5989cce9f00897cfc1fc57987cce4862b5343bc8e91ddf2bd9e23aea9316a69f28f407cfe324d546a7dde13eb0bd052f694aefe8ec0f5298800277dbab4a33bbL 278 | # the cipher 279 | c = 0xe3505f41ec936cf6bd8ae344bfec85746dc7d87a5943b3a7136482dd7b980f68f52c887585d1c7ca099310c4da2f70d4d5345d3641428797030177da6cc0d41e7b28d0abce694157c611697df8d0add3d900c00f778ac3428f341f47ecc4d868c6c5de0724b0c3403296d84f26736aa66f7905d498fa1862ca59e97f8f866cL 280 | # N = 12238605063252292170613110607692779326628090745751955692266649177882959231822580682548279800443278979485092243645806337103841086023159482786712759291169541633901936290854044069486201989034158882661270017305064348254800318759062921744741432214818915527537124001063995865927527037625277330117588414586505635959411443039463168463608235165929831344586283875119363703480280602514451713723663297066810128769907278246434745483846869482536367912810637275405943566734099622063142293421936734750356828712268385319217225803602442033960930413469179550331907541244416573641309943913383658451409219852933526106735587605884499707827 281 | # e = 11850552481503020257392808424743510851763548184936536180317707155841959788151862976445957810691568475609821000653594584717037528429828330763571556164988619635320288125983463358648887090031957900011546300841211712664477474767941406651977784177969001025954167441377912326806132232375497798238928464025466905201977180541053129691501120197010080001677260814313906843670652972019631997467352264392296894192998971542816081534808106792758008676039929763345402657578681818891775091140555977382868531202964486261123748663752490909455324860302967636149379567988941803701512680099398021640317868259975961261408500449965277690517 282 | # c = 9472193174575536616954091686751964873836697237500198884451530469300324470671555310791335185133679697207007374620225900775502162690848135615431624557389304657410880981454777737587420426091879654002644281066474715074536611611252677882396384453641127487515845176069574754606670518031472235144795376526854484442135299818868525539923568705203042265537204111153151119105287648912908771710419648445826883069030285651763726003413418764301988228077415599665616637501056116290476861280240577145515875430665394216054222788697052979429015400411487342877096677666406389711074591330476335174211990429870900468249946600544116793793 283 | 284 | # the hypothesis on the private exponent (the theoretical maximum is 0.292) 285 | delta = .18 # this means that d < N^delta 286 | 287 | # 288 | # Lattice (tweak those values) 289 | # 290 | 291 | # you should tweak this (after a first run), (e.g. increment it until a solution is found) 292 | m = 4 # size of the lattice (bigger the better/slower) 293 | 294 | # you need to be a lattice master to tweak these 295 | t = int((1-2*delta) * m) # optimization from Herrmann and May 296 | X = 2*floor(N^delta) # this _might_ be too much 297 | Y = floor(N^(1/2)) # correct if p, q are ~ same size 298 | 299 | # 300 | # Don't touch anything below 301 | # 302 | 303 | # Problem put in equation 304 | P. = PolynomialRing(ZZ) 305 | A = int((N+1)/2) 306 | pol = 1 + x * (A + y) 307 | 308 | # 309 | # Find the solutions! 310 | # 311 | 312 | # Checking bounds 313 | if debug: 314 | print "=== checking values ===" 315 | print "* delta:", delta 316 | print "* delta < 0.292", delta < 0.292 317 | print "* size of e:", int(log(e)/log(2)) 318 | print "* size of N:", int(log(N)/log(2)) 319 | print "* m:", m, ", t:", t 320 | 321 | # boneh_durfee 322 | if debug: 323 | print "=== running algorithm ===" 324 | start_time = time.time() 325 | 326 | solx, soly = boneh_durfee(pol, e, m, t, X, Y) 327 | 328 | # found a solution? 329 | if solx > 0: 330 | print "=== solution found ===" 331 | if False: 332 | print "x:", solx 333 | print "y:", soly 334 | 335 | d = int(pol(solx, soly) / e) 336 | m = pow(c,d,N) 337 | print '[-]d is ' + str(d) 338 | print '[-]m is: ' + str(m) 339 | print '[-]hex(m) is: ' + '{:x}'.format(int(m)) 340 | print '[-]str(m) is: ' + '{:x}'.format(int(m)).decode('hex') 341 | else: 342 | print "[!]no solution was found!" 343 | print '[!]All Done!' 344 | 345 | if debug: 346 | print("[!]Timer: %s s" % (time.time() - start_time)) 347 | print '[!]All Done!' 348 | 349 | if __name__ == "__main__": 350 | example() -------------------------------------------------------------------------------- /exp6.sage: -------------------------------------------------------------------------------- 1 | ''' 2 | # p = 0x00f23799c031b942026e420769b74d22fa2114428189139c43c366c6ab8367c6b3d6f821449aafb2058b0e6ed964fa0ad45fb306f96376e80823a72b58101919e50acad3b5e6d079e7ff9218ed6df6edbef536742714ce88b2e717f45af53ef0d04c89faf01c80b28e764973aba27726c85c0236e8756a865c03577722bac5e391 3 | # q = 0x00c9d24330fa4945cfe1e5d6912d6bde0231035a1cc8d8ae67d949347b895f8d579bce2adaf37c568957b17a6564dbf80d36d81e4622ab30e02132b0155aefbd3912a27c625a9b7b05bc72217039f5aa88c20cbf9871c3228e9d80d9106f94b11c1f50c40c96862b5cd6b6f781883dd2eff80a059d3ca027af6a03edeb34a7390f 4 | # n = p*q 5 | e = 3 6 | n = 0x4ac5cbf84a2f9a1042c552c77075459d2273994453caea11fbf696b9a8d41937b48be43c71ec6c37470ba9d280a23301b817314a94c786962e4a98ddb260bf2d53a51a6f9c87258110fb2bc9fe8fa44a24e6f95fd5d098bd907d5f8565a0ed7c681cf5e6a79b28438077f6b8d3ae1edf4229102b4ebe29d1f37b9357d3ffff39 7 | p = 0x80f7a73798f638d10180223d7b482035b69b51ffe09ad9e42602cc9d489837be7d1ac92e90b09837144c1220ed4ff0ea00000000000000000000000000000000 8 | beta = 0.5 9 | epsilon = beta^2/7 10 | 11 | pbits = p.nbits() 12 | kbits = floor(n.nbits()*(beta^2-epsilon)) 13 | pbar = p & (2^pbits-2^kbits) 14 | print "upper %d bits (of %d bits) is given" % (pbits-kbits, pbits) 15 | 16 | PR. = PolynomialRing(Zmod(n)) 17 | f = x + pbar 18 | 19 | print 'p_fake =',p 20 | x0 = f.small_roots(X=2^kbits, beta=0.3)[0] # find root < 2^kbits with factor >= n^0.3 21 | print 'p =',x0 + pbar 22 | ''' 23 | 24 | 25 | # next exp 26 | 27 | 28 | n = 0x73cec712124b33c0294e01eb52e8c3cd2fe9ddbcbf457b3b950360063dfae42cbbe9855bd986bcfea0948fadfb252f5e2ff3c982ff47afb6596a496636f1fc5ecfe9f5db7620b23fe9e30d230aa9299ab9a78bfb5e0630fd1149259b2b2104ea65d2e27b89785e4bf01d0594d9f94575cbcc3383f63c5aabe4d5b48eb761cce3ab21689b3f3155b5f15efee240d5ac11cee2acbd019de7c06f607ea618b5cd735b5a6972d2b446a12ff58cf8314822fa5ea09d0963acd00441b2a1b37aca01d7f39052927db98a0bd5ca1c49a7ad67923e3aac30ecd33cc8b4b30a40cdb3acc721ee5da53a02977cee959affe672a668525eb78df96af0a14f4ac04fab68efa8eabe9535e1064a5fc2ff7cac9520210311db0c3bf91101bc55a67a81e4f69364c724ee6ad6bdc301df642c9392e9befa4ff0d65481adb6feac251cd207044587da9710809700246cb3c63e659a97249f5e7418568e37db2fb2c1115e719d6682bb2e89b4e23d40ba4c532f289e10e0b89a5647c486a09b9e376844171b229d74f871004d4945a702a391a04ac704f43809e972891e6ab33b3c0f03f0b6f9ae005b26be6e647a1865c727277423f59a595187ffbfea13501e23b6b57ef115eaa6febcb207a3112628652a39578847241c33989e84607b0f683b30ddf773348b07360b063d9120a397809591ca18a04cd32ad9cbfe0494ed3ae8d2c5b43fdb51cb 29 | p_fake = 25469341510015610710601677541490068882874022771473379147959682877979811860690835905177575433486769235926750944378553837429714908846121392087707617153368450157831411033840331452402635316893579428297241392591768100008774205252294780519995317089863801331600746389471563346749402400584048767782402832414560955794979239140648096754408560344380360521300295416056532504527346890878830708030202503589314586128121926254376071861981570648841288044240102936057199541504839050994656267226010545841307490110261343492485615893311098351703701000220286503350522201318815497988460167971677642567134161349144833221240627311534482202273 30 | pbits = p_fake.nbits() 31 | kbits = 900 32 | #kbits = 200 33 | pbar = p_fake & (2^pbits-2^kbits) 34 | print "upper %d bits (of %d bits) is given" % (pbits-kbits, pbits) 35 | PR. = PolynomialRing(Zmod(n)) 36 | f = x + pbar 37 | x0 = f.small_roots(X=2^kbits, beta=0.4)[0] # find root < 2^kbits with factor >= n^0.3 38 | p= x0 + pbar 39 | print 'p =',p -------------------------------------------------------------------------------- /exp7.sage: -------------------------------------------------------------------------------- 1 | e = 0x3 2 | b = 0xfedcba98765432100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 3 | n = 0x79982a272b9f50b2c2bc8b862ccc617bb39720a6dc1a22dc909bbfd1243cc0a03dd406ec0b1a78fa75ce5234e8c57e0aab492050906364353b06ccd45f90b7818b04be4734eeb8e859ef92a306be105d32108a3165f96664ac1e00bba770f04627da05c3d7513f5882b2807746090cebbf74cd50c0128559a2cc9fa7d88f7b2d 4 | c = 0x381db081852c92d268b49a1b9486d724e4ecf49fc97dc5f20d1fad902b5cdfb49c8cc1e968e36f65ae9af7e8186f15ccdca798786669a3d2c9fe8767a7ae938a4f9115ae8fed4928d95ad550fddd3a9c1497785c9e2279edf43f04601980aa28b3b52afb55e2b34e5b175af25d5b3bd71db88b3b31e48a177a469116d957592c 5 | kbits=64 6 | 7 | PR. = PolynomialRing(Zmod(n)) 8 | f = (x + b)^e-c 9 | x0 = f.small_roots(X=2^kbits, beta=1)[0] 10 | m = b + int(x0) 11 | print '[-]x is ' + hex(int(x0)) 12 | print '[-]m is: ' + str(m) 13 | print '[-]hex(m) is: ' + '{:x}'.format(m) 14 | print '[-]str(m) is: ' + '{:x}'.format(m).decode('hex') 15 | print '[!]All Done!' -------------------------------------------------------------------------------- /exp8.sage: -------------------------------------------------------------------------------- 1 | def partial_p(p0, kbits, n): 2 | PR. = PolynomialRing(Zmod(n)) 3 | nbits = n.nbits() 4 | 5 | f = 2^kbits*x + p0 6 | f = f.monic() 7 | roots = f.small_roots(X=2^(nbits//2-kbits), beta=0.3) # find root < 2^(nbits//2-kbits) with factor >= n^0.3 8 | if roots: 9 | x0 = roots[0] 10 | p = gcd(2^kbits*x0 + p0, n) 11 | return ZZ(p) 12 | 13 | def find_p(d0, kbits, e, n): 14 | X = var('X') 15 | 16 | for k in xrange(1, e+1): 17 | results = solve_mod([e*d0*X - k*X*(n-X+1) + k*n == X], 2^kbits) 18 | for x in results: 19 | p0 = ZZ(x[0]) 20 | p = partial_p(p0, kbits, n) 21 | if p: 22 | return p 23 | 24 | 25 | if __name__ == '__main__': 26 | n = 0xbef498e6eb2cffe71312da47ab89d2c47db7438ea2cfa992ddddbc2a01978001fc51e286e6ebf028396cdb8b3323c60e6b9d50cd84187cf7f48e3875a2f0890f70b02333ad89db2923863ce146562286f63fb0a1d0198e3a6862ba5ac12e85a5c6d0d27cb1c81bdf69cc5bc95b8001a2f744517f9437b4ddd5a076fc0e9a5de1a7a268c40f31aa29e8dc27c0b3a182299ca7a9335b4bd4585452f6107c238e486c98dd73a5f9862e9e80b152f53381c72f897107551c281259ac3ee32c4b4f46cc03127d1bf699acd0266f3c6729253c70da0c69b1560fa172735709866b375b6eba294e1ce8b46fba798ba380080b4bf9603998cac199d9cd46e30ae8da9e7f 27 | e = 3 28 | d = 0x47bb07e1ecca16e51078312e89f0561e31b55db8b0ea5bc87a6ca7464a3d7c28a68c60e2ba88fe6a7d2b300d723e549910a987da89fc0a1c0de197a3d62c501b1f0e819891b1c32a0d6c233f2a285df87bb9e5c6c72d983ff3e706696bba639f573f9c3646968f02f3a615a438e20bb7c38d53621079f2899547a95350f3abeb 29 | beta = 0.5 30 | 31 | 32 | epsilon = beta^2/7 33 | 34 | nbits = n.nbits() 35 | kbits = floor(nbits*(beta^2+epsilon)) 36 | d0 = d & (2^kbits-1) 37 | print "lower %d bits (of %d bits) is given" % (kbits, nbits) 38 | 39 | p = find_p(d0, kbits, e, n) 40 | print "p = %d" % p 41 | q = n//p 42 | print "d0 = %d" % d 43 | print "d = %d" % inverse_mod(e, (p-1)*(q-1)) -------------------------------------------------------------------------------- /exp9.sage: -------------------------------------------------------------------------------- 1 | def short_pad_attack(c1, c2, e, n): 2 | PRxy. = PolynomialRing(Zmod(n)) 3 | PRx. = PolynomialRing(Zmod(n)) 4 | PRZZ. = PolynomialRing(Zmod(n)) 5 | 6 | g1 = x^e - c1 7 | g2 = (x+y)^e - c2 8 | 9 | q1 = g1.change_ring(PRZZ) 10 | q2 = g2.change_ring(PRZZ) 11 | 12 | h = q2.resultant(q1) 13 | h = h.univariate_polynomial() 14 | h = h.change_ring(PRx).subs(y=xn) 15 | h = h.monic() 16 | 17 | kbits = n.nbits()//(2*e*e) 18 | diff = h.small_roots(X=2^kbits, beta=0.5)[0] # find root < 2^kbits with factor >= n^0.5 19 | 20 | return diff 21 | 22 | def related_message_attack(c1, c2, diff, e, n): 23 | PRx. = PolynomialRing(Zmod(n)) 24 | g1 = x^e - c1 25 | g2 = (x+diff)^e - c2 26 | 27 | def gcd(g1, g2): 28 | while g2: 29 | g1, g2 = g2, g1 % g2 30 | return g1.monic() 31 | 32 | return -gcd(g1, g2)[0] 33 | 34 | 35 | if __name__ == '__main__': 36 | n = 0x2030ca024a23fb978752ccc2897947fd9c82b682915771e447fc1eefa6be8cbcc00df7cc2dfc401516b88b06a044b6fa595ce67f7b02f4a441a2a4495fb05463da88b059f4c1a924b3f6bc1e2a4938be37f5a44dd7a495c6bb264fdae9eda265f5a4c2a5147d84566d8122e25954b94575ec97f4d979fff756f95cbfcc49fcc9 37 | e = 3 38 | 39 | #nbits = n.nbits() 40 | #kbits = nbits//(2*e*e) 41 | #print "upper %d bits (of %d bits) is same" % (nbits-kbits, nbits) 42 | 43 | # ^^ = bit-wise XOR 44 | # http://doc.sagemath.org/html/en/faq/faq-usage.html#how-do-i-use-the-bitwise-xor-operator-in-sage 45 | #m1 = randrange(2^nbits) 46 | #m2 = m1 ^^ randrange(2^kbits) 47 | #c1 = pow(m1, e, n) 48 | #c2 = pow(m2, e, n) 49 | c1=0x45204e3e2d780d6fded3ed4c53ca2a0300a78bd7f9b30afb5e3267bcb7074756ab386a165cf0678e3af272151b0635c784df30117f89d92afe83156d55fc8d45f0d9db0b868737cad674e2407fc83e234498542162f86132f2edaed3580b8da605a3d2df4ccd49150aed3686401790e5d0742ef5288d756fd9a011666c4018d 50 | c2=0x1c17423e4aa0ee916c513f9f6f7f7f6efda060974ad06282bd846a50571c2b26465aba50a48eda745b0bb5b410d0b89a199256d5034cb2932a03b0b9dffa065a01c856ff967addc8834e9e09d8d51c020f2a115144e20ac17dd23bb645db39f71eb22aa9175f92bc822c102270f183b1cf60cd6460d6cc28624a9cedbd17484c 51 | 52 | 53 | diff = short_pad_attack(c1, c2, e, n) 54 | print "difference of two messages is %d" % diff 55 | 56 | #print m1 57 | m1 = related_message_attack(c1, c2, diff, e, n) 58 | print 'm1 =',m1 59 | #print m2 60 | print 'm2 =',m1 + diff 61 | print 'diff =',diff -------------------------------------------------------------------------------- /expa.py: -------------------------------------------------------------------------------- 1 | # 已知dp或dq 2 | import gmpy2 3 | e = 65537 4 | n = 9637571466652899741848142654451413405801976834328667418509217149503238513830870985353918314633160277580591819016181785300521866901536670666234046521697590230079161867282389124998093526637796571100147052430445089605759722456767679930869250538932528092292071024877213105462554819256136145385237821098127348787416199401770954567019811050508888349297579329222552491826770225583983899834347983888473219771888063393354348613119521862989609112706536794212028369088219375364362615622092005578099889045473175051574207130932430162265994221914833343534531743589037146933738549770365029230545884239551015472122598634133661853901 5 | dp = 81339405704902517676022188908547543689627829453799865550091494842725439570571310071337729038516525539158092247771184675844795891671744082925462138427070614848951224652874430072917346702280925974595608822751382808802457160317381440319175601623719969138918927272712366710634393379149593082774688540571485214097 6 | c = 5971372776574706905158546698157178098706187597204981662036310534369575915776950962893790809274833462545672702278129839887482283641996814437707885716134279091994238891294614019371247451378504745748882207694219990495603397913371579808848136183106703158532870472345648247817132700604598385677497138485776569096958910782582696229046024695529762572289705021673895852985396416704278321332667281973074372362761992335826576550161390158761314769544548809326036026461123102509831887999493584436939086255411387879202594399181211724444617225689922628790388129032022982596393215038044861544602046137258904612792518629229736324827 7 | 8 | for i in range(1,65538): 9 | if (dp*e-1)%i == 0: 10 | if n%(((dp*e-1)//i)+1)==0: 11 | p=((dp*e-1)//i)+1 12 | q=n//(((dp*e-1)//i)+1) 13 | phi = (p-1)*(q-1) 14 | d = gmpy2.invert(e,phi)%phi 15 | m = gmpy2.powmod(c,d,n) 16 | print ('m:',m) -------------------------------------------------------------------------------- /expb.py: -------------------------------------------------------------------------------- 1 | # Least Significant Bit Oracle Attack 2 | from pwn import * 3 | from string import hexdigits 4 | from hashlib import md5 5 | import gmpy2 6 | import re 7 | import time 8 | 9 | # this example from 2019SUCTF RSA 10 | # e=0x10001 11 | # n=0x0b765daa79117afe1a77da7ff8122872bbcbddb322bb078fe0786dc40c9033fadd639adc48c3f2627fb7cb59bb0658707fe516967464439bdec2d6479fa3745f57c0a5ca255812f0884978b2a8aaeb750e0228cbe28a1e5a63bf0309b32a577eecea66f7610a9a4e720649129e9dc2115db9d4f34dc17f8b0806213c035e22f2c5054ae584b440def00afbccd458d020cae5fd1138be6507bc0b1a10da7e75def484c5fc1fcb13d11be691670cf38b487de9c4bde6c2c689be5adab08b486599b619a0790c0b2d70c9c461346966bcbae53c5007d0146fc520fa6e3106fbfc89905220778870a7119831c17f98628563ca020652d18d72203529a784ca73716db 12 | # c=0x4f377296a19b3a25078d614e1c92ff632d3e3ded772c4445b75e468a9405de05d15c77532964120ae11f8655b68a630607df0568a7439bc694486ae50b5c0c8507e5eecdea4654eeff3e75fb8396e505a36b0af40bd5011990663a7655b91c9e6ed2d770525e4698dec9455db17db38fa4b99b53438b9e09000187949327980ca903d0eef114afc42b771657ea5458a4cb399212e943d139b7ceb6d5721f546b75cd53d65e025f4df7eb8637152ecbb6725962c7f66b714556d754f41555c691a34a798515f1e2a69c129047cb29a9eef466c206a7f4dbc2cea1a46a39ad3349a7db56c1c997dc181b1afcb76fa1bbbf118a4ab5c515e274ab2250dba1872be0 13 | # upper=n 14 | # lower=0 15 | # k=1 16 | io=remote('47.111.59.243',9421) 17 | t = time.clock() 18 | line = io.recvline() 19 | for i in range(3): 20 | l = io.recvuntil('Please input your option:',drop =True ) 21 | pattern = re.compile(r'(?<=n = )\d+\.?\d*') 22 | print(l) 23 | n = int(pattern.findall(l)[0]) 24 | pattern = re.compile(r'(?<=e = )\d+\.?\d*') 25 | e = int(pattern.findall(l)[0]) 26 | pattern = re.compile(r'(?<=c = )\d+\.?\d*') 27 | c = int(pattern.findall(l)[0]) 28 | u = n 29 | l = 0 30 | d = gmpy2.powmod(2,e,n) 31 | m = c 32 | i = 0 33 | while u - l > 1: 34 | m = (m*d)%n 35 | io.sendline('D') 36 | io.send(str(m)+'\n') 37 | res = io.recvuntil('!',drop = True) 38 | if 'even' in res: 39 | u = (u+l)/2 40 | else: 41 | l = (u+l)/2 42 | 43 | ans = 0 44 | for i in range(-1024,1025): 45 | m = u + i 46 | if pow(m,e,n) == c: 47 | ans = m 48 | break 49 | io.sendline('G') 50 | io.send((str(ans)).strip('L')+'\n') 51 | res = io.recvuntil('!',drop = True) 52 | res = io.recvline() 53 | print(res) 54 | res = io.recvline() 55 | print(res) 56 | print('bye') 57 | print('[!]Timer:',round((time.clock()-t),2),'s') 58 | io.close() 59 | --------------------------------------------------------------------------------