vlambda博客
学习文章列表

APK校验机制(1):非对称加密?签名?证书?


前言

最近在看apk的签名校验,因为加密这块之前没有了解过,所以就学习了一下非对称加密相关的内容。

正文

1.对称加密

对称加密的方式是很传统的加密方法,通讯过程就像是谍战片中的发密文,然后特工们用密码本进行解密。但是只要密码本被泄漏,那么一切加密系统都要推倒重新。

所以对称加密一个致命的问题:无法解决安全传递密钥的问题。

因此革命性的出现了非对称加密的思想。密钥不再是一个而是分为公钥和私钥两个。用任意其一加密,只能用另一个进行解密。并且由于其密钥的特殊性在一定程度上不用传递密钥,也就变相的“解决”了密钥传递的问题。

2.非对称加密

非对称加密的巧妙之处就在于公钥的特殊性,公钥甚至不用传递,可以随意公开,谁都可以使用;而私钥是一个无需传递的密钥,自己保留的密钥。所以巧妙的“解决”了密钥传递的问题。

注意,这里的解决加了引号,因为仅靠现在的机制还是有办法破解。

因此非对称加密的通讯模型是这样的:

用户A生成公钥A1私钥A2,将公钥A1公开;用户B同理生成公钥B1私钥B2,同样将公钥B1公开。二者通讯时,用户A拿用户B公开的公钥B1,加密原文message生成密文message1。用户B拿到message1,用自己的私钥B2解密就能拿到原文message。

这种方案的特点就是:核心解密用的密钥(私钥)是非公开的,所以理论上不存在泄漏的问题。而且也能一定程度上验证消息的真伪:如果用户B用自己的私钥B2无法解密消息,那么就说明这个消息不是用自己的公钥B1加密的。

3.中间人

为什么说一定程度?因为有很大的局限性:无法保证来源。

因为大家的公钥都是公开的,即使目标用户用私钥解密了,也不能说明发送过来的内容就一定是对方发送过来的。

比如:此时有个中间人C,在监听A和B的通讯。C可以拦截掉了A发送给B的密文,虽然此时C没有B的私钥,无法解密内容。但是C有B的公钥;可以用B的公钥B1加密一份全新的内容发送给B。

在此种情况下,收到消息的一方,即使成功解密的内容,也没办法相信内容的真伪。因为无法确定内容的来源。

这种case下,咱们假设的这种情况是中间人C没有办法解密截获的密文,但是实际上也可以。这里为了保证文章阅读的连贯性先留个坑,如何解密密文的操作咱们在章节:无法保证公钥 展开。

因此为了解决这个问题,就引申出了:签名。

4.签名

签名的玩法,就是用私钥加密后产生的产物。既然用私钥加密,那么解密的过程就是用公钥,这里听起来似乎很奇怪。公钥是公开的,那么就意味着所有人都能看到解密后的内容,那这样有什么意义呢?

意义就在于,签名就是让所有人都能用公钥解密,这样解密人就能确定是用对方私钥加密的。也就做到了“识别”对方身份的能力。

注意这里加了引号,因为仍然有方法破解。

签名的过程是这样:对原文进行摘要处理(保证内容的唯一性),对摘要后的内容进行私钥加密,进而得到了加密后的内容(取名为:签名),最后将签名和加密后的密文一同发送给对方。这样对方就能够知道收到的信息是否真的是对方发过来的。

换成用户AB的例子就是:

用户A想发送原文message,此时A对message取摘要,假设得到了mes,此时用私钥A2对摘要mes进行加密,得到了签名mes1;然后用用户B的公钥B1,对message进行加密,得到了密文message1。将签名和密文一同发送给用户B。

用户B拿到消息后,用用户A的公钥A1,对签名mes1进行解密得到摘要mes;然后用自己的私钥B2,对密文message1进行解码得到原文message,然后对原文进行取摘要的mes。此时发现签名反解出来的摘要和原文的摘要相同,那么说明内容无误。

那么这个过程中,中间人C为什么没有发起攻击?不是没有,而是不能。因为C虽然截获了密文,也能通过用户B的公钥B1重新生成新的的密文,但是C没有A的私钥,所以没办法对伪造的内容进行重新签名。

一切听起来很完美,但是事实真是如此吗?非也,接下来就是填坑环节。也是一个最为致命的问题:

5.无法保证公钥来源

咱们刚才中间人C发动攻击的操作中,提到了没办法解密密文,因为没有对应的私钥。但是中间人想要解密密文根本不需要知道私钥。

因为只要公钥是在互联网上被公布,那么就有可能被替换。

我们模拟这样的场景,用户A向用户B公布自己的公钥A1,在互联网的链路上,无论怎样传递都存在被劫持的风险。此时中间人C就劫持的发布的公钥A1,他也生成了自己的公钥C1和私钥C2。截留下了公钥A1,将自己的公钥C1伪装成“A

1”发送给用户B,用户B以为拿到的是A1,但其实是C1。

中间人C也可以如法炮制B,生成新的公钥D1和私钥D2。截留公钥B1,发送给用户A公钥D1。

接下来AB都以为用对方的公钥在加密,实际上全用的中间人C,所以C可以从容的用私钥C2和D2进行解密;再用截留下来的A1和B1加密任意篡改的原文。

那时这条链路上再也没有秘密可言。双方公钥被偷天换日,那么无论是密文还是签名,中间人可以随意篡改。因为公钥被替换成中间人的了,因此中间人可以随意用自己的私钥进行解密,也可以用自己的私钥重新签名。

所以到目前为止,一切毫无信任可言。而这一切皆因为公钥的来源目前不能被保证!

接下来就引出最终的内容:证书。

6.证书

此时大家陷入了很诡异的信任怪圈。原本公平公正公开的公钥,变得不再可信,一切都变得很脆弱。不过既然咱们谁都不信任对方的公钥,那咱们就找一个都信得过的第三方为我们彼此的公钥做背书。

现实也是如此,如果双方互不让步,一般都会想到寻找第三方。

此方案的思路是这样的:公钥公布方不贸然发布公钥,而是找三方机构(CA机构),申请他们用他们的私钥对自己的公钥进行签名。然后把自己的公钥以及签名还有一些其他信息打包生成一个产物:证书。

然后将证书传递出去,接收方用CA机构的公钥来解密证书的签名,验证此时证书中的公钥是否被篡改,如果没有被篡改那么公钥就没有问题。

听起来这个路子很完美,但是细琢磨下来还是有瑕疵。如何保证三方机构的公钥是正确的呢?(咱们就是因为公钥的问题来找第三方,结果第三方也要保证这个问题。)

我们现在使用第三方的公钥去解密第三方的证书来取出目标公钥,但是如果第三方的公钥和证书都被篡改了怎么办?所以必须要找到一种方式能够保证证书的正确性才行。

难道要用另一个证书去证明当前的证书…嗯?这不成套娃了??事实上就是套娃,只不过最终有一个根证书来表明到此一定没有问题,进而反推这条链路上的所有证书都是没问题的。

为啥根证书就这么嚣张?因为它们的确是有一些特殊性,这些CA机构的签发的根证书会随电脑的生产而直接内置,由于这些根证书不是通过互联网进行传播,所以从源头保证不正确性。

当我们信任了这些证书,那么就意味着信任了他们的公钥,因此就相当于信任了证书的这种校验公钥的机制。

尾声

聊完了证书,我们可以说只要三方机构不作恶,那么这套信任体系是没有问题的。

但是如果我们不分青红皂白随便信任别人的证书,那么…