zoukankan      html  css  js  c++  java
  • 4椭圆曲线密码学:破坏安全性及与RSA的比较

    原文链接:https://andrea.corbellini.name/2015/06/08/elliptic-curve-cryptography-breaking-security-and-a-comparison-with-rsa/

    这篇文章是ECC系列的第四篇,也是最后一篇。

    在上一篇文章中,我们已经看到了两种算法,ECDH和ECDSA,我们也看到了椭圆曲线的离散对数问题是如何对其安全性起重要作用的。但是,如果你还记得,我们说过对于离散对数问题的复杂性我们没有数学证明:我们认为它是“困难的”,但我们不能确定。在这篇文章的第一部分,我们将试着了解在实践中使用今天的技术有多“困难”。

    然后,在第二部分,我们将尝试回答这个问题:如果RSA(和其他基于模算术的密码系统)可以很好地工作,我们为什么需要ECC(椭圆曲线密码学)?

    破解离散对数问题(Breaking the discrete logarithm problem)

    现在我们将看到计算椭圆曲线离散对数的两种最有效的算法:the baby-step, giant-step algorithm和Pollard's rho method。

    在开始之前,提醒一下,下面是离散对数问题的内容:给定两点P和Q,找出满足方程Q = xP的整数x。这些点属于椭圆曲线的一个子群,它有一个基点G,阶数为n。

    Baby-step, giant-step

    在输入算法细节之前,先快速考虑一下:我们总是可以将任意整数写成,其中a、m和b是三个任意整数。例如,我们可以写成10=2·3+4。

    考虑到这一点,我们可以将离散对数问题的方程重写如下:

    baby-step giant-step算法是一种“中间相遇”的算法。与暴力破解(逐个计算每一个[公式]来找到满足方程Q = xP要求的[公式])相反,对于[公式]我们可以计算得更少,对于[公式]也可以计算得更少,直到我们找到一个满足条件的。算法的工作原理如下:

    1. 计算
    2. [公式]中的每一个b,计算并将结果存储在一个哈希表中
    3. [公式]中的每一个a,:

          (1)计算

          (2)计算

          (3)检查哈希表,看看是否存在一个点bP使得

          (4)如果这样的点存在,那么我们就找到了

    正如你所看到的,我们计算[公式]时的系数[公式]用很小的步长,但在第二部分当中,我们计算[公式]使用很大的步长,这两部分分别就是算法“baby”部分和“giant”部分。具体它可以如下图所示:

    baby-step, giant-step算法:最初我们通过小步骤计算几个点,并将它们存储在一个哈希表中。然后我们执行大步骤,并将新点与哈希表中的点进行比较。一旦找到匹配,计算离散对数就是重新排列项的问题。

    为了理解这个算法的原理,先暂时忘记这些被缓存的点[公式],来看方程。看以下步骤:

    • 当a =0时,我们检查Q是否等于bP,其中b是从0到m的整数之一。这样,我们将Q与从0P到mP的所有点进行比较
    • 当a =1时,我们检查Q是否等于mP +bP。我们将Q与mP到2mP的所有点数进行比较
    • 当a =2时,我们将Q与从2mP到3mP的所有点数进行比较
    • 当a = m-1时,我们将Q与从(m-1)mP到m2P=nP的所有点进行比较

    总之,我们检查从0P到nP的所有点(即所有可能的点),最多需要执行2m次加法和乘法运算(精确的说,baby-step过程是m步, giant-step过程最多m步)。

    如果考虑查找哈希表的时间复杂度需要[公式],很容易看出该算法具有时间和空间复杂度均为[公式](如果考虑字节的长度,则为[公式])。这仍然是指数级的时间,但比暴力破解要好得多。

    Baby-step giant-step实践(Baby-step giant-step in practice)

    我们来看看复杂度[公式]在实践中意味着什么。以标准化曲线为例:prime192v1(又名secp192r1l,ansix9p192r1)。这个曲线的阶n = Oxffffff ffffff fffff 9gdef836 146bc9b1 b4d22831。n的平方根约为7.922816251426434·1028(几乎是八百亿)。

    现在想象一下在一个哈希表中存储个点。假设每个点恰好需要32个字节:我们的哈希表大约需要2.5·1030个字节的内存空间。目前整个世界的存储能力比起这个需求都相差甚远,即便每一个点只需要1个字节的存储空间,我依然离将它们全部存下来相去甚远。

    更加令人绝望的是prime192v1是阶数最低的曲线。另外一个来自NIST的标准曲线的阶数高达6.9·[公式],其时间和空间的复杂度更加不可想象。

    Playing with baby-step giant-step

    我做了 a Python script,使用baby-step giant-step算法计算离散对数。显然,它只适用于小订单的曲线:不要尝试secp521r1,除非你想接收一个MemoryError。

    它应该产生这样的输出:

    Curve: y^2 = (x^3 + 1x - 1) mod 10177
    Curve order: 10331
    p = (0x1, 0x1)
    q = (0x1a28, 0x8fb)
    325 * p = q
    log(p, q) = 325
    Took 105 steps
    View Code

    Pollard's ρ

    Pollard's rho是另一种计算离散对数的算法。它和baby-step giant-step算法的时间复杂度[公式]相同。算法的空间复杂度仅为[公式]。如果由于巨大的内存需求,baby-step giant-step算法都不能解决离散对数问题,Pollard's rho可以解决吗?让我们看看…

    首先,离散对数问题的另一个提示给定P和Q找到x使Q =xP。用Pollard's rho求解,我们将解决一个完全不同的问题:给定P和Q,找到整数a, b, A和B使得

    一旦找到这四个整数,我们就可以用方程Q=xP来求出x:

     

    现在我们可以消去P,但在此之前,记住我们的子群是n阶循环的,因此点乘所用的系数是模n:

    Pollard's rho的运算原理很简单的:生成一个伪随机序列的点其中每个。序列可以使用伪随机函数f生成,如下所示:

    即:伪随机函数取序列中最近的点作为输入,并给出系数作为输出。由此,我们可以计算出,然后再把输入到中重复。

    在内部如何工作并不重要(尽管某些函数可能比其他函数产生的结果更快),重要的是决定序列中的下一个点基于前一个点,所有的系数是已知的。

    通过使用这样的,我们迟早会在序列中看到一个循环。也就是说,我们会看到一个点

     序列中的循环可能是这样的:有一些初始点和循环本身,由点组成。之后, ,以此类推。这幅图类似于希腊字母ρ (rho),因此得名。

    我们肯定能看到循环的原因很简单:点的数量是有限的,因此它们迟早会重复。一旦我们知道循环的位置,我们可以用上面的方程来算出离散对数。

    现在的问题是:我们如何以一种有效的方式检测这种循环?

    快慢指针法(Tortoise and Hare)

    为了检测周期,我们有一个有效的方法:Tortoise and Hare(也称为Floyd's cycle-finding算法)。下图展示了Tortoise and Hare的操作原理,也是Pollard's rho的核心。

    我们有曲线和点。这些点属于阶数为5的循环子群。我们以不同的速度连续走几对,直到找到两组不同的整数对产生同一个点。在这种情况下,我们已经找到整数对(3,3)和(2,0),使我们可以计算出对数为。事实上我们也正确地得到

    我们让tortoise和hare从序列的左边走到序列的右边,绿色的是走得慢的tortoise,一步一步地走,红色的hare每次跳过一个点得走,本质上是快慢指针法来寻找循环开始的地方。

    一段时间以后,tortoise和hare会找到相同的点,但是系数对却不相同。或者用方程来表达,tortoise找到的对是[公式],hare找到的对是[公式],且满足[公式]

    非常容易看出这个算法只需要固定大小的内存空间[公式]。但是计算时间依然开销很大,可以从概率的角度来证明时间复杂度为[公式]。严格的证明是基于birthday paradox,指的是两个人生日相同的概率,这和我们所考虑的两个不同的整数对[公式]得到相同的点的概率类似。

    Playing with Pollard's ρ

    我构建了 a Python script ,可以使用Pollard's计算离散对数。它不是原始Pollard’s的实现,而是它的一个微小变体(我使用了一种更有效的方法来生成伪随机对序列)。该脚本包含一些有用的注释,如果您对算法的细节感兴趣,请阅读它。

    这个脚本与baby-step giant-step算法脚本一样,也仅仅在一些小的椭圆曲线上面有效工作,并产生类似的输出。

    Pollard's ρ in practice

    我们说过,由于巨大的内存需求,baby-step giant-step不能在实践中使用。另一方面,Pollard's rho只需要很少的内存。那么,它的实用性如何呢?

    Certiccom在1998年发起了一项挑战,要求在字节长从109到359的椭圆曲线上计算离散对数。截至今天,只有109位长曲线被成功打破。最近一次成功的尝试是在2004年。摘自维基百科:

    The prize was awarded on 8 April 2004 to a group of about 2600 people represented by Chris Monico. They also used a version of a parallelized Pollard rho method, taking 17 months of calendar time.

    我们已经说过,prime192v1是“最小的”椭圆曲线之一。我们还说过Pollard's rho的时间复杂度是[公式]。如果我们使用与Chris Monico相同的技术(相同的算法,相同的硬件,相同数量的机器),在prime192v1上计算一个对数需要多少时间?

    数字不言自明的,并清楚地说明了使用这种技术求解离散对数是多么困难。

    Pollard's ρ vs Baby-step giant-step

    我决定把 baby-step giant-step script和 Pollard's rho script与一个 brute-force script放到第四段代码中来比较它们的性能。 

    运行第四段代码可以对比所有的算法在一个阶数较小的曲线上面求解一个离散对数问题所需要的时间对比:

    Curve order: 10331
    Using bruteforce
    Computing all logarithms: 100.00% done
    Took 2m 31s (5193 steps on average)
    Using babygiantstep
    Computing all logarithms: 100.00% done
    Took 0m 6s (152 steps on average)
    Using pollardsrho
    Computing all logarithms: 100.00% done
    Took 0m 21s (138 steps on average)
    View Code

    正如我们所料,与其他两个方法相比,brute-force方法非常慢。baby-step giant-step更快,而Pollard's rho比baby-step giant-step慢三倍多(尽管它使用的内存和步数平均要少得多)。

    还要查看运算步数:brute-force平均使用5193步计算每个对数。5193非常接近10331 /2(曲线顺序的一半)。Baby-step giant-steps和Pollard's rho分别用了152步和138步,这两个数字非常接近根号10331(101.64)。

    最后考虑Final consideration

    在讨论这些算法时,我给出了许多数字。在阅读这些算法时,一定要足够重视:算法可以在许多方面进行极大的优化。硬件可以提高。可以建立专门的硬件。

    目前看起来不可行的方法,并不意味着后续不能提升。更不是说已经没有其它更好的方法存在。(再次记住,我们没有证明离散对数问题的复杂性)。

    Shor's algorithm

    如果今天的技术不合适,那明天的技术呢?好吧,事情的发展有点令人担忧:存在一种量子算法可以在多项式的时间复杂度内解决离散对数问题:Shor's algoritm的时间复杂度是[公式],空间复杂度是[公式]

    量子计算机还远没有成熟到足以运行Shor's这样的算法,但抗量子的加密算法的需求可能是现在值得研究的事情。我们今天加密的东西明天可能就不安全了。

    ECC and RSA

    现在让我们忘记量子计算,它还不是一个足够重要的问题。我现在要回答的问题是:如果RSA很好用,为什么还要用椭圆曲线呢? 

    NIST给出了一个快速的答案,它提供了一个表,比较RSA和ECC密钥的大小需要达到相同的安全级别。( a table that compares RSA and ECC key sizes )

     注意,RSA密钥大小和ECC密钥大小之间没有线性关系(换句话说:如果我们将RSA密钥大小加倍,我们就不必将ECC密钥大小加倍)。这个表告诉我们,ECC不仅使用更少的内存,而且密钥生成和签名要快得多。

    但为什么会这样呢?答案是,在椭圆曲线上计算离散对数的快速算法是Pollard's和baby-step giant-step,而在RSA的例子中,我们有更快的算法。其中一个特别的是一般的数字域筛选(general number field sieve):整数分解的算法,可以用来计算离散对数。一般数字域筛选算法是迄今为止最快的整数分解算法。

    Hidden threats of NSA

    现在是最难的部分。到目前为止,我们已经讨论了算法和数学。现在是讨论人的时候了,事情变得更复杂了。

    如果你还记得,在上一篇文章中,我们说过某些类型的椭圆曲线是弱的,为了解决来自可疑来源的信任曲线的问题,我们在域参数中添加了一个随机种子。如果我们看看NIST的标准曲线我们会发现它们都是随机的。

    如果我们阅读维基百科页面上的"nothing up my sleeve",我们可以看到:

    • MD5的随机数来自整数的正弦值。
    • Blowfish的随机数来自∏的第一个数字。
    • RC5的随机数来自于e和黄金比例。

    这些数字是随机的,因为它们的数字是均匀分布的。

    首先让我们放出问题,问题是:NIST曲线的随机数种子是哪里来的?答案是令人失望的:我们并不知道。这些种子并没有经过大家一致讨论而被认为是正当的。

    是不是有这种可能,NIST发现了大量的弱椭圆曲线,然后尝试了大量可能的种子找到了一个有漏洞的曲线?这个问题我无法回答,但是却非常重要且关乎法律。我们知道,NIST确实成功标准化了至少一个有漏洞的随机数生成器。或许他们也能够标准化出一系列的含有漏洞的弱椭圆曲线。对于问题的答案,我们依然无法知晓。

    尤其重要的是,需要特别理解的是“可验证的随机”和“安全”并不是等价的。不论你的离散对数问题有多难,你的密钥有多长,如果算法本身被破解了,皮之不存,毛将焉附,那么我们也是束手无策的。

    基于这一点的考虑,RSA胜出。它并不需要特别的可能可以作弊的领域参数。在我们不信任任一权威机构以及自己无法构建我们自己的领域参数的时候,RSA以及其它基于幂模运算的加密系统是一个好的替代选择。如果你问:是的,传输安全层(TLS)可以使用NIST的曲线。如果你检查一下google,你可以看到连接就是使用了ECDHEECDSA,基于prime256v1的认证证书。

    That's all!

    最后,希望大家能够喜欢这一系列的文章。我的目的是能够给大家介绍基本的知识、术语和惯例来理解当前的ECC。如果能够达到我的目标,你现在可以理解现存基于ECC的加密系统并将你的知识延伸到阅读一些其它不那么友好的文档。当撰写这一系列的文章的时候,我本可以跳过一些详细细节,使用一个更简单的术语,但我觉得这样做你将无法理解。我相信我在简单和面面俱到之间做了很好的权衡。

    务必注意,仅仅通过阅读本系列文章,你并不能实现安全的ECC加密系统,为了确保安全性,我们需要了解很多细微但重要的细节。记住Smart's attackSony's mistake──这两个例子应该可以让你知道产生不安全的算法是多么的容易,不安全的算法被人恶意利用也是多么的容易。

    那么,后面如果有志于更加深入的探索ECC的世界,应该从哪里开始呢?

    首先,到目前为止,我们已经看到了素数域上的Weierstrass曲线,但你必须知道,还有其他类型的曲线和域,特别是:

    • 二元域上面的Koblitz曲线:它们是形如(其中a是0或1)定义在包含2m(其中m是质数)个元素的有限域上的椭圆曲线。它们可以实现特别高效的点加和标量乘法。标准化的 Koblitz曲线有nistk163,nistk283,nistk571(这三条曲线分别定义在 163, 283 和 571 位的域上)
    • 二元曲线:这类曲线与Koblitz曲线类似,它们是形如(其中b是整数,通常来源于一个随机数种子)。顾名思义,二元曲线被限制在二元域上。标准化的二元曲线有nistb163nistb283 和 nistb571。 必须要说明的是, 有越来越多的担忧认为 Koblitz 曲线和二元曲线可能并没有质数曲线那么安全
    • Edwards曲线:它们形如(其中d是0或1)。它们特别有趣,不仅在于点加法和标量乘法特别快,而且计算点加的公式在任何情况下()都是一样的。该特性充分考虑了旁路攻击的可能性,即当你在测量标量乘法所耗费的时间以后用这个计算所耗费的时间来猜测标量参数的一种攻击方式。Edwards相对较新(2007年出现),目前尚未有CerticomNIST之类的权威机构对其进行标准化
    • Curve25519和 Ed25519 是两种分别为ECDH 和ECDSA 的某种变体特别设计的椭圆曲线。 和 Edwards 曲线一样, 这两种曲线也很快速并且能够抵御旁路攻击。也和 Edwards 曲线一样, 这两种曲线也尚未被标准化所以我们不能在流行软件中看到它们的身影(除了 OpenSSH, 它从 2014 年起支持了 Ed25519 密钥对)

    如果你对 ECC 的实现细节感兴趣, 那么我建议你阅读 OpenSSL 和 GnuTLS 的源码。

    最后,如果你对数学细节感兴趣,而不是算法的安全性和有效性,你必须知道:

    • 椭圆曲线是亏格(genus)为 1 的代数变体
    • 无限远处的点的概念来源于影射几何(projective geometry) 并可以通过齐次坐标(homogeneous coordinates)来表现 (尽管椭圆曲线并不需要影射几何中的绝大部分特性)

    更别忘记研究有限域(finite fields)和域理论(field theory)。

    如果对这些主体感兴趣,可以通过上面的这些关键字去了解。

    现在这个系列文章就正式结束了,感谢大家的阅读,下次再见!

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    linux系统中将一列数据转换为若干列数据(列的顺序不变)
    linux系统中将矩形数据转换为一行、一列的形式
    linux系统中实现文本转置。
    linux shell 如何将多列数据变为一行数据
    linux系统中如何将一行数据变为一列
    bash: unlzma: command not found...
    linux系统中实现对行的批量替换
    linux系统中对指定行的字符串进行替换
    linux系统中对指定列的数据中的字符串进行替换
    linux系统中如何将每行特定数目字符后的字符替换为指定字符
  • 原文地址:https://www.cnblogs.com/Duxue/p/15041723.html
Copyright © 2011-2022 走看看