EIGamal算法
什么是EIGamal算法
ElGamal公钥密码算法是1985年由塔希尔·盖莫尔提出,是一个基于迪菲-赫尔曼密钥交换的非对称加密算法,是在密码协议中有着重要应用的一类公钥密码算法,其安全性是基于有限域上离散对数学问题的难解性。它至今仍是一个安全性良好的公钥密码算法,是一种既可用于加密又可用于数字签名的公钥密码算法。
数学基础
有限域:对于素数p,整数集合(0,1,2,…,p-1),在mod p意义下,关于求四则代数运算(”+”,”*”)构成域,当域的元素数目有限时称为有限域。
阶:有限域中元素的个数。如,模19下7的阶为3(7^1≡7mod 19,7^2≡11 mod 19,7^3≡1 mod 19,7^4≡7 mod 19)
本原元:设p为素数,若存在一个正整数g使得g1,g2,…,g^p-1,关于模p互不同余(模p下g的阶=φ§),则g为模p的本原元(又称为原根)。
离散对数:离散对数:是一种基于同余运算和原根的一种对数运算。如果对于一个整数b和质数p的一个原根a,可以找到一个唯一的指数i,使得
b
≡
a
i
(
mod
p
)
,
0
≤
i
≤
p
−
1
b \equiv a^i(\text{mod}p),0 ≤i≤p-1
b≡ai(modp),0≤i≤p−1成立,那么指数i称为b以a为基数的模p的离散对数。离散对数在一些特殊情况下可以快速计算。然而,在一般情况下,还没有有效的方法来计算它们。离散对数难题是指:当已知一个大质数p和它的一个原根a,如果给定一个b,要计算i的值是相当困难的。ElGamal算法的安全性就是基于有限域上离散对数问题的难解性。
1、参数定义和密钥生成
取大素数 p ,要求p-1有大素数因子,再选择一个模p的本原元g;
随机选取一整数 x (2 <= x <= (p - 2),
计算 y = g^x (mod p)
(p,g,x) 是私钥、((p,g,y) 是公钥
2、加、解密
加密M:
- 假定:用户A发送明文M给用户B,A加密明文M得到密文C;
- A将M编码为一个在0到p-1之间的整数m作为传输的明文;
- 随机选取一整数 r (2 <= r<= (p - 2) 且 k 与 (p - 1) 互素);
- 计算 c1= g^r mod p,c2 = m*y^r mod p(y为用户B的公钥);
- 得到密文 C = (c1, c2);
- 用户A把密文C传给用户B;
解密C:
- 用户B接受到密文,计算明文m;
- m = c2 * c1^(-x) mod p ;(x为用户B的私钥)
- c2 * c1^(-x) mod p Ξ m * y^r * g^(-xr) Ξ m * g^(xr) * g^(-xr) Ξ m
ez_Math
from Crypto.Util.number import *
from secret import flag
m1, m2 = bytes_to_long(flag[:len(flag)//2]), bytes_to_long(flag[len(flag)//2:])
p, q, r, s = [getStrongPrime(512) for _ in range(4)]
e = 0x10001
n = p * q * r * s
x = pow(q + r, p, n)
y = pow(p * q + r, p, n)
z = pow(s + 1, m1, s ** 3)
c = pow(m2, e * (s - 1), n)
print(f'{n = }')
print(f'{x = }')
print(f'{y = }')
print(f'{z = }')
print(f'{c = }')
# n = 16063619267258988011034805988633616492558472337115259037200126862563048933118401979462064790962157697989038876156970157178132518189429914950166878537819575544418107719419007799951815657212334175336430766777427972314839713871744747439745897638084891777417411340564312381163685003204182743581513722530953822420925665928135283753941119399766754107671729392716849464530701015719632309411962242638805053491529098780122555818774774959577492378249768503656934696409965037843388835948033129997732058133842695370074265039977902884020467413323500218577769082193651281154702147769044514475692164145099161948955990463002411473013
# x = 3021730035236300354492366560252387204933590210661279960796549263827016146230329262559940840168033978439210301546282150367717272453598367244078695402717500358042032604007007155898199149948267938948641512214616076878271433754986480186150178487625316601499002827958344941689933374158456614113935145081427421623647242719093642478556263121508238995676370877385638074444859047640771188280945186355013165130171802867101829647797879344213688981448535289683363612035513789240264618036062440178755665951650666056478493289870170026121826588708849844053588998886259091357236645819074078054595561158630194224419831088510266212458
# y = 8995787142441643101775260550632842535051686960331455373408888374295557050896156890779515089927839904014859222004906681231525326673182671984194300730575609496770604394218160422560576866112460837985407931067753009696969997384839637927957848613356269534870170452152926447601781637641134982178028922559652443398183848786034348994249923007092159192374765197460466878587635412657807328348343062302127490267456095927890461140420639805398464266081441243108883599713672104446500850203779995739675784794478089863001309614674686652597236324659979849324914804032046113978246674538411441434320732570934185579553749616238819583998
# z = 1283646988194723153191718393109711130382429329041718186548715246082834666179475883560020086589684603980734305610989683434078096863563033623169666389076830792095374856743015929373461198718962686411467443788047511292138922700655772772117855226419561159782734009961921473456332468653898105909729309377890721920937410781006337057478451806364879679045839945032594716202888196404203782734864187890231653321470085251
# c = 4988583141177813116287729619098477713529507701428689219486720439476625736884177254107631282807612305211904876847916760967188201601494592359879509876201418493870112712105543214178376471651715703062382025712952561985261461883133695993952914519494709871429166239968478488380137336776740647671348901626710334330855078254188539448122493675463406596681080368929986034772169421577420193671300532508625180845417164660544286332963072804192276425664877337357353975758574262657585309762422727680851018467657523970318042829660721433987195369353660020476598195375492128671951807024027929490113371463210453342974983253996717176870
因为
x
≡
y
≡
r
p
mod
q
x\equiv y \equiv r^p \text{mod} q
x≡y≡rpmodq,所以kq = x-y,q =
gcd
\text{gcd}
gcd(kq,n)
然后
x
≡
q
+
r
mod
p
x\equiv q+r\text{mod} p
x≡q+rmodp,我直接把
y
≡
r
mod
p
y \equiv r \text{mod}p
y≡rmodp,然后kp = y-x+q,gcd(kp,n)算出来数据太大,不对,就一直卡在这了。
然后看wp才知道,可以
y
≡
p
q
+
r
mod
p
y \equiv pq +r\text{mod} p
y≡pq+rmodp,
y
−
x
+
q
≡
p
q
mod
p
y - x + q \equiv pq \text{mod}p
y−x+q≡pqmodp,pq = gcd(y-x+q,n),p = pq /q
然后根据别人的思路算出来了
import gmpy2
from Crypto.Util.number import *
e = 0x10001
n = 16063619267258988011034805988633616492558472337115259037200126862563048933118401979462064790962157697989038876156970157178132518189429914950166878537819575544418107719419007799951815657212334175336430766777427972314839713871744747439745897638084891777417411340564312381163685003204182743581513722530953822420925665928135283753941119399766754107671729392716849464530701015719632309411962242638805053491529098780122555818774774959577492378249768503656934696409965037843388835948033129997732058133842695370074265039977902884020467413323500218577769082193651281154702147769044514475692164145099161948955990463002411473013
x = 3021730035236300354492366560252387204933590210661279960796549263827016146230329262559940840168033978439210301546282150367717272453598367244078695402717500358042032604007007155898199149948267938948641512214616076878271433754986480186150178487625316601499002827958344941689933374158456614113935145081427421623647242719093642478556263121508238995676370877385638074444859047640771188280945186355013165130171802867101829647797879344213688981448535289683363612035513789240264618036062440178755665951650666056478493289870170026121826588708849844053588998886259091357236645819074078054595561158630194224419831088510266212458
y = 8995787142441643101775260550632842535051686960331455373408888374295557050896156890779515089927839904014859222004906681231525326673182671984194300730575609496770604394218160422560576866112460837985407931067753009696969997384839637927957848613356269534870170452152926447601781637641134982178028922559652443398183848786034348994249923007092159192374765197460466878587635412657807328348343062302127490267456095927890461140420639805398464266081441243108883599713672104446500850203779995739675784794478089863001309614674686652597236324659979849324914804032046113978246674538411441434320732570934185579553749616238819583998
z = 1283646988194723153191718393109711130382429329041718186548715246082834666179475883560020086589684603980734305610989683434078096863563033623169666389076830792095374856743015929373461198718962686411467443788047511292138922700655772772117855226419561159782734009961921473456332468653898105909729309377890721920937410781006337057478451806364879679045839945032594716202888196404203782734864187890231653321470085251
c = 4988583141177813116287729619098477713529507701428689219486720439476625736884177254107631282807612305211904876847916760967188201601494592359879509876201418493870112712105543214178376471651715703062382025712952561985261461883133695993952914519494709871429166239968478488380137336776740647671348901626710334330855078254188539448122493675463406596681080368929986034772169421577420193671300532508625180845417164660544286332963072804192276425664877337357353975758574262657585309762422727680851018467657523970318042829660721433987195369353660020476598195375492128671951807024027929490113371463210453342974983253996717176870
kq = y - x
q = gmpy2.gcd(kq,n)
# print(q)
pq = gmpy2.gcd(kq + q,n)
p = pq // q
# print(p)
r = (x - q)%p
# print(r)
s = n // p // q // r
# print(s)
z %= s * s;
# print(z)
# print(p * q * r * s)
m1 = (z - 1) // s
#print(m1)
phi = (p - 1) * (q - 1)
d = gmpy2.invert(e * ( s - 1) // 4, phi)
mm = pow(c % (p * q), d, p * q)
m2, _ = gmpy2.iroot(mm,4)
print(long_to_bytes(m1),long_to_bytes(m2))
b'nkctf{cb5b7392-cca4-4' b'ce2-87e7-930cf6b29959}'