白话数字签名(1)——基本原理(新!)
本系列通过通俗易懂的讲解,让您就像读小说一般,轻轻松松就能理解数字签名的基本原理和应用方法(即使您是一个并不精通计算机的企业老总,也能读懂本篇文章)。然后我们再逐步深入技术细节,最后将给出一个在B/S信息系统中使用数字签名的DEMO。
由于数字签名基于非对称加密技术,所以我们需要先啰嗦一下对称加密和非对称加密技术。
对称加密
何谓加密?加密是一种“把数据搞乱掉”的技术。加密技术涉及到4种东东:
明文:可以被人或程序识别的数据。例如一个文本文件、一段歌词、一个Word文档、一首MP3、一个图片文件、一段视频等等。
加密算法:将数据搞乱掉的方法。
密钥(密码):一个你在进行加密操作时给出的字符串,让加密算法不但把明文“搞乱掉”,而且要乱得“与众不同”。这样即使别人搞到了解密算法,如果没有当初加密时所使用的密码,一样无法进行解密操作。
密文:明文被加密算法和密钥加密后的结果。它看上去就是一堆乱码,没有人或程序能知道它到底表示什么信息。
作为加密的一个实例,我将使用由我杜撰的“景氏替换加密算法”演示一下加密过程。
明文:good good study, day day up.
密钥:google
景氏替换加密算法:将明文中的所有的字母“d”替换成密钥。
密文:将“good good study, day day up.”中的所有字母“d”替换成“google”,就得到密文“googoogle googoogle stugoogley, googleay googleay up.”。这个密文乱得还可以吧?一般人看了肯定不知道它是什么意思。
那么什么是解密呢?解密就是把密文再变回明文的过程。
例如“景氏替换解密算法”就是:将密文中所有与密钥相同的字符串替换成“d”。
密文:googoogle googoogle stugoogley, googleay googleay up.
密钥:google
景氏替换解密算法:将密文中所有与密钥相同的字符串替换成“d”。
明文:将“googoogle googoogle stugoogley, googleay googleay up.”中的所有“google”替换成“d”,就得到了明文“good good study, day day up.”。
您肯定已经注意到了,我们在进行加密和解密时使用的密钥必须是相同的,例如在上例中,加密和解密都必须使用相同的密钥“google”。所以像“景氏替换加密算法”这种就被称为 对称加密算法。目前最为流行的对称加密算法是DES和AES,此外,对称加密算法还有IDEA、FEAL、LOKI、Lucifer、RC2、RC4、RC5、Blow fish、GOST、CAST、SAFER、SEAL等。WinRAR的文件加密功能就是使用的AES加密算法。
非对称加密
非对称加密算法是一类与众不同的加密算法,它的密钥不是1个,而是2个(一对),我们先姑且称它们为密钥K1和密钥K2。非对称加密算法的特点是,如果用密钥K1进行加密,则有且仅有密钥K2能进行解密;反之,如果使用密钥K2进行了加密,则有且仅有密钥K1能进行解密。注意“有且仅有”的意思——如果用密钥K1进行了加密,是不能用密钥K1进行解密的;同样,如果用密钥K2进行了加密,也无法用密钥K2进行解密。这是一个非常重要的特性,至于如何在实际中运用这个特性,请看下文。
我想给Clark传送一个AV小电影,又怕被他的老婆发现......
话说俺得了一个很不错的AV小电影,想通过网络传送给Clark,可是又怕被他的老婆发现(因为Clark的老婆是一个超级黑客,她可以使用sniffer技术截获 任何通过网线传送给Clark的数据。别跟我说用VPN,它超出了本文讨论的范围),怎么办呢?对了,我们需要一个“将数据搞乱掉”的技术——加密技术。我先使用WinRAR对小电影进行压缩,然后加上密码“TswcbyyqjsjhfL”(还记得么?WinRAR的文件加密功能使用的是叫作AES的对称加密算法)。接着,将这个加密后的文件通过QQ传送给Clark。然后,兴冲冲地拨打Clark的手机:
“喂?Clark么?好久不见,呵呵......我给你发了个好东东呦,在QQ上,收到没?......密码是TswcbyyqjsjhfL,对,就是天生我才必有用,千金散尽还复来的首字母,第一个和最后一个字母要大写呦......”
可是,Clark,我是真的不知道你的老婆大人刚刚就在你的身边呀!而且你也知道,我打电话从来都是喜欢很大声的......呜呜呜......
在Clark跪了一夜的搓衣板之后,我们都明白:如果是已经保存在自己硬盘上的文件,使用对称加密技术进行加密是没有问题的;如果是两个人通过网络传输文件,使用对称加密就很危险——因为在传送密文的同时,还必须传送解密密钥。我们需要一个与众不同的加密算法,一个不需要传递解密密钥的加密算法。非对称加密正好可以满足我们的需要。基本思路是这样的:首先,生成一对满足非对称加密要求的密钥对(密钥K1和密钥K2)。然后,将密钥K1公布在网上,任何人都可以下载它,我们称这个已经公开的密钥K1为 公钥;密钥K2自己留着,不让任何人知道,我们称这个只有自己知道的密钥K2为 私钥。当我想给Clark传送小电影时,我可以用Clark的公钥对小电影进行加密,之后这个密文就连我也无法解密了。这个世界上只有一个人能将密文解密,这个人就是拥有私钥的Clark。
后来......
后来,Clark痛定思痛,决定申请一个数字证书。流程是这样的:首先,登录 当地的数字证书认证中心网站,填表->出示个人有效证件原件和复印件->缴费->等待数字证书认证中心制作数字证书->领取数字证书。如果您的公司需要申请大量的数字证书,还可以与认证中心的销售人员商量,先领取免费的试用版的数字证书供技术人员试用。
后来的后来,我又得到了一本电子版的不良漫画,当然,我又想到了Clark。我先在数字证书认证中心下载了Clark的公钥证书(就是一个含有公钥信息的文件),使用非对称加密算法对不良漫画进行加密,再将密文通过QQ传送给Clark。然后,我兴冲冲地拨打Clark的手机:
“喂?Clark么?好久不见,呵呵......我给你发了个好东东呦,在QQ上,收到没?......已经用你的公钥加密了。用你的私钥解密就行了^_^”
Clark兴冲冲地插入他的私钥(忘了说了,私钥并不是一个文件,而是一个USB设备,外形就跟U盘一样,至于为什么要这样,下一篇再说),解密,然后开始看漫画,完全没察觉他的老婆大人就在身后......
Clark,俺这个月手头有点紧......
唉,这个月买了太多的书,到月底揭不开锅了。正巧在QQ上遇到了Clark:
1-2-3:“Clark,我需要200两纹银,能否借给我?”
Clark:“没问题。我这就给你转账。请给我一张借条。”
1-2-3:“太谢谢了,我这就用Word写一个借条给你。”
然后,我新建一个Word文档,写好借条,存盘。然后,然后怎么办呢?我不能直接把借条发送给Clark,原因有:
1. 我无法保证Clark不会在收到借条后将“纹银200两”改为“纹银2000两”。
2. 如果我赖账,Clark无法证明这个借条就是我写的。
3. 普通的Word文档不能作为打官司的证据。
好在我早就申请了数字证书。我先用我的私钥对借条进行加密,然后将加密后的密文用QQ发送给Clark。Clark收到了借条的密文后,在数字证书认证中心的网站上下载我的公钥,然后使用我的公钥将密文解密,发现确实写的是“借纹银200两”,Clark就可以把银子放心的借给我了,我也不会担心Clark会篡改我的借条,原因是:
1. 由于我发给Clark的是密文,Clark无法进行修改。Clark倒是可以修改解密后的借条,但是Clark没有我的私钥,没法模仿我对借条进行加密。这就叫 防篡改。
2. 由于用我的私钥进行加密的借条,有且只有我的公钥可以解密。反过来讲,能用我的公钥解密的借条,一定是使用我的私钥加密的,而只有我才拥有我的私钥,这样Clark就可以证明这个借条就是我写的。这就叫 防抵赖。
3. 如果我一直赖着不还钱,Clark把我告上了法庭,这个用我的私钥加密过的Word文档就可以当作程堂证供。因为我国已经出台了 《中华人民共和国电子签名法》,使数字签名具有了法律效力。
您一定已经注意到了,这个使用我的私钥进行了加密的借条,具有了防篡改、防抵赖的特性,并且可以作为程堂证供,就跟我对这个借条进行了“签名”的效果是一样的。对了,“使用我的私钥对借条进行加密”的过程就叫做 数字签名。(由于数字签名算法的速度比较慢,所以在实际对文件签名的过程比上面提到的方法稍稍复杂一些,这个在下一篇再讲)。
我是1-2-3,我真的是1-2-3,我是真的1-2-3
正如您已经知道的,Clark的老婆是一名超级黑客——就是传说中能用计算机作任何事的人。这不,不久前她就轻松入侵了QQ数据库,下载了Clark的所有好友的ID和密码以及聊天记录。然后,时不时地伪装成Clark的好友跟Clark聊天,搞得Clark最近总是神经兮兮、疑神疑鬼的。这不,昨天我在QQ上遇到了Clark:
1-2-3:“Clark,最近还好吧?我又搞到一个好东东呦,要不要?”
Clark:“48475bbt556”
Clark并不是疯掉了,那个“48475bbt556”也不是我跟Clark之间的什么通关暗语。这个“48475bbt556”就是Clark在键盘上胡乱敲上去的,不过,我却知道Clark是什么意思。我立刻把“48475bbt556”粘贴到Word里,然后用我的私钥对这个Word文档加密,再将这个Word文档发送给Clark。Clark在那边用我的公钥将Word文档解密,打开,发现里面写的就是“48475bbt556”,就知道QQ这边的确就是真正的我本人了。因为拥有我的私钥的人在这个世界上就只有我一人而已,Clark的老婆大人就是再神通广大也模仿不了,这就是数字签名的 验证功能。
顺便提一句,不但人可以申请数字证书,设备(例如Web服务器)也可以申请数字证书(叫作设备证书)。利用数字签名的验证功能,就可以验证服务器的身份了,这可是防钓鱼的终极解决方案呦。
思考题
如果Clark每次都向我发送相同的字符串(例如“1234”),而不是每次在键盘上胡乱地(随机地)敲一些字符,Clark的老婆就会利用Clark的懒惰模仿我跟Clark聊QQ,这是为什么?
本篇到此结束,下一篇将介绍电子签名技术的产品&设备。
白话数字签名(2)——软件&设备
非对称加密算法有一个重大缺点——加密速度慢,或者说得更拽一些,编码率比较低。例如在上一篇里我给Clark传的那个1GB的小电影,进行非对称加密足足用了66小时。那个借条小一些吧,也用了将近2分钟。所以在实际使用非对称加密的时候,往往不直接对文件进行加密,而是使用摘要算法与非对称算法相结合(适用于数字签名)或对称加密和非对称加密相结合(适用于加密传输文件)的办法来解决或者说绕过非对称加密算法速度慢的问题。
摘要算法
摘要算法,又叫作Hash算法或散列算法,是一种将任意长度的输入浓缩成固定长度的字符串的算法,注意是“浓缩”而不是“压缩”,因为这个过程是不可逆的。它的特点是:
1. 不同内容的文件生成的散列值一定不同; (转者注:这句话有问题。不同内容生成的散列值可能会相同,否则就不存在“冲突”问题了) 相同内容的文件生成的散列值一定相同。由于这个特性,摘要算法又被形象地称为文件的“数字指纹”。
2. 不管文件多小(例如只有一个字节)或多大(例如几百GB),生成的散列值的长度都相同,而且一般都只有几十个字符。
这个神奇的算法被广泛应用于比较两个文件的内容是否相同——散列值相同,文件内容必然相同;散列值不同,文件内容必然不同。如果您用过BT或eMule,应该对散列值比较熟悉了,右图分别是BT和eMule的文件详细信息的截图。
细心的朋友可能已经注意到了,BT和eMule的散列值的长度不一样,这是因为它们所使用的摘要算法不同,目前比较流行的摘要算法主要有MD5和SHA-1,您可以在.Net的System.Security.Cryptography命名空间找到它们的身影。
另,由于本篇是只重理解和应用的白话文,所以上面对摘要算法的讨论并不十分全面严谨,喜欢看文言文的朋友可以看这篇 《Hash 算法及其应用》 。还有就是MD5和SHA-1算法已经从理论上被山东大学王小云教授及其研究小组破解(向中国的科学家致敬!),不过并不是这两个算法从此就不能用了。
实际对文件作数字签名的方法
由于非对称加密的速度实在太慢了,所以在实际对文件作数字签名的时候,例如对上一篇中我用Word写给Clark的借条进行签名,总是先生成这个借条的散列值,然后用我的私钥对这个散列值进行非对称加密,然后把加密后的散列值(我们就叫它“散列值密文”吧)和借条一同发送到Clark那里。Clark在收到借条和散列值密文后,用从网上下载的我的公钥将散列值解密,然后Clark自己再生成一次借条的散列值,比对这两个散列值是否相同,如果相同,就叫作 验证签名 成功。由于散列值只有几十个字节,所以签名的速度还可以忍受。看下图会更直观一些。
思考题
虽然我们只是对借条的散列值进行了非对称加密,但是此过程仍然具有防篡改、防抵赖的作用,为什么?
又太麻烦了
我们费了好大的劲终于解决了数字签名速度慢的问题。但是上面那个复杂的签名过程用户能接受吗?当然不能!所以我们必须要开发出一个数字签名的程序来简化签名过程,最好让数字签名看起来就跟传统的盖章差不多。这样的程序已经有了,叫作 电子签章程序 。 它是一个桌面程序,一般以Word或Excel插件的形式存在。下面就演示一下用电子签章程序对我的借条进行签名的过程。
1. 安装了电子签章程序后,Word和Excel中就会多出一个签名用的工具条。
2. 写好借条,存盘。然后用鼠标点击“添加电子签章”按钮。然后在需要显示印章图片的位置上再按一次鼠标左键。
3. 电子签章程序会弹出一个对话框,注意在这步一定要勾选“签章后锁定文件”复选框,至于为什么要这样,稍后再讲。然后点击确定按钮。
4. 在上一步按确定按钮后,电子签章程序还会提示要求我输入存放私钥的USB-Key的使用密码,然后Word中就会出现一个印章了。这个印章图片是我提供给数字证书中心,在制作USB-Key的时候就烧录在USB-Key之中的。
5. 之后我把借条发送给Clark。Clark想验证签名的话只要按“验证所有印章”就可以了。电子签章会弹出如左图所示的对话框。
是不是即直观又简单?那么诸如“散列值”、“公钥证书”这些东东都跑到哪里去了呢?它们都被电子签章程序插入到Word文档中的某个特定的地方了,如果你熟悉Word文档的结构,是不难找到它们的。
电子签章程序的Bug
电子签章程序本来可以支持两种用法:
1. 在上面的第3步不勾选“签章后锁定文件”复选框,这样在进行了数字签名之后,仍然可以更改Word文档的内容。当然如果在进行了数字签名之后又更改了Word文档的内容,验证签名操作就会失败。这时需要再次进行签名操作。
2. 在上面的第3步勾选“签章后锁定文件”复选框,这样在进行了签名操作后,Word文档的内容就再也无法更改了。
但是,电子签章程序有一个大Bug——在进行了签名操作后,如果只是更改了文字的颜色,验证签名操作仍然会成功。这就意味着,如果我在Word中写到“向公司借款2000元”,然后把“2000”的最后一个0的颜色改为白色,在领导看来就是“向公司借款200 元”。领导欣然签章,然后我再把那最后一个0的颜色改为黑色,就又变成了“向公司借款2000元”,而且验证签名居然会成功。这也是为什么我在上面的第3步要强调一定要勾选“签章后锁定文件”复选框了。我猜测造成这个Bug的原因很可能是因为电子签章程序仅仅对文档中的纯文本生成散列值,而不是对文本+全部格式信息一同生成散列值。大家在购买电子签章程序前一定要作这方面的测试。
数字信封
我们可以通过使用信息摘要技术解决数字签名的速度问题,那么数字加密的速度问题怎么解决呢?相信除了我和Clark以外,很少有人愿意为传送一个小电影而等待66个小时。其实这个问题也简单,我们可以用对称加密与非对称加密相结合的方式来解决这个问题。对称加密速度快,但是必须在传送密文的同时传送解密密钥;非对称加密速度慢,但是不需要传送解密密钥。把两个技术一起使用,各取优点,就OK了。方法是,先把小电影用对称加密算法加密,然后把解密密钥用非对称加密算法加密。再将小电影的密文与解密密钥的密文同时传送给Clark。Clark收到这两样东西后,先用自己的私钥将解密密钥的密文解密,得到解密密钥,再用解密密钥将小电影的密文解密,就得到了小电影的明文。Clark收到的这两样东西——小电影的密文和解密密钥的密文——加在一起就叫作数字信封。看下图会更直观一些。
数字证书
非对称加密的公钥和私钥的长度都很长,一般都在1024位以上。这么长且无规律的密码,用户是记不住的,所以只能保存在文件中啦。保存了公钥的文件就叫作数字证书。且慢,这个定义是十分错误的!为什么呢?想一想第1篇里的那个我给Clark发送小电影的例子。例子中我在网上下载了Clark的公钥(也就是数字证书),然后用它对小电影进行非对称加密,然后心想只有拥有Clark的私钥的Clark才能解密——Clark的老婆一定没辙啦。没想到螳螂捕蝉,黄雀在后,我下载Clark的公钥的那个网站是Clark的老婆制作的钓鱼网站!里面的公钥证书统统都是Clark的老婆的公钥!!结果呢,我的小电影用Clark的私钥解不开,反倒是只有用Clark老婆的私钥才能解开,用Clark的话来说,就是“无语了......”。
所以聪明的你一定想到了,数字证书之所以可以称之为“证书”,就一定要有“防伪”功能。方法是,数字证书里不但要包含Clark的公钥,还要包含Clark的自然信息(姓名、单位等),并且最重要的,要有证书颁发部门对这些信息的数字签名(每个证书颁发部门也都有自己的数字证书——称之为根证书——和与之配对使用的私钥)。这样我就可以验证数字证书的真伪了。所以,让我们重新定义数字证书,数字证书是由一个权威机构发行的,至少包含一个公开密钥、证书持有人(或单位)的名称以及证书授权中心对这些信息的数字签名的文件。一般情况下证书中还包括密钥的有效时间,发证机关(证书授权中心)的名称,该证书的序列号等信息,证书的格式遵循ITUT X.509国际标准。
您可以使用IE的菜单“工具 | Internet 选项... -> 内容 -> 证书... -> 受信任的根证书颁发机构”来查看IE中已经安装的根证书。点击“导入...”按钮可以导入新的根证书。
复制破解的解决方案——USB Key
我们已经知道, 非对称加密的密钥很长,一般都在1024位以上,所以只能保存在文件里。好,我把私钥文件保存在了硬盘上,却难保哪天这个文件不会被某个坏蛋拷贝走。然后,在这个“没有人知道你是一条狗”的网络世界里,他就变成了我——他可以冒充我写借条甚至向银行贷款;他可以冒充我跟别的公司签署上亿美元的合同;他甚至可以冒充我签署卖身契,300块钱就把我卖了——而我却懵然不知。直到有一天,我突然发现自己突然增加了几百万外债、公司把我Fire了、一个9岁的小女孩拿着卖身契等在我家门口声称我已经是她的奴隶......
所以千万不能把私钥保存在硬盘上。那么保存在U盘上,并且把U盘放在内裤的口袋里怎么样呢?好像好了一些,但是你在签名的时候还是得把U盘插在电脑上吧?可知道你的电脑中有多少木马程序正在用For循环扫描你的USB端口,就等着拷贝你的私钥?
我们需要的是无论如何也不可能被别人复制的私钥保存方案,USB Key应运而生。USB Key是一种USB设备,外形就跟U盘一样,只不过无法用它来存取文件。证书发行单位会使用特殊的设备将你的数字证书、私钥和电子签章程序所要使用的印章图片烧录到USB Key中。你无法使用资源管理器或木马程序取得USB Key中的私钥,当需要用私钥进行签名时,直接通过USB Key的驱动程序提供的API将明文传输到USB Key中,由USB Key中的加密芯片对明文进行加密,加密结果会以API函数的返回值的形式返回,这样就可以有效解决私钥被坏蛋复制的问题了。还有就是USB Key本身还有一个简短的使用密码,每次加密前使用者必须输入正确的使用密码方能使用,这样即使USB Key不慎丢失,也不用担心了。
USB Key的缺点
本篇到此结束,下一篇将专门介绍在B/S信息系统中对数据库中的信息进行数字签名的一些问题和解决方法。并在最后给出一个十分实用的DEMO。
白话数字签名(2)——软件&设备
非对称加密算法有一个重大缺点——加密速度慢,或者说得更拽一些,编码率比较低。例如在上一篇里我给Clark传的那个1GB的小电影,进行非对称加密足足用了66小时。那个借条小一些吧,也用了将近2分钟。所以在实际使用非对称加密的时候,往往不直接对文件进行加密,而是使用摘要算法与非对称算法相结合(适用于数字签名)或对称加密和非对称加密相结合(适用于加密传输文件)的办法来解决或者说绕过非对称加密算法速度慢的问题。
摘要算法
摘要算法,又叫作Hash算法或散列算法,是一种将任意长度的输入浓缩成固定长度的字符串的算法,注意是“浓缩”而不是“压缩”,因为这个过程是不可逆的。它的特点是:
1. 不同内容的文件生成的散列值一定不同; (转者注:这句话有问题。不同内容生成的散列值可能会相同,否则就不存在“冲突”问题了) 相同内容的文件生成的散列值一定相同。由于这个特性,摘要算法又被形象地称为文件的“数字指纹”。
2. 不管文件多小(例如只有一个字节)或多大(例如几百GB),生成的散列值的长度都相同,而且一般都只有几十个字符。
这个神奇的算法被广泛应用于比较两个文件的内容是否相同——散列值相同,文件内容必然相同;散列值不同,文件内容必然不同。如果您用过BT或eMule,应该对散列值比较熟悉了,右图分别是BT和eMule的文件详细信息的截图。
细心的朋友可能已经注意到了,BT和eMule的散列值的长度不一样,这是因为它们所使用的摘要算法不同,目前比较流行的摘要算法主要有MD5和SHA-1,您可以在.Net的System.Security.Cryptography命名空间找到它们的身影。
另,由于本篇是只重理解和应用的白话文,所以上面对摘要算法的讨论并不十分全面严谨,喜欢看文言文的朋友可以看这篇 《Hash 算法及其应用》 。还有就是MD5和SHA-1算法已经从理论上被山东大学王小云教授及其研究小组破解(向中国的科学家致敬!),不过并不是这两个算法从此就不能用了。
实际对文件作数字签名的方法
由于非对称加密的速度实在太慢了,所以在实际对文件作数字签名的时候,例如对上一篇中我用Word写给Clark的借条进行签名,总是先生成这个借条的散列值,然后用我的私钥对这个散列值进行非对称加密,然后把加密后的散列值(我们就叫它“散列值密文”吧)和借条一同发送到Clark那里。Clark在收到借条和散列值密文后,用从网上下载的我的公钥将散列值解密,然后Clark自己再生成一次借条的散列值,比对这两个散列值是否相同,如果相同,就叫作 验证签名 成功。由于散列值只有几十个字节,所以签名的速度还可以忍受。看下图会更直观一些。
思考题
虽然我们只是对借条的散列值进行了非对称加密,但是此过程仍然具有防篡改、防抵赖的作用,为什么?
又太麻烦了
我们费了好大的劲终于解决了数字签名速度慢的问题。但是上面那个复杂的签名过程用户能接受吗?当然不能!所以我们必须要开发出一个数字签名的程序来简化签名过程,最好让数字签名看起来就跟传统的盖章差不多。这样的程序已经有了,叫作 电子签章程序 。 它是一个桌面程序,一般以Word或Excel插件的形式存在。下面就演示一下用电子签章程序对我的借条进行签名的过程。
1. 安装了电子签章程序后,Word和Excel中就会多出一个签名用的工具条。
2. 写好借条,存盘。然后用鼠标点击“添加电子签章”按钮。然后在需要显示印章图片的位置上再按一次鼠标左键。
3. 电子签章程序会弹出一个对话框,注意在这步一定要勾选“签章后锁定文件”复选框,至于为什么要这样,稍后再讲。然后点击确定按钮。
4. 在上一步按确定按钮后,电子签章程序还会提示要求我输入存放私钥的USB-Key的使用密码,然后Word中就会出现一个印章了。这个印章图片是我提供给数字证书中心,在制作USB-Key的时候就烧录在USB-Key之中的。
5. 之后我把借条发送给Clark。Clark想验证签名的话只要按“验证所有印章”就可以了。电子签章会弹出如左图所示的对话框。
是不是即直观又简单?那么诸如“散列值”、“公钥证书”这些东东都跑到哪里去了呢?它们都被电子签章程序插入到Word文档中的某个特定的地方了,如果你熟悉Word文档的结构,是不难找到它们的。
电子签章程序的Bug
电子签章程序本来可以支持两种用法:
1. 在上面的第3步不勾选“签章后锁定文件”复选框,这样在进行了数字签名之后,仍然可以更改Word文档的内容。当然如果在进行了数字签名之后又更改了Word文档的内容,验证签名操作就会失败。这时需要再次进行签名操作。
2. 在上面的第3步勾选“签章后锁定文件”复选框,这样在进行了签名操作后,Word文档的内容就再也无法更改了。
但是,电子签章程序有一个大Bug——在进行了签名操作后,如果只是更改了文字的颜色,验证签名操作仍然会成功。这就意味着,如果我在Word中写到“向公司借款2000元”,然后把“2000”的最后一个0的颜色改为白色,在领导看来就是“向公司借款200 元”。领导欣然签章,然后我再把那最后一个0的颜色改为黑色,就又变成了“向公司借款2000元”,而且验证签名居然会成功。这也是为什么我在上面的第3步要强调一定要勾选“签章后锁定文件”复选框了。我猜测造成这个Bug的原因很可能是因为电子签章程序仅仅对文档中的纯文本生成散列值,而不是对文本+全部格式信息一同生成散列值。大家在购买电子签章程序前一定要作这方面的测试。
数字信封
我们可以通过使用信息摘要技术解决数字签名的速度问题,那么数字加密的速度问题怎么解决呢?相信除了我和Clark以外,很少有人愿意为传送一个小电影而等待66个小时。其实这个问题也简单,我们可以用对称加密与非对称加密相结合的方式来解决这个问题。对称加密速度快,但是必须在传送密文的同时传送解密密钥;非对称加密速度慢,但是不需要传送解密密钥。把两个技术一起使用,各取优点,就OK了。方法是,先把小电影用对称加密算法加密,然后把解密密钥用非对称加密算法加密。再将小电影的密文与解密密钥的密文同时传送给Clark。Clark收到这两样东西后,先用自己的私钥将解密密钥的密文解密,得到解密密钥,再用解密密钥将小电影的密文解密,就得到了小电影的明文。Clark收到的这两样东西——小电影的密文和解密密钥的密文——加在一起就叫作数字信封。看下图会更直观一些。
数字证书
非对称加密的公钥和私钥的长度都很长,一般都在1024位以上。这么长且无规律的密码,用户是记不住的,所以只能保存在文件中啦。保存了公钥的文件就叫作数字证书。且慢,这个定义是十分错误的!为什么呢?想一想第1篇里的那个我给Clark发送小电影的例子。例子中我在网上下载了Clark的公钥(也就是数字证书),然后用它对小电影进行非对称加密,然后心想只有拥有Clark的私钥的Clark才能解密——Clark的老婆一定没辙啦。没想到螳螂捕蝉,黄雀在后,我下载Clark的公钥的那个网站是Clark的老婆制作的钓鱼网站!里面的公钥证书统统都是Clark的老婆的公钥!!结果呢,我的小电影用Clark的私钥解不开,反倒是只有用Clark老婆的私钥才能解开,用Clark的话来说,就是“无语了......”。
所以聪明的你一定想到了,数字证书之所以可以称之为“证书”,就一定要有“防伪”功能。方法是,数字证书里不但要包含Clark的公钥,还要包含Clark的自然信息(姓名、单位等),并且最重要的,要有证书颁发部门对这些信息的数字签名(每个证书颁发部门也都有自己的数字证书——称之为根证书——和与之配对使用的私钥)。这样我就可以验证数字证书的真伪了。所以,让我们重新定义数字证书,数字证书是由一个权威机构发行的,至少包含一个公开密钥、证书持有人(或单位)的名称以及证书授权中心对这些信息的数字签名的文件。一般情况下证书中还包括密钥的有效时间,发证机关(证书授权中心)的名称,该证书的序列号等信息,证书的格式遵循ITUT X.509国际标准。
您可以使用IE的菜单“工具 | Internet 选项... -> 内容 -> 证书... -> 受信任的根证书颁发机构”来查看IE中已经安装的根证书。点击“导入...”按钮可以导入新的根证书。
复制破解的解决方案——USB Key
我们已经知道, 非对称加密的密钥很长,一般都在1024位以上,所以只能保存在文件里。好,我把私钥文件保存在了硬盘上,却难保哪天这个文件不会被某个坏蛋拷贝走。然后,在这个“没有人知道你是一条狗”的网络世界里,他就变成了我——他可以冒充我写借条甚至向银行贷款;他可以冒充我跟别的公司签署上亿美元的合同;他甚至可以冒充我签署卖身契,300块钱就把我卖了——而我却懵然不知。直到有一天,我突然发现自己突然增加了几百万外债、公司把我Fire了、一个9岁的小女孩拿着卖身契等在我家门口声称我已经是她的奴隶......
所以千万不能把私钥保存在硬盘上。那么保存在U盘上,并且把U盘放在内裤的口袋里怎么样呢?好像好了一些,但是你在签名的时候还是得把U盘插在电脑上吧?可知道你的电脑中有多少木马程序正在用For循环扫描你的USB端口,就等着拷贝你的私钥?
我们需要的是无论如何也不可能被别人复制的私钥保存方案,USB Key应运而生。USB Key是一种USB设备,外形就跟U盘一样,只不过无法用它来存取文件。证书发行单位会使用特殊的设备将你的数字证书、私钥和电子签章程序所要使用的印章图片烧录到USB Key中。你无法使用资源管理器或木马程序取得USB Key中的私钥,当需要用私钥进行签名时,直接通过USB Key的驱动程序提供的API将明文传输到USB Key中,由USB Key中的加密芯片对明文进行加密,加密结果会以API函数的返回值的形式返回,这样就可以有效解决私钥被坏蛋复制的问题了。还有就是USB Key本身还有一个简短的使用密码,每次加密前使用者必须输入正确的使用密码方能使用,这样即使USB Key不慎丢失,也不用担心了。
USB Key的缺点
本篇到此结束,下一篇将专门介绍在B/S信息系统中对数据库中的信息进行数字签名的一些问题和解决方法。并在最后给出一个十分实用的DEMO。
白话数字签名(3)——Web程序中的数字签名
摘要
阅读本文并探索
- 如何突破Web程序无状态性这个让人抓狂的障碍实现自动显示签名结果和批量签名功能。
- 如何将签名功能封装到一个实现了IHttpHandler接口的类库中,使Client端的代码尽可能的简单。
- 使用数字签名API函数需要注意的几个问题。
本文介绍在Web程序中使用数字签名所遇到的特殊困难和解决方法,并给出一个超简单但相当实用的DEMO。
DEMO程序的效果
让我们先来看看实现之后的效果。
让Client端代码尽可能的简单
我们将数字签名操作的复杂性全部封装到一个命名空间为mylib.util.lnca的类库中,类库只暴露一个名为Signer的类。
Signer的Client (本例中的Default.aspx)的职责只有
- 构造一个含有待签名的数据的Dictionary作为Signer的输入,然后调用Signer.do_sign()函数进行数字签名。
- 在页面上放置一个专门用于取得并显示签名结果的按钮,并将这个按钮的ClientID传递给Signer,这样Signer在完成签名后就可以自动触发这个按钮。在将程序发布给最终用户时,要把这个按钮的top属性设为-10000,这样最终用户就看不到这个按钮了。
Default.aspx 的设计视图的截图
Default.aspx 的源代码如下
由于Signer是一个HTTP 处理程序,所以需要在Web.config中添加一行对Signer.ashx的注册:
有关HTTP处理程序的创建和应用,可以看《实战 HTTP 处理程序(HTTP Handler)系列》。
由于我们把复杂性都放在了Signer.cs中,Signer.cs的代码有些长,我们会在后面讨论它的几个要点。
Signer.cs的第227和228行的“Settings.Default.controls”和“Settings.Default.js”是需要发送给客户端浏览器用于回传签名结果的HiddenFields和执行签名操作的Javascript语句。我把它们放在了类库的配置文件里,它们的代码如下:
自动显示签名结果
我们想要实现这样的交互效果:用户选定想要进行签名的数据后,只要按一个按钮就会自动弹出一个小窗体显示签名的进度;当签名结束后,可以自动显示签名结果,就像上面那个DEMO程序所展示的那样。
如果我们开发的是WinForm的信息系统,实现这样的效果简直易如反掌。可是在Web程序中,我们却遇到了一点麻烦。
自动显示签名结果的困难
正如我们在第2篇所介绍的,为了防复制破解,我们是使用USB Key做数字签名。这个USB Key必须插在客户端的电脑上,我们在Server端无法直接控制它,只能通过在客户端浏览器上执行的javascript代码调用一个由辽宁CA认证中心开发的一个ActiveX控件操作USB Key进行签名,再将签名结果通过HiddenFields Post回Server端——不过这个Server端已经不是以前的Server端了,Web程序的这种无状态性没少让我们吃亏。
换句话说,我们没办法像下面这样写(伪码):
protected void do_sign_button_Click(object sender, EventArgs e)
{
1 Dictionary<string, string> sign_candidates = prepare_sign_candidates();
2 Dictionary<string, string> signed_datas = excute javascript at client browser to sign data, and return signed datas
3 signed_data_gridview.DataSource = signed_datas;
4 signed_data_gridview.DataBind();
}
实现自动显示签名结果
我们遇到的问题的实质是:准备签名数据(伪代码第1行)、显示签名结果(伪代码第3、4行)的操作在Server端进行;而使用USB Key进行签名的操作(伪代码第2行)必须在Client端的浏览器上执行,并且这两种操作是异步的!所以我们只能将显示签名结果的代码放到另一个函数中,在签名结束后以某种方法触发它。我们在Demo中所使用的方法是,将显示签名结果的代码放到“显示签名结果(自动)”按钮的Click事件中,在签名结束后,使用
javascript:opener.document.getElementById(show_signed_data_button.ClientID).click();
来触发这个按钮的Click事件。
思考题
我们使用一个“伪隐藏”的按钮可以简单地实现自动显示签名结果的效果,不过这种作法似乎有点土。你能否使用其它更“高级”的方法来实现同样的效果?
实现批量签名
我们需要让用户按一次按钮,就可以签名 n 条数据,可是数字签名API SignDataEx(sourcedata,...) 一次只能签名一条数据。我们需要遍历每条待签名数据,调用SignDataEx()进行签名。我们有两种选择:
1. 在Server端进行遍历,每次传送一条数据给Client端进行签名。
2. 将 n 条待签名数据一次全部传给Client端,在Client端使用javascript的for循环遍历待签名数据并进行签名。
我们在Demo程序中是使用了第1种方法。基于和“自动显示签名结果”一节所述的同样的困难,我们无法在Signer.cs的ProcessRequest()中这样写(伪码):
public void ProcessRequest(System.Web.HttpContext context)
{
foreach (string key in sign_candidates.Keys)
{
string signed_data = excute javascript at client browser to sign data, and return signed data
}
}
好在已经有大师发明了外部迭代器(external iterator),我们可以在第一次迭代之前,先创建一个待签名数据的一个外部迭代器,并把它保存在Session中。每次签名后,Client端PostBack回Server端,在Server端从Session中取出这个外部迭代器,调用sign_candidates_enumerator.MoveNext(),之后继续向Client端发送签名用的javascript语句,直至完成全部遍历,请参见Signer.cs的250~268行。下面的时序图表示批量签名3条数据的过程。
思考题
我们的DEMO实现了第1种方法,你能否实现第2种方法?这两种实现方法各有什么优缺点?
综合起来
我们把批量签名与自动显示签名结果的功能都放在Signer.cs中,可以用下面这个经过简化的时序图来表示。
附录 数字签名API简介
我们使用的是辽宁省数字认证中心发放的数字证书。他们还提供了两套数字签名API:一个是ActiveX控件;一个是COM组件。两套API都有完整、丰富的数字签名相关的函数,可以单独使用。如果是WinForm程序,直接使用COM组件即可。不过由于Web程序必须使用ActiveX控件,所以我们在作数字签名的时候使用ActiveX控件,在验证签名的时候使用COM组件。也许您手头的API和我们使用的API并不相同,不过您仍然可以下载这两套API的手册找找感觉。
LNCAToolkits 控件(通用版)程序员手册_v2.pdf <- 这个是ActiveX控件的手册
LNCA-CryptoAPI-Com版程序员手册_v1.pdf <- 这个是COM组件的手册
作数字签名的API函数是SignDataEx()。
函数声明: BSTR SignDataEx (BSTR szSrc,
BSTR sSignAlgo,
long IsAddSignCert,
long IsAddSrcData,
BSTR szInnerOid,
long IsAddTime,
BSTR pPin);
说明:进行签名数据操作(使用客户端证书)。
参数:
.. szSrc :原文数据
.. sSignAlgo:指定签名算法
szOID_OIWSEC_sha1 = “1.3.14.3.2.26”
szOID_RSA_MD5 = “1.2.840.113549.2.5”
szOID_RSA_MD2 = “1.2.840.113549.2.2”
.. IsAddSignCert 是否在结果中携带证书
0 = 不携带证书
1 = 携带证书
.. IsAddSrcData 是否在结果中携带原文
0 = 不携带原文
1 = 携带原文
.. szInnerOid:数据类型OID,(默认:NULL)
szOID_TSP_TSTInfo = "1.2.840.113549.1.9.16.1.4"
.. IsAddTime:是否添加签名时间
0: 不进行时间编码
1: 取当前系统时间,进行时间编码
2、从时间戳服务器取得时间,必须首先设置时间戳服务器URL。请参考7.14
章节的时间戳操作。
.. pPin:用户Key 口令
如果输入正确的口令,则不弹出输入口令窗口,直接签名数据。
如果输入错误的口令,则弹出输入口令窗口
其中:通过InputDataType 属性来指定原文数据格式
0 = 输入原文为二进制编码,此函数内部不进行转码
1 = 输入原文为BASE64 编码,此函数内部进行转码
返回值:成功时返回签名数据(BASE64 编码),
失败时返回空,由ErrorCode 属性中取错误码,由ErrorMessage 属性中取错误信
息。
需要说明的是IsAddSignCert这个参数。它指示是否在签名数据中携带证书。
携带证书的优点:如果选择携带证书,在验证签名时就不用再向验证签名的函数显式传递一个证书。验证签名的函数会自动从签名数据中解析出证书,然后验证签名,这在编程上无疑是非常方便的!如果选择不携带证书,我们就必须将系统所有用户的证书保存在一个“证书表”中,再在含有签名数据字段的表中创建一个专门保存“证书表”ID的字段,在验证签名前要从“证书表”中取得证书,再验证签名。
携带证书的缺点:缺点是会使签名数据比较长,例如对“1234”签名的Base64编码会有1942个字符;而如果不携带证书只有560个字符。所以如果客户十分吝啬数据库的存储空间,就需要使用不携带证书的方式。不过我个人是十分喜欢携带证书的方式的(偶是懒人^_^)
还有就是IsAddSrcData这个参数应该指定为“携带原文”,这样在验证签名的时候(使用COM组件的VerifySign函数)就不用再给出原文了(SourceData参数设为null),而且VerifySign()函数在验证成功后会返回原文,这样还可以向用户显示这样的信息:“看,以前签名的是这个数据(VerifySign()函数返回的原文),现在被改成了这个数据(表中原文字段中的值),所以验证失败”。
本篇源代码下载
本篇源代码。运行本篇的DEMO需要预先安装签名用的ActiveX控件:ActiveX_bin_v2.8.6.0_20061130.rar,解压缩后运行reg_ActiveX.bat即可完成安装,还有你的 USB Key要支持这个ActiveX控件才行。
致谢
非常感谢辽宁省数字认证中心软件开发部项目经理张铁夫先生的指导和帮助。每次电话咨询都能得到他的耐心讲解,即使我们已经试用了半年多仍然没有购买一个数字证书^_^
感谢一直关注本系列的各位同仁,大家的鼓励和指导令我受益匪浅。感谢古巴、Clark Zheng、菜菜灰在Http 处理程序方面对我的指导。感谢笑望人生、蛙蛙池塘、大石头、aspnetx、银河、慢一拍、游民一族、yoyolion对本系列的补充和指正。
工具箱
本系列的所有流程图均使用Visio 2003绘制。
UML 时序图使用Dia v0.96.1绘制。
抓图软件使用的是SnigIt v7.1.1。图片上使用了手写字体方正静蕾简体。
图片预览和格式转换使用了ACDSee v5.0。
文字部分使用Google 拼音输入法键入。
白话数字签名(2)——软件&设备
非对称加密算法有一个重大缺点——加密速度慢,或者说得更拽一些,编码率比较低。例如在上一篇里我给Clark传的那个1GB的小电影,进行非对称加密足足用了66小时。那个借条小一些吧,也用了将近2分钟。所以在实际使用非对称加密的时候,往往不直接对文件进行加密,而是使用摘要算法与非对称算法相结合(适用于数字签名)或对称加密和非对称加密相结合(适用于加密传输文件)的办法来解决或者说绕过非对称加密算法速度慢的问题。
摘要算法
摘要算法,又叫作Hash算法或散列算法,是一种将任意长度的输入浓缩成固定长度的字符串的算法,注意是“浓缩”而不是“压缩”,因为这个过程是不可逆的。它的特点是:
1. 不同内容的文件生成的散列值一定不同; (转者注:这句话有问题。不同内容生成的散列值可能会相同,否则就不存在“冲突”问题了) 相同内容的文件生成的散列值一定相同。由于这个特性,摘要算法又被形象地称为文件的“数字指纹”。
2. 不管文件多小(例如只有一个字节)或多大(例如几百GB),生成的散列值的长度都相同,而且一般都只有几十个字符。
这个神奇的算法被广泛应用于比较两个文件的内容是否相同——散列值相同,文件内容必然相同;散列值不同,文件内容必然不同。如果您用过BT或eMule,应该对散列值比较熟悉了,右图分别是BT和eMule的文件详细信息的截图。
细心的朋友可能已经注意到了,BT和eMule的散列值的长度不一样,这是因为它们所使用的摘要算法不同,目前比较流行的摘要算法主要有MD5和SHA-1,您可以在.Net的System.Security.Cryptography命名空间找到它们的身影。
另,由于本篇是只重理解和应用的白话文,所以上面对摘要算法的讨论并不十分全面严谨,喜欢看文言文的朋友可以看这篇 《Hash 算法及其应用》 。还有就是MD5和SHA-1算法已经从理论上被山东大学王小云教授及其研究小组破解(向中国的科学家致敬!),不过并不是这两个算法从此就不能用了。
实际对文件作数字签名的方法
由于非对称加密的速度实在太慢了,所以在实际对文件作数字签名的时候,例如对上一篇中我用Word写给Clark的借条进行签名,总是先生成这个借条的散列值,然后用我的私钥对这个散列值进行非对称加密,然后把加密后的散列值(我们就叫它“散列值密文”吧)和借条一同发送到Clark那里。Clark在收到借条和散列值密文后,用从网上下载的我的公钥将散列值解密,然后Clark自己再生成一次借条的散列值,比对这两个散列值是否相同,如果相同,就叫作 验证签名 成功。由于散列值只有几十个字节,所以签名的速度还可以忍受。看下图会更直观一些。
思考题
虽然我们只是对借条的散列值进行了非对称加密,但是此过程仍然具有防篡改、防抵赖的作用,为什么?
又太麻烦了
我们费了好大的劲终于解决了数字签名速度慢的问题。但是上面那个复杂的签名过程用户能接受吗?当然不能!所以我们必须要开发出一个数字签名的程序来简化签名过程,最好让数字签名看起来就跟传统的盖章差不多。这样的程序已经有了,叫作 电子签章程序 。 它是一个桌面程序,一般以Word或Excel插件的形式存在。下面就演示一下用电子签章程序对我的借条进行签名的过程。
1. 安装了电子签章程序后,Word和Excel中就会多出一个签名用的工具条。
2. 写好借条,存盘。然后用鼠标点击“添加电子签章”按钮。然后在需要显示印章图片的位置上再按一次鼠标左键。
3. 电子签章程序会弹出一个对话框,注意在这步一定要勾选“签章后锁定文件”复选框,至于为什么要这样,稍后再讲。然后点击确定按钮。
4. 在上一步按确定按钮后,电子签章程序还会提示要求我输入存放私钥的USB-Key的使用密码,然后Word中就会出现一个印章了。这个印章图片是我提供给数字证书中心,在制作USB-Key的时候就烧录在USB-Key之中的。
5. 之后我把借条发送给Clark。Clark想验证签名的话只要按“验证所有印章”就可以了。电子签章会弹出如左图所示的对话框。
是不是即直观又简单?那么诸如“散列值”、“公钥证书”这些东东都跑到哪里去了呢?它们都被电子签章程序插入到Word文档中的某个特定的地方了,如果你熟悉Word文档的结构,是不难找到它们的。
电子签章程序的Bug
电子签章程序本来可以支持两种用法:
1. 在上面的第3步不勾选“签章后锁定文件”复选框,这样在进行了数字签名之后,仍然可以更改Word文档的内容。当然如果在进行了数字签名之后又更改了Word文档的内容,验证签名操作就会失败。这时需要再次进行签名操作。
2. 在上面的第3步勾选“签章后锁定文件”复选框,这样在进行了签名操作后,Word文档的内容就再也无法更改了。
但是,电子签章程序有一个大Bug——在进行了签名操作后,如果只是更改了文字的颜色,验证签名操作仍然会成功。这就意味着,如果我在Word中写到“向公司借款2000元”,然后把“2000”的最后一个0的颜色改为白色,在领导看来就是“向公司借款200 元”。领导欣然签章,然后我再把那最后一个0的颜色改为黑色,就又变成了“向公司借款2000元”,而且验证签名居然会成功。这也是为什么我在上面的第3步要强调一定要勾选“签章后锁定文件”复选框了。我猜测造成这个Bug的原因很可能是因为电子签章程序仅仅对文档中的纯文本生成散列值,而不是对文本+全部格式信息一同生成散列值。大家在购买电子签章程序前一定要作这方面的测试。
数字信封
我们可以通过使用信息摘要技术解决数字签名的速度问题,那么数字加密的速度问题怎么解决呢?相信除了我和Clark以外,很少有人愿意为传送一个小电影而等待66个小时。其实这个问题也简单,我们可以用对称加密与非对称加密相结合的方式来解决这个问题。对称加密速度快,但是必须在传送密文的同时传送解密密钥;非对称加密速度慢,但是不需要传送解密密钥。把两个技术一起使用,各取优点,就OK了。方法是,先把小电影用对称加密算法加密,然后把解密密钥用非对称加密算法加密。再将小电影的密文与解密密钥的密文同时传送给Clark。Clark收到这两样东西后,先用自己的私钥将解密密钥的密文解密,得到解密密钥,再用解密密钥将小电影的密文解密,就得到了小电影的明文。Clark收到的这两样东西——小电影的密文和解密密钥的密文——加在一起就叫作数字信封。看下图会更直观一些。
数字证书
非对称加密的公钥和私钥的长度都很长,一般都在1024位以上。这么长且无规律的密码,用户是记不住的,所以只能保存在文件中啦。保存了公钥的文件就叫作数字证书。且慢,这个定义是十分错误的!为什么呢?想一想第1篇里的那个我给Clark发送小电影的例子。例子中我在网上下载了Clark的公钥(也就是数字证书),然后用它对小电影进行非对称加密,然后心想只有拥有Clark的私钥的Clark才能解密——Clark的老婆一定没辙啦。没想到螳螂捕蝉,黄雀在后,我下载Clark的公钥的那个网站是Clark的老婆制作的钓鱼网站!里面的公钥证书统统都是Clark的老婆的公钥!!结果呢,我的小电影用Clark的私钥解不开,反倒是只有用Clark老婆的私钥才能解开,用Clark的话来说,就是“无语了......”。
所以聪明的你一定想到了,数字证书之所以可以称之为“证书”,就一定要有“防伪”功能。方法是,数字证书里不但要包含Clark的公钥,还要包含Clark的自然信息(姓名、单位等),并且最重要的,要有证书颁发部门对这些信息的数字签名(每个证书颁发部门也都有自己的数字证书——称之为根证书——和与之配对使用的私钥)。这样我就可以验证数字证书的真伪了。所以,让我们重新定义数字证书,数字证书是由一个权威机构发行的,至少包含一个公开密钥、证书持有人(或单位)的名称以及证书授权中心对这些信息的数字签名的文件。一般情况下证书中还包括密钥的有效时间,发证机关(证书授权中心)的名称,该证书的序列号等信息,证书的格式遵循ITUT X.509国际标准。
您可以使用IE的菜单“工具 | Internet 选项... -> 内容 -> 证书... -> 受信任的根证书颁发机构”来查看IE中已经安装的根证书。点击“导入...”按钮可以导入新的根证书。
复制破解的解决方案——USB Key
我们已经知道, 非对称加密的密钥很长,一般都在1024位以上,所以只能保存在文件里。好,我把私钥文件保存在了硬盘上,却难保哪天这个文件不会被某个坏蛋拷贝走。然后,在这个“没有人知道你是一条狗”的网络世界里,他就变成了我——他可以冒充我写借条甚至向银行贷款;他可以冒充我跟别的公司签署上亿美元的合同;他甚至可以冒充我签署卖身契,300块钱就把我卖了——而我却懵然不知。直到有一天,我突然发现自己突然增加了几百万外债、公司把我Fire了、一个9岁的小女孩拿着卖身契等在我家门口声称我已经是她的奴隶......
所以千万不能把私钥保存在硬盘上。那么保存在U盘上,并且把U盘放在内裤的口袋里怎么样呢?好像好了一些,但是你在签名的时候还是得把U盘插在电脑上吧?可知道你的电脑中有多少木马程序正在用For循环扫描你的USB端口,就等着拷贝你的私钥?
我们需要的是无论如何也不可能被别人复制的私钥保存方案,USB Key应运而生。USB Key是一种USB设备,外形就跟U盘一样,只不过无法用它来存取文件。证书发行单位会使用特殊的设备将你的数字证书、私钥和电子签章程序所要使用的印章图片烧录到USB Key中。你无法使用资源管理器或木马程序取得USB Key中的私钥,当需要用私钥进行签名时,直接通过USB Key的驱动程序提供的API将明文传输到USB Key中,由USB Key中的加密芯片对明文进行加密,加密结果会以API函数的返回值的形式返回,这样就可以有效解决私钥被坏蛋复制的问题了。还有就是USB Key本身还有一个简短的使用密码,每次加密前使用者必须输入正确的使用密码方能使用,这样即使USB Key不慎丢失,也不用担心了。
USB Key的缺点
本篇到此结束,下一篇将专门介绍在B/S信息系统中对数据库中的信息进行数字签名的一些问题和解决方法。并在最后给出一个十分实用的DEMO。