公钥加密
在本章中,将向您介绍公钥加密的概念和实践方面,公钥加密也称为非对称加密或非对称密钥加密。我们将继续使用 OpenSSL,正如我们在上一章中所做的那样,来试验一些加密算法的应用程序,以便您可以获得实践经验。我们将从公钥密码学的理论基础开始,并通过相关的实践练习逐步建立相关的概念。此外,我们还将研究哈希函数,这是在区块链广泛使用的另一种加密原语。在此之后,我们将介绍一些新的和先进的加密构造。
不对称密码术
非对称加密指的是一种加密技术,用于加密数据的密钥不同于用于解密数据的密钥。这也被称为公钥加密。它使用公钥和私钥分别加密和解密数据。各种非对称加密方案正在使用中,包括 RSA、DSA 和 ElGammal。
下图显示了公钥加密的概述:
使用公钥/私钥的加密/解密
上图说明了发送方如何使用接收方的公钥和加密函数 E 对数据 P 进行加密,并产生输出加密数据 C ,然后通过网络传输给接收方。一旦它到达接收者,就可以通过将 C 加密数据输入函数 D 来使用接收者的私钥对它进行解密,函数D将输出明文 P 。这样,私钥保留在接收方,不需要共享密钥来执行加密和解密,对称加密就是这种情况。
下图显示了接收方如何使用公钥加密来验证所接收消息的完整性。在这个模型中,发送方使用他们的私钥对数据进行签名,然后将消息传递给接收方。一旦收到消息,就用发送者的公钥验证其完整性。
值得注意的是,在这个模型中没有执行加密。此处提供它只是为了帮助您彻底理解本章后面涉及消息身份验证和验证的部分:
一种公钥密码签名方案的模型
上图显示,发送者使用签名函数 S 用他的私钥对明文 P 进行数字签名,并产生数据 C ,该数据被发送给接收者,接收者使用发送者公钥和函数 V 验证 C 以确保消息确实来自发送者。
公钥密码系统提供的安全机制包括密钥建立、数字签名、识别、加密和解密。
密钥建立机制与允许在不安全信道上建立密钥的协议设计有关。使用数字签名可以提供不可否认服务,这是许多场景中非常理想的属性。有时,不仅对用户进行身份验证很重要,而且识别交易中涉及的实体也很重要。这也可以通过数字签名和挑战应答协议的组合来实现。最后,提供保密性的加密机制也可以使用公钥密码系统获得,如 RSA、ECC 和 ElGammal。
公钥算法在计算方面比对称密钥算法慢。因此,它们通常不用于加密大型文件或需要加密的实际数据。它们通常用于交换对称算法的密钥。一旦安全地建立了密钥,就可以使用对称密钥算法来加密数据。
公钥密码算法基于各种基础数学函数。这里描述了不对称算法的三个主要类别。
整数因式分解
整数分解方案基于大整数很难分解的事实。RSA 是这种算法的典型例子。
离散对数
一个离散对数方案是基于模运算中的一个问题。计算模函数的结果是容易的,但是要找到生成器的指数在计算上是不切实际的。换句话说,从结果中找到输入是极其困难的。这是一个单向函数。
例如,考虑以下等式:
32mod 10 = 9
现在,给定 9 ,上一个方程求 2 的结果,也就是上一个问题中发生器 3 的指数,是极难确定的。这个难题通常用于 Diffie-Hellman 密钥交换和数字签名算法中。
椭圆曲线
椭圆曲线算法基于之前讨论的离散对数问题,但是在椭圆曲线的环境中。椭圆曲线是域上的代数三次曲线,可由以下方程定义。该曲线是非奇异的,这意味着它没有尖点或自交。它有两个变量 a 和 b ,还有一个无穷远点。
这里, a 和 b 是整数,其值是定义椭圆曲线的域的元素。椭圆曲线可以定义在实数、有理数、复数或有限域上。出于加密的目的,使用素数有限域上的椭圆曲线来代替实数。此外,素数应该大于 3。通过改变 a 和/或 b 的值,可以生成不同的曲线。
基于椭圆曲线的最突出的密码系统是椭圆曲线数字签名算法 ( ECDSA )和椭圆曲线 Diffie-Hellman ( ECDH )密钥交换。
要理解公钥密码学,需要探究的关键概念是公钥和私钥的概念。
公钥和私钥
私钥,顾名思义,是一个随机生成的数字,由用户秘密持有。私钥需要得到保护,并且不应该允许对该密钥进行未经授权的访问;否则,整个公钥加密方案就会受到危害,因为这是用于解密消息的密钥。根据所用算法的类型和类别,私钥可以有不同的长度。例如,在 RSA 中,通常使用 1024 位或 2048 位的密钥。1024 位密钥大小不再被认为是安全的,建议至少使用 2048 位密钥大小。
一个公钥可以自由获得并由私钥所有者发布。然后,任何想要向公钥的发布者发送加密消息的人都可以通过使用发布的公钥加密该消息并将其发送给私钥的持有者来这样做。没有其他人能够解密该消息,因为相应的私钥被预定的接收者安全地持有。一旦接收到公钥加密的消息,接收者就可以使用私钥解密该消息。但是,关于公钥有几个问题。这些包括公钥发行者的真实性和标识。
在下一节中,我们将介绍两个非对称密钥加密的例子:RSA 和 ECC。RSA 是公钥加密的第一个实现,而 ECC 在区块链技术中广泛使用。
南非共和国(Republic of South Africa)
RSA 于 1977 年由罗恩·里维斯特、阿迪·萨莫尔和伦纳德·阿德尔曼发明,因此得名里维斯特-沙米尔-阿德尔曼 ( RSA )。这种类型的公钥密码系统基于整数因式分解问题,其中两个大素数的乘法很容易,但很难将其因式分解(乘法的结果,乘积)回两个原始数。
RSA 算法所涉及的关键工作是在密钥生成过程中。通过执行以下步骤生成 RSA 密钥对:
-
模数生成:
-
生成互质:
-
生成公钥:
步骤 1 中生成的模数和步骤 2 中生成的互质 e 是一对公钥。这部分是可以分享给任何人的公共部分;但是, p 和 q 需要保密。
- 生成私钥:
私钥,这里叫做 d ,是由 p 、 q 、 e 计算出来的。私钥基本上是 e 模(p-1) (q-1) 的逆。在方程式形式中,它是这样的:
ed = 1 mod (p-1) (q-1)
通常使用扩展的欧几里德算法来计算 d 。这个算法取 p 、 q 和 e 并计算 d 。该方案的核心思想是,任何知道 p 和 q 的人都可以通过应用扩展的欧几里德算法很容易地计算出私钥 d 。但是,不知道 p 和 q 的值的人无法生成 d 。这也意味着 p 和 q 应该足够大,以至于模数 n 变得非常难以分解(计算上不切实际)。
使用 RSA 加密和解密
RSA 使用以下等式来生成密文:
c = pemod n
这意味着明文 P 被提升到 e 的次数,然后被简化为模 n 。RSA 中的解密由以下等式提供:
p = cdmod n
这意味着拥有公钥对( n , e )的接收者可以通过将 C 提升到私钥 d 的值,并降低到模 n 来解密数据。
椭圆曲线加密
椭圆曲线密码 ( ECC )是基于有限域(伽罗瓦域)上椭圆曲线建立的离散对数问题。与其他类型的公钥算法相比,ECC 的主要优势在于它需要更小的密钥大小,同时提供与 RSA 相同的安全级别。源于椭圆曲线密码体制的两个著名方案是用于密钥交换的 ECDH 和用于数字签名的 ECDSA。
ECC 也可用于加密,但在实践中通常不用于此目的。相反,它通常用于密钥交换和数字签名。由于 ECC 需要更少的操作空间,它在嵌入式平台和存储资源有限的系统中变得非常流行。相比之下,与 RSA 中的 3072 位操作数相比,ECC 仅使用 256 位操作数就可以实现相同级别的安全性。
ECC 背后的数学
为了理解 ECC,有必要对基础数学进行基本介绍。椭圆曲线基本上是一种称为 Weierstrass 方程的多项式方程,它在有限域上生成曲线。最常用的领域是所有算术运算都以模 a 素数 p 执行的地方。椭圆曲线群由有限域上曲线上的点组成。
椭圆曲线在以下等式中定义:
这里, A 和 B 属于一个有限域 Zp 或 Fp (素数有限域)连同一个特殊值叫做无穷远点。无穷远点(∞)用于为曲线上的点提供恒等运算。
此外,还需要满足一个条件,以确保前面提到的方程没有重复的根。这意味着曲线是非奇异的。
该条件在以下等式中描述,这是需要满足的标准要求。更准确地说,这确保了曲线是非奇异的:
为了构造基于椭圆曲线的离散对数问题,需要一个足够大的循环群。首先,组元素被识别为满足前面等式的一组点。在这之后,需要在这些点上定义组操作。
椭圆曲线上的群运算是点加法和点加倍。点加是将两个不同的点相加的过程,点加倍是指将同一个点加到自身上。
点加法
点添加如下图所示。这是椭圆曲线上点加法的几何表示。在这种方法中,通过曲线画一条对角线,该对角线在两点 P 和 Q 处与曲线相交,如图所示,在曲线和直线之间产生第三个点。这个点镜像为 P+Q ,将加法的结果表示为 R 。
这在下图中显示为 P+Q :
R 上的点加法
由用于加法的 + 符号表示的群组运算产生以下等式:
P + Q = R
在这种情况下,添加两个点来计算曲线上第三个点的坐标:
P + Q = R
更准确地说,这意味着添加坐标,如下式所示:
(x 1 ,y 1 ) + (x 2 ,y 2 ) = (x 3 ,y 3 )
点加法的方程式如下:
x3= s【2】-x【1】【x】【m】T12】od**
和3= s(x1-x3)—y1修改 p
在这里,我们看到前面等式的结果:
上式中的 S 描绘了穿过 P 和 Q 的直线。
下图显示了点添加的一个示例。它是使用 Certicom 的在线计算器生成的。这个例子展示了有限域F23T3】上方程的加法和解。这与之前所示的示例形成对比,该示例针对实数,仅显示了曲线,但没有提供方程的解:
点加法的例子
在前面的示例中,左侧的图表显示了满足该等式的点:
在有限域F23T3】上,前面所示的方程有 27 个解。选择添加 P 和 Q 产生点 R 。计算显示在右侧,计算第三个点 R 。注意这里, l 用于描绘穿过 P 和 Q 的线。
作为一个例子,为了显示图中所示的点如何满足该方程,在 x = 3 和 y = 6 处选取一个点( x , y )。
使用这些值表明该方程确实满足:
T2】
下一小节介绍点加倍的概念,这是可以在椭圆曲线上执行的另一种操作。
点加倍
椭圆曲线上的另一组运算叫做点加倍。这是一个 P 加到自身的过程。在这种方法中,通过曲线绘制一条切线,如下图所示。获得第二个点,该点位于绘制的切线和曲线的交点处。
该点然后被镜像以产生结果,该结果显示为 2P = P + P :
表示实数上的点加倍的图形
在点加倍的情况下,等式变为:
这里, S 是通过 P 的切线(切线)的斜率。这是上图顶部显示的线。在前面的例子中,作为一个简单的例子,曲线是在实数上绘制的,没有显示方程的解。
下面的例子展示了有限域F23T3】上椭圆曲线的解和点加倍。左侧的图表显示了满足等式的点:
点加倍的例子
如前图右侧所示,在 P 之后找到 R 的计算被添加到自身中(点加倍)。这里没有图示的 Q ,同一点 P 用于加倍。注意,在计算中, l 用于描绘穿过 P 的切线。
在下一节中,将介绍离散对数问题。
椭圆曲线密码体制中的离散对数问题
ECC 中的离散对数问题是基于这样的思想:在一定条件下,椭圆曲线上的所有点形成一个循环群。
在椭圆曲线上,公钥是生成点的随机倍数,而私钥是用于生成倍数的随机选择的整数。换句话说,私钥是随机选择的整数,而公钥是曲线上的一点。离散对数问题用于寻找私钥(一个整数),其中该整数落在椭圆曲线上的所有点内。下面的等式更精确地说明了这个概念。
考虑一条椭圆曲线 E ,有两个元素 P 和 T 。离散对数问题是求整数 d ,其中 1 < = d < = #E ,这样:
这里, T 是公钥(曲线上的一点),而 d 是私钥。换句话说,公钥是生成器的随机倍数,而私钥是用于生成倍数的整数。 #E 表示椭圆曲线的阶数,表示椭圆曲线的循环群中存在的点数。循环群由椭圆曲线上的点和无穷远点组合而成。
密钥对与椭圆曲线的特定域参数相关联。域参数包括域大小、域表示、来自域的两个元素 a 和 b ,两个域元素 Xg 和 Yg ,点 G 的顺序 n 计算为 G = (Xg,Yg)和余因子 h = #E(Fq)/n 。本节稍后将描述一个使用 OpenSSL 的实际例子。
各种参数被推荐和标准化以用作具有 ECC 的曲线。这里显示了一个secp256k1
规格的例子。这是比特币使用的规范:
取自 http://www.secg.org/sec2-v2.pdf 的 secp256k1 的规格
六元组中所有这些值的解释如下:
- P 是指定有限域大小的素数 p 。
- a 和 b 是椭圆曲线方程的系数。
- G 是生成所需子组的基点,也称为生成器。基点可以用压缩或未压缩的形式表示。在实际实现中,不需要存储曲线上的所有点。压缩生成器工作是因为曲线上的点可以仅使用 x 坐标和 y 坐标的最低有效位来识别。
- n 是子群的阶。
- h 是子群的余因子。
在下一节中,将展示两个使用 OpenSSL 的示例,以帮助您理解 RSA 和 ECC 加密的实际应用。
使用 OpenSSL 的 RSA
以下示例说明了如何使用 OpenSSL 命令行生成 RSA 公钥和私钥对。
RSA 公钥和私钥对
首先,如何使用 OpenSSL 生成 RSA 私钥将在下面的小节中展示。
私人密钥
执行以下命令来生成私钥:
$ openssl genpkey -algorithm RSA -out privatekey.pem -pkeyopt \
rsa_keygen_bits:1024
...............................++++++
....................++++++
命令中使用的反斜杠(\
)用于延续
执行该命令后,会生成一个名为privatekey.pem
的文件,其中包含生成的私钥,如下所示:
$ cat privatekey.pem
-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKJOFBzPy2vOd6em Bk/UGrzDy7TvgDYnYxBfiEJId/r+EyMt/F14k2fDTOVwxXaXTxiQgD+BKuiey/69 9itnrqW/xy/pocDMvobj8QCngEntOdNoVSaN+t0f9nRM3iVM94mz3/C/v4vXvoac PyPkr/0jhIV0woCurXGTghgqIbHRAgMBAAECgYEAlB3s/N4lJh0l1TkOSYunWtzT 6isnNkR7g1WrY9H+rG9xx4kP5b1DyE3SvxBLJA6xgBle8JVQMzm3sKJrJPFZzzT5 NNNnugCxairxcF1mPzJAP3aqpcSjxKpTv4qgqYevwgW1A0R3xKQZzBKU+bTO2hXV D1oHxu75mDY3xCwqSAECQQDUYV04wNSEjEy9tYJ0zaryDAcvd/VG2/U/6qiQGajB eSpSqoEESigbusKku+wVtRYgWWEomL/X58t+K01eMMZZAkEAw6PUR9YLebsm/Sji iOShV4AKuFdi7t7DYWE5Ulb1uqP/i28zN/ytt4BXKIs/KcFykQGeAC6LDHZyycyc ntDIOQJAVqrE1/wYvV5jkqcXbYLgV5YA+KYDOb9Y/ZRM5UETVKCVXNanf5CjfW1h MMhfNxyGwvy2YVK0Nu8oY3xYPi+5QQJAUGcmORe4w6Cs12JUJ5p+zG0s+rG/URhw B7djTXm7p6b6wR1EWYAZDM9MArenj8uXAA1AGCcIsmiDqHfU7lgz0QJAe9mOdNGW 7qRppgmOE5nuEbxkDSQI7OqHYbOLuwfCjHzJBrSgqyi6pj9/9CbXJrZPgNDwdLEb
GgpDKtZs9gLv3A==
-----END PRIVATE KEY-----
公开密钥
由于私钥在数学上与公钥相关联,因此也有可能从私钥生成或导出公钥。使用前面的私钥示例,可以生成公钥,如下所示:
$ openssl rsa -pubout -in privatekey.pem -out publickey.pem
writing RSA key
可以使用文件阅读器或任何文本查看器查看公钥:
$ cat publickey.pem
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCiThQcz8trznenpgZP1Bq8w8u0 74A2J2MQX4hCSHf6/hMjLfxdeJNnw0zlcMV2l08YkIA/gSronsv+vfYrZ66lv8cv 6aHAzL6G4/EAp4BJ7TnTaFUmjfrdH/Z0TN4lTPeJs9/wv7+L176GnD8j5K/9I4SF
dMKArq1xk4IYKiGx0QIDAQAB
-----END PUBLIC KEY-----
为了查看各种组件的更多细节,例如加密过程中使用的模数、质数或生成的私钥的指数和系数,可以使用以下命令(此处仅显示部分输出,因为实际输出很长):
$ openssl rsa -text -in privatekey.pem
Private-Key: (1024 bit)
modulus:
00:a2:4e:14:1c:cf:cb:6b:ce:77:a7:a6:06:4f:d4:
1a:bc:c3:cb:b4:ef:80:36:27:63:10:5f:88:42:48:
77:fa:fe:13:23:2d:fc:5d:78:93:67:c3:4c:e5:70:
c5:76:97:4f:18:90:80:3f:81:2a:e8:9e:cb:fe:bd:
f6:2b:67:ae:a5:bf:c7:2f:e9:a1:c0:cc:be:86:e3:
f1:00:a7:80:49:ed:39:d3:68:55:26:8d:fa:dd:1f:
f6:74:4c:de:25:4c:f7:89:b3:df:f0:bf:bf:8b:d7:
be:86:9c:3f:23:e4:af:fd:23:84:85:74:c2:80:ae:
ad:71:93:82:18:2a:21:b1:d1
publicExponent: 65537 (0x10001)
privateExponent:
00:94:1d:ec:fc:de:25:26:1d:25:d5:39:0e:49:8b:
a7:5a:dc:d3:ea:2b:27:36:44:7b:83:55:ab:63:d1:
fe:ac:6f:71:c7:89:0f:e5:bd:43:c8:4d:d2:bf:10:
4b:24:0e:b1:80:19:5e:f0:95:50:33:39:b7:b0:a2:
6b:24:f1:59:cf:34:f9:34:d3:67:ba:00:b1:6a:2a:
f1:70:5d:66:3f:32:40:3f:76:aa:a5:c4:a3:c4:aa:
53:bf:8a:a0:a9:87:af:c2:05:b5:03:44:77:c4:a4:
19:cc:12:94:f9:b4:ce:da:15:d5:0f:5a:07:c6:ee:
f9:98:36:37:c4:2c:2a:48:01
prime1:
00:d4:61:5d:38:c0:d4:84:8c:4c:bd:b5:82:74:cd:
aa:f2:0c:07:2f:77:f5:46:db:f5:3f:ea:a8:90:19:
a8:c1:79:2a:52:aa:81:04:4a:28:1b:ba:c2:a4:bb:
ec:15:b5:16:20:59:61:28:98:bf:d7:e7:cb:7e:2b:
4d:5e:30:c6:59
prime2:
00:c3:a3:d4:47:d6:0b:79:bb:26:fd:28:e2:88:e4:
a1:57:80:0a:b8:57:62:ee:de:c3:61:61:39:52:56:
f5:ba:a3:ff:8b:6f:33:37:fc:ad:b7:80:57:28:8b:
3f:29:c1:72:91:01:9e:00:2e:8b:0c:76:72:c9:cc:
9c:9e:d0:c8:39
探索公钥
类似地,可以使用以下命令研究公钥。公钥和私钥是 base64 编码的:
$ openssl pkey -in publickey.pem -pubin -text
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCiThQcz8trznenpgZP1Bq8w8u0 74A2J2MQX4hCSHf6/hMjLfxdeJNnw0zlcMV2l08YkIA/gSronsv+vfYrZ66lv8cv 6aHAzL6G4/EAp4BJ7TnTaFUmjfrdH/Z0TN4lTPeJs9/wv7+L176GnD8j5K/9I4SF
dMKArq1xk4IYKiGx0QIDAQAB
-----END PUBLIC KEY-----
Public-Key: (1024 bit)
Modulus:
00:a2:4e:14:1c:cf:cb:6b:ce:77:a7:a6:06:4f:d4:
1a:bc:c3:cb:b4:ef:80:36:27:63:10:5f:88:42:48:
77:fa:fe:13:23:2d:fc:5d:78:93:67:c3:4c:e5:70:
c5:76:97:4f:18:90:80:3f:81:2a:e8:9e:cb:fe:bd:
f6:2b:67:ae:a5:bf:c7:2f:e9:a1:c0:cc:be:86:e3:
f1:00:a7:80:49:ed:39:d3:68:55:26:8d:fa:dd:1f:
f6:74:4c:de:25:4c:f7:89:b3:df:f0:bf:bf:8b:d7:
be:86:9c:3f:23:e4:af:fd:23:84:85:74:c2:80:ae:
ad:71:93:82:18:2a:21:b1:d1
Exponent: 65537 (0x10001)
现在公钥可以公开共享,任何想给你发消息的人都可以用公钥加密消息发给你。然后,您可以使用相应的私钥来解密该文件。
加密和解密
在本节中,我们将展示一个示例,演示如何使用 RSA 和 OpenSSL 来执行加密和解密操作。
加密
以前一个例子中生成的私钥为例,加密文本文件message.txt
的命令可以如下所示构造:
$ echo datatoencrypt > message.txt
$ openssl rsautl -encrypt -inkey publickey.pem -pubin -in message.txt \
-out message.rsa
这将产生一个名为message.rsa
的文件,它是二进制格式的。如果您在 nano 编辑器或您选择的任何其他文本编辑器中打开message.rsa
,它将显示一些垃圾,如以下截图所示:
message.rsa 显示垃圾(加密)数据
[通信]解密
为了解密 RSA 加密的文件,可以使用以下命令:
$ openssl rsautl -decrypt -inkey privatekey.pem -in message.rsa \
-out message.dec
现在,如果使用cat
读取文件,可以看到解密的明文,如下所示:
$ cat message.dec
datatoencrypt
使用 OpenSSL 的 ECC
OpenSSL 提供了非常丰富的函数库来执行 ECC。以下小节展示了如何在 OpenSSL 中以实用的方式使用 ECC 函数。
ECC 私钥和公钥对
在这一小节中,首先给出一个示例,演示如何使用 OpenSSL 库中可用的 ECC 函数创建私钥。
私人密钥
ECC 基于由各种标准定义的域参数。您可以使用以下命令查看 OpenSSL 中所有可用的标准定义和推荐曲线的列表。(同样,这里只显示了部分输出,并且在中间被截断。):
$ openssl ecparam -list_curves
secp112r1 : SECG/WTLS curve over a 112 bit prime field
secp112r2 : SECG curve over a 112 bit prime field
secp128r1 : SECG curve over a 128 bit prime field
secp128r2 : SECG curve over a 128 bit prime field
secp160k1 : SECG curve over a 160 bit prime field
secp160r1 : SECG curve over a 160 bit prime field
secp160r2 : SECG/WTLS curve over a 160 bit prime field
secp192k1 : SECG curve over a 192 bit prime field
secp224k1 : SECG curve over a 224 bit prime field
secp224r1 : NIST/SECG curve over a 224 bit prime field
secp256k1 : SECG curve over a 256 bit prime field
secp384r1 : NIST/SECG curve over a 384 bit prime field
secp521r1 : NIST/SECG curve over a 521 bit prime field
prime192v1: NIST/X9.62/SECG curve over a 192 bit prime field
.
.
.
.
brainpoolP384r1: RFC 5639 curve over a 384 bit prime field
brainpoolP384t1: RFC 5639 curve over a 384 bit prime field
brainpoolP512r1: RFC 5639 curve over a 512 bit prime field
brainpoolP512t1: RFC 5639 curve over a 512 bit prime field
在以下示例中,secp256k1
用于演示 ECC 的用法。
私钥生成
要生成私钥,请执行以下命令:
$ openssl ecparam -name secp256k1 -genkey -noout -out ec-privatekey.pem
$ cat ec-privatekey.pem
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIJHUIm9NZAgfpUrSxUk/iINq1ghM/ewn/RLNreuR52h/oAcGBSuBBAAK oUQDQgAE0G33mCZ4PKbg5EtwQjk6ucv9Qc9DTr8JdcGXYGxHdzr0Jt1NInaYE0GG
ChFMT5pK+wfvSLkYl5ul0oczwWKjng==
-----END EC PRIVATE KEY-----
名为ec-privatekey.pem
的文件现在包含了基于secp256k1
曲线生成的椭圆曲线 ( EC )私钥。为了从私钥生成公钥,发出以下命令:
$ openssl ec -in ec-privatekey.pem -pubout -out ec-pubkey.pem
read EC key
writing EC key
读取该文件会产生以下输出,显示生成的公钥:
$ cat ec-pubkey.pem
-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE0G33mCZ4PKbg5EtwQjk6ucv9Qc9DTr8J
dcGXYGxHdzr0Jt1NInaYE0GGChFMT5pK+wfvSLkYl5ul0oczwWKjng==
-----END PUBLIC KEY-----
现在,ec-pubkey.pem
文件包含了从ec-privatekey.pem
得到的公钥。可以使用以下命令进一步研究私钥:
$ openssl ec -in ec-privatekey.pem -text -noout
read EC key
Private-Key: (256 bit)
priv:
00:91:d4:22:6f:4d:64:08:1f:a5:4a:d2:c5:49:3f:
88:83:6a:d6:08:4c:fd:ec:27:fd:12:cd:ad:eb:91:
e7:68:7f
pub:
04:d0:6d:f7:98:26:78:3c:a6:e0:e4:4b:70:42:39:
3a:b9:cb:fd:41:cf:43:4e:bf:09:75:c1:97:60:6c:
47:77:3a:f4:26:dd:4d:22:76:98:13:41:86:0a:11:
4c:4f:9a:4a:fb:07:ef:48:b9:18:97:9b:a5:d2:87:
33:c1:62:a3:9e
ASN1 OID: secp256k1
类似地,可以使用以下命令进一步研究公钥:
$ openssl ec -in ec-pubkey.pem -pubin -text -noout
read EC key
Private-Key: (256 bit)
pub:
04:d0:6d:f7:98:26:78:3c:a6:e0:e4:4b:70:42:39:
3a:b9:cb:fd:41:cf:43:4e:bf:09:75:c1:97:60:6c:
47:77:3a:f4:26:dd:4d:22:76:98:13:41:86:0a:11:
4c:4f:9a:4a:fb:07:ef:48:b9:18:97:9b:a5:d2:87:
33:c1:62:a3:9e
ASN1 OID: secp256k1
也可以生成一个包含所需参数的文件,在本例中为secp256k1
,然后进一步研究它以理解底层参数:
$ openssl ecparam -name secp256k1 -out secp256k1.pem
$ cat secp256k1.pem
-----BEGIN EC PARAMETERS-----
BgUrgQQACg==
-----END EC PARAMETERS-----
该文件现在包含所有的secp256k1
参数,可以使用以下命令对其进行分析:
$ openssl ecparam -in secp256k1.pem -text -param_enc explicit -noout
该命令将产生类似如下所示的输出:
Field Type: prime-field
Prime:
00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:
ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:fe:ff:
ff:fc:2f
A: 0
B: 7 (0x7)
Generator (uncompressed):
04:79:be:66:7e:f9:dc:bb:ac:55:a0:62:95:ce:87:
0b:07:02:9b:fc:db:2d:ce:28:d9:59:f2:81:5b:16:
f8:17:98:48:3a:da:77:26:a3:c4:65:5d:a4:fb:fc:
0e:11:08:a8:fd:17:b4:48:a6:85:54:19:9c:47:d0:
8f:fb:10:d4:b8
Order:
00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:
ff:fe:ba:ae:dc:e6:af:48:a0:3b:bf:d2:5e:8c:d0:
36:41:41
Cofactor: 1 (0x1)
前面的例子显示了使用的质数和A
和B
的值,以及secp256k1
曲线域参数的生成器、阶数和余因子。
有了前面的例子,我们从加密和解密的角度对公钥加密的介绍就完成了。其他相关的构造,如数字签名,将在本章后面讨论。
在下一节中,我们将研究另一类密码原语,散列函数。哈希函数不用于加密数据;相反,它们生成固定长度的数据摘要,作为哈希函数的输入。
哈希函数
散列函数用于创建任意长度输入字符串的固定长度摘要。哈希函数是无密钥的,它们提供数据完整性服务。它们通常使用迭代和专用散列函数构造技术来构建。
有各种散列函数,如 MD、SHA-1、SHA-2、SHA-3、RIPEMD 和 Whirlpool。哈希函数常用于数字签名和消息认证码(MAC),比如 HMACs。它们有三个安全属性,即抗原像性、抗第二原像性和抗碰撞性。这些属性将在本节稍后解释。
哈希函数通常也用于提供数据完整性服务。这些既可用作单向函数,也可用于构造其他加密原语,如 MAC 和数字签名。一些应用程序使用哈希函数作为生成伪随机数生成器 ( PRNGs )的手段。根据所需的完整性级别,必须满足散列函数的两个实用属性和三个安全属性。这些属性将在以下小节中讨论。
将任意消息压缩成固定长度的摘要
该属性与这样一个事实相关,即散列函数必须能够接受任意长度的输入文本,并输出固定长度的压缩消息。散列函数产生各种比特大小的压缩输出,通常在 128 比特和 512 比特之间。
易于计算
哈希函数是高效快速的单向函数。无论消息大小如何,散列函数的计算速度都必须非常快。如果消息太大,效率可能会降低,但对于实际应用来说,该功能应该足够快。
在下一节中,将讨论哈希函数的安全属性。
原像电阻
这一特性可以用如下所示的简单等式来解释:
h(x) = y
这里, h 是哈希函数, x 是输入, y 是哈希。第一个安全属性要求 y 不能反算为 x 。 x 被认为是 y 的原像,因此得名原像抗性。这也称为单向属性。
第二原像电阻
秒原像抗性属性要求给定 x 和 h(x) ,几乎不可能找到任何其他消息 m ,其中 m!= x 和 m 的hash = x 的 hash或 h(m) = h(x) 。这种特性也被称为抗碰撞能力弱。
耐碰撞性
抗冲突性属性要求两个不同的输入消息不应该散列到同一个输出。换句话说, h(x)!= h(z) 。这种特性也被称为抗碰撞能力强。
所有这些属性都显示在下图中:
哈希函数的三个安全属性
由于它们的本质,哈希函数总是会有一些冲突。这是两个不同的消息散列到同一输出的地方。然而,要找到它们在计算上应该是不切实际的。一个被称为雪崩效应的概念在所有哈希函数中都是可取的。雪崩效应表明,输入文本中的微小变化,甚至是单个字符的变化,都会导致完全不同的哈希输出。
哈希函数通常是按照迭代哈希函数方法设计的。使用这种方法,输入消息在逐块的基础上进行多轮压缩,以产生压缩的输出。一种流行的迭代散列函数是 Merkle-Damgard 构造。这种构造基于将输入数据划分成相等大小的块,然后以迭代方式通过压缩函数馈送它们的思想。压缩函数的属性的抗冲突性确保散列输出也是抗冲突的。压缩函数可以使用分组密码来构建。除了 Merkle-Damgard,研究人员还提出了各种其他的压缩函数构造,例如 Miyaguchi-Preneel 和 Davies-Meyer。
以下小节将介绍多种类型的哈希函数。
消息摘要
消息摘要 ( MD )功能盛行于 20 世纪 90 年代初。MD4 和 MD5 就属于这一类。两个 MD 函数都不安全,不推荐再使用。MD5 是一种 128 位哈希函数,通常用于文件完整性检查。
安全哈希算法
下面的列表描述了最常见的安全哈希算法 ( SHAs ):
- SHA-0 :这是 NIST 在 1993 年推出的 160 位函数。
- SHA-1:SHA-1 是 NIST 在 1995 年引进的,作为 SHA-0 的替代品。这也是一个 160 位的哈希函数。SHA-1 通常用于 SSL 和 TLS 实现中。应该注意的是,SHA-1 现在被认为是不安全的,并且被证书颁发机构否决。不鼓励在任何新的实现中使用它。
-
SHA-2 :这一类包括由哈希的位数定义的四个函数:SHA-224、SHA-256、SHA-384 和 SHA-512。
-
SHA-3 :这是 SHA 函数的最新家族。SHA-3-224、SHA-3-256、SHA-3-384 和 SHA-3-512 都是该系列的成员。SHA-3 是 Keccak 的 NIST 标准化版本。凯克使用了一种叫做海绵构造的新方法,而不是常用的 Merkle-Damgard 变换。
- RIPEMD : RIPEMD 是的缩写。它基于用于构建 MD4 的设计思想。RIPEMD 有多个版本,包括 128 位、160 位、256 位和 320 位。
- 惠而浦:这是基于 Rijndael 密码的修改版本,称为 W 。它使用 Miyaguchi-Preneel 压缩函数,这是一种单向函数,用于将两个固定长度的输入压缩为一个固定长度的输出。这是一个单块长度压缩函数。
散列函数有许多实际应用,从简单的文件完整性检查和密码存储到用于加密协议和算法。它们用于哈希表、分布式哈希表、布隆过滤器、病毒指纹、对等文件共享和许多其他应用程序。
哈希函数在区块链中起着至关重要的作用。特别地,PoW 函数特别使用 SHA-256 两次,以便验证矿工所花费的计算努力。RIPEMD 160 用于产生比特币地址。这将在后面的章节中进一步讨论。
下一节将介绍 SHA 算法的设计。
安全哈希算法的设计
在下一节中,将向您介绍 SHA-256 和 SHA-3 的设计。这两者分别用于比特币和以太坊。以太坊没有使用 NIST 标准 SHA-3,而是 Keccak,这是提交给 NIST 的原始算法。NIST 在做了一些修改之后,比如增加了循环次数和简化了消息填充,将 Keccak 标准化为 SHA-3。
SHA-256 的设计
SHA-256 的输入消息大小为 64 位。块大小为 512 位,字长为 32 位。输出是 256 位摘要。
压缩功能处理 512 位消息块和 256 位中间哈希值。这个函数有两个主要部分:压缩函数和消息调度。
该算法的工作原理如下,分为八个步骤:
-
预处理:
-
哈希计算:
一轮阿沙-256 压缩函数
在上图中, a , b , c , d , e , f , g , h 为寄存器。 Maj 和 Ch 按位应用。 ∑ 0 与 ∑ 1 进行逐位旋转。回合常数为WjT31】和KjT35】,相加,mod 232T39】。****
沙-3 的设计
沙-3 的结构与 SHA-1 和 SHA-2 的非常不同。SHA-3 背后的关键思想是基于无密钥排列,而不是使用密钥排列的其他典型散列函数构造。Keccak 也没有利用 Merkle-Damgard 转换,这种转换通常用于在散列函数中处理任意长度的输入消息。Keccak 采用了一种叫做海绵和挤压结构的新方法。这是一个随机排列模型。SHA-3 的不同变体已经被标准化,例如 SHA-3-224、SHA-3-256、SHA-3-384、SHA-3-512、SHAKE-128 和 SHAKE-256。SHAKE-128 和 SHAKE-256 是可扩展输出功能 ( XOFs ),也是 NIST 标准化的。XOFs 允许输出扩展至任何所需长度。
下图显示了海绵和挤压模型,这是 SHA-3 或 Keccak 的基础。类似于海绵,数据首先在应用填充后被吸收到海绵中。在那里,使用 XOR 将其变为置换状态的子集,然后从表示转换状态的海绵函数中挤出输出。速率是海绵函数的输入块大小,而容量决定了一般的安全级别:
SHA-3 吸挤功能
散列函数的 OpenSSL 示例
以下命令将使用 SHA-256 算法产生 256 位的Hello
消息的散列:
$ echo -n 'Hello' | openssl dgst -sha256
(stdin)= 185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969
请注意,即使是文本中很小的变化,比如改变字母H
的大小写,也会导致输出散列值的很大变化。如前所述,这就是所谓的雪崩效应:
$ echo -n 'hello' | openssl dgst -sha256
(stdin)= 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
请注意,两种输出完全不同:
Hello:
18:5f:8d:b3:22:71:fe:25:f5:61:a6:fc:93:8b:2e:26:43:06:ec:30:4e:da:51:80:07:
d1:76:48:26:38:19:69
hello:
2c:f2:4d:ba:5f:b0:a3:0e:26:e8:3b:2a:c5:b9:e2:9e:1b:16:1e:5c:1f:a7:42:5e:73:
04:33:62:93:8b:98:24
通常,哈希函数不使用键。然而,如果它们与一个密钥一起使用,那么它们可以被用来创建另一个称为 MACs 的密码结构。
消息认证码
MAC 有时被称为键控散列函数,它们可以用来提供消息完整性和认证。更具体地说,它们用于提供数据源认证。这些是对称加密原语,在发送方和接收方之间使用共享密钥。MAC 可以使用分组密码或散列函数来构造。
使用分组密码的 MAC
通过这种方法,在密码块链接 ( CBC )模式中使用块密码,以便生成 MAC。可以使用任何分组密码,例如 CBC 模式下的 AES。消息的 MAC 实际上是最后一轮 CBC 操作的输出。MAC 输出的长度与用于生成 MAC 的分组密码的分组长度相同。
通过计算消息的 MAC 并将其与接收到的 MAC 进行比较,可以简单地验证 MAC。如果它们相同,则确认消息完整性;否则,该消息被视为已被更改。还应该注意,MAC 的工作方式类似于数字签名,但是由于它们的对称特性,它们不能提供不可否认服务。
基于散列的 MAC
与哈希函数类似,基于哈希的 MAC(hmac)产生固定长度的输出,并接受任意长的消息作为输入。在这个方案中,发送方使用 MAC 对消息进行签名,接收方使用共享密钥对其进行验证。使用被称为秘密前缀或秘密后缀的两种方法中的任何一种,密钥与消息一起被散列。使用秘密前缀方法,密钥与消息连接在一起;也就是说,先有密钥,后有消息,而使用秘密后缀方法时,密钥在消息之后,如下式所示:
秘密前缀:M = MACk(x) = h(k||x)
秘密后缀:M=MACk(x) = h(x||k)
这两种方法各有利弊。这两个计划都遭到了一些攻击。存在使用各种技术的 HMAC 构造方案,例如密码研究人员已经提出的 ipad 和 opad (内部填充和外部填充)。在某些假设下,这些被认为是安全的:
MAC 功能的操作
在对等网络和区块链技术中使用散列函数有各种强大的应用。一些值得注意的例子,如 Merkle 树、Patricia 树和分布式哈希表 ( DHT ),将在下面的小节中讨论。
Merkle 树
Merkle 树的概念是由 Ralph Merkle 提出的。这里显示了 Merkle 树的示意图。Merkle 树能够安全有效地验证大型数据集。
Merkle 树
Merkle 树是一种二叉树,其中输入首先被放置在叶子(没有子节点的节点),然后子节点对的值被散列在一起以产生父节点(内部节点)的值,直到获得被称为 Merkle root 的单个散列值。
帕特丽夏树
为了理解 Patricia 树,你将首先被介绍到一个 trie 的概念。trie 或数字树是用于存储数据集的有序树数据结构。
检索以字母数字编码的信息的实用算法 ( 帕特里夏),也称为基数树,是一个 trie 的紧凑表示,其中作为父节点的唯一子节点与其父节点合并。
Merkle-Patricia 树,基于 Patricia 和 Merkle 的定义,是具有包含整个数据结构的散列值的根节点的树。
分布式哈希表
哈希表是一种用于将键映射到值的数据结构。在内部,哈希函数用于计算桶数组的索引,从中可以找到所需的值。存储桶使用哈希键存储记录,并按照特定的顺序组织。
记住前面提供的定义,我们可以将 DHT 看作一种数据结构,其中数据分布在不同的节点上,节点相当于对等网络中的桶。
下图显示了 DHT 的工作原理。数据通过哈希函数传递,然后生成一个压缩密钥。然后,该密钥与对等网络上的数据(值)相链接。当网络上的用户请求数据(通过文件名)时,可以再次散列文件名以产生相同的密钥,然后可以请求网络上的任何节点找到相应的数据。DHT 提供了去中心化、容错和可伸缩性:
分布式哈希表
散列函数的另一个应用是在数字签名中,它们可以与非对称加密结合使用。这一概念将在以下小节提供的示例中详细讨论。
数字签名
数字签名提供了一种将消息与发出该消息的实体相关联的方法。数字签名用于提供数据源认证和不可否认性。
区块链使用数字签名,发送方在将交易广播到网络之前,使用他们的私钥对交易进行数字签名。这种数字签名证明他们是资产的合法所有者,例如比特币。这些交易由网络上的其他节点再次验证,以确保资金确实属于声称是所有者的节点(用户)。我们将在本书专门讨论比特币和以太坊的章节中更详细地讨论这些概念。
数字签名分两步计算。例如,RSA 数字签名方案的高级步骤如下。
RSA 数字签名算法
下面是 RSA 数字签名算法:
- 计算数据包的哈希值:这将提供数据完整性保证,因为哈希值可以在接收端再次计算,并与原始哈希值匹配,以检查数据是否在传输过程中被修改。从技术上讲,消息签名可以在不首先散列数据的情况下工作,但是不被认为是安全的。
- 用签名人的私钥对哈希值进行签名:由于只有签名人拥有私钥,所以保证了签名和签名数据的真实性。
数字签名有一些重要的属性,如真实性、不可伪造性和不可重用性。真实性意味着数字签名可被接收方验证。不可伪造性属性确保只有消息的发送者可以使用私钥来使用签名功能。换句话说,其他任何人都不能生成由合法发送者生成的签名消息。不可重用性意味着数字签名不能从一条消息中分离出来并再次用于另一条消息。
下图显示了通用数字签名功能的操作:
数字签名(左)和验证流程(右)(RSA 数字签名示例)
如果发送者想要发送一个经过验证的消息给接收者,有两种方法可以使用:签名然后加密和加密然后签名。使用加密数字签名的两种方法如下。
签名然后加密
使用这种方法,发送方使用私钥对数据进行数字签名,将签名附加到数据上,然后使用接收方的公钥对数据和数字签名进行加密。与下面描述的加密然后签名方案相比,这被认为是更安全的方案。
加密然后签名
使用这种方法,发送方使用接收方的公钥加密数据,然后对加密的数据进行数字签名。
实际上,包含数字签名的数字证书是由一个认证机构 ( CA )发布的,它将一个公钥与一个身份相关联。
各种方案,例如 RSA、数字签名算法 ( DSA )和基于 ECDSA 的数字签名方案在实践中被使用。RSA 是最常用的;然而,在 ECC 的推动下,基于 ECDSA 的方案也变得非常流行。这在区块链是有益的,因为 ECC 提供了与 RSA 相同的安全级别,但是它使用更少的空间。此外,与 RSA 相比,ECC 中密钥的生成要快得多,因此它有助于提高系统的整体性能。下表显示 ECC 能够提供与基于 RSA 的系统相同级别的加密强度,但密钥大小更小:
| RSA 密钥大小(比特) | 椭圆曲线密钥大小(比特) | | 10 24 | 16 0 | | 20 48 | 22 four | | 30 seventy-two | 25 six | | 76 80 | 38 four | | 0 , 1536 | fifty-two one |
提供相同安全级别的 RSA 和椭圆曲线密钥大小的比较
ECDSA 方案将在以下小节中详细描述。
椭圆曲线数字签名算法
为了使用 ECDSA 方案进行签名和验证,需要生成第一个密钥对:
-
首先定义一条椭圆曲线 E :
-
随机选择一个整数 d ,使得 0 < d < q.
- 计算公钥 B 使得 B = d A.
公钥是六元组,如下所示:
Kpb = (p,A,B,q,A,B)
私钥 d 是在步骤 2 中随机选择的:
kpresenter = d
现在可以使用私钥和公钥生成签名。
- 首先选择一个短暂的密钥KeT3】,其中0<KeT13】q。应该确保 K e 是真正随机的,并且没有两个签名具有相同的密钥;否则,可以计算私钥。
- 使用 R = K e A 计算另一个值R;也就是说,通过将乘以(生成器点)和随机临时密钥。
- 用点 R 的 x 坐标值初始化变量 r ,使 r = xR 。
- 签名可以通过以下方式计算:
这里, m 是正在计算签名的消息, h(m) 是消息 m 的散列。
签名验证按照以下流程进行:
- 辅助值 w 计算为 w = s-1 mod q 。
- 辅助值 u1 = w. h(m) mod q 。
- 辅助值 u2 = w. r mod q 。
-
计算点 P , P = u1A + u2B 。
-
验证按如下方式进行:
如果步骤 4 中计算的点 P 的 x 坐标与签名参数 r mod q 的值相同,则 r , s 被接受为有效签名;那就是:
Xp = r mod q 表示有效签名
Xp!= r mod q 表示无效签名
在下面的小节中展示了各种实际例子,这些例子演示了如何使用 OpenSSL 生成、使用和验证 RSA 数字签名。
如何使用 OpenSSL 生成数字签名
第一步是生成消息文件的散列:
$ openssl dgst -sha256 message.txt
SHA256(message.txt)=
eb96d1f89812bf4967d9fb4ead128c3b787272b7be21dd2529278db1128d559c
哈希生成和签名都可以在一个步骤中完成,如此处所示。注意privatekey.pem
是在前面提供的步骤中生成的:
$ openssl dgst -sha256 -sign privatekey.pem -out signature.bin message.txt
现在,让我们显示显示相关文件的目录:
$ ls -ltr
total 36
-rw-rw-r-- 1 drequinox drequinox 14 Sep 21 05:54 message.txt
-rw-rw-r-- 1 drequinox drequinox 32 Sep 21 05:57 message.bin
-rw-rw-r-- 1 drequinox drequinox 45 Sep 21 06:00 message.b64
-rw-rw-r-- 1 drequinox drequinox 32 Sep 21 06:16 message.ptx
-rw-rw-r-- 1 drequinox drequinox 916 Sep 21 06:28 privatekey.pem
-rw-rw-r-- 1 drequinox drequinox 272 Sep 21 06:30 publickey.pem
-rw-rw-r-- 1 drequinox drequinox 128 Sep 21 06:43 message.rsa
-rw-rw-r-- 1 drequinox drequinox 14 Sep 21 06:49 message.dec
-rw-rw-r-- 1 drequinox drequinox 128 Sep 21 07:05 signature.bin
让我们通过执行以下命令来看看signature.bin
的内容:
$ cat signature.bin
执行该命令将产生以下输出:
为了验证签名,可以执行以下操作:
$ openssl dgst -sha256 -verify publickey.pem -signature \
signature.bin message.txt
Verified OK
同样,如果使用了其他无效的签名文件,验证将会失败,如下所示:
$ openssl dgst -sha256 -verify publickey.pem -signature someothersignature.bin message.txt
Verification Failure
接下来,给出一个示例,展示如何使用 OpenSSL 来执行与 ECDSA 相关的操作。
使用 OpenSSL 的 ECDSA
首先,使用以下命令生成私钥:
$ openssl ecparam -genkey -name secp256k1 -noout -out eccprivatekey.pem
$ cat eccprivatekey.pem
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIMVmyrnEDOs7SYxS/AbXoIwqZqJ+gND9Z2/nQyzcpaPBoAcGBSuBBAAK oUQDQgAEEKKS4E4+TATIeBX8o2J6PxKkjcoWrXPwNRo/k4Y/CZA4pXvlyTgH5LYm QbU0qUtPM7dAEzOsaoXmetqB+6cM+Q==
-----END EC PRIVATE KEY-----
接下来,从私钥生成公钥:
$ openssl ec -in eccprivatekey.pem -pubout -out eccpublickey.pem
read EC key
writing EC key
$ cat eccpublickey.pem
-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEEKKS4E4+TATIeBX8o2J6PxKkjcoWrXPw
NRo/k4Y/CZA4pXvlyTgH5LYmQbU0qUtPM7dAEzOsaoXmetqB+6cM+Q==
-----END PUBLIC KEY-----
现在,假设一个名为testsign.txt
的文件需要签名和验证。这可以通过以下方式实现:
- 创建测试文件:
$ echo testing > testsign.txt
$ cat testsign.txt
testing
- 运行以下命令,使用私钥为
testsign.txt
文件生成签名:
$ openssl dgst -ecdsa-with-SHA1 -sign eccprivatekey.pem \
testsign.txt > ecsign.bin
- 最后,验证命令可以如下所示运行:
$ openssl dgst -ecdsa-with-SHA1 -verify eccpublickey.pem \
-signature ecsign.bin testsign.txt
Verified OK
还可以使用之前通过以下命令生成的私钥来生成证书:
$ openssl req -new -key eccprivatekey.pem -x509 -nodes -days 365 \
-out ecccertificate.pem
该命令将产生类似于此处所示的输出。输入适当的参数以生成证书:
You are about to be asked to enter information that will be incorporated into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:GB
State or Province Name (full name) [Some-State]:Cambridge
Locality Name (eg, city) []:Cambridge
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Dr.Equinox! Organizational Unit Name (eg, section) []:NA
Common Name (e.g. server FQDN or YOUR name) []:drequinox
Email Address []:drequinox@drequinox.com
可以使用以下命令浏览该证书:
$ openssl x509 -in ecccertificate.pem -text -noout
以下输出显示了证书:
将 ECDSA 算法与 SHA-256 结合使用的 X509 证书
下面介绍的密码学主题是因为它们与区块链的相关性,或者它们在未来区块链生态系统中的潜在用途。
同态加密
通常公钥密码体制如 RSA 是乘法同态或加法同态,如 Paillier 密码体制,称为部分同态加密 ( PHE )系统。附加 phe 适用于电子投票和银行应用。
直到最近,还没有支持这两种操作的系统,但在 2009 年,一个全同态加密 ( FHE )系统被克雷格·金特里发现。由于这些方案能够在不需要解密的情况下处理加密数据,因此它们具有许多不同的潜在应用,特别是在需要维护隐私,但数据也必须由潜在的不可信方处理的情况下,例如云计算和在线搜索引擎。同态加密最近发展非常有前途,研究人员正在积极努力使其更有效和更实用。正如本书后面所描述的,这是区块链技术特别感兴趣的,因为它可以解决区块链的保密性和隐私性问题。
签密
签密是一个公钥加密原语,提供数字签名和加密的所有功能。郑玉良发明了签密,它现在是一个 ISO 标准,ISO/IEC 29150:2011。传统上,先签名后加密或先加密后签名方案用于提供不可伪造性、认证和不可否认性,但是使用签密,所有数字签名和加密服务的成本都低于先签名后加密方案。
签密在单个逻辑步骤中实现了成本(签名&加密)< <成本(签名)+成本(加密)。
零知识证明
零知识证明 ( ZKPs )是由 Goldwasser、Micali 和 Rackoff 在 1985 年提出的。这些证明用于证明一个断言的有效性,而不会透露关于该断言的任何信息。ZKPs 有三个必需的属性:完整性、可靠性和零知识属性。
完整性确保如果某个断言为真,那么验证者将被证明者说服。稳固性属性确保如果断言为假,那么没有不诚实的证明者能够说服验证者。零知识属性,顾名思义,是 ZKPs 的关键属性,由此确保除了断言是真还是假之外,绝对不会泄露关于断言的任何信息。
zkp 由于其隐私属性而在区块链空间的研究人员中引发了特殊的兴趣,这在金融和许多其他领域,包括法律和医学领域是非常可取的。最近一个成功实施 ZKP 机制的例子是 Zcash 加密货币。在 Zcash 中,实现了一种特定类型的 ZKP,称为知识的零知识简洁非交互论证(ZK-斯纳克)。这个会在第十章、备选币中详细讨论。
盲签名
David Chaum 在 1982 年引入了盲签名。它们基于公钥数字签名方案,如 RSA。盲签名背后的关键思想是让签名者对消息进行签名,而不实际暴露消息。这是通过在签名前伪装或隐藏消息来实现的,因此得名盲签名。然后,可以像普通的数字签名一样,对照原始消息来验证该盲签名。盲签名作为一种机制被引入,以允许数字现金方案的发展。
编码方案
除了密码原语,二进制到文本的编码方案也被用于各种场景。最常见的用途是将二进制数据转换为文本,以便可以通过不支持二进制数据处理的协议对其进行处理、保存或传输。例如,有时,图像以 base64 编码存储在数据库中,这允许文本字段能够存储图片。一种常用的编码方案是 base64。另一种名为 base58 的编码因其在比特币中的使用而流行起来。
密码学是一个广阔的领域,本节仅仅介绍了从总体上理解密码学,特别是从区块链和加密货币的角度理解密码学所必需的基本概念。在下一节中,将介绍基本的金融市场概念。
本节描述了与交易、交换和交易生命周期相关的一般术语。更详细的信息将在后面的章节中提供,其中讨论了具体的用例。
金融市场和交易
金融市场允许金融证券的交易,如债券、股票、衍生品和货币。大体上有三种类型的市场:货币市场、信贷市场和资本市场:
- 货币市场:这些是短期市场,资金借出给公司或银行进行银行间借贷。外汇或 FX 是货币交易的另一类货币市场。
- 信贷市场:主要由零售银行组成,他们从中央银行借钱,然后以抵押或贷款的形式借给公司或家庭。
- 资本市场(Capital markets):这些市场促进金融工具的买卖,主要是股票和债券。资本市场可以分为两种:一级市场和二级市场。公司在一级市场直接向投资者发行股票,而在二级市场,投资者通过证券交易所向其他投资者转售他们的证券。如今,交易所使用各种电子交易系统来促进金融工具的交易。
贸易
市场是各方进行交易的地方。它可以是物理位置,也可以是电子或虚拟位置。各种金融工具,包括股票、股票、外汇、商品和各种类型的衍生品都在这些市场进行交易。最近,许多金融机构引入了软件平台来交易来自不同资产类别的各种类型的工具。
交易可以定义为交易者买卖各种金融工具以产生利润和对冲风险的活动。投资者、借款者、对冲者、资产交换者和赌徒是交易者的几种类型。当交易者欠某样东西时,他们有一个空头头寸,换句话说,如果他们卖出了合同,他们有一个空头头寸,当他们买入合同时,他们有一个多头头寸。有各种各样的交易方式,例如通过经纪人或直接在交易所或柜台 ( OTC )买卖双方直接交易,而不是通过交易所。经纪人是为客户安排交易的代理人。经纪人代表客户以给定的价格或最好的价格进行交易。
交换
交易所通常被认为是一个非常安全、规范和可靠的交易场所。在过去的十年里,电子交易比传统的场内交易更受欢迎。现在,交易者将订单发送到中央电子订单簿,订单、价格和相关属性通过通信网络从该电子订单簿发布到所有相关系统,因此实质上创建了虚拟市场。交易所交易只能由交易所会员进行。为了不受这些限制进行交易,交易对手可以直接参与场外交易。
订单和订单属性
订单是交易的指令,是交易系统的主要组成部分。它们具有以下一般属性:
- 乐器名称
- 要交易的数量
- 方向(买入或卖出)
- 代表各种条件的订单类型,例如,限价订单和止损订单是在价格达到订单中指定的价格时买入或卖出的订单,例如,200 英镑的 Google 股票。限价订单允许以特定价格或高于订单中指定价格的价格买卖股票。例如,如果价格为 100 美元或更高,出售微软股票。
订单按买入价和卖出价进行交易。交易者通过在订单上附上买价和卖价来表明他们的买卖意图。交易者买入的价格被称为买入价。交易者愿意卖出的价格被称为卖出价。
订单管理和路由系统
订单路由系统根据业务逻辑将订单路由和交付到不同的目的地。客户用它们向经纪人发送订单,经纪人再将这些订单发送给交易商、清算所和交易所。
订单有不同的类型。最常见的两种是市价订单和限价订单。
市价单是以市场上目前可获得的最佳价格进行交易的指令。这些订单会立即以现货价格成交。另一方面,限价单是一种以最佳价格交易的指令,但前提是不低于交易者设定的限价。这也可以更高,取决于订单的方向:出售或购买。所有这些订单都在一个订单簿中管理,订单簿是由交易所维护的订单列表,它记录了交易者的买入或卖出意图。
头寸是以给定价格卖出或买入大量金融工具的承诺,包括证券、货币或商品。交易员买卖的合约、证券、商品和货币通常被称为交易工具,它们被归入资产类别的大伞下。最常见的类别是实物资产、金融资产、衍生合同和保险合同。
交易的组成部分
一张交易单是与交易相关的所有细节的组合。但是,根据工具类型和资产类别的不同,会有一些差异。这些元素将在以下小节中介绍。
基础工具
基础工具是交易的基础。它可以是货币、债券、利率、商品或股票。
金融工具的属性将在下一小节讨论。
一般属性
这包括与每笔交易相关的一般识别信息和基本特征。典型的属性包括唯一的 ID、工具名称、类型、状态、交易日期和时间。
经济学
经济学是与交易价值相关的特性,例如,买入或卖出价值、报价器、交易所、价格和数量。
销售
销售指与销售特征相关的详细信息,例如销售人员的姓名。它只是一个信息字段,通常对贸易生命周期没有任何影响。
对手方
交易对手是交易的重要组成部分,因为它显示了交易的另一方(交易中涉及的另一方),它需要成功结算交易。正常属性包括交易对手名称、地址、付款类型、任何参考 id、结算日期和交付类型。
贸易生命周期
一般的交易生命周期包括从下单到执行和结算的各个阶段。该生命周期的逐步描述如下:
- 预执行:此阶段下单。
- 执行和预订:当订单匹配并执行后,转换为交易。在这一阶段,交易对手之间的合同已经到期。
- 确认:这是交易双方同意交易细节的地方。
- 登记后:这一阶段涉及确定交易正确性所需的各种审查和验证过程。
- 结算:这是贸易生命周期中最重要的部分。在这个阶段,交易是最终的。
- 隔夜(日终处理):日终处理包括报表生成、损益计算、各种风险计算。
这个生命周期也显示在下面的截图中:
贸易生命周期
在上述所有流程中,涉及到许多人员和业务职能。最常见的是,这些功能分为前台、中台和后台等功能。
在下一节中,您将了解一些概念,这些概念对于理解管理金融行业的严格且必要的规则和条例是必不可少的。一些概念在这里描述,然后在后面的章节中讨论具体的用例时再描述。这些想法将帮助你理解所描述的场景。
订单预期
订单预期者试图在其他交易者进行交易之前获利。这是基于交易者的预期,他知道其他交易的交易活动会如何影响价格。领跑者、情绪导向的技术交易者和挤压者都是订单预期者的例子。
市场操纵
在许多国家,操纵市场绝对是非法的。欺诈交易者可以在市场上传播虚假信息,从而导致价格波动,从而非法牟取暴利。通常,操纵市场行为是基于交易的,它包括一般的和特定时间的操纵。这类行为可能造成人为的库存短缺、虚假活动的印象以及操纵价格以获取犯罪利益。
这里讨论的两个术语都与金融犯罪有关。然而,有可能开发基于区块链的系统,由于其透明性和安全性,可以阻止市场滥用。
摘要
本章一开始,我们介绍了非对称密钥加密技术。我们讨论了各种构造,如 RSA 和 ECC。我们还使用 OpenSSL 进行了一些实验,以了解理论概念如何在实践中实现。之后,我们详细讨论了散列函数及其属性和用法。接下来,我们讨论了一些概念,比如 Merkle 树,它在区块链被广泛使用,事实上,也是它的核心。我们还介绍了其他概念,如 Patricia 树和哈希表。