前言
了解iOS的数字签名机制需要了解以下几个知识
- 加密/解密:1.对称加密 2.非对称加密
- 单向散列函数(MD4 MD5 SHA-1 SHA-2 SHA-3)
- 数字签名
- 证书
1. 加密/解密
1.1 对称加密(DES 3DES AES)
对称加密中,加密和解密用的密钥是一样的。
比如DES使用一个56bit的密钥对64bit的数据进行加密生成64bit的密文,解密即反向。
存在的问题:密钥配送的问题。
我们可以通过以下手段解决密钥的配送问题:
- 事先共享密钥(不适合互联网通讯)
- 密钥分配中心
- Diffie-Hellman密钥交换
- 公钥密码(非对称加密)
1.2 非对称加密(RSA算法)
非对称加密,加密和解密用的密钥是不一样的,有一对密钥,成对生成,分为公钥和私钥,通过公钥加密的数据,通过私钥可以解开,通过私钥加密的数据,通过公钥可以解开。
存在的问题:加密解密速度慢。
解决密钥配送问题:由消息的接收者生成公钥和私钥,将公钥发送给消息的发送者,自己保留私钥。消息的发送者使用公钥加密要配送的密钥(这个密钥是对称加密的密钥),接受者用私钥解密。
1.3 混合密码系统
混合密码系统是将对称密码和非对称密码的优势相结合解决了对称密码密钥配送问题,和非对称密码加密速度慢问题.
2. 单向散列函数(MD4 MD5 SHA-1 SHA-2 SHA-3)
单向散列函数的作用是根据传入的内容生成一个散列值,散列值的长度和内容的长度是没有关系的,计算出固定长度的散列值。
MD4,MD5 为128bit (不安全了)
SHA-1 为160bit(20字节)(不安全了)
SHA-2 (SHA-256,SHA-384,SHA-512)
SHA-3 全新标准
3. 数字签名
数字签名主要是为了验证数据有没有被篡改过,具体流程为:
A要向B发送消息,A----->B,如果有中间人把消息改了,AB都不会察觉到,这时就用到了数字签名:
image.png
- A生成一对公钥和私钥,私钥自己保留,公钥发送给B
- A用私钥对消息进行加密生成签名,把【消息+签名】一起发送给B
- B收到【消息+签名】,用公钥对签名进行解密和收到的消息进行对比,确认数据是否被篡改
上面👆这个过程存在两个问题:
- 签名速度太慢
消息通过非对称加密,由于有时候消息很大,速度很慢,这里就用到了单向散列函数,具体是怎么用的呢?
在上面的第2步,A首先对消息用单向散列函数生成一个散列值,然后用私钥对散列值进行加密生成签名,【消息+签名】一起发送给B
在上面的第3步,B收到【消息+签名】,首先用公钥对签名进行解密得到散列值,然后用相同的单向散列函数对消息生成一个散列值,对比两个散列值,进行签名的认证 - 上面的第一步,A把公钥发送给B时,也有可能遭遇中间人篡改,把自己的公钥发给B,这样能冒充A了,为了解决这个问题,就用到了证书
4.证书(Certificate)
证书也叫公钥证书,主要是为了解决公钥发送问题,主要由认证机构(Certificate Authority, CA)施加数字签名。
CA就是能够认定公钥确实属于此人
,并能够使用生成数字签名的组织或个人。
流程大概如下:
- A生成一对公钥和私钥,A在认证机构CA注册自己的公钥,认证机构用自己的私钥对A的公钥进行数字签名,【A的公钥+数字签名】即为证书
- B去认证机构下载A注册的公钥证书【A的公钥+数字签名】,B使用认证机构的公钥验证证书的签名,验证成功说明A的公钥确实是A生成的,这样就得到了A的公钥。
5. iOS签名机制
我们来看下怎样通过数字签名的机制保证每一个安装到iOS上的App都是经过苹果认证允许的。
5.1 最简单的签名
实现这个需求很简单,最直接的方式,苹果官方生成一对公私钥,在iOS设备里内置一个公钥,私钥由苹果后台保存,我们传App上AppStore时,苹果后台用私钥对App数据进行签名,iOS设备下载这个App后,用公钥验证这个签名,如果这个签名正确,这个App肯定是由苹果后台认证的,并且没有被修改过,也就达到了这个简单的需求:保证安装的每一个App都是经过苹果官方允许的。
image.png
问题:新的需求出来了?
如果我们iOS设备安装App只有从AppStore下载这一种方式的话,这个需求就是这么完成了,只有一个数字签名,非常简单的解决问题。
但是实际上除了从AppStore下载,我们还可以有三种方式安装一个App:
1.开发 App 时可以直接把开发中的应用安装进手机进行调试。
2.In-House 企业内部分发,可以直接安装企业证书签名后的 APP。
3.AD-Hoc 相当于企业分发的限制版,限制安装设备数量,较少用。
所以,就有了新的需求,无法像上面那么简单了。
5.2 新的需求
我们先去看第一个:开发时安装App,他有两个需求:
- 安装包不需要传到苹果服务器,可以直接安装到手机上。如果你编译一个App到手机前要先传到苹果服务器签名,这显然是不能接受的
- 苹果必须对这里的安装有控制权,包括
a. 经过苹果允许才可以这样安装
b. 不能被滥用导致非开发app也能被安装
为了实现这些需求,iOS签名的复杂度也就开始增加了。
苹果这里给出的方案是使用了双层签名,流程大概是这样的:
image.png
- 在你的Mac上生成一对公私钥,这里成为公钥L,私钥L。L:Local
- 苹果自己有固定的一对公私钥,跟上面AppStore例子一样,私钥在苹果后台,公钥在每个iOS设备上,这里成为公钥A,私钥A,A:Apple
- 把公钥L传到苹果后台,用苹果后台里的私钥A去签名公钥L,得到一份数据【公钥L + 签名】,就是证书
- 在开发时,编译完一个App,用本地的私钥L对这个App进行签名,同时把第3步得到的证书一起打包进App里,安装到手机上
- 在安装时,iOS系统取得证书,通过系统内置的公钥A,去验证证书的数字签名是否正确
- 验证通过后,确保公钥L是苹果认证过的,再用公钥L去验证App的签名,这里就间接验证了这个App安装行为是否是经过苹果官方允许的。(这里只验证安装行为,不验证App是否被改动,因为开发阶段App内容总是不断变化的,苹果不需要管)
5.3 再加点东西
上述流程只是解决了第一个需求,也就是需要经过苹果允许才可以安装,还未解决第二个避免被滥用的问题,怎么解决呢?
苹果加了两个限制:
- 限制在苹果后台注册过的设备才可以安装
- 限制签名只能针对某一个具体的App
怎么加的呢?在上面第3步,苹果用私钥A签名我们本地公钥L时,实际上除了签名公钥L,还可以加上无限多数据,这些数据都可以保证是经过苹果官方认证的,不会有被篡改的可能。
image.png
可以想到把允许安装的设备ID列表和App对应的AppID等数据,都在第三步这里跟公钥L一起组成证书,再用苹果私钥A对这个证书签名。在最后第5步验证时就可以拿到设备ID列表,判断当前设备是否符合要求。根据数字签名的原理,只要数字签名通过验证,第5步这里的设备IDs / AppID / 公钥L就都是经过苹果认证的,无法被修改,苹果就可以限制可安装的设备和App,避免滥用。
5.4 最终流程
到这里这个证书已经变得很复杂了,有很多额外信息,实际上除了设备ID / AppID,还有其他信息也需要在这里用苹果签名,像这个App里iCloud/push/后台运行等权限苹果都想控制,苹果把这些权限开关统一称为 Entitlements,它也需要通过签名去授权。
实际上一个“证书”本来就有规定的格式规范,上面我们把各种额外信息塞入证书里是不合适的,于是苹果另外搞了个东西,交Provisioning Profile,也就是描述文件,这个里面就包含了证书以及上述提到的所有额外信息,以及所有信息的签名。
所以整个流程变了一下,变成如下图所示:
image.png
- **我们创建证书时,苹果会让我们提供一个
.certSigningRequest
文件,其实这个文件就是我们Mac电脑的公钥,如下图 **
image.png -
在上面文件创建步骤如下图,这个操作就是在我们电脑生成一对
公钥和私钥
,私钥保存在我们的电脑中,公钥生成.certSigningRequest
文件
image.png -
苹果得到我们的Mac公钥之后,用苹果的私钥对公钥进行签名,生成开发或者发布证书
image.png
image.png -
然后苹果会对证书进行二次签名,【MAC公钥 + 签名】 + 【devices appid + entitlements】,用苹果的私钥进行签名生成一个文件,
.mobileprovision
也就是我们平时所说的描述文件
image.png
image.png .mobileprovision
文件会放到Xcode指定目录里面,当我们打包时,首先编译生成二进制数据包,然后用Mac私钥对其加密生成签名,加上.mobileprovision文件生成我们的ipa包- 我们每个人的iPhone手机都内置了
苹果的公钥
,当App安装时,首先用苹果的公钥对.mobileprovision文件
进行两次认证,得到Mac的公钥
,最后用Mac公钥验证第三个签名,如果成功则安装程序。
网友评论