如何解决在Python中实施窃贼法SETUP攻击
我的任务是复制下面的图:
它来自this journal(第137-145页)
在this article中,作者描述了一种称为SETUP的针对Diffie-Hellman密钥交换的窃贼攻击。他们特别编写了以下算法:
现在,在2中,作者认为“也许我们可以实现诚实的DHKE和恶意的DHKE,然后我们比较这两种算法的运行时间”。然后,创建了上面的图。为此,他们说
“我们已经在ANSI C中实现了Diffie-Hellman协议的受污染版本和未受污染版本,并使用GNU C v 2.7编译器与RSAREF 2.0库链接。所有测试均在Linux系统上使用带有Pentium II处理器(350 MHz)的计算机运行)和64 Mb内存。单个协议的计算时间为10-2s。“
我想做同样的事情,即实施好与坏的DH并比较运行时间。这是我生成的代码:
import timeit #used to measure the running time of functions
import matplotlib.pyplot as plt #plot the results
import random
import numpy as np
import pyDH #library for Diffie-Hellman key exchange
X= pyDH.DiffieHellman() #Eve's private key
Y= X.gen_public_key() #Eve's public key
#The three integers a,b,W embedded by Eve
W=3
a=2
b=2
#Honest DH
def public_key():
d1 = pyDH.DiffieHellman()
return d1.gen_public_key()
#Malicoius Diffie_Hellman (SETUP) #line 1-7 in the algorithm
def mal_public_key():
d1 = pyDH.DiffieHellman().get_private_key()
t=random.choice([0,1])
z1=pow(pyDH.DiffieHellman().g,d1-W*t,pyDH.DiffieHellman().p)
z2=pow(Y,-a*d1-b,pyDH.DiffieHellman().p)
z= z1*z2 % pyDH.DiffieHellman().p
d2=hash(z)
return pow(pyDH.DiffieHellman().g,d2,pyDH.DiffieHellman().p)
#function that plot the results
def plot(ntest=100000):
times = []
times2=[]
for i in range(ntest):
#Running time HOnesT Diffie-Hellman (worked two times = two key generations)
elapse_time = timeit.timeit(public_key,number=2)
#here I collect the times
times += [int(round(elapse_time* pow(10,2) ) )]
# Running time MALICOIUS Diffie-Hellman
elapse_time2 = timeit.timeit(mal_public_key,number= 1)
times2 += [int(round(elapse_time2* pow(10,2)) )]
x_axis=[i for i in range(0,20)]
#collect how many tests last i seconds
y_axis = [times.count(i) for i in x_axis]
y_axis2 = [times2.count(i) for i in x_axis]
plt.plot(x_axis,y_axis,x_axis,y_axis2)
plt.show()
plot()
我曾经用pyDH代表诚实的Diffie-Hellman。这段代码给了我这个数字:
我认为蓝线(诚实的DH)还可以,但是我对与该功能链接的橙线(SETUP DH)有些怀疑:
def mal_public_key(): #line 1-7 in the algorithm
d1 = pyDH.DiffieHellman().get_private_key()
t=random.choice([0,pyDH.DiffieHellman().p)
z= z1*z2 % pyDH.DiffieHellman().p
d2 = hash(z)
return pow(pyDH.DiffieHellman().g,pyDH.DiffieHellman().p)
“有趣的是,代表受污染实施的曲线 在相同的计算时间值处有一个小的峰值,其中正确的实现 有其唯一的高峰。 [...]有两种不同 每秒调用一次设备时发生的部分。第一个与原始相同 协议,而这部分正是在这个小峰上提出的。不相称 代表受污染执行的曲线的两个峰之间 清晰可见。原因是在第一部分之后进行实际使用 协议(即第1-3行)设备不会重复第二部分(即第4-7行) 但很多次。”
您能向我解释这个说法吗?特别是为什么我的地块上没有橙色的小峰?也许mal_public_key()
功能不好。
我正在使用Windows10 64位,8Gb RAM,AMD A10-8700P radeon R6、10个计算核心4C + 6G 1.80GHz,其中使用Python 3.8。我知道我的计算机应该比作者的计算机更好(我认为)。也许这会影响结果。但是,here显示了一个类似的椭圆曲线实验,该图接近原始曲线(但是,它是一个椭圆曲线)。
(P.S。我假设a=b=2
和W=3
是因为Young和Young没有说这些整数应该是什么。)
解决方法
使用具体示例最容易理解该问题:爱丽丝(Alice)拥有一个为她生成Diffie-Hellman密钥的设备。在该设备上实施了恶意的Diffie Hellman变体。
恶意DH变体/ SETUP的实现
恶意DH变体定义如下。 here,秒3.1:
MDH1:对于第一个生成的密钥对,适用以下条件:
- 私钥c 1 是小于p-1的随机值。保存c 1 供以后使用。
- 根据m 1 = g c 1 mod p计算公钥。
- 设备为Alice提供私钥(c 1 )和公钥(m 1 )。
MDH2:对于第二个生成的密钥对,适用以下条件:
- 选择了一个随机的t(0或1)。
- z 2 是根据z 2 = g (c 1 -Wt) * Y (-ac 1 -b) mod p。
- 根据H(z 2 )计算私钥c 2 。这里H是加密哈希函数。保存c 2 供以后使用。
- 根据m 2 = g c 2 mod p计算公钥。
- 设备为Alice提供私钥(c 2 )和公钥(m 2 )。
MDHi:第三个及随后的密钥对会发生什么?与第二个生成的密钥对使用相同的算法,例如,对于第三次密钥交换,现在使用c 2 代替c 1 和m 现在使用2 代替m 1 ,或者通常使用第i个密钥对c i ,m i 生成:
- 选择了一个随机的t(0或1)。
- z i 是根据z i = g (c i-1 -Wt) *计算的Y (-ac i-1 -b) mod p。
- 根据H(z i )计算私钥c i 。 H是(相同的)密码哈希函数。 c i 被存储以供以后使用。
- 公钥是根据m i = g c i mod p计算的。
- 设备为Alice提供私钥(c i )和公钥(m i )。
请注意,密钥交换过程分为两类:MDH1和MDHi,它们稍后将在计时行为的讨论中发挥重要作用。
对恶意DH变体的已发布实施的评估:
SETUP(带有Universal Protection的秘密嵌入式活板门)未实施DH变体发布在问题中。
SETUP建立两个连续生成的密钥对之间的关系。这使得有可能从两个这样的相关公共密钥中得出最后一个密钥生成的私有密钥,该公共密钥可以例如被拦截。在密钥交换过程中。
但是为此,必须在连续的密钥生成之间传递私钥,以在最后的密钥生成中使用它来建立这种关系。在实现中不会发生这种情况,因此无法实现所需的关系。
从更技术的角度来看,实现失败的主要原因是MDH1和MDHi案例不是分开实现的,而是一起作为封闭的过程。在私钥没有存储在后续调用之间的意义上,它已关闭,因此无法继续传递。因此,该实现的后续调用会生成彼此之间不具有所需关系的随机密钥对。
还应注意,从发布的实现和本文中使用的实现的相似时间行为(仅相似,因为例如缺少第二个峰值,将在下文中进行讨论)来看,当然没有 working 实现可以得出结论。
SETUP的有效Python实现或恶意的Diffie-Hellman变体可能如下所示:
import timeit
import matplotlib.pyplot as plt
import Crypto.Random.random
import hashlib
import pyDH
DH = pyDH.DiffieHellman()
xBytes = bytes.fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
X = int.from_bytes(xBytes,'big') #Attacker's private key
Y = pow(DH.g,X,DH.p) #Attacker's public key
W = 3
a = 1
b = 2
...
privateKey = -1
def maliciousDH():
global privateKey
DH = pyDH.DiffieHellman()
if privateKey == -1:
privateKeyBytes = Crypto.Random.get_random_bytes(32)
privateKey = int.from_bytes(privateKeyBytes,'big')
publicKey = pow(DH.g,privateKey,DH.p)
return publicKey
else:
t = Crypto.Random.random.choice([0,1])
z1 = pow(DH.g,privateKey - W*t,DH.p)
z2 = pow(Y,-a*privateKey - b,DH.p)
z = z1 * z2 % DH.p
privateKey = hashVal(z)
publicKey = pow(DH.g,DH.p)
return publicKey
def hashVal(value):
valBytes = value.to_bytes((value.bit_length() + 7) // 8,'big')
hashBytes = hashlib.sha256(valBytes).digest()
hashInt = int.from_bytes(hashBytes,'big')
return hashInt
请注意以下几点:
- 大小写
privateKey == -1
对应于第一密钥对(MDH1)的生成,另一种情况对应于后续密钥对(MDHi)的生成。私钥存储在全局变量privateKey
中。 -
W
,a
,b
是攻击者已知的常数。X
,Y
是攻击者的密钥对。只有作为私钥X
所有者的攻击者才能执行攻击。W
,a
,b
是可以自由选择的常量,应该引入随机性。W
从定义上来说很奇怪。 - 加密功能用于生成随机数据(例如,来自
Crypto.Random
的私钥)和哈希(SHA256摘要)。 - pyDH 仅用于生成p和g。
以下函数现在为Alice生成5个连续的密钥对:
def maliciousDHRepeated(nRepeats):
for repeat in range(nRepeats):
publicKey = maliciousDH()
print('Key Exchange: {0}\nPublic Key: {1}\nPrivate Key: {2}\n'.format(repeat,publicKey,privateKey))
maliciousDHRepeated(5)
输出看起来像如下:
Key Exchange: 0
Public Key: 18226633224055651343513608182055895594759078768444742995197429721573909831828316605245608159842524932769748407369962509403625808125978764850049011735149830412617126856825222066673989542531319225049606268752217216534778109596553167314895529287398326587713050976475410688145977311375672549266099133534202232996468144930213166214281451969286299514333332818247602266349875280576154902929160410595469062077684241858299388027340353827453534708956747631487004964946083413862389303833607835673755108949997895120758537057516467051311896742665758073078276178999259778767868295638521495976727377437778558494902010641893884127920
Private Key: 4392204374130125010330067842931188140034970327696589536054104764110713347126
Key Exchange: 1
Public Key: 30139618311151172765747180096035363693813051643690049553112194419098573739435580694888705607377666692401242533649667511485491747154556435118981839182970647673078490062996731957675595514634816595774261281319221404554602729724229286827390637649730469857732523498876684012366691655212568572203566445090111040033177144082954609583224066018767573710168898588215102016371545497586869795312982374868713234724720605552587419481534907792549991537554874489150528107800132171517459832877225822636558667670295657035332169649489708322429766192381544866291328725439248413336010141524449750548289234620983542492600882034426335715286
Private Key: 3611479293587046962518596774086804037937636733424448476968655857365061813747
Key Exchange: 2
Public Key: 15021809215915928817738182897850696714304022153200417823361919535871968087042467291587809018574692005905960913634048699743462124350711726491325639829348819265101140044881197573825573242439657057004277508875703449827687125018726500056235788271729552163855744357971593116349805054557752316498471702822698997323082247192241750099101807453692393170567790930805933977981635528696056267034337822347299945659257479795868510784724622533533407893475292593560877530083021377556080457647318869173210614687548861303039851452268391725700391477968193268054391569885481465079263633084038436082726915496351243387434434747413479966869
Private Key: 60238983934252145167590500466393092258324199134626435320227945202690746633424
Key Exchange: 3
Public Key: 10734077925995936749728900841226052313744498030619019606720177499132029904239020745125405126713523340876577377685679745194099270648038862447581601078565944941187694038253454951671644736332158734087472188874069332741118722988900754423479460535064533867667442756344440676583179886192206646721969399316522205542274029421077750159152806910322245234676026617311998560439487358561468993386759527957631649439920242228063598908755800970876077082845023854156477810356816239577567741067576206713910926615601025551542922545468685517450134977861564984442071615928397542549964474043544099258656296307792809119600776707470658907443
Private Key: 62940568050867023135180138841026300273520492550529251098760141281800354913131
Key Exchange: 4
Public Key: 2425486506974365273326155229800001628001265676036580545490312140179127686868492011994151785383963618955049941820322807563286674799447812191829716334313989776868220232473407985110168712017130778639844427996734182094558266926956379518534350404029678111523307272488057571760438620025027821267299005190378538083215345831756055838193240337363440449096741629258341463744397835411230218521658062737568519574165810330776930112569624066663275971997360960116063343238010922620695431389619027278076763449139206478745130163740678443228451977971659504896731844067323138748945493668050217811755122279988027033740720863980805941221
Private Key: 3330795034653139675928270510449092467425071094588264172648356254062467669676
验证
为验证实现,执行了两个测试:
测试1:是生成的密钥对Diffie-Hellman对吗?这可以通过比较生成的秘密来验证,例如如下(对于爱丽丝,使用交换过程4中的密钥对):
def determineSecrets():
# Bob's key pair
DH = pyDH.DiffieHellman()
privateKeyBob = DH.get_private_key()
publicKeyBob = DH.gen_public_key()
#Alice's key pair (from Key Exchange 4)
privateKeyAlice = 3330795034653139675928270510449092467425071094588264172648356254062467669676
publicKeyAlice = 2425486506974365273326155229800001628001265676036580545490312140179127686868492011994151785383963618955049941820322807563286674799447812191829716334313989776868220232473407985110168712017130778639844427996734182094558266926956379518534350404029678111523307272488057571760438620025027821267299005190378538083215345831756055838193240337363440449096741629258341463744397835411230218521658062737568519574165810330776930112569624066663275971997360960116063343238010922620695431389619027278076763449139206478745130163740678443228451977971659504896731844067323138748945493668050217811755122279988027033740720863980805941221
#Secrets
secretBob = pow(publicKeyAlice,privateKeyBob,DH.p)
secretAlice = pow(publicKeyBob,privateKeyAlice,DH.p)
print("Bob's secret: {0}\nAlices's secret: {1}\n".format(secretBob,secretAlice))
determineSecrets()
计算出的机密是相同的:
Bob's secret: 7003831476740338689134311867440050698619657722218522238000557307099433806548522159881608160975874841852430612290661550184838734726150744064473827597359598057583882560698588377500873394072081781357504452653998970161870108172814907873339750240946592215609078441859786431410312119968080615568505910664062291703601148542762668346870718638131670350107907779759989388216242619752036996919178837249552098220438246127095430336587506739324288803914290366560286806624611103226334708363046293511682782019638354540305524062643841864120561080971292493441027391819191342193393031588366711412191000779126089156632829354631140805980
Alices's secret: 7003831476740338689134311867440050698619657722218522238000557307099433806548522159881608160975874841852430612290661550184838734726150744064473827597359598057583882560698588377500873394072081781357504452653998970161870108172814907873339750240946592215609078441859786431410312119968080615568505910664062291703601148542762668346870718638131670350107907779759989388216242619752036996919178837249552098220438246127095430336587506739324288803914290366560286806624611103226334708363046293511682782019638354540305524062643841864120561080971292493441027391819191342193393031588366711412191000779126089156632829354631140805980
测试2:攻击者可以确定爱丽丝的私钥吗?
导出密钥的算法为s。 here,秒3.1:
- 根据r = m i-1 a * g b mod p 确定r
- 根据u = m i-1 / r X mod p确定u。如果m i = g H(u) mod p,则私钥为c i = H(u)并结束
- 根据v = u / g W mod p确定v。如果m i = g H(v) mod p,则私钥为c i = H(v)
除了常量W
,a
,b
和私钥X
(攻击者都知道)之外,只有公钥m i 和m i-1 来确定私钥c i 。
此算法的可能实现是:
def stealPrivateKey(currentPublicKey,previousPublicKey):
r = pow(previousPublicKey,a,DH.p) * pow(DH.g,b,DH.p) % DH.p
u = previousPublicKey * pow(r,-X,DH.p) % DH.p
if currentPublicKey == pow(DH.g,hashVal(u),DH.p):
return hashVal(u)
v = u * pow(DH.g,-W,hashVal(v),DH.p):
return hashVal(v)
return -1
为了进行验证,使用了密钥交换过程3和4中的公共密钥:
previousPublicKey = 10734077925995936749728900841226052313744498030619019606720177499132029904239020745125405126713523340876577377685679745194099270648038862447581601078565944941187694038253454951671644736332158734087472188874069332741118722988900754423479460535064533867667442756344440676583179886192206646721969399316522205542274029421077750159152806910322245234676026617311998560439487358561468993386759527957631649439920242228063598908755800970876077082845023854156477810356816239577567741067576206713910926615601025551542922545468685517450134977861564984442071615928397542549964474043544099258656296307792809119600776707470658907443
currentPublicKey = 2425486506974365273326155229800001628001265676036580545490312140179127686868492011994151785383963618955049941820322807563286674799447812191829716334313989776868220232473407985110168712017130778639844427996734182094558266926956379518534350404029678111523307272488057571760438620025027821267299005190378538083215345831756055838193240337363440449096741629258341463744397835411230218521658062737568519574165810330776930112569624066663275971997360960116063343238010922620695431389619027278076763449139206478745130163740678443228451977971659504896731844067323138748945493668050217811755122279988027033740720863980805941221
currentPrivateKey = stealPrivateKey(currentPublicKey,previousPublicKey)
print(currentPrivateKey)
结果是
3330795034653139675928270510449092467425071094588264172648356254062467669676
,因此对应于密钥交换4中的私钥。
时间行为分析
要比较恶意和标准DH变体的计时行为,需要标准DH变体的实现:
SDHi:对于所有生成的密钥对,适用以下条件:
- 私钥c i 是小于p-1的随机值。
- 公钥是根据m i = g c i mod p计算的。
- 设备为Alice提供私钥(c i )和公钥(m i )。
带有以下实现:
def standardDH():
DH = pyDH.DiffieHellman()
privateKeyBytes = Crypto.Random.get_random_bytes(32)
privateKey = int.from_bytes(privateKeyBytes,'big')
publicKey = pow(DH.g,DH.p)
return publicKey
通过以下实现对恶意DH和标准DH变体进行比较:
def plot(nTests = 1000,nKeyExPerTest = 10):
global privateKey
timesStandardDH = []
timesMaliciousDH = []
for test in range(nTests):
for keyExPerTest in range(nKeyExPerTest):
elapseTimeStandardDH = timeit.timeit(standardDH,number = 1)
timesStandardDH += [int(round(elapseTimeStandardDH * pow(10,3) ) )]
privateKey = -1
for keyExPerTest in range(nKeyExPerTest):
elapseTimeMaliciousDH = timeit.timeit(maliciousDH,number = 1)
timesMaliciousDH += [int(round(elapseTimeMaliciousDH * pow(10,3)) )]
x_axis=[i for i in range(0,50)]
y_axisStandardDH = [timesStandardDH.count(i) for i in x_axis]
y_axisMaliciousDH = [timesMaliciousDH.count(i) for i in x_axis]
plt.plot(x_axis,y_axisStandardDH,x_axis,y_axisMaliciousDH)
plt.show()
plot()
以下适用于此:
-
nTests
=进行了1000次测试。 - 对于每个测试
nKeyExPerTest
=进行10个密钥交换过程。privateKey
= -1确保每次测试均从MDH1重新开始。 - 对于每个密钥交换过程,都会测量持续时间并创建持续时间的频率分布。
- 所有测量均使用Intel Core i7-6700处理器(3.40 GHz),内核/线程:4 / 8、16 GB RAM,在Win10 / 64位和python 3.8下的NVIDIA Geforce GTX 960 / 4GB。
以下两个图显示了密钥交换过程持续时间的频率分布:
左:x轴:x 1000 -1 秒,右:x轴:x 10000 -1 秒
这些数字在质量上与论文中发布的数字相对应:
-
如预期的那样,恶意Diffie-Hellman变体的主峰的时间值高于标准DH变体的主峰。该比率大约为3。
- 恶意的Diffie-Hellman变体在标准DH变体的主峰处具有次要峰。
- 恶意DH变体的次要峰明显小于恶意DH变体的主峰。
- 波形差异可能是由于不同的实现方式,不同的硬件等导致的。
恶意DH变体的次要峰的解释:
对于恶意DH变体,有两种不同的情况,即MDH1和MDHi。 MDH1实际上对应于标准DH变体SDHi的情况。这就是恶意软件的次要高峰与标准DH变体的主要高峰重合的原因。
但是,MDH1和MDHi以不同的频率出现。例如。对于测试,每个测试定义了10个关键交换过程,即MDH1与MDHi交换的比率为1:9,这说明相对于主峰,次峰明显较小。
可以轻松更改代码以随机确定每次测试的密钥交换过程的数量,这将更为现实。但是通过固定数量的密钥交换过程,这种关系更容易说明。
为什么在问题中发布的恶意DH变体的实现中没有出现次高峰?这是因为此实现将MDH1和MDHi的情况组合在一起,并且将它们实现为一种情况,因此仅测量单个值。
最后,这是艾恩德霍芬科技大学在该主题上的一项有益工作的link。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。