一、对称性加密
对称性密码,也叫共享密钥密码,顾名思义,这种加密方式用相同的密钥进行加密和解密。
举例一种最简单的对称加密的方法:生成一个长度和原始信息一样的随机比特0/1序列作为密钥,用它对原始信息做异或运算就生成了密文, 再用该密钥对密文做一次异或运算就可以恢复原始信息
存在问题:密钥的长度和原始信息完全一致,如果原始信息很大,密钥也会一样大,而且生成大量真随机比特序列的计算开销也比较大(Rijndael 算法、三重 DES 算法等等有效解决了这些问题。它们从算法上是无懈可击的,也就是拥有巨大的密钥空间,基本无法暴力破解,而且加密过程相对快速)
但是,一切对称加密算法的软肋在于密钥的配送:加密和解密用同一个密钥,发送方必须设法把密钥发送给接收方。如果窃听者有能力窃取密文,肯定也可以窃取密钥;
解决密钥配送问题最常见的算法:Diffie-Hellman 密钥交换算法和非对称加密算法。
二、密钥交换算法
我们所说的密钥一般就是一个很大的数字,算法用这个数加密、解密。问题在于,信道是不安全的,所有发出的数据都会被窃取。换句话说,有没有一种办法,能够让两个人在众目睽睽之下,光明正大地交换一个秘密,把对称性密钥安全地送到接收方的手中?
Diffie-Hellman 密钥交换算法可以做到。准确的说,该算法并不是把一个秘密安全地「送给」对方,而是通过一些共享的数字,双方「心中」各自「生成」了一个相同的秘密,而且双方的这个秘密,是第三方窃听者无法生成的。
并不是所有运算都有逆运算:单向散列函数,给一个数字 a 和一个散列函数 f,你可以很快计算出 f(a),但是如果给你 f(a) 和 f,推出 a 是一件基本做不到的事。密钥交换算法之所以看起来如此玄幻,就是利用了这种不可逆的性质。
下面,看下密钥交换算法的流程是什么,按照命名惯例,准备执行密钥交换算法的双方称为 Alice 和 Bob,在网络中企图窃取他俩通信内容的坏人称为 Hack 吧。
首先,Alice 和 Bob 协商出两个数字 N 和 G 作为生成元,当然协商过程可以被窃听者 Hack 窃取,所以我把这两个数画到中间,代表三方都知道:
现在 Alice 和 Bob 心中各自想一个数字出来,分别称为 A 和 B 吧:
现在 Alice 将自己心里的这个数字 A 和 G 通过某些运算得出一个数 AG,然后发给 Bob;Bob 将自己心里的数 B 和 G 通过相同的运算得出一个数 BG,然后发给 Alice:
现在的情况变成这样了:
注意,类似刚才举的散列函数的例子,知道 AG 和 G,并不能反推出 A 是多少,BG 同理。
那么,Alice 可以通过 BG 和自己的 A 通过某些运算得到一个数 ABG,Bob 也可以通过 AG 和自己的 B 通过某些运算得到 ABG,这个数就是 Alice 和 Bob 共有的秘密。
而对于 Hack,可以窃取传输过程中的 G,AG,BG,但是由于计算不可逆,怎么都无法结合出 ABG 这个数字。
以上就是基本流程,至于具体的数字取值是有讲究的
该算法可以在第三者窃听的前提下,算出一个别人无法算出的秘密作为对称性加密算法的密钥,开始对称加密的通信。
但是,对于该算法,Hack 又想到一种破解方法,不是窃听 Alice 和 Bob 的通信数据,而是直接同时冒充 Alice 和 Bob 的身份,也就是我们说的「中间人攻击」:
这样,双方根本无法察觉在和 Hack 共享秘密,后果就是 Hack 可以解密甚至修改数据。
可见,密钥交换算法也不算完全解决了密钥配送问题,缺陷在于无法核实对方身份。所以密钥交换算法之前一般要核实对方身份,比如使用数字签名。
三、非对称加密
非对称加密的思路:把加密密钥和解密密钥分开,公钥用于加密,私钥用于解密。只把公钥传送给对方,然后对方开始给我发送加密的数据,我用私钥就可以解密。至于窃听者,拿到公钥和加密数据也没用,因为只有我手上的私钥才能解密。
可以这样想,私钥是钥匙,而公钥是锁,可以把锁公开出去,让别人把数据锁起来发给我;而钥匙一定要留在自己手里,用于解锁。我们常见的 RSA 算法就是典型的非对称加密算法;
非对称性加密的运算速度要比对称性加密慢很多的,所以传输大量数据时,一般不会用公钥直接加密数据,而是加密对称性加密的密钥,传输给对方,然后双方使用对称性加密算法传输数据。
类似 Diffie-Hellman 算法,非对称加密算法也无法确定通信双方的身份,依然会遭到中间人攻击。比如 Hack 拦截 Bob 发出的公钥,然后冒充 Bob 的身份给 Alice 发送自己的公钥,那么不知情的 Alice 就会把私密数据用 Hack 的公钥加密,Hack 可以通过私钥解密窃取
如果双方有一个对称加密方案,希望加密通信,而且不能让别人得到钥匙,那么可以使用 Diffie-Hellman 算法交换密钥。
如果你希望任何人都可以对信息加密,而只有你能够解密,那么就使用 RSA 非对称加密算法,公布公钥。
四、数字签名
刚才说非对称加密,把公钥公开用于他人对数据加密然后发给你,只有用你手上对应的私钥才能将密文解密。其实,私钥也可用用来加密数据的,对于 RSA 算法,私钥加密的数据只有公钥才能解开。
数字签名也是利用了非对称性密钥的特性,但是和公钥加密完全颠倒过来:仍然公布公钥,但是用你的私钥加密数据,然后把加密的数据公布出去,这就是数字签名。
数字签名的作用本来就不是保证数据的机密性,而是证明你的身份,证明这些数据确实是由你本人发出的。
你的私钥加密的数据,只有你的公钥才能解开,那么如果一份加密数据能够被你的公钥解开,不就说明这份数据是你(私钥持有者)本人发布的吗?
当然,加密数据仅仅是一个签名,签名应该和数据一同发出,具体流程应该是:
1、Bob 生成公钥和私钥,然后把公钥公布出去,私钥自己保留。
2、用私钥加密数据作为签名,然后将数据附带着签名一同发布出去。
3、Alice 收到数据和签名,需要检查此份数据是否是 Bob 所发出,于是用 Bob 之前发出的公钥尝试解密签名,将收到的数据和签名解密后的结果作对比,如果完全相同,说明数据没被篡改,且确实由 Bob 发出。
为什么 Alice 这么肯定呢,毕竟数据和签名是两部分,都可以被掉包呀?原因如下:
1、如果有人修改了数据,那么 Alice 解密签名之后,对比发现二者不一致,察觉出异常。
2、如果有人替换了签名,那么 Alice 用 Bob 的公钥只能解出一串乱码,显然和数据不一致。
3、也许有人企图修改数据,然后将修改之后的数据制成签名,使得 Alice 的对比无法发现不一致;但是一旦解开签名,就不可能再重新生成 Bob 的签名了,因为没有 Bob 的私钥。
综上,数字签名可以一定程度上认证数据的来源。之所以说是一定程度上,是因为这种方式依然可能受到中间人攻击。一旦涉及公钥的发布,接收方就可能收到中间人的假公钥,进行错误的认证,这个问题始终避免不了。
说来可笑,数字签名就是验证对方身份的一种方式,但是前提是对方的身份必须是真的… 这似乎陷入一个先有鸡还是先有蛋的死循环,要想确定对方的身份,必须有一个信任的源头,否则的话,再多的流程也只是在转移问题,而不是真正解决问题。
五、公钥证书
证书其实就是公钥 + 签名,由第三方认证机构颁发。引入可信任的第三方,是终结信任循环的一种可行方案。
证书认证的流程大致如下:
1、Bob 去可信任的认证机构证实本人真实身份,并提供自己的公钥。
2、Alice 想跟 Bob 通信,首先向认证机构请求 Bob 的公钥,认证机构会把一张证书(Bob 的公钥以及自己对其公钥的签名)发送给 Alice。
3、Alice 检查签名,确定该公钥确实由这家认证机构发送,中途未被篡改。
4、Alice 通过这个公钥加密数据,开始和 Bob 通信。
以上只是为了说明,证书只需要安装一次,并不需要每次都向认证机构请求;一般是服务器直接给客户端发送证书,而不是认证机构。
也许有人问,Alice 要想通过数字签名确定证书的有效性,前提是要有该机构的(认证)公钥,这不是又回到刚才的死循环了吗?
我们安装的正规浏览器中都预存了正规认证机构的证书(包含其公钥),用于确认机构身份,所以说证书的认证是可信的。
Bob 向机构提供公钥的过程中,需要提供很多个人信息进行身份验证,比较严格,所以说也算是可靠的。
获得了 Bob 的可信公钥,Alice 和 Bob 之间的通信基于加密算法的保护,是完全无懈可击的。
现在的正规网站,大都使用 HTTPS 协议,就是在 HTTP 协议和 TCP 协议之间加了一个 SSL/TLS 安全层。在你的浏览器和网站服务器完成 TCP 握手后,SSL 协议层也会进行 SSL 握手交换安全参数,其中就包含该网站的证书,以便浏览器验证站点身份。SSL 安全层验证完成之后,上层的 HTTP 协议内容都会被加密,保证数据的安全传输。