python判断素数的方法简书_深入浅出RSA在CTF中的攻击套路

0x01 前言

本文对RSA中常用的模逆运算、欧几里得、拓展欧几里得、中国剩余定理等算法不展开作详细介绍,仅对遇到的CTF题的攻击方式,以及使用到的这些算法的python实现进行介绍。目的是让大家能轻松解决RSA在CTF中的套路题目。

0x02 RSA介绍

介绍

首先,我这边就不放冗长的百度百科的东西了,我概括一下我自己对RSA的看法。

RSA是一种算法,并且广泛应用于现代,用于保密通信。

RSA算法涉及三个参数,n,e,d,其中分为私钥和公钥,私钥是n,d,公钥是n,e

n是两个素数的乘积,一般这两个素数在RSA中用字母p,q表示

e是一个素数

d是e模 varphi(n) 的逆元,CTF的角度看就是,d是由e,p,q可以求解出的

一般CTF就是把我们想要获得的flag作为明文,RSA中表示为m。然后通过RSA加密,得到密文,RSA中表示为C。

加密过程

c=m^e mod n

c=pow(m,e,n)

解密过程

m=c^d mod n

m=pow(c,d,n)

求解私钥d

d = gmpy2.invert(e, (p-1)*(q-1))

一般来说,n,e是公开的,但是由于n一般是两个大素数的乘积,所以我们很难求解出d,所以RSA加密就是利用现代无法快速实现大素数的分解,所存在的一种安全的非对称加密。

基础RSA加密脚本

from Crypto.Util.number import *

import gmpy2

msg = 'flag is :testflag'

hex_msg=int(msg.encode("hex"),16)

print(hex_msg)

p=getPrime(100)

q=getPrime(100)

n=p*q

e=0x10001

phi=(p-1)*(q-1)

d=gmpy2.invert(e,phi)

print("d=",hex(d))

c=pow(hex_msg,e,n)

print("e=",hex(e))

print("n=",hex(n))

print("c=",hex(c))

基础RSA解密脚本

#!/usr/bin/env python

# -*- coding:utf-8 -*-

import binascii

import gmpy2

n=0x80b32f2ce68da974f25310a23144977d76732fa78fa29fdcbf

#这边我用yafu分解了n

p=780900790334269659443297956843

q=1034526559407993507734818408829

e=0x10001

c=0x534280240c65bb1104ce3000bc8181363806e7173418d15762

phi=(p-1)*(q-1)

d=gmpy2.invert(e,phi)

m=pow(c,d,n)

print(hex(m))

print(binascii.unhexlify(hex(m)[2:].strip("L")))

0x03 p和q相差过大或过小

利用条件

因为n=p*q

其中若p和q的值相差较小,或者较大,都会造成n更容易分解的结果

例如出题如下

p=getPrime(512)

q=gmpy2.next_prime(p)

n=p*q

因为p和q十分接近,所以可以使用yafu直接分解

yafu分解

使用

factor(*)

括号中为要分解的数

0305f01b7d2a15c20257203075bee409.png

在线网站分解

http://factordb.com/

通过在此类网站上查询n,如果可以分解或者之前分解成功过,那么可以直接得到p和q

df98529960bd648477888cf11ed81287.png

0x04 公约数分解n

利用条件

当题目给的多对公钥n是公用了一个素数因子的时候,可以尝试公约数分解

出题一般如下

p1=getPrime(512)

p2=getPrime(512)

q=getPrime(512)

n1=p1*q

n2=p2*q

所以当题目给了多个n,并且发现n无法分解,可以尝试是否有公约数。

欧几里得辗转相除法

求公约数可以使用欧几里得辗转相除法,实现python脚本如下

def gcd(a, b): #求最大公约数

if a < b:

a, b = b, a

while b != 0:

temp = a % b

a = b

b = temp

return a

用例

def gcd(a, b): #求最大公约数

if a < b:

a, b = b, a

while b != 0:

temp = a % b

a = b

b = temp

return a

n1=0x6c9fb4bf11344e4c818be178e3d3db352797099f929e4ba8fa86d9c4ce3d8f71e3daa8c795b67dc2dabe1e1608836904386c364ecec759c27eaa83eb93710003d4cc848e558f7b11372405c5787b60eca627372767455a5fcf30cb6c157ca5a6267d63ffa16fe49e7433136a47945de2219f46a35f2b6a58196057c602e72a0b

n2=0x46733cc071bdee0d178fb32836a6b0a2f145a681df47d31ea9d9fc5b5fa0cc7ddbcd34531aefeace9840fc890f7a111f73593c9a41886b9a6f91cde3e6f9c71821a8ad877de51f78094599209746e80635c5625459ad7ba14f926b74875c8980a9436d6bbd54e1d9da72ae200383516098c04e24f58b23b4a8142cef0c931a55

print(gcd(n1,n2))

使用欧几里得辗转相除得到共有的因子,然后n1和n2除以这个因子,即可得到另一个素数因子。

0x05 模数分解

场景

已知e,d,n求p,q

例如

('d=', '0x455e1c421b78f536ec24e4a797b5be78df09d8d9e3b7f4e2244138a7583e810adf6ad056bb59a91300c9ead5ed77ea6bafdebf7ab2d9ec200127901083c7ffca45e83f2c934358366a2b6207b96a0eae6df0476060c063c281512834a42350a3b56bc09f5cec1a6975257d7f12a58f6389060e49b41f05e88ea2b30b395f6391')

('e=', '0x10001')

('n=', '0x71ee0f4883690893ab503e97e25e6308d4c1e0a050cbea7b9c040f7a5b5b484afcecc8a9b3cc6bf089a1e83281562df217caab7220e3dfc14399139ce437af2f131f9345675e4d848cfab5827818eeab7834374be4a0513f81f3df125a932c2bb4c24c834d798bcc80f9c4a8770b01f8e54620b72a4f0491edd391e635d48e71L')

模数分解

私钥d的获取是通过

d = gmpy2.invert(e, (p-1)*(q-1))

分解p,q python实现如下

import random

def gcd(a, b):

if a < b:

a, b = b, a

while b != 0:

temp = a % b

a = b

b = temp

return a

def getpq(n,e,d):

p = 1

q = 1

while p==1 and q==1:

k = d * e - 1

g = random.randint ( 0 , n )

while p==1 and q==1 and k % 2 == 0:

k /= 2

y = pow(g,k,n)

if y!=1 and gcd(y-1,n)>1:

p = gcd(y-1,n)

q = n/p

return p,q

完整用例

import random

def gcd(a, b):

if a < b:

a, b = b, a

while b != 0:

temp = a % b

a = b

b = temp

return a

def getpq(n,e,d):

p = 1

q = 1

while p==1 and q==1:

k = d * e - 1

g = random.randint ( 0 , n )

while p==1 and q==1 and k % 2 == 0:

k /= 2

y = pow(g,k,n)

if y!=1 and gcd(y-1,n)>1:

p = gcd(y-1,n)

q = n/p

return p,q

n=0x71ee0f4883690893ab503e97e25e6308d4c1e0a050cbea7b9c040f7a5b5b484afcecc8a9b3cc6bf089a1e83281562df217caab7220e3dfc14399139ce437af2f131f9345675e4d848cfab5827818eeab7834374be4a0513f81f3df125a932c2bb4c24c834d798bcc80f9c4a8770b01f8e54620b72a4f0491edd391e635d48e71

e=0x10001

d=0x455e1c421b78f536ec24e4a797b5be78df09d8d9e3b7f4e2244138a7583e810adf6ad056bb59a91300c9ead5ed77ea6bafdebf7ab2d9ec200127901083c7ffca45e83f2c934358366a2b6207b96a0eae6df0476060c063c281512834a42350a3b56bc09f5cec1a6975257d7f12a58f6389060e49b41f05e88ea2b30b395f6391

p,q=getpq(n,e,d)

print("p=",p)

print("q=",q)

print(p*q==n)

0x06 dp&dq泄露

介绍

首先了解一下什么是dp、dq

dp=d%(p-1)

dq=d%(q-1)

这种参数是为了让解密的时候更快速产生的

场景

假设题目仅给出p,q,dp,dq,c,即不给公钥e

('p=', '0xf85d730bbf09033a75379e58a8465f8048b8516f8105ce2879ce774241305b6eb4ea506b61eb7e376d4fcd425c76e80cb748ebfaf3a852b5cf3119f028cc5971L')

('q=', '0xc1f34b4f826f91c5d68c5751c9af830bc770467a68699991be6e847c29c13170110ccd5e855710950abab2694b6ac730141152758acbeca0c5a51889cbe84d57L')

('dp=', '0xf7b885a246a59fa1b3fe88a2971cb1ee8b19c4a7f9c1a791b9845471320220803854a967a1a03820e297c0fc1aabc2e1c40228d50228766ebebc93c97577f511')

('dq=', '0x865fe807b8595067ff93d053cc269be6a75134a34e800b741cba39744501a31cffd31cdea6078267a0bd652aeaa39a49c73d9121fafdfa7e1131a764a12fdb95')

('c=', '0xae05e0c34e2ba4ca3536987cc2cfc3f1f7f53190164d0ac50b44832f0e7224c6fdeebd2c91e3991e7d179c26b1b997295dc9724925ba431f527fba212703a0d14a34ce133661ae0b6001ee326303d6ccdc27dbd94e0987fae25a84f197c1535bdac9094bfb3846b7ca696b2e5082bea7bff804da275772ca05dd51b185a4fc30L')

解密代码如下

InvQ=gmpy2.invert(q,p)

mp=pow(c,dp,p)

mq=pow(c,dq,q)

m=(((mp-mq)*InvQ)%p)*q+mq

print '{:x}'.format(m).decode('hex')

解题完整脚本

import gmpy2

import binascii

def decrypt(dp,dq,p,q,c):

InvQ = gmpy2.invert(q,p)

mp = pow(c,dp,p)

mq = pow(c,dq,q)

m=(((mp-mq)*InvQ)%p)*q+mq

print (binascii.unhexlify(hex(m)[2:]))

p=0xf85d730bbf09033

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值