数字签名
基于对称密码系统和仲裁者的文件签名
这种方式顾名思义,就是基于信任一个有权、值得绝对信任的仲裁者Trent的签名方式,Trent和Alice共享私密密钥KA,和Bob共享私密密钥KB。这些密钥在协议开始前就建立好,并为了签名可以重复使用:
- Alice用KA加密她准备发给Bob的消息的声明,并发给Trent。
- Trent用KA解密消息。
- Trent把这个解密消息和收到的消息声明,一起用KB加密。
- Trent把这个加密的消息包发给Bob
- Bob用KB解密消息,这样他能读取到Alice发的消息和Trent的证书,证明消息来自Alice。
接下来根据签名需要的特点来分析这种方式的可靠性:
- **签名是可信的。**Trent是可信的,并且知道消息是从Alice那边发来的。Trent的证书对Bob起证明作用。
- 所以签名是不可伪造的。只有Alice知道KA(当然Trent也知道,但是大家都相信他),如果有人伪造,第2步Trent就会察觉。
- **签名不可被重复使用。**如果Bob想把Trent的证书附加到另一个消息上,Trent就会要求Bob同时提供消息和Alice加密后的消息,Bob没有KA,那肯定不能提供加密后的消息了。
- 签名不能被改变。理由和上面一样,Bob没有KA。
- 签名不能抵赖。Alice如果想抵赖,说他没有发那个消息,Trent的证书会说明她发了这个消息。
这个协议不是不可行,但是对于Trent来说很耗时。他必须在每一对人中间充当中间人,即使Trent只是个软件程序,这个耗时的操作也是通信的瓶颈。再者,这个协议整个都是基于相信Trent是绝对可靠的,如果Trent犯了一次错误,那么整个系统就不可信了,所有人签名都变得混乱。
使用公开密钥密码系统对文件签名
很好理解,就是用私钥加密,公钥解密,由于私钥是只有Alice自己持有的,所以只有她自己能签名,而所有人都能拥有Alice的公钥,所以所有人都能读取到这个签名,但是没办法伪造。
协议过程略。
这种方法不依赖Trent,省去了很多麻烦,所以比前面的好。
特点也很好理解:
- 可信的。因为用Alice的公钥能解开,所以可以取信是来自Alice的。
- 不可伪造。只有Alice有私钥,其他人都不能伪造。
- 不可被重复使用。签名是文件的函数,并且不可能转换成另外的文件。(*这个不太懂)
- 不能被改变。文件如果被改变,用Alice的公钥就不能验证。
- 不可抵赖。如果用Alice的公钥能解开,Alice就不能否认这个文件来自她,
文件签名和时间标记
比如数字签名的是一个银行支票,如果没有时间戳,Bob可以一直用这个带签名的支票去银行取钱。
所以数字签名经常包括时间标记。把时间日期附在消息中,然后一起签名这个消息。银行就把这个时间存在数据库中,Bob第二次去取的时候,银行就会发现对应时间的支出已经进行过了。
使用公开密钥密码系统和单向散列函数对文件签名
公开密钥密码算法本身效率没那么高,对长文件签名效率很低。为了节约时间,数字签名协议经常和单向散列函数一起使用。Alice不对文件签名,而是对文件的散列值签名。单向散列函数和数字签名算法事先商量好:
- Alice产生文件的散列值
- Alice用私钥加密散列值,实现对文件的签名。
- Alice把文件和签名的散列值发给Bob。
- Bob用Alice发送的文件产生散列值,再用Alice的公钥解密已签名的散列值,进行对比,确认文件来自Alice。
这样计算速度大大提高。两个文件有相同160位散列值的可能性为1/2160。但是如果用非单向的散列函数,就很容易产生多个文件散列值相同。
多重签名
比如Alice和Bob都要对一个文件签名,然后给Carol,如果不用单向散列的话,有两种方法:
- Alice和Bob分别对文件副本签名,结果就是签名消息是原文的两倍,太浪费空间了
- Alice先签名,Bob再对Alice的签名再签名,结果就是Carol要验证Alice的签名,必须先验证Bob的签名,太浪费时间了。
如果用单向散列函数,就容易多了:
- Alice对文件散列签名
- Bob对文件散列签名
- Bob把他的签名交给Alice
- Alice把文件、她的签名和Bob的签名一起交给Carol
- Carol验证
这样又节约空间,又节约时间。
抗抵赖和数字签名
这里有一个抵赖的可能性:
Alice故意把自己的私钥泄露,这样任何人都可以伪装成Alice签名,Alice就可以抵赖说以前某些签名不是自己签的,即使加上时间戳,她也可以声称自己的私钥在更早的时间就泄露了。
这里有一个通用的协议:
- Alice对消息签名
- Alice产生一个报头,报头中含有一些鉴别消息。把报头和签名的消息连接起来,再对连接起来的消息签名,然后把签名发给Trent(*疑惑:为什么又有Trent了,之前不是讨论Trent参与每次会话的方案比较费时吗?)。
- Trent验证外面的签名,并确认鉴别消息。他在Alice 签名消息中增加一个时间标记和鉴别消息。然后对所有的消息再签名,分别发给Alice和Bob
- Bob验证
- Alice验证,如果这个消息她没有发,应该会大喊大叫。
带加密的数字签名
这个其实就是公开密钥密码系统通信和数字签名结合起来,在数字签名外面再套一层公开密钥密码系统通信,也就是把数字签名用公开密钥密码系统来传递:
Alice用自己的私钥签名,再用Bob的公钥加密 : EB(DA(M))
Bob用自己的私钥解密,然后在用Alice的公钥验证签名 E(ADB(EB(DA(M)))) = M
重新发送消息作为收据
比如有以下这种场景:
Bob在接收了Alice发送的消息后,需要向Alice确认自己已经收到了消息,那么除了上述的过程还有这么一个过程:
Bob在收到消息得到明文后,用自己的私钥签字,然后用Alice的公钥加密,再发给Alice;
Alice拿到后,用自己的私钥解密,然后用Bob的公钥验证Bob的签名;
如果Alice接收到的消息和她传给Bob的相同,她就知道Bob准确接收到了自己的消息。
这样一个过程,同样的算法既用作加密又用作解密,就有可能被攻击。数字签名操作是加密操作的逆操作:
VX=EX and SX = DX —— S-签名 V-验证
现在有一个Mallory是持有自己的公钥和私钥的系统合法用户,想要窃取明文M:
-
Mallory把Alice在第一步中发的消息记录下来,在某个时间发给Bob
-
Bob收到消息后,以为是Mallory发过来的合法消息,于是就用自己的私人密钥解密,然后用Mallory的公钥来验证,得到这样一堆乱七八糟的东西:
EM(DB(EB(DA(M)))) = EM(DA(M)) = MASS
-
Bob继续执行协议,把按上面处理再发回去:
EM(DB(MASS)) = EM(DB(EM(DA(M))))
-
这样Mallory拿到消息后,用自己的私钥解密,再用Bob的公钥加密,再用自己的私钥解密,就会得到DA(M),然后他再用Alice的公钥加密,这样他就得到明文M了
这个攻击流程之所以能成,是因为Bob在不知情的情况下用自己的私钥帮Mallory解密了。
阻止重新发送攻击
上述攻击能成的根本原因是签名和加密用的同一套算法,加密运算与签名/验证运算相同,解密运算和签名运算相同。解决方法也很好理解
- 加上时间戳,这样不至于每次消息内容都相同
- 单向散列函数也可以解决这个问题
- 加密和签名不用同一套算法
对公开密钥密码系统的攻击
针对公开密钥密码系统,公钥的保存是个极其重要的问题。比如把公钥存在一个数据库中,这个数据库所有人都可以从里面得到数据,但是也必须阻止除了Trent以外的人写入数据。否则Mallory就可以篡改数据,比如把Bob的公钥换成自己的,这样Bob读不到发给自己的数据,而Mallory可以。
阻止上述情况的方法是Trent用自己的私钥把所有公钥加密一遍,这时候Trent一般称为密钥鉴定机关或密钥分配中心(KDC),这样当Alice得到Bob的公钥的时候,用KDC验证一遍,以确认来源可靠。
但是这样,Mallory还是有办法,比如可以把自己的公钥替代那个密钥,然后破坏数据库,用自己的密钥替代有效密钥(就好像他自己是KDC一样)。