我们需要数字签名
之前的文章我们讲了MAC(Message Authentication Code)消息认证码,MAC是认证消息的完整性的技术。它是由任意长度的消息和在发送者和接受者中间共享的密钥生成的。
MAC有个缺点就是秘钥是共享的,因为是共享的所以发送者可以计算MAC值,接收者也可以计算出同样的MAC值。因为两者都可以计算出同样的MAC值,所以我们无法判断这个MAC值到底是由谁来计算出来的。这里提到了MAC的缺点就是无法防止否认。
如果发送者A和接收者B使用不同的密钥,例如A发送消息的时候使用私钥对消息进行加密,B接收消息的时候使用公钥对消息进行解密。因为消息只能由A的私钥进行加密,所以这个签名一定是由A签发的,这样就没有否认的问题了。这个就是数字签名(digital signature)。
签名的生成和验证
生成消息签名这一行为是由发送者A来完成的,也称为对消息进行签名。生成签名就是根据消息内容计算签名值,生成签名意味着A认可这个消息的内容。
验证数字签名可以由消息接受者B来完成,也可以由第三方来完成。验证成功意味着这个消息是由A发出,失败则表示这个消息不是A发出的。
在数字签名的过程中,消息发送者A和消息接受者B使用不同的密钥来进行签名和验证。这里使用的不同的密钥就是公钥和私钥。
数字签名其实就是公钥密码的反向应用,下面我们看看两种的不同:
名称 | 私钥 | 公钥 |
---|---|---|
公钥密码 | 接受者解密时使用 | 发送者加密时使用 |
数字签名 | 签名者生成签名时使用 | 验证者验证签名时使用 |
谁持有密钥? | 个人持有 | 主要需要,任何人都可以持有 |
数字签名的方法
通常来说数字签名一般有两种方式:
- 直接对消息进行签名
- 对消息的hash值进行签名
下面我们分别来介绍两种方式。
直接对消息进行签名
直接对消息签名包含如下几个步骤:
- 发送者A用自己的私钥对消息进行加密生成签名。
- A将加密后的签名和消息发送给B。
- B用A的公钥对消息签名进行解密,从而得到签名之前的消息M1。
- B将M1和A直接发送过来的消息M2进行对比,两者一致则签名成功,否则失败。
这里我们注意一下第四个步骤,签名的目的是保证消息是由只持有该密钥的人生成的,而并不是要保证消息传递的机密性。也就是说数字签名本身并不是用来保证机密性的。如果要保证机密性则可以将消息加密之后再发出去。
对消息的hash值进行签名
上面的直接对消息进行签名,看起来非常简单,但是在实际应用中很少用到。因为要对整个消息进行签名时一个非常耗时的操作,所以通常我们会使用单向散列函数对消息进行处理得出一个hash值,然后对这个hash值进行签名:
- A用单向散列函数对消息进行计算hash值。
- A用自己的私钥对hash值进行签名。
- A将消息和签名发给B
- B用A的公钥对签名进行解密得到hash值。
- B使用单向散列函数对消息进行计算,将结果和4进行比对。
数字签名可以替代现实生活中的签名吗?
我们讲解了怎么实现数字签名,我们也可能听说在现实生活中有电子签名这个东西。
数字签名有很多技术上的优点,不需要物理交互就可以签订合同,并可以对任何数据进行签名。那么在实际上数字签名能不能替代实际签名的问题是一个复杂的社会行为。
因为我们在使用电子签的时候,没有人会亲自去设计签名算法,而是简单的根据软件提供的信息按下签名按钮。
那么这个签名软件是否值得信任,就是我们需要关注的问题。
数字签名无法解决的问题
使用数字签名我们可以防止伪造和篡改,也无法防止否认。但是还需要一个大前提就是验证签名的公钥必须是真正属于发送者。
这里我们就需要一个可信任的机构来为我们颁发可信任的公钥,这里就涉及到证书和PKI的知识了。我们将会在后面的文章中讲到。
更多精彩内容且看:
- 区块链从入门到放弃系列教程-涵盖密码学,超级账本,以太坊,Libra,比特币等持续更新
- Spring Boot 2.X系列教程:七天从无到有掌握Spring Boot-持续更新
- Spring 5.X系列教程:满足你对Spring5的一切想象-持续更新
- java程序员从小工到专家成神之路(2020版)-持续更新中,附详细文章教程