本文取材自《计算机网络自顶向下(第7版)英文版》,因为中文版电子书实在没找到……,所以文中某些截图会出现少量英文字母,这是去年助我拿offer的好书之一,2017年出版,可以保证时效性和正确性。然后再通过大牛的博客查缺补漏。以樱木花道,赤木晴子,流川枫三人的故事展开,虽仍不如大牛,但亦有闪光之处
某天,晴子家买了电脑,于是赶紧登上,打算给远在美国的流川枫发消息,但是80年代的时候,http才刚刚出现,不久樱木知道这件事,气的拿头撞篮板,伴随着嘴角的一丝微笑,他打算窃听
密码
晴子发了一句“哦哈哟”,哦不对,是“流川枫,你好帅”
樱木马上劫持了这句话,改成了“死开”
流川枫收到后,马上明白了问题,告诉晴子,你的消息被篡改了
聪明的晴子马上懂了,她想,如果我把消息加密的话,就不会被改了
“流川枫,你好帅”称为明文,需要使用某种加密算法将其变为密文,而且这个加密算法一定是可以公开的,否则就没有推广的意义
如果加密算法类比成一个函数的话,那么必须传入某些独属于我的信息作为参数才能让加密结果不一样,这就是密钥
晴子打算提供一个密钥 KA,这是一个字符串,作为加密算法的一部分,m表示明文, KA(m)表示用 KA加密m得到的密文,流川枫也会有一个KB,使用KB(KA(m))=m的解密算法获得明文m
当KA==KB时,这是对称密钥系统
当KA!=KB时,这是公钥系统
密码学知识广博,本文不深入到具体某个加密算法是如何加密的,默认使用这个加密算法就可以使得窃听者无法破解
对称密钥
对于破解密文,有三种不同的攻击
- 唯密文攻击
樱木只收集到了密文,然后通过各种数学手段破解 - 已知明文攻击
樱木推断密文中会有“流川枫”,“两年半”,“唱”,“跳”,“篮球”等词汇,或者晴子在句子开头常用的开场白,就可以轻松的破解一部分密文,然后再解决其他密文 - 选择明文攻击
樱木获得一些明文,和对应的密文,这就像英汉字典一样,可以轻松破解密文
这些晴子都想到了,所以她开始思考加密方法
单码替换密码
古时候的凯撒密码就是将英文字母向右移动k位
那么 "i love you" 就会变成 "s gktc wky"
当然,这种办法用统计学的方法就可以破解,因为英语中e的频率最高,只要樱木收集足够多的密文,就可以统计出谁是e,r其他字母类似
多码代替密码
单码只有一个未知数k,然后所有字母都移动k位
显然,可以使用多个k,第一句用k1,第二句用k2
加密时,我们可以使用 1,2,2,1,2的次序循环
第一个字母用k==5,第2,3个字母用k==19,第4个字母用k==5,第5个字母用k==19
然后依次循环,就可以破解统计规律
当然,以上都是入门对称加密的简单方法,在现代,对称加密主要有两种方式,流密码和块密码,由于https使用的是块密码,我们只讨论块密码
块密码
块密码思想很简单,他维护一个表,每种输入对应一个输出,加入3个bit算一个输入,那么总共有2^2=8种可能,表中的每一个输出都是传入密钥后的加密算法对输入计算后得到的密文
也就是说,通过这个表,所有的01数据流都可以加密成为密码
比如010110001111将会加密成为101000111001
但是,对于樱木来说,如果这个算法推广的话,他也有这个表,只需要蛮力尝试,就可以破解,因为这八种输入将可以组合成为8!=40320(8的阶乘)
那么,密钥一定就藏在这40320种组合里面,只要获取晴子的密文,进行最多40320次解码运算,就可以解密
所以关键在于k位bit密码,这个k越大,可以组成的可能输入就越多,蛮力找到密钥的方法就越不奏效,但是有个问题,k越大,上面那个表也越大,比如k==64,那么表就有2^64个输入,而且一旦更改密钥,表就要跟着变,因为输出就是加密算法和密钥共同对输入加密产生的结果
量大不决,分治解决!!,
如果2^64做不到,
那8个2^8如何?
这里的T1到T8都是不同版本的表,就像上面那个表
分别进行加密后,再进行混淆,然后循环n次,这样子就使得运算复杂度大大降低!
这好比将并列的for循环打出了嵌套for循环的效果,而樱木如果想蛮力破解的,就需要面对嵌套for循环得到复杂度
当密钥长度为56位时,这个算法叫做DES
当密钥长度为128位时,这个算法叫做AES
还有一个问题,不管算法多么精妙,如果相同明文加密后的密文是一样的话,就还是有被破解的风险,如何让相同明文加密后的密文变化呢?
加密算法是不会变的,但是参数——密钥可以变,可是难道要不断改密钥吗?
我们前面一段明文生成的密文,难道不是最好的加密下一段明文的密钥吗?
也就是说,在上图中,每一轮只能处理64比特的明文,将最后的输出作为下一轮的加密密钥即可
具体数学算法不展开讲,有兴趣可以搜索DES,3DES,AES等相关介绍
公钥系统
晴子这边虽然加密没问题,但是如何让流川枫解密呢?他需要密钥,可是晴子如果发消息告诉他密钥的话,樱木也会知道,如果对密钥加密发送的话……
或许打电话告诉他是个好办法,但是这里我们可以使用公钥系统
晴子有两个密钥,公钥和私钥,公钥加密的信息只有私钥能解开,反之亦然,加密算法就是我们上面说的
流川枫也有两个,而却他们的公钥是公开的,也就是说,樱木也有他两的公钥
如果晴子用流川枫的公钥加密信息,发送给流川枫,那么这个世界上只有流川枫能解开,因为只有他有私钥!
公钥思想就是这么简单!
也就是说,谁收消息,用谁的公钥加密,并解密
流川枫发消息给晴子也一样,就用晴子的公钥加密
这方面的代表算法是RSA,有兴趣可以查查资料
似乎公钥系统吊打对称加密,但是不幸的是RSA是很慢的,而对称加密里面的DES,AES算法很快,所以现在一般采用两者结合的方法
用RSA加密密钥,发给对方
然后双方相同的密钥进行对称加密传输真正想传输的信息
晴子写好了加密算法,按下回车键,一句加密过的信息就发过去了!
消息完整
樱木再次截到了晴子的信息,发现是一堆乱码,不禁悲从中来,脸颊不觉落下晶莹的水珠
原来,是看到这许多英文字符,学渣属性激活,瞬间大睡了起来,口水竟滴在了键盘上
熟睡中,无意间切掉了一部分字符,导致发给流川枫的,是一段残缺的话
流川枫再次反馈了这个bug,于是晴子又开动了脑筋
入侵者虽然看不懂加密后的消息,但是他可以随意篡改消息啊!
所以,必须让流川枫能够确定消息的完整性,让他知道哪些是我想发的,哪些是被改过的
如果我发的消息我可以算出一个特征值,发给他,他拿到消息后用同样的算法计算特征值,如果两个特征值一样,那就证明我发的和他收到的一样!
这就是核心思想
密码散列
要想让不同消息的特征值不一样,算法H()一定要找好,使得不同的消息x,y
一定满足H(x)!=H(y)
然后将(m,H(m)打包成为扩展报文发出去,这里的m表示是密文
然后流川枫收到后,用同样的H()算法计算H(m)=h,看这个h和发过来的H(m)是否一致,如果不一样,就证明m已经被改过了
这个H()算法就是现在流行的md5,SHA-1算法
但是,还有问题!!
如果樱木拿到(m,H(m),他虽然不能破解,也不能直接修改m,但是他可以两个一起修改
(m',H(m'),发给流川枫,此时就可以骗过流川枫
所以必须要让m与H(m)产生关联,而且是只有双方才知道的关联,防止两个被一起掉包
这个时候需要一个鉴别密钥 s
晴子计算H(m+s),这个称为报文鉴别码(Message Authentication Code, MAC)
这个MAC很重要,后面还会提哦,多看两眼吧~
然后晴子发送的是(m,H(m+s)),发送给流川枫
此时如果樱木还是替换成为(m',H(m'),流川枫在那边计算的将是 H(m'+s)发现不一样,就会认为整个报文都被替换了
最后一个问题,如何让流川枫知道这个s呢?或许我们可以用公钥系统中RSA加密发过去
不过这个工作不是晴子做的,是网络管理员来做
端点鉴别
樱木终于醒了,看着晴子一条一条宛如天书的消息发过去,自己却毫无作为,不经怒从心中起,发尽上指冠,突然仰天一大笑,恶向胆边生。一拍手,叫樱木军团把晴子的网线拔了!然后自己伪装成晴子,给流川枫发了句“爱你哦,么么哒”
流川枫眉头一皱,发现事情并不简单,于是想了一个办法
流川枫如何知道和他聊天的是晴子还是女装大佬呢?
查ip地址?
不行,有点水平的人一定会在发出的报文中修改自己的ip成为晴子的
和晴子商量一个口令?在报文中没有口令就认为是假的
也不行,这种方法无法推广,难道跟10个人聊天就要10个口令?
如果只用一个口令,当你telnet远程到一个计算机时,口令也会明文发送出去,容易被窃取
那我使用加密口令如何?
一样的,樱木并不在意口令是一段话还是一段随机数,
上面失败的根本原因在于,流川枫无法判断晴子是否还在线,如果晴子还在线,樱木是无法伪装晴子的ip地址的
所以判断晴子是否在线成为关键
使用不重数(nonce),所谓不重,就是他只在一个协议的生存期中使用一次
流川枫会在一开始选择一个不重数R,发送给晴子
然后晴子用他两都有的对称密钥K加密这个不重数,然后流川枫解密
如果解密出来的是R,证明对面是晴子,因为密钥只有他两有,樱木是没有的!
樱木花道终于服了,听着《一剪梅》,正黯然神伤,突然电脑想起了滴滴滴的声音,是晴子发来的,内容是两个字——“在吗”
总结 https
晴子最后跟樱木说什么呢?最后他们让我保密,所以我不说了,现在来总结下
https就是在http的基础上加了一层SSL(Secure Socket Layer),中文是安全套接字层,注意正确断句哦
就是这里的SSL socket,SSL sublayer是SSL的子层,这里只是分得更细一些
我们知道,并不是晴子真的和流川枫聊天,而是中间有个服务器进行转发,
服务器会有证书,证明这是一个可信任的服务器(所以你打开某些网站的时候会发现他说证书过期,不可信)
所以,整个SSL的步骤是这样的
- 晴子发送他支持的密码算法的列表,和一个不重数
- 从这个列表中,服务器选一种对称算法(比如AES,用来加密信息),一种公钥算法(比如RSA,用来加密对称密钥),一种MAC算法(比如SHA-1,还记得MAC吗,在密码散列哪里),同时把证书和一个服务器不重数返回给晴子
- 晴子验证这个证书,证明这个服务器是可信任的,然后找到服务器公钥,生成一个前主密钥(Pre Master Secret,PMS),用服务器公钥加密PMS,并发送给服务器
- 使用相同的密钥导出函数,晴子和服务器独立的从PMS和不重数中计算出主密钥(MS),然后将MS拆分成两个密钥和两个MAC密钥
- 晴子发送所有握手报文和一个MAC
- 服务器发送所有握手报文和一个MAC
第3和第4条可能难以理解,他们的主要目的就是让双方都获得一样的加密密钥和散列密钥,为什么各有两个呢?因为从安全性看
晴子发给流川枫需要一个加密密钥
流川枫发给晴子应该再找一个不同的加密密钥
保持文档完整性的散列密钥同样两个
至于前主密钥和主密钥,只是用来生成最后四个密钥的步骤而已,但是这个东西不能给第三方,所以需要那样生成
第5和第6条似乎有点多余,但是想一下这种情况,在第一条中,樱木截取了列表,并删除了其中的厉害的加密算法(比如DES,AES),因为此时没有密钥产生,晴子发送的是明文
然后将加密算法改成比较弱的(比如凯撒密码?)
所以,为了确保第一条时晴子发送消息的完整性,在第5条中发一个级联之前所有报文的MAC,(此时已经有密钥,保证了完整和安全),服务器也将晴子发的消息进行MAC,后将这两个MAC比对,如果不一样,证明第一条的时候被篡改了!!
最安全的SSL方法总算弄好了,这就是https,晴子长舒一口气,挠了挠头,发现手中似乎有不少头发……
作者简介:小松与蘑菇,一个即将家里毕业的大学生,本文参考自《计算机网络自定向下第7版》,英文版,但是我有第6版的中文版,关注微信公众号【小松与蘑菇】回复【计算机网络】即可获得资源哦