赞
踩
Android开发者都知道,如果一个APK没有签名或者签名异常是无法安装到手机上的,那么APK为什么需要签名呢?某些人可能会说这是Google的硬性规定,如下:
Android 系统要求所有 APK 必须先使用证书进行数字签名,然后才能安装到设备上或进行更新。
但这并不是本质原因,上述规定只是由本质原因所引申出来广大Android开发者需要遵守的做法,那本质原因是什么呢?
首先,大家可以考虑这个场景,A公司全员辛苦几个月,终于开发一款APK,准备在平台进行上架盈利,哪料道,黑客B公司来了一招狸猫换太子,在APK上传过程中,鬼使神差地将A公司的APK替换成自家APK(界面外观都一样,只是替换成B公司支付渠道),APK上架后异常火爆,但是钱都赚进了B公司口袋。(不要问我B公司为什么不自己上架,我猜可能需要借助A公司的名气)
上诉问题发生主要原因在于,平台根本不知道这个APK到底是由哪家公司开发出来的,如果平台能够发现这个APK不是A公司开发的,那么它完全可以驳回上架。那么就需要一种机制,可以验证APK身份的机制。这种机制就是签名机制。
在深入本文之前,我们可以先简单理解 签名就是盖公章
。如果一份文件盖了A公司的公章,那么我们知道这份文件是A公司签发的(不考虑伪造公章的情况,毕竟搞不好要吃牢饭的事)。
除此之外,签名还有一个好处,防篡改,这里简单总结一下:
在讲解Android签名机制之前,让我们先回顾一些密码学知识。
已经会的同学,可以直接跳转 【Android签名机制详解】二:Android V1、V2、V3、V4签名方案
在信息传输过程中存在四大安全隐患:窃听、假冒、篡改和事后否认。
我们可以通过“数字签名+加密通信”的方式尽可以降低这四种安全隐患的发生概率,但并不能完全杜绝,因为加密机制也可能会被破解、密钥也可能会被泄漏、权威机构被黑客攻击等,只是破解、伪造成本极高。所以“数字签名+加密通信”是现阶段人类能拿得出手的、公认的解决方案。
我们先来了解其中涉及到的四个基本概念:消息摘要、非对称加密、数字签名、数字证书
。
又称之为数字摘要、数字指纹。将任意长度的消息,通过Hash算法,变成固定长度的短消息,也就是所谓的消息摘要。
哈希碰撞
)。举例,SHA-256算法得到的输出结果一定是256位bit,所以输出空间的范围是2256种可能性,而输入空间是无限大的,只要输入空间超过2256种,必然会发生哈希碰撞;简而言之,一个无限输入的集合映射到一个有限的集合里,必然会发生哈希碰撞。另外根据生日悖论,如果随机挑选其中的2128+1输入,则有99.8%的概率发现至少一对哈希碰撞;但我们也要知道如果计算机每秒进行10000次哈希计算,需要约1027年才能完成2128次哈希计算;
感兴趣的同学可以了解一下什么是生日攻击
?
消息摘要算法,又可以称之为哈希(Hash)算法,主流的算法可分为MD系列和SHA系列:
密码+盐值进行hash计算
),这样在当网站数据遭到泄露的时候,也不会直接暴露用户的登陆密码;加密可以分为三种,分别是对称加密、非对称加密、混合加密。
发送方A和接收方B使用同一个密钥进行加密解密;
优点:相对于后续要讲的非对称加密来说,对称加密的加密解密速度更快;
缺点:存在密钥分配问题
——B需要提前知道共享密钥,这就存在A在发送共享密钥给B的时候,会被中间人窃听到;
A和B在进行对称加密通信之前,除了要实现商定好使用的算法,还需要确定好密钥。算法被其他人知道了,无所谓,反正著名对称加密算法本身就是公开的(除非你暗地里捣鼓一个高明的算法),关键是算法的参数,也就是密钥,不能让其他人知道。这就涉及好如何将密钥安全无误的传输给对方。密钥本身就是一个消息,难不成还要为密钥的传输再做一次对称加密?这样不就陷入了死循环?
接下来会具体讲解什么是非对称加密,其他方式,感兴趣的同学可以自行了解。
发送方A和接收方B使用两个不同密钥进行加密解密(公钥和私钥)
公钥(Public Key):公开的密钥,大家都可以知道的;
私钥(Secret Key):私藏的密钥,只有自己可以知道的,大家一定要保管好;
重要原则:用私钥加密的密文只能用公钥进行解密,用公钥加密的密文只能用私钥进行解密
思考题:既然私钥和公钥都能用来加密,那什么时候用私钥加密?什么时候用公钥加密呢?
如果
你想给对方发消息
,那你就用对方的公钥进行加密,对方收到消息后用自己的私钥解密。
如果
你想让对方验证你的身份
,你就用自己的私钥进行加密,对方收到数据后用你的公钥进行·解密。因为这个世界上能用你的公钥解密出来的数据,一定是用你的私钥加密出来的,而私钥保管在你自己手上,那发这份数据的人肯定是你。大家是不是感觉“验证身份”这几个相关字眼在“前言”里出现过,当时我们说是签名,我们提出“签名就是盖公章
”的理念,现在我们升级一下,“签名就是用私钥加密数据,而验签就是用公钥解密数据
”。
A想向B发加密消息的过程:
注意这边是A想向B发加密消息的过程,如果B也想向A发加密消息,就需要A自己生成一对公私钥,私钥自己保管,公钥发给B。后文会讲问什么。
RSA :安全性是基于极其困难的大整数的分解(两个素数的乘积),是目前主流、优秀、公认的非对称算法之一;
DSA :安全性是基于整数有限域离散对数难题;
两者的安全性都差不多,但DSA 只能用于数字签名,而无法用于加密(某些扩展可以支持加密);RSA 即可作为数字签名,也可以作为加密算法。不过作为加密使用的 RSA 有着随密钥长度增加,性能急剧下降的问题
优点:比对称加密算法更安全,不存在密钥分配问题
,反正公钥是公开的,知道就知道呗;
缺点:加解密速度慢,处理速度只有对称加密的几百分之一。存在公钥认证问题
;
公钥认证问题/中间人攻击
:假如接收方B将公钥发送给发送方A的过程中,中间人X进行拦截,并将B的公钥替换成自己公钥发送给A,这样A用X的公钥对信息加密,X就可以拦截并用自己的私钥破解。还可以篡改信息中的内容,用B的公钥加密,发送给B;这里就涉及了信息传输过程中的两个隐患:“篡改”和“假冒”。
非对称加密
虽然解决了对称加密
的密钥分配问题
,但引发了新的问题:公钥认证问题
。有人可能会说,这两个问题不就是同一个问题吗,只不过是换了个名字。
No,No,No。密钥分配问题 是 对称加密 存在的问题,它是 密钥不敢分配出去,怕被其他人知道
。而 公钥认证问题 是 非对称加密 存在的问题,它是 密钥敢分配,不怕被其他人知道,但不能确定接收方收到的是不是我给的密钥,怕密钥被篡改
。
那么公钥认证问题如何解决呢?先别急,后文会具体说明,让咱们先循序渐进,继续下一部分。
混合加密=非对称加密+对称加密
首先通过A和B通过非对称加密通信来交换对称加密的密钥,之后就通过对称加密进行信息传输。充分利用了 非对称加密的高安全性+对称加密的高效率
混合加密在安全性和处理速度上都有优势。能够为网络提供通信安全的SSL协议也应用了混合加密方法。SSL是Secure SocketsLayer(安全套接层)的简写,该协议经过版本升级后,现在已正式命名为TLS(Transport Layer Security,传输层安全)。但是,SSL这个名字在人们心中已经根深蒂固,因此该协议现在也常被称为SSL协议或者SSL /TLS协议。
另外我们常见的加密的视频通话、语音通话都是使用的混合加密。适合客户端和服务器之间的大量数据传输。
终于来的本文的主角了——数字签名。签名过程是计算数据的消息摘要,然后用私钥对消息摘要进行加密。最终生成内容就是签名。我们也可以将签名作为一个动词,比如说:“对某某数据进行签名”,“对APK进行签名”,实际上也就是“先算摘要,再私钥加密”的过程,也可以说“用私钥进行签名”,反正都一个意思,大家懂了都懂。
那为什么不直接对数据本身进行签名,而是对消息摘要进行签名呢?
因为加密的过程需要进行复杂的数学运算,数据源越多,加密的过程也就越慢。而消息摘要的长度是固定的,一般远小于数据源本身的长度。而且消息摘要是对数据源的一个映射。对消息摘要进行签名,就相当于对数据源进行签名。
而验签
就是一个反向的过程。如下图所示。
这里以APK举例:
签名:将APK当中的所有内容通过消息摘要算法进行计算,生成一个摘要值,然后用提前生成好的一对公私钥中的私钥(存放在keystore文件中,keystore又被称为密钥库)进行加密,生成的密文就是签名。然后把 APK+签名+公钥 捆绑在一起,发送到手机上进行安装。
验签:手机上的Android系统会拆分这三者,先用公钥解密签名,还原出[消息摘要1],还原成功就说明,这个签名确实是公钥主人发的。然后再重新对APK计算[消息摘要2],比较这两个消息摘要是否相等,相等的话,就说明APK中的数据没有遭到篡改,验签成功,可以进行安装了。
这里我不得不再强调一下签名的作用:
验身份(防假冒、防事后否认)+防篡改
数字签名的过程中,是用私钥对明文进行加密,用公钥对密文进行解密
。
消息通信的过程中,是用公钥对消息进行加密,用私钥对消息进行解密
,也就是说A和B进行双向通信,需要两对公私钥。
思考题:从上面的学习中,我们知道,用私钥加密的密文只能用公钥进行解密,用公钥加密的密文只能用私钥进行解密
,为什么消息通信需要两对公私钥?一对公私钥不行吗?A用公钥进行加密发消息,B用私钥解密。B用私钥进行加密发消息,A用公钥进行解密。这边只需要一对公私钥,岂不更好?
本质原因在于,“
公钥是公开的
”,也就是说B用自己的私钥进行加密,将密文发送给A,A可以用B的公钥进行解密,但是攻击者C也可以窃听本次通信,用B的公钥进行解密,因为B的公钥是公开的。但反过来,A用B的公钥进行加密发送消息,即使攻击者C窃听了本次通信,但C不可能拿到B的私钥,也就解密不了,只有B可以用自己私藏好的私钥进行解密。所以如果A和B需要双向通信,就需要两对公私钥。要记住“发消息用对方的公钥进行加密
”
优点:保证数据的完整性和来源的真实性。
如何保证数据的完整性的?
消息=数据+签名,即使消息在传输的过程数据被修改,但签名校验失败,两个消息摘要值不一致,那么该数据就不会被使用。
如何保证数据来源的真实性的?
如果用B的公钥验签成功,那么说明这条消息肯定是B发送的,因为世界上只有B拥有该公钥对应的私钥。B也不好事后否认他没发送过这条消息。
综上:数字签名可以解决消息传输过程中的假冒、篡改及事后否认这三大隐患。
但一切的一切都有一个前提,
“公钥必须是真正的发送者的”
缺点:依旧存在公钥认证问题/中间人攻击
,数字签名只是利用了非对称加密,并没有解决非对称加密遗留的问题。即数字签名和公钥在发送的过程中,一起遭到中间人C的篡改。C自己生成一对公私钥,篡改了数据,并用自己私钥进行签名,将原公钥替换成自己的。也就是说,本来是“数据+B的签名+B的公钥”变成了“篡改的数据+C的签名+C的公钥”,A以为是和B进行通信,但是实际上A是拿着C的公钥和C进行通信。
那么,A该如何确认自己收到的公钥就是B的呢?有些人可能会说,这不还是原来的“验证身份
”问题,搞了半天“数字签名”还是没解决“验证身份”问题啊?
怎么解释呢,作者我表示也很无奈,数字签名是可以“验证身份”,但前提是公钥必须是对的人给的,我们可以这样理解,数字签名可以“验证身份”,它具备这个功能,但它验证出来的身份对不对,是不是你期待的身份,那就有待商榷了。
现在“数字签名”只不过机制上还存在一个BUG,别着急。下面我们立马打个补丁,就是数字证书啦。
数字证书是指在互联网通讯中标志通讯各方身份信息的一个数字认证,人们可以在网上用它来识别对方的身份。
也可以称之为“保存公钥的数字签名”
为了解决公钥认证问题,我们从社会学中的信任体系
得到了启示。
假设:接收者A在收到发送者B的公钥后,此时政府出面进行担保,说“你收到公钥的确是发送者B的”,那么接收者A就可以放心大胆的使用该公钥进行加密通信,因为大家都相信政府的权威。接收者A要是不信,那请他滚出地球。
政府肯定不会为A和B通信,这种小事进行出面担保,而是交给某些权威机构进行操作。这些权威机构被称之为CA机构(CertificateAuthority机构)
。那具体该怎么操作呢?
证书信息
拼接在一起,进行消息摘要计算,然后用自己私钥对摘要进行加密,生成CA签名。然后将CA签名、证书信息以某种特定格式(证书标准格式)封装在一起,就形成了一张数字证书
。也就是说 数字证书=CA签名+证书信息
。之后的A和B通信流程就是:
证书(内含B的公钥)+B的签名+数据
一并发送给A。B的签名
进行解密生成[消息摘要3],然后对数据
计算,生成[消息摘要4],比较两个消息摘要是否一致,一致的话就说明这份数据确实是B发的。假设在第2步的时候,攻击者C将证书替换成自己的证书,那么A在收到证书后,发现这个证书并不是自己信任的CA机构颁发的,就会验证失败。即使是自己信任的CA机构颁发的,但证书里面的身份信息并不是B的,依旧验证失败。我们再进一步假设,C拦截A的第一次请求,假冒成B的身份,将B的证书响应回去(因为证书也是公开的),但是C拿不到B的私钥,所以伪造不了B的签名。也就是说,A在进行验证的时候,虽然第一步 证书的正确性 通过了验证,但 B的签名 验证失败。
上述场景的关键点在于,A是怎么记住CA机构的公钥的?世界上拥有成百上千家CA机构,难道靠一个个死记硬背吗?为什么我们在通信的过程中没有感觉到数字证书的存在呢?
这是因为,我们的设备在安装操作系统时候就已经内置了许多数字证书,不信的话,你在windows运行 certmgr.msc 命令,就会看到系统内置好的琳琅满目、分门别类的数字证书的呢。而我上述所说的证书校验的过程,都是系统、浏览器或者应用自动帮我们完成的。
其实密码学的知识博大精深、浩瀚无垠,一本书都讲不完,那可是一门技术科学哟。
接下来,让我们继续学习【Android签名机制详解】二:Android V1、V2、V3、V4签名方案
关于密码学更加详细的信息,可以自行以下文章
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。