数论基础

素数

1.定义: 一个大于1的自然数,除了1和它本身外,不能被其他自然数整除(除0以外)的数称之为素数(质数);否则称为合数。

如:3×4 = 12,不是素数。11除了等于11×1以外,不能表示为其它任何两个整数的乘积,所以11是一个素数。

2.关于素数的事实:

(1)如果p是素数,且p | ab(表示ab能被p整除),则p | a或 p | b ,即p 至少整除a与b中的一个。

(2)算术基本定理:任何一个大于1的自然数 ,如果N不为质数,都可以唯一分解成有限个质数的乘积,即

(3)素数有无穷多个。

最大公约数与最小公倍数

1.最大公约数

定义:几个数公有的约数,叫做这几个数的公约数,其中最大的一个叫做这几个数的最大公约数。数学上,a和b的最大公约数记为(a, b),编程中,计算两个数最大公约数的方法通常记为gcd(a,b)

2.最小公倍数

定义:几个数公有的倍数,叫做这几个数的公倍数,其中最小的一个叫做这几个数的最小公倍数。数学上,a和b的最小公倍数记为[a,b],编程中,计算两个数最小公倍数的方法通常记为lcm(a,b)

欧拉函数

1.定义: 在数论中,对正整数n,欧拉函数φ(n)是小于或等于n的正整数中与n互质的数的数目。此函数以其首名研究者欧拉命名,它又称为φ函数(由高斯所命名)或是欧拉总计函数。例如:φ(8) = 4 ,因为1,3,5,7均与8互质。

2.性质:

欧拉函数是积性函数——若m,n互质,φ(mn)=φ(m)φ(n)

特殊性质:当n为奇数时,φ(2n)=φ(n)

欧几里得(Euclid)算法

1.定义: 欧几里得算法又称为辗转相除法,用于求两个数的最大公约数。基于如下原理:两个整数的最大公约数等于其中较小的数和两数相除余数的最大公约数,即GCD(x,y) = GCD(y,x mod y) ,x>y。

2.代码实现:

def GCD(x, y):|
	if(y==0):
		return x
  	else:
  		return GCD(y,x %y)
from gmpy2 import*
m = gcd(a,b)
#from Crypto.Util. number import*
#m = GCD(a, b)

扩展欧几里得算法

1.定理: 扩展欧几里德算法是欧几里得算法的扩展。若a和b为正整数,则存在整数x,y使得gcd(a,b)=ax+by;换句话说gcd(a,b)可以表示为a,b的整洗数线性组合。
例如:gcd(6,14)=2,而2=(-2)* 6+1 *14.

2.代码实现:

from gmpy2 import*
x=17
y = 65537
#扩展欧几里得算法
s = gcdext(x,y)
#返回元组tuple,满足s[1]*x+s[2]*y = 1
print(s)
#输出: (mpz(1), mpz(30841), mpz(-8))
print(s[1]*x+s[2]*y)
#输出: 1

同余

1.定义: 设a,b是整数,n≠0,如果n|(a-b),则称a和b模n同余,记为a≡b(mod n),整数n称为模数。由于n|(a-b) 等价于 -n|(a-b),所以a≡b(mod n) 与 a≡b(mod (-n))等价。因此,一般我们总假定模数n≥1。

2.性质1:

(1)自反性:a ≡ a (mod m)

(2)对称性:a ≡ b (mod m),↔b ≡ c (mod m) ↔a ≡ c (mod m)

(3)保持基本运算:

模运算

1.定义: a模n的运算给出了a对模n的余数,这种运算称为模运算。注意:模运算的结果是从0到n-1的一个整数。

2.性质: 模运算就像普通的运算一样,它是可交换、可结合、可分配的。而且,对每一个中间结果进行模m运算后再进行模m运算,其作用与先进行全部运算,然后再进行模m运算所得到的结果是一样的。

(a+b)mod m=((a mod m)+(b mod m)) mod m

(a-b)mod m=((a mod m)-(b mod m)) mod m

(a×b)mod m=((a mod m) ×(b mod m)) mod m

(a×(b+c))mod m=((a×b) mod m+(a×c) mod m) mod m

3.用途:

(1)用于判断一个数是否能被另一个数整除。对 2 取模即可判断整数的奇偶性;从 2 到 n-1 取模则可判断一个数是否为质数。
(2)进制之间的转换。
(3)用于求取最大公约数的辗转相除法使用取模运算。
(4)密码学中的应用:从古老的凯撒密码到现代常用的RSA、椭圆曲线密码,它们的实现过程均使用了取模运算。

模逆元

1.定义: 模逆元也称为模倒数,或者模逆元。

一整数a对同余n之模逆元是指满足以下公式的整数 b

2.求解方法:

(1)扩展欧几里得算法:设exgcd(a,n)为扩展欧几里得算法的函数,则可得到ax+ny=g,g是a,n的最大公因数。若g=1,则该模逆元存在;若g≠1,则该模逆元不存在。

(2)欧拉定理:欧拉定理证明当a,n为两个互素的正整数时,则有aφ(n)≡1(modn),φ(n)为欧拉函数,其中 aφ(n)-1即为a关于模n之模逆元

中国剩余定理

中国剩余定理给出了以下的一元线性同余方程组有解的判定条件,并用构造法给出了在有解情况下解的具体形式。

中国剩余定理说明:假设整数m1, m2, … , mn其中任两数互质,则对任意的整数:a1, a2, … , an,上述一元线性同余方程组有解,并且通解可以用如下方式构造得到:

RSA算法

RSA算法简介

RSA攻击方法

思维导图

常见题型

1.模数分解

题目链接(buu平台)

from flag import FLAG
from Cryptodome.Util.number import *
import gmpy2
import random

e=65537
p = getPrime(512)
q = int(gmpy2.next_prime(p))
n = p*q
m = bytes_to_long(FLAG)
c = pow(m,e,n)
print(n)
print(c)
# n=177606504836499246970959030226871608885969321778211051080524634084516973331441644993898029573612290095853069264036530459253652875586267946877831055147546910227100566496658148381834683037366134553848011903251252726474047661274223137727688689535823533046778793131902143444408735610821167838717488859902242863683
# c=1457390378511382354771000540945361168984775052693073641682375071407490851289703070905749525830483035988737117653971428424612332020925926617395558868160380601912498299922825914229510166957910451841730028919883807634489834128830801407228447221775264711349928156290102782374379406719292116047581560530382210049

题目为最基础的RSA加密,其中p q为相邻的素数。可以用yafu分解

基础RSA解密:

n=177606504836499246970959030226871608885969321778211051080524634084516973331441644993898029573612290095853069264036530459253652875586267946877831055147546910227100566496658148381834683037366134553848011903251252726474047661274223137727688689535823533046778793131902143444408735610821167838717488859902242863683
c=1457390378511382354771000540945361168984775052693073641682375071407490851289703070905749525830483035988737117653971428424612332020925926617395558868160380601912498299922825914229510166957910451841730028919883807634489834128830801407228447221775264711349928156290102782374379406719292116047581560530382210049
e=65537
p = 13326909050357447643526585836833969378078147057723054701432842192988717649385731430095055622303549577233495793715580004801634268505725255565021519817179293
q = 13326909050357447643526585836833969378078147057723054701432842192988717649385731430095055622303549577233495793715580004801634268505725255565021519817179231
from Crypto.Util.number import *
phi=(p-1)*(q-1)
d=inverse(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))
# actf{p_and_q_should_not_be_so_close_in_value}

2.n有相同的质因数

题目链接(buu平台)

题面:一份秘密发送给两个人不太好吧,那我各自加密一次好啦~~~
素数生成好慢呀
偷个懒也……不会有问题的吧?

附件:
public1.pub
public2.pub
flag_encry1
flag_encry2

首先尝试取出两份公钥文件的n,e,测试发现n1 n2有公约数,正好印证了题面给的懒得生成素数,所以共用了其中一个素数。

求解公约数即可:

from Crypto.PublicKey import RSA
import gmpy2
from Crypto.Util.number import *
f=open("public1.pub","r")
rsa1=RSA.import_key(f.read())
n1=rsa1.n
e1=rsa1.e
f.close()
f=open("public2.pub","r")
rsa2=RSA.import_key(f.read())
n2=rsa2.n
e2=rsa2.e
f.close()
#print(n1,e1)
#print(n2,e2)
p=gmpy2.gcd(n1,n2)
q=n2//p
assert(p*q==n2)
phi=(p-1)*(q-1)
d=gmpy2.invert(e2,phi)
c_bytes=open("flag_encry2","rb").read()
c=bytes_to_long(c_bytes)
m=pow(c,d,n2)
print(long_to_bytes(m))
#afctf{You_Know_0p3u55I}

3.共模攻击

题目链接(BUU平台)

hint.py如下:

from gmpy2 import *
from Crypto.Util.number import *
from secret import hint

m = bytes_to_long(hint)
p = getPrime(256)
c = pow(m, 256, p)
print(p)

p, q = getPrime(256), getPrime(256)
n = p * q
e1, e2 = getPrime(32), getPrime(32)
c1, c2 = pow(c, e1, n), pow(c, e2, n)
print(n)
print(e1, c1)
print(e2, c2)

''' 107316975771284342108362954945096489708900302633734520943905283655283318535709 6807492006219935335233722232024809784434293293172317282814978688931711423939629682224374870233587969960713638310068784415474535033780772766171320461281579 2303413961 1754421169036191391717309256938035960912941109206872374826444526733030696056821731708193270151759843780894750696642659795452787547355043345348714129217723 2622163991 1613454015951555289711148366977297613624544025937559371784736059448454437652633847111272619248126613500028992813732842041018588707201458398726700828844249 '''

task.py如下:

from gmpy2 import *
from Crypto.Util.number import *
from secret import flag

flag = flag.strip(b"npuctf{").strip(b"}")
m = bytes_to_long(flag)

p, q = getPrime(512), getPrime(512)
n = p * q
e1, e2 = p, q
c1, c2 = pow(m, e1, n), pow(m, e2, n)

print(n)
print(c1)
print(c2)

''' 128205304743751985889679351195836799434324346996129753896234917982647254577214018524580290192396070591032007818847697193260130051396080104704981594190602854241936777324431673564677900773992273463534717009587530152480725448774018550562603894883079711995434332008363470321069097619786793617099517770260029108149 96860654235275202217368130195089839608037558388884522737500611121271571335123981588807994043800468529002147570655597610639680977780779494880330669466389788497046710319213376228391138021976388925171307760030058456934898771589435836261317283743951614505136840364638706914424433566782044926111639955612412134198 9566853166416448316408476072940703716510748416699965603380497338943730666656667456274146023583837768495637484138572090891246105018219222267465595710692705776272469703739932909158740030049375350999465338363044226512016686534246611049299981674236577960786526527933966681954486377462298197949323271904405241585 '''

共模攻击,用扩展欧几里得算法求出c。

原理:当GCD(e1, e2) == 1时,由扩展欧几里得算法得,存在s1, s2使 e1s1 + e2s2 = 1,m = pow(m, e1s1 + e2s2, n),而pow(m, e1s1 + e2s2, n) = pow(m, e1s1, n) * pow(m, e2s2, n) = pow(c1, s1, n) * pow(c2, s2, n)

由c和p可以求得m。得到c后,根据表达式:c = m256 mod p,可以借助Python的sympy库nthroot_mod方法,最终由m得到hint:# m =“m.bit_length() < 400”

from gmpy2 import*
from sympy import*
from Crypto.Util.number import *
p = 107316975771284342108362954945096489708900302633734520943905283655283318535709

e1 = 2303413961
c1 = 1754421169036191391717309256938035960912941109206872374826444526733030696056821731708193270151759843780894750696642659795452787547355043345348714129217723

e2 = 2622163991
c2 = 1613454015951555289711148366977297613624544025937559371784736059448454437652633847111272619248126613500028992813732842041018588707201458398726700828844249
n =  6807492006219935335233722232024809784434293293172317282814978688931711423939629682224374870233587969960713638310068784415474535033780772766171320461281579

s = gcdext(e1,e2)
c = pow(c1,s[1],n)*pow(c2,s[2],n) % n
print(c)
#c = 19384002358725759679198917686763310349050988223627625096050800369760484237557

m = nthroot_mod(c,256,p)
print(long_to_bytes(m))

# m ="m.bit_length() < 400"

参考博客
求m:

from Crypto.Util.number import*

n = 128205304743751985889679351195836799434324346996129753896234917982647254577214018524580290192396070591032007818847697193260130051396080104704981594190602854241936777324431673564677900773992273463534717009587530152480725448774018550562603894883079711995434332008363470321069097619786793617099517770260029108149
c1 = 96860654235275202217368130195089839608037558388884522737500611121271571335123981588807994043800468529002147570655597610639680977780779494880330669466389788497046710319213376228391138021976388925171307760030058456934898771589435836261317283743951614505136840364638706914424433566782044926111639955612412134198
c2 = 9566853166416448316408476072940703716510748416699965603380497338943730666656667456274146023583837768495637484138572090891246105018219222267465595710692705776272469703739932909158740030049375350999465338363044226512016686534246611049299981674236577960786526527933966681954486377462298197949323271904405241585

a = c1+c2
b = c1*c2

print(a)
print(b)

# a = 106427507401691650533776606268030543324548306805584488340881108460215302001780649045082140067384306297497785054794169701530927082798998717147796265177082494273319180022953309137549878052025764276170773098393102683446915458123682447310617265418188192465923366892572673596378919944244343124060963227516817375783
# b = 926651656671911333597022401968870409343942400492881255142377951759176631494915016941991504123810265329862246592861145719213675502795378053564904818765377025096483601036025012267103260702787555612216755188521913405305861451125814149409508425602231670292131422273268728629782633354498648021859614223672123489318899205627785426402597996319440198218774038390809403281952702730883306007226797632389267386912707857093556335846269954270572920361347019614365402744026533713442449916555425678184406380167614011131702418493073759816310890056281917310110034453007210415242707924141697749818907383248545179118594511927630223830

flag = 4242839043019782000788118887372132807371568279472499477998758466224002905442227156537788110520335652385855
print(long_to_bytes(flag))
# verrrrrrry_345yyyyyyy_rsaaaaaaa_righttttttt?

本文地址:https://blog.csdn.net/m0_46591654/article/details/111088874