2017-03-14 10:58:18 byeweiyang 阅读数 617

感谢作者 bang 的授权发布,版权归原作者所有,未经允许,请勿转载。
原文地址:http://blog.cnbang.net/tech/3386/
作者:陈振焯,网名 bang,iOS 开发者,推特中文圈 / JSPatch 作者。
CSDN 有奖征稿啦】技术之路,共同进步,有优质移动开发、VR/AR/MR、物联网原创技术文章欢迎发送邮件至 mobilehub@csdn.net

iOS 签名机制挺复杂,各种证书,Provisioning Profile,entitlements,CertificateSigningRequest,p12,AppID,概念一堆,也很容易出错,本文尝试从原理出发,一步步推出为什么会有这么多概念,希望能有助于理解 iOS App 签名的原理和流程。

目的

先来看看苹果的签名机制是为了做什么。在 iOS 出来之前,在主流操作系统(Mac/Windows/Linux)上开发和运行软件是不需要签名的,软件随便从哪里下载都能运行,导致平台对第三方软件难以控制,盗版流行。苹果希望解决这样的问题,在 iOS 平台对第三方 App 有绝对的控制权,一定要保证每一个安装到 iOS 上的 App 都是经过苹果官方允许的,怎样保证呢?就是通过签名机制。

非对称加密

通常我们说的签名就是数字签名,它是基于非对称加密算法实现的。对称加密是通过同一份密钥加密和解密数据,而非对称加密则有两份密钥,分别是公钥和私钥,用公钥加密的数据,要用私钥才能解密,用私钥加密的数据,要用公钥才能解密。

简单说一下常用的非对称加密算法 RSA 的数学原理,理解简单的数学原理,就可以理解非对称加密是怎么做到的,为什么会是安全的:

  1. 选两个质数 p 和 q,相乘得出一个大整数 n,例如 p = 61,q = 53,n = pq = 3233;
  2. 选 1-n 间的随便一个质数 e,例如 e = 17;
  3. 经过一系列数学公式,算出一个数字 d,满足:
    • 通过 n 和 e 这两个数据一组数据进行数学运算后,可以通过 n 和 d 去反解运算,反过来也可以。
    • 如果只知道 n 和 e,要推导出 d,需要知道 p 和 q,也就是要需要把 n 因数分解。

上述的 (n,e) 这两个数据在一起就是公钥,(n,d) 这两个数据就是私钥,满足用私钥加密,公钥解密,或反过来公钥加密,私钥解密,也满足在只暴露公钥 (只知道 n 和 e)的情况下,要推导出私钥 (n,d),需要把大整数 n 因数分解。目前因数分解只能靠暴力穷举,而 n 数字越大,越难以用穷举计算出因数 p 和 q,也就越安全,当 n 大到二进制 1024 位或 2048 位时,以目前技术要破解几乎不可能,所以非常安全。

若对数字 d 是怎样计算出来的感兴趣,可以详读这两篇文章:RSA 算法原理()、()。

数字签名

现在知道了有非对称加密这东西,那数字签名是怎么回事呢?

数字签名的作用是我对某一份数据打个标记,表示我认可了这份数据(签了个名),然后我发送给其他人,其他人可以知道这份数据是经过我认证的,数据没有被篡改过。

有了上述非对称加密算法,就可以实现这个需求:

  1. 首先用一种算法,算出原始数据的摘要。需满足 a.若原始数据有任何变化,计算出来的摘要值都会变化。 b.摘要要够短。这里最常用的算法是 MD5。
  2. 生成一份非对称加密的公钥和私钥,私钥我自己拿着,公钥公布出去。
  3. 对一份数据,算出摘要后,用私钥加密这个摘要,得到一份加密后的数据,称为原始数据的签名。把它跟原始数据一起发送给用户。
  4. 用户收到数据和签名后,用公钥解密得到摘要。同时用户用同样的算法计算原始数据的摘要,对比这里计算出来的摘要和用公钥解密签名得到的摘要是否相等,若相等则表示这份数据中途没有被篡改过,因为如果篡改过,摘要会变化。

之所以要有第一步计算摘要,是因为非对称加密的原理限制可加密的内容不能太大(不能大于上述 n 的位数,也就是一般不能大于 1024 位 / 2048 位),于是若要对任意大的数据签名,就需要改成对它的特征值签名,效果是一样的。

好了,有了非对称加密的基础,知道了数字签名是什么,怎样可以保证一份数据是经过某个地方认证的,来看看怎样通过数字签名的机制保证每一个安装到 iOS 上的 App 都是经过苹果认证允许的。

最简单的签名

要实现这个需求很简单,最直接的方式,苹果官方生成一对公私钥,在 iOS 里内置一个公钥,私钥由苹果后台保存,我们传 App 上 App Store 时,苹果后台用私钥对 App 数据进行签名,iOS 系统下载这个 App 后,用公钥验证这个签名,若签名正确,这个 App 肯定是由苹果后台认证的,并且没有被修改过,也就达到了苹果的需求:保证安装的每一个 App 都是经过苹果官方允许的。

如果我们 iOS 设备安装 App 只有从 App Store 下载这一种方式的话,这件事就结束了,没有任何复杂的东西,只有一个数字签名,非常简单地解决问题。

但实际上因为除了从 App Store 下载,我们还可以有三种方式安装一个 App:

  1. 开发 App 时可以直接把开发中的应用安装进手机进行调试。
  2. In-House 企业内部分发,可以直接安装企业证书签名后的 App。
  3. AD-Hoc 相当于企业分发的限制版,限制安装设备数量,较少用。

苹果要对用这三种方式安装的 App 进行控制,就有了新的需求,无法像上面这样简单了。

新的需求

我们先来看第一个,开发时安装 App,它有两个个需求:

  1. 安装包不需要传到苹果服务器,可以直接安装到手机上。如果你编译一个 App 到手机前要先传到苹果服务器签名,这显然是不能接受的。
  2. 苹果必须对这里的安装有控制权,包括:
    • 经过苹果允许才可以这样安装;
    • 不能被滥用导致非开发 App 也能被安装。

为了实现这些需求,iOS 签名的复杂度也就开始增加了。

苹果这里给出的方案是使用了双层签名,会比较绕,流程大概是这样的:

  1. 在你的 Mac 开发机器生成一对公私钥,这里称为公钥 L,私钥 L。L:Local
  2. 苹果自己有固定的一对公私钥,跟上面 App Store 例子一样,私钥在苹果后台,公钥在每个 iOS 设备上。这里称为公钥 A,私钥 A。A:Apple
  3. 把公钥 L 传到苹果后台,用苹果后台里的私钥 A 去签名公钥 L。得到一份数据包含了公钥 L 以及其签名,把这份数据称为证书。
  4. 在开发时,编译完一个 App 后,用本地的私钥 L 对这个 App 进行签名,同时把第三步得到的证书一起打包进 App 里,安装到手机上。
  5. 在安装时,iOS 系统取得证书,通过系统内置的公钥 A,去验证证书的数字签名是否正确。
  6. 验证证书后确保了公钥 L 是苹果认证过的,再用公钥 L 去验证 App 的签名,这里就间接验证了这个 App 安装行为是否经过苹果官方允许。(这里只验证安装行为,不验证 App 是否被改动,因为开发阶段 App 内容总是不断变化的,苹果不需要管。)

加点东西

上述流程只解决了上面第一个需求,也就是需要经过苹果允许才可以安装,还未解决第二个避免被滥用的问题。怎么解决呢?苹果再加了两个限制,一是限制在苹果后台注册过的设备才可以安装,二是限制签名只能针对某一个具体的 App。

怎么加的?在上述第三步,苹果用私钥 A 签名我们本地公钥 L 时,实际上除了签名公钥 L,还可以加上无限多数据,这些数据都可以保证是经过苹果官方认证的,不会有被篡改的可能。

可以想到把 允许安装的设备 ID 列表 和 App 对应的 AppID 等数据,都在第三步这里跟公钥 L 一起组成证书,再用苹果私钥 A 对这个证书签名。在最后第 5 步验证时就可以拿到设备 ID 列表,判断当前设备是否符合要求。根据数字签名的原理,只要数字签名通过验证,第 5 步这里的设备 IDs / AppID / 公钥 L 就都是经过苹果认证的,无法被修改,苹果就可以限制可安装的设备和 App,避免滥用。

最终流程

到这里这个证书已经变得很复杂了,有很多额外信息,实际上除了 设备 ID / AppID,还有其他信息也需要在这里用苹果签名,像这个 App 里 iCloud / push / 后台运行 等权限苹果都想控制,苹果把这些权限开关统一称为 Entitlements,它也需要通过签名去授权。

实际上一个“证书”本来就有规定的格式规范,上面我们把各种额外信息塞入证书里是不合适的,于是苹果另外搞了个东西,叫 Provisioning Profile,一个 Provisioning Profile 里就包含了证书以及上述提到的所有额外信息,以及所有信息的签名。

所以整个流程稍微变一下,就变成这样了:

因为步骤有小变动,这里我们不辞啰嗦重新再列一遍整个流程:

  1. 在你的 Mac 开发机器生成一对公私钥,这里称为公钥 L,私钥 L。L:Local
  2. 苹果自己有固定的一对公私钥,跟上面 App Store 例子一样,私钥在苹果后台,公钥在每个 iOS 设备上。这里称为公钥 A,私钥 A。A:Apple
  3. 把公钥 L 传到苹果后台,用苹果后台里的私钥 A 去签名公钥 L。得到一份数据包含了公钥 L 以及其签名,把这份数据称为证书。
  4. 在苹果后台申请 AppID,配置好设备 ID 列表和 App 可使用的权限,再加上第③步的证书,组成的数据用私钥 A 签名,把数据和签名一起组成一个 Provisioning Profile 文件,下载到本地 Mac 开发机。
  5. 在开发时,编译完一个 App 后,用本地的私钥 L 对这个 App 进行签名,同时把第④步得到的 Provisioning Profile 文件打包进 App 里,文件名为 embedded.mobileprovision,把 App 安装到手机上。
  6. 在安装时,iOS 系统取得证书,通过系统内置的公钥 A,去验证 embedded.mobileprovision 的数字签名是否正确,里面的证书签名也会再验一遍。
  7. 确保了 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 系统自动做的事。

这里再总结一下这些概念:

  1. 证书: 内容是公钥或私钥,由其他机构对其签名组成的数据包。
  2. Entitlements: 包含了 App 权限开关列表。
  3. CertificateSigningRequest: 本地公钥。
  4. p12: 本地私钥,可以导入到其他电脑。
  5. Provisioning Profile: 包含了 证书 / Entitlements 等数据,并由苹果后台私钥签名的数据包。

其他发布方式

前面以开发包为例子说了签名和验证的流程,另外两种方式 In-House 企业签名和 AD-Hoc 流程也是差不多的,只是企业签名不限制安装的设备数,另外需要用户在 iOS 系统设置上手动点击信任这个企业才能通过验证。

而 App Store 的签名验证方式有些不一样,前面我们说到最简单的签名方式,苹果在后台直接用私钥签名 App 就可以了,实际上苹果确实是这样做的,如果去下载一个 App Store 的安装包,会发现它里面是没有 embedded.mobileprovision 文件的,也就是它安装和启动的流程是不依赖这个文件,验证流程也就跟上述几种类型不一样了。

据猜测,因为上传到 App Store 的包苹果会重新对内容加密,原来的本地私钥签名就没有用了,需要重新签名,从 App Store 下载的包苹果也并不打算控制它的有效期,不需要内置一个 embedded.mobileprovision 去做校验,直接在苹果用后台的私钥重新签名,iOS 安装时用本地公钥验证 App 签名就可以了。
那为什么发布 App Store 的包还是要跟开发版一样搞各种证书和 Provisioning Profile?猜测因为苹果想做统一管理,Provisioning Profile 里包含一些权限控制,AppID 的检验等,苹果不想在上传 App Store 包时重新用另一种协议做一遍这些验证,就不如统一把这部分放在 Provisioning Profile 里,上传 App Store 时只要用同样的流程验证这个 Provisioning Profile 是否合法就可以了。

所以 App 上传到 App Store 后,就跟你的 证书 / Provisioning Profile 都没有关系了,无论他们是否过期或被废除,都不会影响 App Store 上的安装包。

到这里 iOS 签名机制的原理和主流程大致说完了,希望能对理解苹果签名和排查日常签名问题有所帮助。

P.S.一些疑问

最后这里再提一下我关于签名流程的一些的疑问。

企业证书

企业证书签名因为限制少,在国内被广泛用于测试和盗版,fir.im / 蒲公英等测试平台都是通过企业证书分发,国内一些市场像 PP 助手、爱思助手,一部分安装手段也是通过企业证书重签名。通过企业证书签名安装的 App,启动时都会验证证书的有效期,并且不定期请求苹果服务器看证书是否被吊销,若已过期或被吊销,就会无法启动 App。对于这种助手的盗版安装手段,苹果想打击只能一个个吊销企业证书,并没有太好的办法。

这里我的疑问是,苹果做了那么多签名和验证机制去限制在 iOS 安装 App,为什么又要出这样一个限制很少的方式让盗版钻空子呢?若真的是企业用途不适合上 App Store,也完全可以在 App Store 开辟一个小的私密版块,还是通过 App Store 去安装,就不会有这个问题了。

App Store 加密

另一个问题是我们把 App 传上 App Store 后,苹果会对 App 进行加密,导致 App 体积增大不少,这个加密实际上是没卵用的,只是让破解的人要多做一个步骤,运行 App 去内存 dump 出可执行文件而已,无论怎样加密,都可以用这种方式拿出加密前的可执行文件。所以为什么要做这样的加密呢?想不到有什么好处。

本地私钥

我们看到前面说的签名流程很绕很复杂,经常出现各种问题,像有 Provisioning Profile 文件但证书又不对,本地有公钥证书没对应私钥等情况,不理解原理的情况下会被绕晕,我的疑问是,这里为什么不能简化呢?还是以开发证书为例,为什么一定要用本地 Mac 生成的私钥去签名?苹果要的只是本地签名,私钥不一定是要本地生成的,苹果也可以自己生成一对公私钥给我们,放在 Provisioning Profile 里,我们用里面的私钥去加密就行了,这样就不会有 CertificateSigningRequest 和 p12 的概念,跟本地 keychain 没有关系,不需要关心证书,只要有 Provisioning Profile 就能签名,流程会减少,易用性会提高很多,同时苹果想要的控制一点都不会少,也没有什么安全问题,为什么不这样设计呢?

能想到的一个原因是 Provisioning Profile 在非 App Store 安装时会打包进安装包,第三方拿到这个 Provisioning Profile 文件就能直接用起来给他自己的 App 签名了。但这种问题也挺好解决,只需要打包时去掉文件里的私钥就行了,所以仍不明白为什么这样设计。

关于文章末尾的疑问,唐巧在微博分享了他的看法:
1. 企业发布可以构建出绝对的私有网络下载和使用环境,避免一些极其机密内容在公网传播。
2. 加壳防止的是静态分析,否则无需越狱手机即可反汇编 IPA 源码。
如果你有好的看法与建议,欢迎与我们一起分享,技术之路,共同进步,谢谢。

2018-05-17 16:49:55 quwenjie 阅读数 257

iOS App签名原理

在学习iOS签名之前,需要对密码学有一定的了解,比如RSA加密、HASH哈希函数
参考:https://www.jianshu.com/p/003288dfb3b7

一、简单的签名原理:

  • 目的:

    • 保证每个App都是经过苹果公司官方认证的
  • 背景:因为手机和系统都是苹果公司生产的,所以苹果公司可以在手机上内置公钥,然后在App Store上放置私钥

    • 苹果手机:公钥
    • App Store:私钥
  • 原理:
    1.App上传到App Store时,苹果公司拿到App的HASH(MD5,SHA等)值,然后用私钥进行加密(签名),这时候只有手机上的公钥才可以解密;
    2.手机下载应用安装App时,先用公钥解密(验证签名),拿到HASH值,然后将此HASH值,与要安装的App的HASH值进行校验,如果App有被修改过,则校验失败。这样就可以有效的保证每个App都是经过苹果公司官方认证的。

弊端:
这样的做法,需要所有的App上传App Store,才能在手机上安装使用,那么当开发者要用真机调试时,则必须将开发阶段的App上传App Store,才能调试;另外企业账号的App并不用上传到App Store就能安装使用。这样的做法明显不合理,所以苹果公司在此基础上再做修改。

签名原理图1:

image.png

二、进阶的签名原理:

*目的:
* 没上传App Store的应用,要经过苹果的允许才能安装
* 背景:
* mac电脑:私钥M和公钥M(电脑生成)
* 苹果服务器:私钥A
* iPhone手机:公钥A
* 原理:
1.mac电脑将公钥M(生成的CSR文件)和开发者信息传到苹果服务器,这个过程叫做申请证书
2.苹果服务器对公钥M进行加密(用私钥A来加密),生成证书文件(包含公钥M和公钥M的HASH值),发送给mac电脑安装证书,存在本地钥匙串
3.苹果电脑安装App到手机时,做了一件事情:用私钥M对App的HASH值进行加密(签名) ,这时的APP内部实际包含了APP的签名(私钥M加密App的HASH值)、第2步生成的证书文件(包含公钥M和公钥M的HASH值),App可执行文件以及其他信息
4.两次解密过程:
4.1. iPhone手机拿到证书文件(包含公钥M和公钥M的HASH值),因为手机里有公钥A,所以能解密证书文件,得到公钥M和公钥M的HASH值,先验证公钥M生成的HASH值(MD5,SHA等)是不是和证书文件里的公钥M的HASH值一致,确保证书没有被修改;
4.2. 验证一致后,就可以用公钥M来解密第2步的APP的签名,同样道理可以验证App是否被修改过。 因为在开发阶段App会经常修改,所以App就算是修改过,也能安装。第4步主要是验证证书是不是苹果认证的,只要证书对就可以安装运行。

这种方式能够保证安装的App是经过苹果允许的,但是还有弊端。
弊端:
只要申请一个证书,就可以安装在所有的iOS设备。

签名原理图2:

IMG_2817.JPG

三、终极的签名原理:

*目的:
* 不能滥用安装
* 背景:
* mac电脑:私钥M和公钥M(电脑生成)
* 苹果服务器:私钥A
* iPhone手机:公钥A
* 原理:
加了两个限制:
第一个:需要在苹果服务器注册过的设备才能安装,证书对应的是有设备的(UUID)
第二个:签名只能针对某一个App,并且还需要UUID、AppID、推送,后台运行等权力描述信息,苹果公司把这些权限统一生成一个文件,称为权限文件,专门用来描述App签名的权限,并最生成Provision Profile(描述文件):包含设备IDs,AppID,Entitlements(权力文件包含是否可调试,推送,后台运行等信息)。

1.在进阶的签名原理中的第2步,证书文件(包含公钥M和公钥M的HASH值)和Provision Profile(描述文件)传给发送给mac电脑;
2.在进阶的签名原理中的第3步,Provision Profile(描述文件)也会和证书文件一起打包进去 。

查看Provision Profile信息:

cd ~/Library/MobileDevice/Provisioning\ Profiles/
ls

image.png
打开文件夹:
“`
open .

![image.png](https://upload-images.jianshu.io/upload_images/1013424-299b01f8ab4e505e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

在该目录下用终端查看:

security cms -D -i 0ae1aea3-6094-5dc4dc867596.mobileprovision
“`
image.png
image.png

其中包含了一些重要信息:
* TeamName
* AppIDName
* ProvisionedDevices 设备
* UUID 描述文件本身的UUID
* Entitlements:
* get-task-allow 是否可以调试
* com.apple.developer.team-identifier

签名原理图3

image.png

2017-12-24 23:05:39 liuxinyang666 阅读数 1215

前言

在移动开发中,iOS系统下的app和andorid系统下的app一个很大的区别是:android系统下,app的安装很方便,可以从多个应用商店下载(小米应用商店、华为应用商店),也可以直接下载apk的包安装。而在iOS系统下,对app的安装限制比较严格,非开发的app,只能从App Store下载。即使是开发人员,拥有开发者帐号,所开发的app 也不能随意的安装,有最多100台设备的限制,还需要知道设备的UDID……苹果这样做的目的是保证每个app都是经过检验的,都是经过苹果官方审核允许的。那么苹果是如何做到这一点的呢?这就和本文要介绍的内容相关,iOS app的签名机制。
在介绍iOS app签名机制之前,先介绍一些关于加密的知识。

常用的加密方式

目前主流的加密方式有对称密钥加密和非对称密钥加密。

对称密钥加密

维基百科中对对称密钥加密的定义如下:

对称密钥加密(英语:Symmetric-key algorithm)又称为对称加密、私钥加密、共享密钥加密,是密码学中的一类加密算法。这类算法在加密和解密时使用相同的密钥,或是使用两个可以简单地相互推算的密钥
简单来说,就是加密方和解密方使用的是同一个密钥。
常见的对称密钥加密有AES、DES 等。

非对称密钥加密

非对称密钥加密,又称为公开密钥加密。
非对称密钥加密需要两个密钥,一个是公开密钥,一个是私有密钥。私有密钥用来加密,公开密钥用来解密。私有密钥由加密方保管,公有密钥则公布出来。
实际上,私有密钥和共有密钥在数学上是有一定的关系的。但是仅仅从共有密钥是推断不出私有密钥的,这也是共有密钥可以公布出来的原因。
通过共有密钥推断私有密钥和质数分解有关。目前质数分解没有特别快的算法,通常是通过暴力枚举的方法来分解。当质数非常大时(如2的1024次方级别),暴力分解质数是不现实的,因此非对称加密是安全的。
非对称加密的安全还依赖于加密方对私钥的管理,一旦私钥暴露,也就毫无加密可言。
常见的非对称加密有RSA、DSA。

MD5加密

MD5全称MD5消息摘要算法(MD5 Message-Digest Algorithm)。严格来说,MD5并不是一种加密方式,MD5只是一个哈希算法,对同一个明文生成的密文(哈希值)是统一的。MD5相较于普通加密来说还有一个优点:MD5生成的密文长度很短(16位或者32位字符)。

数字签名

了解了常用加密方式之后,介绍一下数字签名,数字签名实际上和生活中的签名效果一致。想一下工作中的报销,报销单只有经过领导签名之后,递交给财务,财务才会发对应的钱。这里的领导签名实际是保证了两件事:
1. 这笔钱的花销是合理的,应该报销
2. 这笔钱的数目是正确的
即:数据是正确的,且是领导认可的。
现实生活中这样做当然是没有问题的,然而在网络上呢,比如客户端请求服务器的数据,如何确认数据中间没有被篡改过?肯定不能像现实中使用笔来签名,于是就有了数字签名。
数字签名和现实生活中签名的作用是一致的,即:
1. 保证数据没有没有被篡改过
2. 保证数据是经过我认证的
数字签名是如何保证上述两点的呢?使用的是非对称加密+MD5线性加密。
数字签名的过程如下:

  1. 首先算出原始数据的摘要。这里的算法要保证:如果原始数据有任何变化,则摘要也会发生变化;对同一份原始数据,使用相同的算法,计算出的摘要是相同的。这一步使用的算法通常是MD5消息摘要算法。
  2. 生成一对公钥和私钥,使用非对称加密方式,用私钥对上一步生成的摘要进行加密,加密的结果就是数字签名。
  3. 在返回数据时,将原始数据和数字签名一起返回给请求数据方。
    请求数据方在接收到数据之后,如何确认数据正确以及数据是合法的呢?请求数据方含有公钥,会对数字签名进行验证,过程如下:

  4. 首先用含有的公钥对数字签名进行解密,如果能够解密成功,说明返回的数据是经过数据发送方认证的(否则数据发送方不会对该数据加密)。

  5. 对原始的数据使用MD5算法,生成原始数据的摘要。
  6. 对比第一步和第二步生成的摘要,如果生成的摘要相等,说明原始数据没有被篡改过。
    由此,通过数字签名可以达到确保数据没有被篡改过以及数据是合法的目的。

通过AppStore下载的app签名机制

了解了数字签名之后,来看下苹果是如何通过AppStore确保app合法的。
我们都知道,iPhone只有一家生产商,iOS系统只有一个开发者,那就是苹果公司。因此苹果公司可以在所有的iOS系统中做一些统一的事情。实际上,苹果公司生成了一对私钥和公钥,每一个iOS 系统上都内置有公钥,而私钥保存在苹果后台上。开发者再将app上传到苹果服务器之后,苹果公司使用私钥对app进行数字签名。用户从AppStore 下载的app,既包含app包,也包含数字签名。下载到本地后,iOS 系统使用公钥验证签名,就可以确定该app 是经过苹果公司认证的,且包没有被篡改过。整个流程如下:

如果app仅仅只能从AppStore下载安装,那无疑是非常简单的。实际上,除了从AppStore下载安装,开发者还可以通过Xcode打包来安装,打好的包还可以安装在100台设备上,那么这些是如何控制的呢?

通过Xcode将app安装到手机上

在申请成为苹果开发者之后,可以通过Xcode将开发的app安装到手机上,实际上,即使是开发时的app,也需要通过苹果的验证。对于开发时app的安装,苹果使用的是双层验证。先看一些其他的知识。

CertificateSigningRequest文件

申请成为苹果开发者之后,需要在开发者后台上传 CertificateSigningRequest文件,那么CertificateSigningRequest 到底是什么呢?
CertificateSigningRequest 实际上是本地Mac 生成的公钥文件。
Mac可以通过钥匙串访问中的从证书颁发机构请求证书生成一对公钥、私钥。如下图:

生成的CertificateSigningRequest文件里面保存的是公钥,私钥保存在本地Mac 中。

p12文件

在工作中,通常是多个同事共同开发一个app,每个人都可以安装app到真机上。多个人共同开发一个app时,就需要公用一份p12文件。那么p12文件又是什么呢?
p12其实就是保存在本地Mac的私钥。本地Mac的私钥可以导出,导出后的文件即为p12文件。如下图:

双层签名机制

双层签名的流程如下:

  1. 在本地Mac 生成一对公钥、私钥
  2. 苹果生成一对公钥、私钥。其中私钥在苹果后台管理,每台iOS设备中都有公钥。
  3. 将本地Mac生成的公钥(CertificateSigningRequest)上传至开发者后台,在这个过程中,苹果会使用私钥对该公钥进行签名,最后生成一个证书文件。该证书文件中包含公钥L的原始数据,以及签名信息。开发者需要将该证书下载到本地的Mac。
  4. 在开发阶段,将app安装到手机上时,使用本地Mac的私钥(p12文件)对app进行签名,最终打包到手机上的有 App原数据,使用本地私钥对app加密后的签名文件,以及上一步下载的证书文件。
  5. iOS 设备使用公钥A验证证书中的签名,如果验证通过,说明该公钥是经过苹果认证的(也就是证实了开发者身份)。
  6. 之后使用证书中的公钥L 验证App 签名,如果验证通过,说明该app 的安装是合法的。
    这样,通过两次验证,间接验证了app的安装是经过苹果允许的。
    通过上述的双层验证,只是保证了某app的安装是经过苹果允许的,实际上苹果还有更多的限制:
  7. 只有属于开发者开发的app 才被允许安装
  8. 开发者开发的app不能被随便安装,最多只能安装到100台设备上。
    为了达到上述两个目的,上面流程中在使用私钥A对本地公钥加密时,还有一些其他的信息,如AppID,设备列表等。加上额外信息的流程如下:

主要变化在第3步。使用私钥加密生成数字签名时,不仅仅是本地的公钥,还包括在开发者后台设置的AppID和设备列表。
第5步验证时,如果签名验证通过,说明本地的公钥是经过苹果认证的,且设备列表和AppID 没有被篡改过。
第6步验证时,除了验证App签名,还要验证该设备是否在设备列表中,AppID是否正确等信息。
通过这些附加的信息,就限制了安装数量,避免被滥用。
这也是为何当在开发者后台添加新的设备UDID 时,需要更新证书的原因。因为重新添加了UDID,苹果会重新用私钥加密,重新生成一个新的证书。
到这一步,我们基本上理解了iOS app的签名机制。通过上面的介绍,可以看到第三步生成的证书是非常复杂的,包含了非常多的信息。实际上,除了上述的内容,还有一些推送等权限也需要控制,这些数据也需要签名验证。如果再加上这些信息,证书会变的非常复杂,而且证书也是有一些固定格式的,太多的内容也不符合证书的格式。为了解决这个问题,苹果又搞了个Provisioning Profile文件(也就是俗称的pp文件)。Provisioning Profile文件中除了包含证书,还包含设备列表、AppID、各种权限控制等。
对于各种权限的控制,苹果也统一的处理了一下,叫做Entitlements 文件。
最终的流程也就变成了下面这样:

实际的开发环境中,在将本地的公钥传到开发者中心后,在开发者中心配置设备列表、AppID、以及各种权限控制,之后苹果使用自己的私钥对这些数据进行签名,生成Provisioning Profile文件。开发时,需要将Provisionging Profile文件下载到本地,通过Xcode打包时,会将Provisioning Profile 文件也一起打包进app中。

结语

本文通过引入常见的加密方式,到数字签名,由浅入深介绍了iOS app签名的机制。本文参考了微信阅读的一篇博客加上自己的理解,包括所使用的插图均来自该博客。如果有理解不对的地方,欢迎大家留言交流。

参考文章

https://wereadteam.github.io/2017/03/13/Signature/

2017-11-20 22:51:07 Bug_money 阅读数 965

APP开发完成后都需要做的就是打包上架,这里列举三种打包方法,着重讲解官网Android打包方式(结合android的打包)进行最详细的讲解。【学不会你可以打死我】

打包执行命令:(ionic其实可以省略,尾部可以加–save)

1、ionic cordova platform remove android (移除平台)

2、ionic cordova platform add android@6.2.2 (添加平台)【建议6.2.2
对应的是android-25 SDK】

3、ionic cordova build android –prod (测试版)
android-debug.apk【默认是这个版本】 ionic cordova build android
–prod –release(正式未签名版) 打包后出现 android-release-unsigned.apk

4、ionic cordova build android –prod –release(正式签名版) 打包后出现
android-release.apk【前提是创建了密钥 并配置了release.properties文件】

加完平台后包执行Android打包 完成后会显示: Building successful

**IOS的打包上架可参考blog.csdn.net/liujiawei00/article/details/73822707。(这里不详细讲解)
使用webStorm工具打包签名APP www.jianshu.com/p/dfd98ad47af1 【本人没试过】
方法一:(未打包好,想直接打包签名的。)

项目目录下执行:

1、先移除平台防止错误:ionic cordova platform remove android –save 【ionic
不要也行】(如果成功,以后直接打包覆盖平台即可)

2、再添加平台:ionic cordova platform add android@6.2.2 –save

3、再制作密钥(随便在哪制作):keytool -genkey -v -keystore lappfront.keystore -alias
lappfront.keystore -keyalg RSA (-keysize 2048) -validity 20000

这里写图片描述
4、制作完生成的lappfront.store(我这里是lappfront) 移动到项目生成的platform >android目录下【和下面的release-signing.properties文件在同目录】

4、再platform >android文件夹下创建release-signing.properties文件(内容如下):
这里写图片描述
5、最后如下: 【打包正式的话就执行 ionic cordova build android –prod –release】【debug.apk的话如下图】
这里写图片描述

经过上面几步的操作,ionic打包签名APK:android-release.apk便已完成。

【最后就是优化APK,优化步骤下面有 (不优化也可以) 上线就行了】

方法二:要给未签名的apk重新签名,需要用到jarsigner工具:

1、已经执行了 ionic cordova build android –prod –release

打包成功的前提下出现:android-release-unsigned.apk【需要转成签名APK】

1)、创建密钥:同上 【这次在打包好的apk目录下执行】

2)、密钥弄好后,cd到项目的apk 目录 执行:【根据你要的app名称进行下面命令】

jarsigner -verbose -keystore my-release-key.keystore -storepass 123456
-signedjar lvshi.apk -digestalg SHA1 -sigalg MD5withRSA android-release-unsigned.apk alias_name 【这里要注意这些参数的意思,和密钥设置的匹配就行】
这里写图片描述
这里面,你的apk地址,要么是绝对地址,要么是你工程内的相对地址,如果地址不对,就会出现下面的错误【所以直接直接放一起,不然要找路径】

这里写图片描述
这里写图片描述
【结尾是jar 已签名,出现新的签名apk】

jarsigner是JDK自带的签名工具,我们需要将release版本的apk文件利用keystore文件进行加密,也就是签名,签名之后的apk才能发布到应用市场。

【项目apk的 目录下,创建密钥并签名如下】

一、keytool -genkey -v -keystore my-release-key.keystore -alias
alias_name -keyalg RSA -keysize 2048 -validity 10000

二、jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore
my-release-key.keystore HelloWorld-release-unsigned.apk
alias_name【这里用下面MD5那种的签名】

SHA-1与MD5的比较:【都是摘要加密算法】

http://blog.csdn.net/lplj717/article/details/51828692【加密算法中BASE64、MD5、SHA、HMAC等之间的区别】

因为二者均由MD4导出,SHA-1和MD5彼此很相似。相应的,他们的强度和其他特性也是相似,但还有以下几点不同:

l对强行攻击的安全性:最显著和最重要的区别是SHA-1摘要比MD5摘要长32
位。使用强行技术,产生任何一个报文使其摘要等于给定报摘要的难度对MD5是2^128数量级的操作,而对SHA-1则是2^160数量级的操作。这样,SHA-1对强行攻击有更大的强度。

l 对密码分析的安全性:由于MD5的设计,易受密码分析的攻击,SHA-1显得不易受这样的攻击。

l 速度:在相同的硬件上,SHA-1的运行速度比MD5慢。

三、参考http://e2web.cn/2016/12/23/
这里写图片描述

这种打包完成后需要优化 【虽然你在build的时候–prod 了,但这里一样可以再优化】:

cd到下面目录(针对你apk的版本):
这里写图片描述
这里写图片描述

这里面apk的路径最好是绝对路径,要不然也会报错。

执行:zipalign -v 4
E:\my_project\lappfront\platforms\android\build\outputs\apk\lvshi.apk
E:\my_project\lappfront\platforms\android\build\outputs\apk\lvshi_fabu.apk

【到此为止,你还剩下最后一步工作,如果想要真正的发布软件,你需要将之前生成的签名文件(.keystore)放到一个安全的地方,要不然你上传到商店后就无法对这个软件进行升级。】

2016-02-24 18:15:19 lvchaman 阅读数 9252

http://blog.csdn.net/a351945755/article/details/46472523

作为一个app应用程序开发者,在app应用程序在苹果商店上架前总需要将安装包安装到ios机器上进行测试,这个时候我们就需要打包in house版本的ipa了,打包in house实际上是一个将ipa应用程序重新签名的一个过程。一般来...

   作为一个app应用程序开发者,在app应用程序在苹果商店上架前总需要将安装包安装到ios机器上进行测试,这个时候我们就需要打包in house版本的ipa了,打包in house实际上是一个将ipa应用程序重新签名的一个过程。一般来说打包in house需要以下东西:MAC机器,一般打包ipa都是在MAC机上打包的,一个后缀名为.mobileprovision概要配置文件,一个后缀名为P12的证书,还有一个后缀名为.cer的证书,还有就是你想重新签名的ipa.

  如何给ipa重新签名

步骤1 : 
unzip YourApp.ipa
步骤2:  
rm -rf Payload/YourApp.app/_CodeSignature
步骤3:  
cp InHouse.mobileprovision Payload/YourApp.app/embedded.mobileprovision
步骤4:  
/usr/bin/codesign -f -s "iPhone Distribution: YourCompanyName" --resource-rules Payload/YourApp.app/ResourceRules.plist Payload/YourApp.app
步骤5: 
zip -r YourApp_inhouse.ipa Payload


* InHouse.mobileprovision 是你要用来签名的provision文件
* iPhone Distribution: YourCompanyName 是指该签名对应的证书的名字。这个可以在keychain中找到


1. 先通过TestFlight安装build
  2. 再把build通过ifanbox把build导出来成为ipa文件
  3. 下面就需要把ipa文件重新签名,方法有两种
  方法一:
  利用商业化工具签名,SeeTest支持把ipa重新签名,签名需要提供 provision文件,和开发者证书私钥和密码
  方法二:
  自己想办法签,代码参考如下

unzip app.ipa
rm -rf Payload/MyApp.app/_CodeSignature/
cp ~/Downloads/AdHoc.mobileprovision Payload/MyApp.app/embedded.mobileprovision
codesign -f -s "iPhone Distribution: Company Certificate" --resource-rules Payload/MyApp.app/ResourceRules.plist Payload/MyApp.app
zip -qr app-resigned.ipa Payload/

  其中"iPhone Distribution: Company Certificate"是你证书的common name, 别的没什么要注意的。
  方法三:
  网上有推荐用一个叫iresign的工具签名,其实挺好用,该工具只能工作在mac下面
  个人推荐用方法三,但是要注意一个问题,就是iresign需要你提供四个信息,一个是ipa文件,一个是provision文件,一个是证书的common name,最后一个是entitlements.plist文件。前三个想必大家都懂,但是第四个之前真没听过,网上资料也有限。
  请用下面的方法生成entitlements.plist文件
【  需要cd到Payload文件下,才可以生成】
/usr/libexec/PlistBuddy -x -c "print :Entitlements " /dev/stdin <<< $(security cms -D -i production.app/embedded.mobileprovision) > Entitlements.plist
/usr/libexec/PlistBuddy -c 'Set :get-task-allow true' Entitlements.plist

  生成之后,再利用iresign,就可以做出一个可以被xcode instrument的ipa包了。

没有更多推荐了,返回首页