安全,安全…1…公钥私钥

前一段做了很多安全相关的东西,简单总结一下。

Public Key Cryptography

首先,最基础的,也是目前应用广泛的公私钥加解密理论(公开密钥加密 public key cryptography,又称非对称加密),简单地说指的是公钥和私钥成对被创建,一段信息被公钥加密后只能用对应私钥解密,类似的,一段信息被私钥加密后只能用对应公钥解密。

为什么把这对密钥叫做公钥和私钥呢?假设某人A生成了一对公私钥,公钥是公共的可以告诉其他人的密钥,而私钥是私有的需要保密的的密钥。

这个理论有什么用呢?典型的两个用途,一是消息加密(防截获破解),二是消息签名(防篡改)。

消息加密

先说消息加密。假设A需要发送消息给B。那么A可以用B的公钥加密消息,然后将加密后的消息发送给B。B得到加密后的消息,用自己的私钥解密,就能获得这条消息。假设因为传输不安全,加密后的消息被C截获,因为C并没有B的私钥。也就不能解密这条消息。但是这样做并不能防篡改,假设B获得一条声称是发给自己的消息,B并没有办法验证这条消息有没有被篡改。防篡改的内容在下一节讲到。

先暂时跳出公私钥加解密理论的框架。说下对称加密。对称加密很好理解,一段消息用一个密钥加密过后,也要用同样的密钥解密。回过头看上面的例子,假如A要安全地发送消息给B,或者发给很多人,那假如大家都知道密钥的情况下。A只需要用这个密钥加密消息,然后发送给大家,接收者各自用这个密钥解密。这样在大家都安全地拥有这个密钥的情况下自然不会有问题。不过问题又来了,在密钥被生成出来的时候,如何安全地把这个密钥传送给A以及其他接收者呢?鸡生蛋,蛋生鸡…当然,可以跳出这个系统,怎样安全地把这个密钥传送给A以及其他人呢?走过去直接告诉他们,确保安全即可…

消息签名

再说消息签名。假设A需要对外发布一条消息“明天去徐家汇吃饭”,并且让接收者能证明这条消息是A发送的。那么A可以用自己的私钥加密消息,然后发布加密后的消息(假设是“ASDFGGHKI”)。这时任何接收者都可以用A的公钥解密消息,问题来了,怎么防止消息本身被篡改过呢?比如B得到的是没篡改过的“ASDFGGHKI”,但C得到的是被篡改过的“DSADFALKDJS”。B用A的公钥解密得到“明天去徐家汇吃饭”,C用A的公钥解密得到“明天去莲花路吃饭”。怎么判断哪个才是A原本发布的消息呢?

显然,除了解密过程,我们还需要验证过程。如果A发布的消息包括加密后的消息“ASDFGGHKI”作为签名和原本的消息“明天去徐家汇吃饭”,会怎样?假设B得到没篡改过的“ASDFGGHKI明天去徐家汇吃饭”,那么B用A的公钥解密签名得到“明天去徐家汇吃饭”,前后比较一致,说明消息没有被篡改过。假设C得到篡改过的消息“DSADFALKDJS明天去徐家汇吃饭”,C用A的公钥解密签名得到“明天去莲花路吃饭”与后面部分不合,说明消息被篡改。假设D得到篡改过的消息“ASDFGGHKI明天不吃饭”,D解密签名获得“明天去徐家汇吃饭”与后面不合,说明消息被篡改。

看起来没问题了?还是有问题的…前面两个例子都是假设篡改者或者只改签名,或者只改消息。假设篡改者两者都改,有两种情况:

情况一, 假设篡改者希望将消息改为“明天不吃饭”。那么篡改者必须得到“明天不吃饭”被A的私钥加密后的字符串,然后替换掉原来的签名。A的私钥他能拿到吗?不能,所以不可行。

情况二,假设篡改者只是简单地希望破坏掉这条消息,那么他可以把签名部分任意篡改比如改成“SDDF”,然后用A的公钥解密“SDDF”得到比如“呵呵呵”,那么他就能把消息篡改为“SDDF呵呵呵”。接收者并不能判断出这条A发布的消息经过篡改。

好吧,我们只好得出结论,发布消息本身和签名,也不能100%地防止篡改。

怎样才能解决掉上面第二种情况呢?首先,因为A的公钥是公开的,篡改者总是可以根据A的公钥去“解密”一个他给定的字符串。所以问题就出在验证过程上。我们目前的做法是用解密后的数据与消息相比较。所以篡改者可以直接用解密后的字符串替换掉消息。如果我们的验证过程是用解密后的数据与经过不可逆算法处理的消息相比较呢?换句话讲,对消息发布者而言,先用经过不可逆算法处理消息M得到N(消息摘要),再用私钥加密N得到签名,是否可行?

假设我们有算法S,能够根据输入数据I生成数据O,整个过程不可逆,且I如果不同,则O一定不同。A用算法S处理消息“明天去徐家汇吃饭”,得到消息摘要比如“SDFDFS”,然后用再用私钥加密“SDFDFS”得到比如“SDLKFJDD”作为签名。这时候A发送出去的消息是“SDLKFJDD明天去徐家汇吃饭”。这样能够防篡改吗?

假设B得到没有篡改过的消息。B先用A的公钥解密签名得到“SDFDFS”,再用S算法处理“明天去徐家汇吃饭”得到消息摘要“SDFDFS”,两者匹配,证明消息没被篡改过。类似的,假设这条消息只是消息本身或者签名被篡改,接收者也能够验证。那么,这个方案能解决掉上面第二种情况吗?

假设篡改者只是简单地希望破坏掉这条消息,那么他可以把签名部分任意篡改比如改成“SDDF”,然后用A的公钥解密“SDDF”得到比如“呵呵呵”。这时候他需要S的逆算法,通过消息摘要“呵呵呵”来生成出消息比如“这不是真的”,最后将消息篡改为“SDDF这不是真的”。假如S逆算法存在,那么他能够将消息篡改为“SDDF这不是真的”。S逆算法存在吗?不存在,所以篡改者不能这么篡改消息。所以,公私钥+生成消息摘要的不可逆算法,可以防止来自公私钥拥有者的消息被篡改

总结一下使用数字签名防止消息被篡改的过程:消息发布者使用不可逆算法计算出消息摘要,再用私钥加密消息摘要生成出数字签名,然后将消息与数字签名一起发布;消息接收者使用同样算法根据消息生成出消息摘要,再用消息发布者的公钥解密数字签名并将结果与消息摘要比较,以此验证消息是否被篡改过。

有一点值得一提的是,上面的做法,有个重要的假设:消息接收者都能拿到消息发送者真正的公钥,设想假如某些消息接收者拿到了假的公钥…那么拥有对应假私钥的篡改者就能任意篡改数据了。

消息签名+消息加密

好了,在以上两节的基础上。如果A需要发送消息“明天去徐家汇吃饭”给B,且既需要防截获破解,又需要防篡改。那么结合以上两节的做法,A需要发送这样的信息:“用A的私钥加密(S(明天去徐家汇吃饭))用B的公钥加密(明天去徐家汇吃饭)”。

杂项&参考

RSA算法:一种公开密钥加密算法

SHA算法:一种不可逆的生成报文摘要的哈希算法。

MD5算法:一种不可逆的生成报文摘要的哈希算法。

注:注意在上面防篡改的证明中,用了不严谨的三段论。比如,篡改者需要A的私钥才能生成加密后的数据,篡改者没有A的私钥,所以篡改者不能生成加密后的数据。这是充分条件当作必要条件来用,但是你懂的,写东西很累的,每次都反证必要条件很烦的…

安全,安全…木有100%的安全,假设有黑客能以某种方式破解公开密钥加密算法,或者能破解S算法,或者简单点直接拿了你的私钥,或者让你拿到了假的公钥,那神马都是浮云…有意思的是,正如上面黑体字提到的,利用消息签名防篡改,还是要建立在“消息接收者能拿到消息发送者真正的公钥”这个基础上的。那对消息接收者来说,怎样才能100%安全地拿到这个真正的没被篡改过的公钥呢?…很有意思,这个防篡改安全系统的建立,还是要基于另一个安全假设成立的前提。

To be continued…

本来这篇blog的目的是从理论一直讲到各种应用,比如.NET强命名,授权认证等等。由于我的本事就是把很简单的事情讲的很复杂,所以篇幅很长得分开了…

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>