如何给文件数字签名 (如何给文件数字签名打印)

最近项目当中涉及到了数字签名,也给小伙伴们推荐了李永乐老师数字签名的视频。大家看完之后觉得还是有点抽象,没办法,必须在周五下午来一个内部分享。要是能讲清楚,就是“赛永乐”了[捂脸]

什么是数字签名?

要了解什么是数字签名,先想一想日常生活中常见的手写签名。比如你跟公司签订了一份劳动合同,需要你在纸质合同上签上自己的名字。签名的目的是证明你对合同内容的认可,将来发生纠纷,有据可查。从上述场景中,我们可以归纳出两点:1. 签名必须针对于特定内容才有意义,上例中的签合同,必须在合同上签字才有意义,你在一张空白纸上签名就毫无意义(数字签名也是一样,脱离了原信息谈数字签名毫无意义,必须原信息数字签名一起传输才有意义)2. 签名的目的是为了有据可查,具体来说,需要做到两点:a. 是本人签名、b. 数据没有被篡改(一式两份、涂改无效)电脑

数字签名也是同样的道理,只是把手写签名变成了数字形式(即一串代码)

以传送一个PDF文件为例,机构A需要向机构B传送一份PDF文件,为了确保安全,采用了数字签名,那么机构B在收到PDF文件后(同时收到一个数字签名),需要确认两件事情:

1. 这份PDF文件是机构A发送的;2. 这份PDF文件在传输过程中没有被篡改。

上述两个需求,分别可以通过非对称加密 与 哈希函数 技术来实现,简单来说:

数字签名 = 非对称加密 + 哈希函数

下面分别来讨论上述两个需要确认的问题。

1. 通过非对称加密确认文件是A发送的。

什么是非对称加密?

与非对称加密对应的加密算法是对称加密,这个比较容易理解。机构A与机构B通信,约定一个密码,A把要传送的数据加密;B接收到A传送的加密数据后,进行解密,获得A传送的原始数据。上述流程简单易懂,但是存在几个问题:(1)机构A或者机构B任何一方不小心泄露了密码,就会发生安全性问题 (2)任何两方通信都需要确定一个密码,导致密码太多,难以管理。上述机构A与机构B之间约定了一个密码,如果机构A还要向机构C,机构D,机构E等等几百个机构发送数据,那么机构A需要管理几百个密码,任何一个密码出错都会导致发送异常。

怎么解决上面提到的对称加密的两个问题呢?答案就是使用“非对称加密”。

非对称加密到底是个啥?

首先,如果你是机构A,你需要向机构B,机构C,机构D等几百个机构发送数据,你不需要跟他们一个一个地确定通信密码,那样既不安全又很麻烦,而是向“数字证书颁发的权威机构”(必须是权威机构,能背书的那种,小作坊可不行)进行申请,说我要进行加密传输,而且是非对称加密传输。那么权威机构会给你一组密钥对,即公钥和私钥(实际应用中会以Ukey等形式发放),而且再三嘱咐你:私钥一定要管好!

现在你顺利地拿到了公钥和私钥电脑,可以准备向几百家机构传输数据了。在此之前,你还要做一件事情:隆重地召开一个新闻发布会,告诉几百家机构,我拿到密钥对了,可以跟你们通信了。额... 算了... 开发布会是雷布斯的事情,我们就不要操作了,还是群发一个邮件吧,把公钥群发给他们(实际我们已经处理了对称加密中的第二个问题,不需要管理太多的密码。如果是对称加密,那就不是群发了,而是一家一家私发邮件,万一邮件内容泄露了,麻烦就大了)。群发邮件的内容简单如下:

Hi All:我是机构A,我的公钥是ABC12345,你们可以通过这个密码跟我进行通信!

本来邮件内容到此就可以结束了,但是你觉得几百家机构里面可能有几家技术实力太弱,不知道如何使用,于是你又给他们加了一些备注。

Hi All:我是机构A,我的公钥是ABC12345,你们可以通过这个密码跟我进行通信!(a) 当你接收到号称是“我”发送的信息, 请用ABC12345进行解密! 如果能解密成功,说明信息是我发送的, 只有我才能加密,因为只有我才有私钥。 如果解密失败,说明有人冒充我,不要上当!(b) 如果要向我发送信息,可以使用ABC12345进行加密, 不要担心数据泄露, 只有我才能解密,因为只有我有私钥。

Good!你的邮件言简意赅,效果比雷布斯的发布会还要好,几百家机构不但收到了你的公钥信息,还明白了 非对称加密的 核心应用场景。

现在回到我们需要确认的第一件事情,机构B接收到了号称是你发送的一份PDF和一个数字签名(假设为MxMt778899)。他又仔细看了一下你发的邮件,并且严格按照你教的步骤操作,用公钥ABC12345对签名进行解密。

解密成功了!!!

机构B现在可以确定了,这份PDF就是你发送的!

即使你说私钥泄露了,法律也会站在机构B这边,别忘了这个密钥对可是权威机构发放的!所以说数字签名能起到抗否的作用。你的银行卡丢了,密码写在银行卡上,100块存款被人取走了,然后你说不是我本人操作,要求银行赔钱。银行:Get Out

好了,通过非对称加密,我们顺利地解决了第一个问题。

PS:这里有一个问题需要讨论一下。有同学问:机构A发送给机构B的加密数据,如果数据被机构C获取到了,因为公钥是公开的,那机构C也可以解密查看了?是的,没错,机构C确实可以查看。但这不影响非对称加密的应用场景,这里的应用场景是起到机构A的抗否性,就是确认这份文件是机构A发送的,机构A无法抵赖!就好像你跟公司签订的劳动合同,被其他同事看到了,也不影响你对合同的内容负责。(非对称加密是为了证明合同是你签的,无法抵赖!)你总不能说,合同被同事看到了,那我不需要对这份合同负责了吧。至于如何避免让机构C获取到数据,我们可以通过其他的方式来解决,比如必须输入用户名,密码才能查看。

2.通过哈希函数确认文件在传输过程中没有被篡改。

好了,现在机构B已经拿到了机构A发送的PDF文件,而且确定这是机构A发送的一份PDF。PDF上面的内容是:10月1号下午3点到218会议室开会。

机构B一脸懵,10月1号不是放假吗?怎么还要开会?真的假的?

机构B现在严重怀疑这份PDF的准确性!急切需要知道这份PDF内容是否被篡改!

那如何通过哈希函数来使机构B相信这份文件的真实性呢?首先我们先来了解一下哈希函数

什么是哈希函数?

假设有一个哈希函数 f(x) = y,那么这个函数满足如下特征:

x可以是任何事物,不同事物的y值不一样y的长度和格式固定不能通过y值推测出x

上面是纯理论,可能有点抽象,我们再用点白话文来解释一下。

假设我有一个杯子,那么 f(杯子) = 1122334455假设我有一件衣服,那么 f(衣服) = 0022331122假设我有一颗钻石,那么 f(钻石) = 9999999999假设我有一份PDF,那么 f(PDF) = 6677009911

根据上面的特征3,如果我现在拿到了一个哈希值 0022331122,那会怎么样?毫无意义!你根本不知道这是个什么东西,你无法通过 0022331122 知道这是一个杯子!那要怎么办?碰撞!!!不停地碰撞!!!无限循环地碰撞!!!你找来了1亿本书、1亿件衣服、1亿份pdf,不停地通过哈希函数获取哈希值... 很遗憾,没有一个哈希值是 0022331122。 你又找来了1亿个杯子,1亿张椅子,还是没有... 因为你之前的那个杯子是绝品,而且已经被你打碎了。理论上来讲,这个世界上再也没有一个物品能够得到 0022331122 的哈希值了。(排除哈希函数碰撞的可能性)

现在是不是有点理解哈希函数了,在实际的程序开发中,哈希函数大有用武之地,常见的:

1. 密码加密你的原始密码123,在数据库里面当然不能明文存储。程序做一下哈希,变成 11axcx88aa,即使数据库泄露,黑客也无法知道你的原始密码。当然,在实际的程序开发中,考虑到彩虹表等问题,我们还需要通过加盐salt等方式,进一步保证密码的安全性。2. 上传文件你觉得一部电影非常精彩,想到把它上传到你的网盘上去。这是一部高清电影,有10G,按照你的设想,至少要上传10分钟。结果呢?神奇的事情出现了,秒传!!!几乎在一瞬间,你的视频上传完成了。What happend ? 原来是网盘程序在上传视频到服务器之前,先在本地对你的视频做了一次哈希,哈希值 aavv222000,然后它拿着这个哈希值到数据库检索了一下,额... 早就有人上传了这部电影(看来你们爱好相似)。那就不用继续上传,浪费资源了,直接增加一条记录就OK了。

通过上面的讨论,你大概已经理解了哈希函数,也熟悉了它常见的应用场景,那么我们的问题应该也可以顺利解决了。怎么确定这份PDF文件是否被篡改呢?对比PDF文件的哈希值啊!

首先,在机构A传输文件之前,先通过哈希函数对这个PDF文件进行一次哈希(信息摘要),获取到一个哈希值, 假设为szsz112266,然后再通过非对称加密的私钥对szsz11226进行加密,得到一个加密值MxMt778899。把这个加密值作为数字签名,和PDF文件一起,发送到机构B。机构B在接收到PDF文件和数字签名之后,首先就是通过利用机构A的公钥进行解密,解密成功,获取到一个值 szsz112266。至此,可以说明PDF文件是机构A发送的。然后,机构B为了确认PDF文件是否被篡改,可以通过哈希函数对PDF文件进行一次哈希,如果哈希的结果值与 szsz112266 一致,就说明这份文件没有被篡改过;如果不一致,对不起,这份PDF文件有问题。

至此,我们就成功地解释了数字签名技术是如何解决我们最关心的两个问题。