非对称加密应用实例详解

1前言

在现代信息安全技术应用中,非对称加密已经是组成整个互联网大厦的基础架构。像网络支付,https协议,ssh通讯,加密电子邮件等涉及到信息安全的地方几乎都能见到非对称加密的身影。在互联网技术分工相对细化的企业或技术团队中,通常会有专人负责维护这一部分。对于技术团队中的其他人,或许对于“非对称加密”这个名词也仅限于听说过的程度。但多理解一些技术细节总归是好的,就像我常常看到的一个名言“为了成为一个更好的开发者,你必须对日常接触到的软件系统底层有个清晰的理解。它包括编程语言,编译器,解释器,数据库,操作系统,网络服务器,服务器架构等等”。这篇文章就试图为非对称加密在现实中的应用描绘一个清晰的轮廓。

简单的介绍

这篇文章的目的是为了描绘非对称加密的应用,而不是去讨论它的具体实现细节和机制,因此这里仅仅对非对称加密是何物做一个简单的解释。简单的说,非对称加密的“非对称”体现在加密和解密采用不同的密码。我们可以通过它的反面“对称加密”来理解。在日常生活中的普通机械钥匙,就是一种“对称加密”。机械锁孔中弹珠的深浅位置是按照钥匙的轮廓打造的,最后开锁的钥匙也采用相同的轮廓。像这样配置锁芯和制造钥匙都用同一个轮廓做的机械锁就是对称加密。再比如说常见的密码包的锁,它一般允许用户在锁开状态时设定一个密码,然后开锁时也用同一个密码。这也是一种对称加密。非对称加密就相当于制造锁芯是按照一把锁而做,而开锁时却要用另一把完全不一样的锁。在信息技术中,那把加密的锁被称为公钥,解密的锁被称为私钥。公钥可以公开给很多人看,这些人用公钥把信息加密后,只有持有私钥的人才能解密。这个加密逻辑的妙处就在于通信双方在一开始可以完全没有联系,而在通信过程中通过发送公开信息(公钥)而建立秘密连接。仔细想想,这其实是一个绝妙的艺术般的体验。这就像你和一个陌生人在广场上喊话,你唯一确定的就是对方能听懂普通话,然后你用普通话对它说了一串数字,他根据这一串数字就能回答一句只有你才懂的方言(这一句方言里面通常也包含一串用于之后通信的数字),再然后你就可以用只属于你和他能理解的方言对话了!而其他人虽然能听懂你说的第一句话,却完全听不懂你们之后的对话!

3 https中的应用

https可以很好的作为一个经典范例来解释非对称加密的用法。在互联网网页的访问流程中遇见的第一个风险就是:“它可能不是它”!例如你访问某宝网准备购物,但你怎么确认你访问的网页就是在某宝网的服务器上呢?仅仅凭借访问地址吗?有可能会有坏人劫持了你的访问,并安排一个看起来和某宝网一样,但实际上是由那个坏人控制的服务器操作的呢!你下单,付款有可能就付给那个坏人了!非对称加密就是我们的英雄,它完美的解决了“如何证明我就是我”的难题!

3.1证明我就是我——不对称之外的对称

前面提到了非对称加密的精髓就是公钥加密的信息只有私钥才能打开,这里还要提到的一个精髓就是:私钥加密的信息也只有公钥才能打得开!公钥和私钥在这一层应用的意义上来说是对称的!于是乎,当用户访问某宝网时,某宝网会发送一个包含其公钥和被私钥加密的信息给用户(私钥的加密在技术角度上就叫做“数字签名”)。用户接到这些信息后,将尝试用接收到的公钥来解密被私钥的加密的信息,如果能够解密成功,则证明了发送给我信息的服务器确实拥有这个公钥的私钥。因为如果对方没有私钥的话,是不可能加密出这个公钥能解密的信息的。

以下两段命令是相反的

1.

openssl rsautl -encrypt -inkeypublic.pem -pubin -in message.txt -out message.ssl

openssl rsautl -decrypt -inkeyprivate.pem -in message.ssl -out message.txt

2.

openssl rsautl -sign -inkeyprivate.pem -in message.txt -out message.ssl

openssl rsautl -inkeypublic.pem -pubin -in message.ssl -out message.txt

利用openssl工具,我们可以用公钥加密,私钥解密;也可以用私钥签名,公钥验证。

用户在验证了对方私钥合法后,还需要验证收到的公钥也合法。因为坏人完全有可能自己生成一对公钥和私钥,然后把信息一起发给你。其实按照同样的逻辑,我们也可以来验证公钥的合法性。

3.2信任链条——另一把私钥

根据上面的逻辑,当你拥有公钥,就能验证某个数据是否来自正确的地方。如果公钥不能保证合法,那么这个信任验证也就无效了。因此,在所有计算机或者浏览器里都存有一组权威机构的公钥。这组公钥并非来自别人发来的数据,而是本地数据(它或者保存在操作系统中,或者保存在浏览器中)。这些权威机构通常是世界知名信用公司,它们公开自己的财务等所有信息,受到世界人民的监管(如果这些公司出现信任问题,将会立即倒闭,历史上发生过几次类似的大事件)。如果计算机收到一组数据,这组数据可以通过本地的某个公钥解密,那么就可以断定该组数据来源于某个权威机构(或者该权威机构认可的值的信任的下一级机构)。

结合3.1和3.2当用户接收到服务器发来的数据时,将发生以下事情:

1. 用户接到服务器发来的证书和一组由服务器私钥加密的数据

2. 用户用本地的某个公钥对证书解密成功,这证明了该证书一定来自于权威机构

3. 上一步解密后得到一个公钥和一些服务器的ip地址等信息

4.用解密后得到公钥对从服务器收到那组由服务器私钥加密的数据进行解密,并解密成功。这就证明了服务器拥有被权威机构认证的公钥的私钥。

5.验证服务器通信的ip地址确实是第2步解密后得到的ip地址信息。(这是防止服务器私钥被盗,并被用在了其他服务器上欺骗用户)

重新理一遍信任逻辑,用户用自身携带的公钥确定了证书的合法性,而证书确定了来源站点的合法性。

这里的实际情况其实还涉及到权威机构的下一级权威机构所构成的信任链条,但其逻辑基本与前文所述保持一致。即用私钥对公钥签名,再用另一个私钥对其签名,这样一连串下来可以形成一个信任链条。

3.3如何攻击https

应用https是为了安全,那么推测演算如何攻击https可以让我们防范于未然。3.2小节中介绍了5个环环相扣的步骤来保证服务器能够证明“我就是我”。那么攻击https的目的就在于,让访问网站的人以为“我就是他”。下面将仅从逻辑上列举几条让你以为“我就是他”的方法。

1.掉包访问者的证书目录。黑入访问者的电脑,获取足够的权限后将自己的证书载入访问者电脑。

2. 盗窃服务器私钥,并伪装服务器ip。

3. 强行破解非对称加密(非常困难,但没有绝对)

等等

因此对于服务器而言,保护私钥非常重要。而对于普通用户,给自己高权限的用户设置难以破解的密码,不去下载乱七八糟的软件,不让陌生人随便碰自己的电脑和手机是非常重要的。

3.4确认身份后

在https通信过程中确认身份后,事情就开始变得简单了。用户用收到的公钥加密一串新的数据发送给服务器,这串我们可以理解为对称加密的钥匙。用户用公钥把下一把自己钥匙发给服务器,接下来服务器和用户的通信信息,将用这一把钥匙来打开。这就保证了后续的通信过程中,只有用户和服务器能够对信息解密。

4校验软件来源

这是非对称加密另一个常见的用武之地。开发过安卓app的朋友肯定知道,要发布一款app就必须对其做数字签名。这其实就是用非对称加密的私钥对某个信息加密,并附上公钥。当安卓系统第一次安装某个软件时,它会接收该软件的签名和公钥(或者说证书)。如果用户想安装该软件的升级包,那么这个升级包所含的签名必须能够被原先已有的软件所带的公钥所认可。如果不被认可那么安卓系统会拒绝安装该升级包!除非你把之前的软件卸载掉,当然这也删掉了与该软件相关的用户数据。各位看官注意到了吧,非对称算法用来追溯源头的用法早就出现了,至于最近火起来的区块链技术,说的好像追溯源头的技术是新技术一样。

5ssh免密登录

做linux维护的朋友经常会用ssh登录到服务器。ssh是安全通信,因此登录的时候需要密码。但你也可以借助公钥和私钥对来免密登录。这整个执行过程可以分两步,1生成公钥私钥对2将公钥拷贝给服务器。参照代码如下:

1 sshs -keygen -t rsa -b 4096

2 ssh-copy-id -i/home/you/.ssh/id_rsa.pub user@host

这样,每次你登录ssh服务器时都会发送私钥签字的数据给服务器,而服务器通过公钥验证合法。这就构成了安全条件。除了ssh可以这样做以外,还有很多登录的免密手段都应用了公钥私钥对。(例如github上传代码的免密等场景)

6密钥的容器

在这一个小节里要介绍一下各种保存密钥的文件。我们或许会常常碰到各种保存私钥,公钥,证书的文件,像.pem,.csr,.crt,.p12,.p7,.key,.keystore,.der等后缀名的文件。这里要对这些后缀名首先分两类,一类后缀名是表达文件数据类型,一类是表达文件内容的类型。在列举的这些后缀中,csr,crt,key,keystore都是表达的文件内容类型,而.pem,p12,p7,der表达的都是文件数据类型。我做了一个表格列在下面,用以表达这些后缀名的意义:

后缀名 意义
内容类型 .crt(cert,cer) 都指的是证书文件,它包含公钥和一些证书拥有者的身份数据。它本身的数据类型通常是pem类型
内容类型 .csr 它指的是要求签名的文件。在https的构成过程中,服务器的应用商生成公钥后需要一个权威机构签名以示合法。这时应用商就会生成一个.csr文件提交给权威机构。权威机构签名之后,就会返回一个crt文件给应用商。它本身的数据类型也通常是pem
内容类型 .key 它通常指的是私钥。数据类型通常是pem
内容类型 .keystore 通常用在java和windows系统中,用来保存公钥和私钥对。它本身的数据类型通常不是pem,而是加密的文件,例如采用p12或者jks类型解密。前文提到的安卓app开发所用到的私钥公钥就存在这个后缀名的文件中。
数据类型 pem 是一种结构上类似于xml的文件数据,通常用来直接保存公钥,私钥和证书数据
数据类型 p12(pfx,pkcs12) 通常用来保存公钥和私钥,但却是加密的文件。用户要读出.p12中的公钥私钥内容,需要密码才能解读。
数据类型 p7 用来保存公钥,与pem的不同之处在于它有特定的格式来保存认证路径的证书
数据类型 der 不同于pem之处主要在于它是2进制保存密钥文件

7密钥相关的常用命令

1.生成pem数据格式的私钥公钥对

ssh-keygen -t rsa -b 4096

2. 根据私钥生成自签字的证书

openssl req -new -x509 -keyprivkey.pem -out cacert.pem -days 1095

3. 根据私钥生成“要求签字”文件

openssl req -new -keyprivkey.pem -out certreq.csr

4. 采用公钥加密文件

openssl rsautl -encrypt -inkeypublic.pem -pubin -in message.txt -out message.ssl

5. 采用私钥解密文件

openssl rsautl -decrypt -inkeyprivate.pem -in message.ssl -out message.txt

6. 采用私钥签字文件

openssl rsautl -sign -inkeyprivate.pem -in message.txt -out message.ssl

7. 采用公钥验证文件

openssl rsautl -inkeypublic.pem -pubin -in message.ssl -out message.txt

8. 拷贝公钥到目标服务器的目标用户

ssh-copy-id -i/home/you/.ssh/id_rsa.pub user@host