数字签名是一种将相当于现实世界中的盖章、签字的功能在计算机世界中进行实现的技术。使用数字签名可以识别篡改和伪装,还可以防止否认。
通过消息认证码,我们可以识别消息是否被篡改或者发送者身份是否被伪装,也就是可以校验消息的完整性,还可以对消息进行认证。然而,在出具借条的场景中却无法使用消息认证码,因为消息认证码无法防止否认。
消息认证码之所以无法防止否认,是因为消息认证码需要在发送者Alice和接收者Bob两者之间共享同一个密钥。正是因为密钥是共享的,所以能够使用消息认证码计算出正确MAC值的并不只有发送者Alice,接收者Bob也可以计算出正确的MAC值。由于Alice和Bob双方都能够计算出正确的MAC值,因此对于第三方来说,我们无法证明这条消息的确是由Alice生成的。
我们假设Alice使用的密钥是一个只有Alice自己才知道的私钥。当Alice发送消息时,她用私钥生成一个“签名”。相对地,接收者Bob则使用一个和Alice不同的密钥对签名进行验证。使用Bob的密钥无法根据消息生成签名,但是用Bob的密钥却可以对Alice所计算的签名进行验证,也就是说可以知道这个签名是否是通过Alice的密钥计算出来的。如果真有这么一种方法的话,那么不管是识别篡改、伪装还是防止否认就都可以实现了吧?
实际上,这种看似很神奇的技术早就已经问世了,这就是数字签名( digital signature )
生成消息签名这一行为是由消息的发送者Alice来完成的,也称为“对消息签名”。生成签名就是根据消息内容计算数字签名的值,这个行为意味着“我认可该消息的内容”。
验证数字签名这一行为一般是由消息的接收者Bob来完成的,但也可以由需要验证消息的第三方来完成,这里的第三方验证者Victor。验证签名就是检查该消息的签名是否真的属于Alice,验证的结果可以是成功或者失败,成功就意味着这个签名是属于Alice的,失败则意味着这个签名不是属于Alice的。
在数字签名中,生成签名和验证签名这两个行为需要使用各自专用的密钥来完成。
Alice使用“签名密钥”来生成消息的签名,而Bob和Victor则使用“验证密钥”来验证消息的签名。数字签名对签名密钥和验证密钥进行了区分,使用验证密钥是无法生成签名的。这一点非常重要。此外,签名密钥只能由签名的人持有,而验证密钥则是任何需要验证签名的人都可以持有。
实际上,数字签名和公钥密码有着非常紧密的联系,简而言之,数字签名就是通过将公钥密码“反过来用”而实现的。
1、直接对消息签名的方法
2、对消息的散列值签名的方法
直接对消息签名的方法比较容易理解,但实际上并不会使用;对消息的散列值签名的方法稍微复杂一点,但实际中我们一般都使用这种方法。
1、直接对消息签名的方法
Alice需要事先生成一个包括公钥和私钥的密钥对,而需要验证签名的Bob则需要得到Alice的公钥。在此基础上,签名和验证的过程如下
(1) Alice 用自己的私钥对消息进行加密。
用私钥加密得到的密文就是Alice对这条消息的签名,由于只有Alice才持有自己的私钥,因此除了Alice 以外,其他人是无法生成相同的签名(密文)的。
(2)Alice 将消息和签名发送给Bob。
(3)Bob 用 Alice的公钥对收到的签名进行解密。
如果收到的签名确实是用Alice的私钥进行加密得到的密文(签名),那么用Alice的公钥应该能够正确解密。如果收到的签名不是用Alice的私钥进行加密得到的密文,那么就无法用Alice的公钥正确解密(解密后得到的数据看起来是随机的)。
(4)Bob将签名解密后得到的消息与Alice直接发送的消息进行对比。
如果两者一致,则签名验证成功;如果两者不一致,则签名验证失败。
2、对消息的散列值签名的方法
使用直接对消息签名的方法,需要对整个消息进行加密,非常耗时,这是因为公钥密码算法本来就非常慢。
我们不必再对整个消息进行加密(即对消息签名),而是只要先用单向散列函数求出消息的散列值,然后再将散列值进行加密(对散列值签名)就可以了。无论消息有多长,散列值永远都是这么短,因此对其进行加密(签名)是非常轻松的。
(1) Alice 用单向散列函数计算消息的散列值。
(2)Alice用自己的私钥对散列值进行加密。
用私钥加密散列值所得到的密文就是Alice对这条散列值的签名,由于只有Alice才持有自己的私钥,因此除了Alice 以外,其他人是无法生成相同的签名(密文)的。
(3) Alice将消息和签名发送给Bob。
(4) Bob 用Alice的公钥对收到的签名进行解密。
如果收到的签名确实是用Alice的私钥进行加密而得到的密文(签名),那么用Alice的公钥应该能够正确解密,解密的结果应该等于消息的散列值。如果收到的签名不是用Alice的私钥进行加密而得到的密文,那么就无法用Alice的公钥正确解密(解密后得到的数据看起来是随机的)。
(5) Bob将签名解密后得到的散列值与Alice直接发送的消息的散列值进行对比。
如果两者一致,则签名验证成功;如果两者不一致,则签名验证失败。
1、数字签名是利用了“没有私钥的人事实上无法生成使用该私钥所生成的密文”这一性质来实现的。这里所生成的密文并非被用于保证机密性,而是被用于代表一种只有持有该密钥的人才能够生成的信息。
这样的信息一般称为认证符号( authenticator ),消息认证码也是认证符号的一种,数字签名也是一样。数字签名是通过使用私钥进行加密来产生认证符号的。
2、数字签名的作用本来就不是保证机密性。
3、数字签名可以随意复制。虽然叫作签名,但它也仅仅是计算机上的一种普通的数据而已。数字签名可以附加在消息的末尾,也可以和消息分离,单独作为文件来发送,但无论如何,我们都可以像复制普通的文件一样,很容易地复制出任意个内容相同的副本。
但是,签名可以被复制,并不意味着签名就没有意义,因为签名所表达的意义是特定的签名者对特定的消息进行了签名,即便签名被复制,也并不会改变签名者和消息的内容。
4、消息内容会不会被任意修改。会的,签名之后也可以对消息和签名进行修改,但是这样修改之后,验证签名就会失败,进行验证的人就能够发现这一修改行为。数字签名所要实现的并不是防止修改,而是识别修改,修改没问题,但验证签名会失败。
5、能不能同时修改消息和签名,使得验证签名能够成功呢?事实上是做不到的。
以对散列值签名为例,只要消息被修改1比特,重新计算的散列值就会发生很大的变化,要拼凑出合法的签名,必须在不知道私钥的前提下对新产生的散列值进行加密,事实上这是无法做到的,因为不知道私钥就无法生成用该私钥才能生成的密文。
6、如果得到了某人的数字签名,应该就可以把签名的部分提取出来附加在别的消息后面,这样的签名还有效吗?
的确,可以将签名部分提取出来并附加到别的消息后面,但是验证签名会失败。
将签名提取出来这一行为,就好像是现实世界中把纸质合同上的签名拓下来一样。然而在数字签名中,签名和消息之间是具有对应关系的,消息不同签名内容也会不同,因此事实上是无法做到将签名提取出来重复使用的。
总之,将一份签名附加在别的消息后面,验证签名会失败。
7、删除签名也无法“作废合同”吗?
的确,带有数字签名的借据即便删除掉也无法作废,要作废带有数字签名的借据,可以重新创建一份相当于收据的文书,并让对方在这份文书上加上数字签名。
拿一个具体的例子来说,如果我们想要将过去使用过的公钥作废,就可以创建一份声明该公钥已作废的文书并另外加上数字签名。
8、如何防止否认
防止否认与“谁持有密钥”这一问题密切相关。
在消息认证码中,能够计算MAC值的密钥(共享密钥)是由发送者和接收者双方共同持有的,因此发送者和接收者中的任何一方都能够计算MAC值,发送者也就可以声称“这个MAC值不是我计算的,而是接收者计算的”。
相对地,在数字签名中,能够生成签名的密钥(私钥)是只有发送者才持有的,只有发送者才能够生成签名,因此发送者也就没办法说“这个签名不是我生成的”了。当然,严格来说,如果数字签名的生成者说“我的私钥被别人窃取了”,也是有可能进行否认的。
9、数字签名真的能够代替签名吗
数字签名技术有很多优点,例如不需要物理交换文书就能够签订合同,以及可以对计算机上的任意数据进行签名等。然而,对于实际上能不能代替签名这个问题还是有一些不安的因素。其中一个很大的原因恐怕是签订合同、进行认证这样的行为是一种社会性的行为。
数字签名技术在未来将发挥重要的作用,但是单纯认为数字签名比普通的印章或手写签名更可信是很危险的。一种新技术只有先被人们广泛地认知,并对各种问题制定相应的解决办法之后,才能被社会真正地接受。
信息发布的目的是尽量让更多的人知道,因此我们没有必要对消息进行加密,但是必须排除有人恶意伪装成该组织来发布假消息的风险。因此,我们不加密消息,而只是对消息加上数字签名,这种对明文消息所施加的签名,一般称为明文签名( clearsign )。
在网络下载软件时,我们需要判断所下载的软件是否可以安全运行,为了防止软件程序被恶意攻击,软件的作者可以对软件加上数字签名,而我们只要在下载之后验证数字签名,就可以识别出软件是否遭到了攻击者的篡改。
在验证数字签名时我们需要合法的公钥,那么怎么才能知道自己得到的公钥是否合法呢?我们可以将公钥当作消息,对它加上数字签名。像这样对公钥施加数字签名所得到的就是公钥证书
SSL/TLS在认证服务器身份是否合法时会使用服务器证书,它就是加上了数字签名的服务器公钥。相对地,服务器为了对客户端(用户)进行认证也会使用客户端证书。
1、RSA算法
2、EIGamal方式
3、DSA
4、Rabin方式
(1)对数字签名的攻击
1、中间人攻击
对数字签名的中间人攻击,具体来说就是主动攻击者Mallory介人发送者和接收者的中间,对发送者伪装成接收者,对接收者伪装成发送者,从而能够在无需破解数字签名算法的前提下完成攻击。
2、对单向散列函数的攻击
数字签名中所使用的单向散列函数必须具有抗碰撞性,否则攻击者就可以生成另外一条不同的消息,使其与签名所绑定的消息具有相同的散列值。
(2)数字签名无法解决的问题
无法得知公钥的正确安全性