笔者接触打包已经一段时间了,但一直对签名都是似懂非懂,最近从加密数论知识起回看这部分知识,感觉还是有很多不懂的地方。先简单说明一哈数学原理,然后说RSA 算法密钥生成的步骤,最后回到 iOS 签名打包,以及分享一哈利用重签名做过的坏事(以学习、省时间为目的)。
非对称加密
对称加密是通过同一份密钥加密和解密数据;而非对称加密则有两份密钥,分别是公钥和私钥,用公钥加密的数据,要用私钥才能解密,用私钥加密的数据,要用公钥才能解密。
(1)乙方生成两把密钥(公钥和私钥)。公钥是公开的,任何人都可以获得,私钥则是保密的。
(2)甲方获取乙方的公钥,然后用它对信息加密。
(3)乙方得到加密后的信息,用私钥解密。
数学原理
数学原理太长(难)不看篇:有一条等式,三个数字可以关联起来,从而达到互相验证对方的数字是否配对。如果已知数字验证等式很容易,但是如果未知这些数字,要推测出来对方的数字目前的技术还十分艰难。
互质的简单结论
关于互质关系,我们不难得出以下结论:
- 任意两个质数互质。
- 一个数是质数,另一个数只要不是它的倍数,两数互质。
- 一个质数与比它小的数,两数互质。
- 1 和任意自然数互质。
- p 是大于1的整数,p 和 p - 1互质。
- p 是大于1的奇数,p 和 p - 2互质。
欧拉函数
思考下面这个问题。
任意给定正整数n,请问在小于等于n的正整数之中,有多少个与n构成互质关系?
计算这个值的方法就叫做欧拉函数 ,以φ(n) 表示。• 如果n = 1,则φ(1) = 1 。• 如果n是质数,则 φ(n)=n-1 。由以上结论(3)得出。• 如果 n = pk (p为质数,k为大于等于1的整数),那么
因为 n 的因数只有 1、p、n,所以只要一个数因数分解不包含质数 p,才可能与 n 互质。而比p小,包含质数 p 的数有 1 p、2 * p、3 * p、...、pk-1×p,共有 pk-1 个。减去即可。比如 φ(8) = φ(23) =23 - 22 = 8 -4 = 4。• 如果 n 可以分解成两个互质 的整数之积。• n = p1 * p2网上有种证明是“中国剩余定理”,看不懂🙈。。。说说自己的理解。比如 35 = 5 * 7。由于35 的因数只有1、5、7、35。对于比35小的数来说,有7个5的倍数,5个7的倍数,则有12个,由于35是重复计算的,则有11个。所以结果是 35 - 24 = 11。*φ(n) = p1 * p2 - p1 - p2 + 1 = (p1 - 1)(p2 -1) = φ(p1)φ(p2) **• 因为任意大于1的正整数,都可以由一系列质数相乘所得。
这就是欧拉函数 。
欧拉定理
欧拉定理是RSA算法的核心。理解了这个定理,就可能可以理解RSA。直接给结论。感兴趣的可以自己去看证明(我也想看懂,但懵懵懂懂)。即 a的φ(n)次方被n除的余数为1。
这个定理结合取余分配率可以用来简化幂的模运算。
(ab)%c=(a%cb%c)%c
费马小定理假设正整数 a 与质数 p 互质,n = p的情况下,由结论(3)可得:
模反元素
如果 a 和 n 互质,那么一定可以找到整数 b,使得 ab - 1 被 n 整除。这时,b 就叫做 a 的“模反元素”。不难发现,如果b是模反元素,那么b + a、b - a也是模反元素,模反元素不止一个 。密钥生成的步骤
假设龙神要与那个ta 进行加密通信,他要怎么做才能瞒过八卦的群众呢?第一步,随机选择两个不相等的质数 。龙神的幸运数字是61 那个ta 的幸运数字是53。第二步,相乘。
n = 61 * 53 = 3233
写成二进制是 110010100001,一共有12位,所以这个密钥是12位。(通常1024位,更安全的场合2048位)。第三步,计算n的欧拉函数φ(n)。
φ(n) = (p-1)(q-1),φ(3233) = 3120。
第四步,随机选择一个整数e,条件是1< e < φ(n),且e与φ(n) 互质。龙神选了17。第五步,计算e对于φ(n) 的模反元素d。
ed ≡ 1 (mod φ(n))
等价于
ed - 1 = kφ(n)
ex + φ(n)y = 1
即
17x + 3120y = 1
龙神算出一组整数解为(2753,-15),即 d = 2753。第六步,将 n 和 e 封装成公钥,n 和 d 封装成私钥。所以公钥(3233,17),私钥(3233,2753)。第七步, RSA 的可靠性。回顾上面的步骤,一共出现了六个数字。
p = 61
q = 53
n = p * q = 3233
φ(n) = (p-1)(q-1) = 3120
e = 17
d = 2753
我们上面提过,公钥是公开的,所以 n 和 e 都是所有人能知道的。关键是d,如果泄漏了,就等于私钥泄漏。那么,在已知 n 和 e 的情况下,怎么推导出 d?
(1) ed≡1 (mod φ(n))。只有知道e和φ(n),才能算出d。
(2) φ(n)=(p-1)(q-1)。只有知道p和q,才能算出φ(n)。
(3) n=pq。只有将n因数分解,才能算出p和q。
所以,只要因数分解n,就可以得到d。但是,对于一个很大的质数,要因数分解是非常困难的事 。所以,以目前的技术来看, RSA 是可靠的 。
加密和解密
公钥:e 和 n
私钥:d 和 n
明文:m
密文:c
公钥和私钥通过一条等式能互相验证。有兴趣的可以自己研究。RSA算法原理(二)[1]
加密假设龙神想说的悄悄话m,他就要用公钥(3233,17)进行一次加密。这里必须注意,m是小于n的整数。然后算出下面式的c:
me ≡ c (mod n)
假设龙神说的悄悄话是 65,算出c 为2790。我们要用到欧拉定理
6517 mod 3233 = 2790
所以龙神就把2790发给那个ta。解密那个ta 收到2790后,就用私钥(3233,2753)进行解密。
cd ≡ m (mod n)2790 ^ 2753 ≡ 65 (mod 3233)
所以原文就是65。RSA 的优缺点优点:目前来说安全。缺点:• 速度慢• 只适合加密小数据简单介绍完一番我没完全理解的数学理论后,下面进入签名环节。
数字签名
作用
数字签名的作用是利用非对称加密方法,自己持有私钥,公布公钥。互相加密以及验证消息来源。
步骤
首先用一种算法,算出原始数据的摘要。需满足
a. 若原始数据有任何变化,计算出来的摘要值都会变化。
b. 摘要要够短。这里最常用的算法是MD5 。
</pre>生成一份非对称加密的公钥和私钥,私钥保留,公钥公布出去。
对一份数据,算出摘要 后,用私钥加密 这个摘要,得到一份加密后的数据,称为原始数据的签名。把它跟原始数据一起发送给用户。
-
用户收到数据和签名后,用公钥解密得到摘要。同时用同样的算法计算原始数据的摘要,对比这里计算出来的摘要和用公钥解密签名得到的摘要是否相等,若相等则表示这份数据中途没有被篡改过,因为如果篡改过,摘要会变化 。
最简单的签名
iOS 设备用公钥验证一遍就知道该 App 是不是经过苹果后台认证的。如果被篡改过,肯定是不行的。然而,App 除了从 AppStore 下载,还有三种方式安装:
- 开发 App 时可以直接把开发中的应用安装进手机进行调试。
- In-House 企业内部分发,可以直接安装企业证书签名后的 APP。
- AD-Hoc 相当于企业分发的限制版,限制安装设备数量,较少用。所以苹果的签名还有额外的事情要做。
苹果的 App 签名
我们来考虑上面第一种情况。首先,它既要有能不经苹果私钥验证,马上安装的便利,又要经过苹果验证。听起来有点绕。苹果采用的方案是双层签名。- 在 Mac 生成一对公私钥,这里称为公钥L,私钥L。
- 苹果自己有固定的一对公私钥,私钥在苹果后台,公钥在每个 iOS 设备上。
- 把公钥 L 传到苹果后台,用苹果后台里的私钥 A 去签名公钥 L。得到一份数据包含了公钥 L 以及其签名,把这份数据称为证书 。
- 在开发时,编译完一个 APP 后,用本地的私钥 L 对这个 APP 进行签名,同时把第三步得到的证书一起打包进 APP 里,安装到手机上。
- 在安装时,iOS 系统取得证书,通过系统内置的公钥 A,去验证证书的数字签名是否正确。
- 验证证书后确保了公钥 L 是苹果认证过的,再用公钥 L 去验证 APP 的签名,这里就间接验证了这个 APP 安装行为是否经过苹果官方允许。(这里只验证安装行为,不验证APP 是否被改动,因为开发阶段 APP 内容总是不断变化的,苹果不需要管。)除了要保证经过验证外,苹果还要防止滥用这种途径下载。想象一下,把真机连到 Mac 上,不就能想装多少装多少 App 吗?那多部设备连到 Mac 上,App 不就能想装在哪装在哪吗?苹果的方案是识别 设备和 App。
想调试的设备必须要到开发者网站申请,并且设备数量是有限制的。
然后还针对每个Bundle Identifier(App ID)配不同的证书。
这两种数据都在上面第三步一起组成证书(暂且这么认为)。
至此,证书就能实现 经过苹果认证,并且能限制安装设备数量和 App ID 。
当然,证书不止有这些信息,还有推送等权限,苹果把这些权限开关统一称为Entitlements 。如果App 一开始的证书没申请推送权限,那么后面新增权限后,需要更新配置。实际上,一个“证书”有规定的格式规范,不应把这些额外的信息往里塞。****所以上面的暂且这么认为部分是不对的。所以苹果把证书和额外信息包装起来 ,把它叫做 Provisioning Profile 。所以能拓展整个流程图如下。
- 在你的 Mac 开发机器生成一对公私钥,这里称为公钥L,私钥L。L:Local
- 苹果自己有固定的一对公私钥,跟上面 AppStore 例子一样,私钥在苹果后台,公钥在每个 iOS 设备上。这里称为公钥A,私钥A。A:Apple
- 把公钥 L 传到苹果后台,用苹果后台里的私钥 A 去签名公钥 L。得到一份数据包含了公钥 L 以及其签名,把这份数据称为证书。
- 在苹果后台申请 AppID,配置好设备 ID 列表和 APP 可使用的权限,再加上第③步的证书,组成的数据用私钥 A 签名,把数据和签名一起组成一个 Provisioning Profile 文件,下载到本地 Mac 开发机。
- 在开发时,编译完一个 APP 后,用本地的私钥 L 对这个 APP 进行签名,同时把第④步得到的 Provisioning Profile 文件打包进 APP 里,文件名为 embedded.mobileprovision,把 APP 安装到手机上。
- 在安装时,iOS 系统取得证书,通过系统内置的公钥 A,去验证 embedded.mobileprovision 的数字签名是否正确,里面的证书签名也会再验一遍。
- 确保了 embedded.mobileprovision 里的数据都是苹果授权以后,就可以取出里面的数据,做各种验证,包括用公钥 L 验证APP签名,验证设备 ID 是否在 ID 列表上,AppID 是否对应得上,权限开关是否跟 APP 里的 Entitlements 对应等。
关于证书等概念
上面的步骤对应到我们平常具体的操作和概念是这样的:
- 第 1 步对应的是 keychain 里的 “从证书颁发机构请求证书”,这里就本地生成了一对公私钥,保存的 CertificateSigningRequest 就是公钥,私钥保存在本地电脑里。
- 第 2 步苹果处理,不用管。
- 第 3 步对应把 CertificateSigningRequest 传到苹果后台生成证书,并下载到本地。这时本地有两个证书,一个是第 1 步生成的,一个是这里下载回来的,keychain 会把这两个证书关联起来,因为他们公私钥是对应的,在XCode选择下载回来的证书时,实际上会找到 keychain 里对应的私钥去签名。这里私钥只有生成它的这台 Mac 有,如果别的 Mac 也要编译签名这个 App 怎么办?答案是把私钥导出给其他 Mac 用,在 keychain 里导出私钥,就会存成 .p12 文件,其他 Mac 打开后就导入了这个私钥。
- 第 4 步都是在苹果网站上操作,配置 AppID / 权限 / 设备等,最后下载 Provisioning Profile 文件。
- 第 5 步 XCode 会通过第 3 步下载回来的证书(存着公钥),在本地找到对应的私钥(第一步生成的),用本地私钥去签名 App,并把 Provisioning Profile 文件命名为 embedded.mobileprovision 一起打包进去。这里对 App 的签名数据保存分两部分,Mach-O 可执行文件会把签名直接写入这个文件里,其他资源文件则会保存在 _CodeSignature 目录下。
- 第 6 – 7 步的打包和验证都是 Xcode 和 iOS 系统自动做的事。
• CSR:Certificate Singing Request,证书签名请求文件。包含电脑的公钥信息。所以创建时不需要填任何和发布等有关的信息。
• Certificates证书:发布者证书。Apple Develop的ID 对某部电脑的授权证书。内容是公钥或私钥,由其他机构对其签名组成的数据包。
电脑拥有这个证书后,有权对该Apple Developer的ID下所有App进行真机测试、打包、发布。注意这里,并未指定App,换句话说,和App无关。
• CSR 和 Certificates 的联系上面提到了Certificates包含了电脑的信息,这个信息来自于CSR。所以在创建Certificates时,需要提交CSR。相当于 Mac 的公钥被苹果私钥 加密的过程。
• p12: 本地私钥,可以导入到其他电脑。上面提到,拥有证书才有权做那些事。如果另一部电脑想发布,也需要证书。如果又创建一个新证书也能解决,但一般一个开发者帐号创建一个发布证书就够了,而且苹果对这证书数量有限制。这时候导出p12文件,相当于拷贝了一份私钥。给另一部电脑安装后,另一部电脑就有权了。
• Entitlements:包含了 App 权限开关等信息。
• Provisioning Profile: 描述文件。包含了证书、App ID、设备、Entitlements 等数据,并由后台私钥签名的数据包。也称为PP文件,.mobileprovision后缀文件。
小结
CSR文件包含本地公钥,被苹果私钥加密后生成 Cer 证书。该证书与权限、App ID、设备等数据经苹果私钥加密后生成 PP文件。装到真机时,会对 PP文件整体进行验证,还会对 PP 文件中的 Cer 证书进行验证。
苹果的 App 验证
上面说了开发包的验证流程 。实际上 App 安装以及每次启动都会验证。
各种证书的有效期
企业帐号发布证书有效期是3年,而开发证书有效期为1年,而描述文件开发发布都是只有1年有效期。个人帐号开发证书发布证书有效期都是1年,描述文件也全是1年有效期。下面再说说企业包 和 AD - Hoc以及 App Store的验证流程。
企业包和 AD - Hoc包验证流程
企业包和 AD -Hoc 的区别在于企业包不会限制安装设备数量,并且需要信任证书。
因为这两种包不经过 App Store,对App的签名是用证书签名的。所以证书经苹果发布后,苹果还想要限制的话,就必须检查证书是否过期。这个步骤被放到了启动 App 时。因此,如果证书过期或者 revoke掉,开发者账号被封禁,都会导致 App 启动时闪退。
- 证书过期或 revoke• app 会马上不能使用,并且由于 PP 文件包含它,也会失效。
- PP 文件过期 或 revoke• 也会闪退,但可能不会马上反应过来,可能由于网络原因等,不能马上验证失效。
- 账号被注销• 闪退
App Store 的验证流程
blog.cnbang.net/wp-content/…其实就是最简单的验证流程。我们上传 App 到 App Store时验证我们的证书、PP文件。从此,与我们的文件再无关系。上传后,苹果在后台直接用私钥签名 App 就可以了。如果去下载一个 AppStore 的安装包,会发现它里面是没有 embedded.mobileprovision 文件的,也就是它安装和启动的流程是不依赖这个文件,验证流程也就跟上述几种类型不一样了。已经在苹果商店下载安装的app不受影响(无论是过期还是Revoke,甚至是开发者账号被注销,因为这个时候,对于app的签名,是通过苹果私钥直接签名的,没有使用开发者名下的私钥签名)。但App Store 会下架相关的 App。笔者之前遇到一个场景就是,违规操作被注销是没办法的(注意保护开发者账号,可以开启双重验证,不要被偷去做马甲包然后被举报了)。那么对于企业包证书过期问题怎么处理呢?因为有效期为1年,我们可以申请两个 PP 文件,相隔半年,差不多到时间发新版时就换个新 PP 文件。更多可以看iOS 各种证书的作用、有效期、过期的后果和解决办法[2]
重签名
正常的打包流程就不再说了。iOS完整的证书申请和打包过程[3]对 ipa 包进行修改后,由于摘要变了,所以验证会不通过。我们可以采用重签名达到验证的效果。常用于逆向别人的 App,微信多开等途径。
App 的大致结构
打包出来 ipa 后,我们解压可以看到大致结构。• 资源文件:例如图片、html等等• CodeSignature/CodeResources:这是一个 plist 文件,可用文本查看,其中的内容就是程序包(不包括Frameworks)所有文件的签名。意味着你的程序一旦签名,就不能更改其中任何文件。• 可执行文件:此文件跟资源文件一样需要签名。• mobileprovision:校验证书文件、Bundle ID。• Frameworks:程序引用的系统自带的Frameworks,每个Frameworks其实就是一个 app,也包含签名信息。
iOS 系统验证签名有效性的过程
- 解压ipa2) 取出 embedded.mobileprovision,校验是否被篡改过3) 校验所有文件的签名4) 验证设备是否符合embedded.mobileprovision 的信息5) 对比 Info.plist 的 Bundle Id 是否符合 embedded.mobileprovision 文件中的信息
重签名的原理
既然签名是由证书和mobileprovision共同实现,那么重签名的过程其实就是将新的证书和mobileprovision替换旧文件的过程,但由于系统在验证app是否合法的时候还会随机验证授权设备列表和Bundle ID、所以必须修改Bundle ID与新的mobileprovision中的信息保持一致,否则将会有验证失败的风险。
重签名的尝试
笔者之前打的是企业包,针对不同客户要实现不同 App Icon 和 App name等。如果一个一个打,一个打7分钟。💩利用重签名,可以快速替换 ipa 中的内容,实现装逼的效果。步骤如下1) 打包出一份 ipa。2) 修改 ipa 内对应文件。此时摘要变化了,相当于签名失效,苹果校验时就知道该 app 被篡改 了。3) 重签名• 3.1 删除插件
• 3.2 对FrameWorks进行签名
• 3.3 给可执行文件执行权限
• 3.4 拷贝描述文件
• 3.5 修改info.plist中的Bundle ID
• 3.6 生成plist权限文件
• 3.7 签名整个APP
• 3.8 生成ipa包具体实现,更多可查看之前写过的一篇文章 iOS —— 两套自动打包脚本[3]
参考
[1]http://www.ruanyifeng.com/blog/2013/07/rsa_algorithm_part_two.html
[2]https://www.jianshu.com/p/95ca850e7ece
[3]https://juejin.im/post/5be2e07fe51d454d5c7c2b9