• ECC椭圆曲线算法3


    转:https://wonderful.blog.csdn.net/article/details/72850644

    在之前的文章中,我们看到了什么是椭圆曲线,并且我们为了做一些数学运算,定义了椭圆曲线上的点为一个群,然后我们约束了曲线的取值范围(即定义在有限域上的群)。有了这个约束,我们也看到了椭圆曲线上的点能够生成循环子群。我们也介绍了基点、解、cofactor的概念。

    最后,我们看到了在有限域上的数乘运算是一个简单的操作,但是离散对数问题是比较难的。现在我们来看看ECC算法的应用。

    椭圆曲线参数
    我们的椭圆曲线算法是工作在循环子群上的。因此我们需要如下几个参数
    (1)素数p,这个值定义了有限域的大小
    (2)椭圆曲线的系数a、b
    (3)基点G(子群的生成元)
    (4)子群的阶n
    (5)cofactor h (h = N/n)

    总的来说,这些参数可以用一个六元组表示(p, a, b, G, n, h)

    随机椭圆曲线
    我们之前说到离散对数问题是难的,其实不是很准确。有那么一些椭圆曲线是可被弱化的,即可以被特殊的算法来求得离散对数。例如,当p = hn时,换句话说,有限域的大小和椭圆曲线的阶相同时,容易受到smart’s attack 攻击。

    现在,假设我给你了一个椭圆曲线参数,以前都是安全的,但是突然现在有针对这个椭圆曲线的攻击,并且没有公布,只有我知道。显然这样是不安全的。为了解决上述这种情况,我们增加一个椭圆曲线参数 seed S.
    这个随机数被用来生成系数a、b或者G或者a、b、G。这些参数由S的哈希值得到:
    这里写图片描述
    这里写图片描述
    一个由seed生成的椭圆曲线被称为“verifiably random”。使用哈希算法来生成参数被称为“nothing up my sleeve”。

    椭圆曲线算法
    现在我们终于开始介绍椭圆曲线算法了。

    1:私钥是一个随机数d, d的范围是[1, n -1 ], n是子群的阶
    2:公钥是点 H = dG,G是子群的生成元,也即 基点。

    我们可以看到,如果我们知道了d 和G,计算H是非常方便的,但是我们如果只知道H 和G,计算d是非常难的,因为这就牵扯到了离散对数问题。

    现在我介绍ECDH算法,和ECDSA签名算法。

    ECDH
    ECDH是EC是“ elliptic curves”的意思,DH是“ Diffie-Hellman”的意思。它实际上是密钥协商算法,而不是加解密算法。
    该算法可以用来解决如下问题:两端(Alice 和 Bob)想要安全的交换信息并且第三方不能获取到该信息。当然这是TLS协议中的目的之一,我们给出一个例子。
    (其实下面的描述其实是ECDHE,而不是ECDH)

    (1)Alice 和 Bob 生成他们自己的私钥和公钥,即Alice 有 da、Ha = daG;Bob有db、Hb = db G
    (2)Alice把Ha发给Bob,Bob把Hb发给Alice。这样Alice 有da,Ha,Hb,Bob有db,Ha,Hb。
    (3)Alice计算S = da
    Hb(即自己的私钥乘上Bob的公钥),同样的,Bob计算S = db
    Ga(自己的私钥乘上Alice的公钥)。两边计算的S是相同的。

    S = da*Hb = da *(db * G) = db *(da G) = dbHb 等式1

    中间人支持到Ha和Hb,无法计算出共享密钥S。即离散对数问题为:
    中间人 要计算 S,必须通过上述 等式1 中的一个等式来计算。显然必须知道da或者db,而中间人至知道Ha和Hb,即中间人为了获得da或者db需要从H或Hb中分离出da或db,显然这就是之前所说的离散对数问题。
    现在Alice和Bob得到了共享密钥,后续可以使用共享密钥进行对称加密进行数据传输。通常情况下,点S中x向量被作为共享密钥。

    我们现在给出一个例子,设椭圆曲线为secp256k1(在SECG中被定义),它的
    参数如下:

    这里写图片描述
    Alice’s 私钥(随机数):
    0xe32868331fa8ef0138de0de85478346aec5e3912b6029ae71691c384237a3eeb
    Alice’s 公钥(由Alice的随机数乘上基点):
    (0x86b1aa5120f079594348c67647679e7ac4c365b2c01330db782b0ba611c1d677, 0x5f4376a23eed633657a90f385ba21068ed7e29859a7fab09e953cc5b3e89beba)

    Bob’s 私钥(随机数):
    0xcef147652aa90162e1fff9cf07f2605ea05529ca215a04350a98ecc24aa34342
    Bob’s公钥(由Bob的随机数乘上基点):
    (0x4034127647bb7fdab7f1526c7d10be8b28174e2bba35b06ffd8a26fc2c20134a, 0x9e773199edc1ea792b150270ea3317689286c9fe239dd5b9c5cfd9e81b4b632)

    双方得到的共享密钥:
    (0x3e2ffbc3aa8a2836c1689e55cd169ba638b58a3a18803fcf7de153525b28c3cd, 0x43ca148c92af58ebdb525542488a4fe6397809200fe8c61b41a105449507083)

    ECDSA签名算法

    现在有一个场景:Alice想要用私钥签名一个数据,Bob想要使用Alice的公钥验证这个签名;只有Alice能够进行计算签名然后得到签名,每个人都能验证签名值。

    首先Alice和Bob拥有相同的椭圆曲线参数,算法被签名称之为ECDSA,是DSA算法的一个变体。

    ECDSA签名算法的输入 是 数据的哈希值,而不是数据的本身,至于哈希算法选用哪一个就取决于自己了。为了使得ECDSA的输入值的比特数和子群的阶n的比特数一样,哈希值可能会被截断。我们把ECDSA输入称之为Z。
    算法工作流程如下:
    (1)取一个范围在[1, n - 1]的随机数k
    (2)计算点P=kG
    (3)计算r = xp mod n
    (4)如果 r == 0,执行第一步
    (5)计算s = k^-1 (z + r*da) mod n (da是Alice的公钥,k^-1 是 k 对n的逆元)
    (6)如果s==0,执行第一步
    (7)二元组(r, s)就是签名值
    (一般情况,最后的结果r和s是用asn1格式封装的,至少的TLS签名和数字证书签名中是这样的,不是简单的r+s这样字节直接拼接)
    这里写图片描述

    上图中,Alice使用私钥da对z进行签名,生成二元组(r, s)。
    Bob使用Alice的公钥对(r, s)和Z进行验证。

    现在我们来看看Bob如何验证的:
    (1)计算u1 = s^-1 * z mod n
    (2)计算u2 = s^-1 * r mod n
    (3)计算P = u1G + u2Ha
    (4)如果r == xp mod n,则验证正确

    ECDSA原理以及证明

    首先,我们计算了P = u1G + u2Ha
    这里写图片描述
    代入u1、u2
    这里写图片描述

    我们得到这个等式。
    然后再看看这个等式:
    s = k^-1 (z + rda) mod n
    两边乘以(s^-1 * k)
    得到 等式 k = s^-1 (z + r
    da) mod n
    两边再乘以G,得到
    kG = s^-1*(z + r *da)*G mod n = P
    换句话说,如果(r,s)是有客户端私钥签名Z得到,则我们通过u1,u2计算的到的P值得x分量和r相同。

    K的重要性

    当我们使用ECDSA进行签名的时候,k的保密性非常重要。如果我们对所以的签名操作都用一样的k或者我们的随机数生成器存在可预测性,一个攻击者可能会猜出私钥。

    索尼几年前曾犯过这个错误。PlayStation 3 只能运行被索尼的进行ECDSA签名的游戏。如果我想为PlayStation 3开发了一个新的游戏,除非我从索尼获得签名值,否则我及时发布了,也运行不了这个游戏。问题是,索尼签名时用了一个静态的k值而不是随机生成的。

    这么获取私钥d和随机数k?

    看看这个等式 s = k^-1 (z + r*da) mod n
    显然,未知数只有2个,da和k。我们买2份索尼游戏,签名值分别是(r1 , s1)、(r2, s2), 由于k值一样,故r 值也一样

    s1 = k^-1 (z1 + rda) mod n等式1
    s2= k^-1 (z2 + r
    da) mod n等式2

    等式1-等式2
    s1 -s2 = k^-1 (z1 - z2) mod n
    z1和z2 可以自己使用哈希算法对软件进行哈希能够获取到。s1和s2能够从前面值中获取到。所以k值就轻松的获取到了
    K = (s1 -s2)^-1 * (z1 -z2) mod n
    再把k值代入等式1或者等式2,就能计算da了。

  • 相关阅读:
    linux kernel ftrace 之wakeup tracer and wakeup_rt tracer
    urb传输的代码分析
    open/ioctl in kernel
    淺談C51記憶體優化(data idata xdata)
    8051 XDATA
    Android.bp
    android bionic
    echo +80 > /sys/class/rtc/rtc0/wakealarm
    高清地图下载
    更新和删除数据
  • 原文地址:https://www.cnblogs.com/Netsharp/p/15926867.html
Copyright © 2020-2023  润新知