iOS 应用签名
一、密码学简介
1.1 base64
- Base64 是一种通过查表的编码方法,不能用于加密,即使使用自定义的编码表也不行。
- Base64 适用于小段内容的编码,比如数字证书签名、Cookie 的内容等。
- 由于 = 字符也可能出现在 Base64 编码中,但 = 用在 URL、Cookie 里面会造成歧义,所以,很多Base64编码后会把 = 去掉,解码时,需要加上 = 把 Base64 字符串的长度变为 4 的倍数,再进行解码。
使用 mac 自带的 base64 编码,格式:base64 [文件路径] -o [保存文件路径]
$ base64 a.png
$ base64 a.png -o a.txt
iOS 代码编写:
NSData * data = [@"A" dataUsingEncoding:NSUTF8StringEncoding];
// base64 编码
NSLog(@"%@", [data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]);
// base64 解码
NSData * newData = [[NSData alloc] initWithBase64EncodedString:@"QQ==" options:NSDataBase64DecodingIgnoreUnknownCharacters];
NSLog(@"%@", [[NSString alloc] initWithData:newData encoding:NSUTF8StringEncoding]);
QQ==
A
base64 对照表
1.2 hash
hash 又称为散列函数,在 iOS 中使用到的 hash 算法有:
- MD5
- SHA1/256/512
- HMAC
这些算法都具有以下特点:
- 算法都是公开的;
- 对相同的数据进行加密,得到的结果是相同的;
- 对不同的数据进行加密,得到的结果是定长的。如:MD5 32 个字符;
不能反算。所以常用来做信息摘要,信息“指纹”,用来做信息识别。
md5
$ md5 -s "12345678"
MD5 ("12345678") = 25d55ad283aa400af464c76d713c07ad
应用场景:
用户登录应用时,注册填入的密码,经过 hash 算法加密后,传给服务器,服务器只存储 hash 值。当用户再次登录时,只需要验证登录密码的 hash 值与服务器保存的是否相同。
上面的应用场景足够安全吗?来看下图(网址:https://www.cmd5.com/)
由于相同的数据得到的 hash 值是相同的,当记住很多的原始数据和 hash 值的对应关系之后,是可以查询出来原始数据的。注意:这里是查询而不是反算。
要想更加安全一些,可以采取策略:“加盐”。
加盐:在原始数据中加入一段额外的字符串,降低查询成功率。
$ md5 -s "12345678&&%#**#7*&@&#W#^E"
MD5 ("12345678&&%#**#7*&@&#W#^E") = 28e2829463d71bb8931eac4517436a2e
加盐之后是否就能高枕无忧呢?显然不能,如果开发者将盐固定写死在 app,是有可能泄露的,应用的安全性也就随之降低。
在此基础上,引申出动态“加盐”的 HMAC 算法。
HMAC
使用 KEY 进行明文加密,然后进行两次 Hash 算法。Key 是服务器随机生成的,对应的是一个账号一个 Key。
HMAC 是一种加密策略,两次使用的 hash 算法可以 MD5,也可以是 SHa.
1.3 对称加密算法
- DES 加密算法简单,基本不使用;
- 3DES 执行 3 次 DES 算法,基本不使用。
- AES(高级密码标准),iOS中的钥匙串访问就是使用 AES
算法的特点:可以反算。
加解密过程
- 明文 -> 密钥加密 -> 密文
- 密文 -> 密钥解密 -> 明文
加密方式
EBC
电子代码本,每一个数据块进行独立加密。
a.txt 文件原始数据:
11111111111111
11111111111111
11111111111111
11111111111111
终端执行命令:
$ openssl enc -des-ecb -K 616263 -nosalt -in a.txt -out b.bin
$ xxd b.bin
上面采用
ecb
算法,-nosalt
不需要加盐,616263
是 abc 的 ASCII 码,.bin
是二进制文件,xxd
查看二进制文件。a.txt 文件修改后数据:
11111111111111
11111111111111
11111111111100
11111111111111
终端执行同样的命令后,可以看到差别,如图:
CBC
密码块链,使用一个密钥和一个初始化向量对数据进行加密。
这种加密方式可以有效的保证数据的完整性。也就是说,如果有一个数据块丢失,就会导致后面所有的数据块都无法解密。一般这种技术用于防范窃听。
$ openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -in a.txt -out b.bin
$ xxd b.bin
由上可以看出,EBC 加密方式修改数据后,只影响一个数据块的加密结果;CBC 则影响之后的数据块。
1.4 非对称加密算法
RSA算法
RSA - 原理、特点(加解密及签名验签)及公钥和私钥的生成
- RSA 是非对称加密算法,算法是公开的;
- 公钥加密数据,私钥解密数据;
- 私钥加密数据,公钥解密数据;
- 公钥可以有多个,私钥只要一个。
以下进行 openssl 终端演示
常用指令
- genrsa 生成并输入一个 RSA 私钥
- rsautl 使用 RSA 密钥进行加密、解密、签名和验证等运算
- rsa 处理 RSA 密钥的格式转换等问题
加密过程
生成 RSA 私钥
$ openssl genrsa -out private.pem 1024
Generating RSA private key, 1024 bit long modulus
。。。。。。。。。。。。。。。。。。。。。++++++
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。++++++
e is 65537 (0x10001)
openssl 默认生成 512 位的私钥,上面指定的是 1024 位的。需要注意的是,愈长的私钥被破解的机率愈低,但是相对地,我们在使用加密与解密的时间也会愈长。使用者可以自行评量。
查看 RSA 私钥
$ cat private.pem
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDQNiXkM7Sw3EwCHp1TPEFvKLe5kP7MWr+N/mf4NDlgEZa08xIT
htAI7T7I/e6rW6Ho7HAgbucCb/cx1GEx+kH0ldRCKZ7NxS4Ueo9YjqArbsRlQDx5
w5cVj58g5E1ZuIvR600uXWYZXAK9LS65HQoWZiWtMmuy4qPW5NtgdALQLwIDAQAB
AoGAEby7J6CcAQETXI7dGi0k6eJPHHjUq/YDIYaNtuBEDwIQk6OtY4p1iH0lfxva
zDBHL7+Mocaw2U1Ogqk0CnzmR1drO+ubpRRI15KKYkuS918xXqlPNPszowXns7z8
THjpjeLgWfRAcuvVs7bHPu4C/b2smXwNBptTAtpIS2/6VSECQQDvoHA8cUgL+8Nn
ovPMhcsK7NXoZ/gnSWh3LqECK9JIvDlkQao8mzd8SpZBf5Xya9esqCUYib6gzvlG
/RxpUpG/AkEA3nAxicmTe5K1EBUed3zH1ALxquwy/7s1tsi87brvDlNAGi2MFDXO
AZ9R9H1mVHxqnyekCrpCvgUv6QPsoex9kQJAedzc11BA9J8vy9fKJrvv+3lge5XM
VKZ3cw0KouEISyc2BK+EVNgXCqWf7mVlK2j+wPauDuGWSY+YpCp6tXFhXwJBAMPQ
pntyvWdybfx7averHErSUKa0Ce1Ag/el3VO2VU4aEXs6D2+XMgQRmdcOMXA8mqwC
/JEJCUo4TMXnU3/0LVECQHKC4ARiTNGtCf0e+HZjT8XanqHR+O6QUMZ90m4aQGRg
VaBLs5uNFf945FyyPpvQSJFqTZ3j17Go8dRpgd5k0q0=
-----END RSA PRIVATE KEY-----
转成明文并查看
$ openssl rsa -in private.pem -text -out private.txt
writing RSA key
$ cat private.txt
Private-Key: (1024 bit)
modulus:
00:d0:36:25:e4:33:b4:b0:dc:4c:02:1e:9d:53:3c:
41:6f:28:b7:b9:90:fe:cc:5a:bf:8d:fe:67:f8:34:
39:60:11:96:b4:f3:12:13:86:d0:08:ed:3e:c8:fd:
ee:ab:5b:a1:e8:ec:70:20:6e:e7:02:6f:f7:31:d4:
61:31:fa:41:f4:95:d4:42:29:9e:cd:c5:2e:14:7a:
8f:58:8e:a0:2b:6e:c4:65:40:3c:79:c3:97:15:8f:
9f:20:e4:4d:59:b8:8b:d1:eb:4d:2e:5d:66:19:5c:
02:bd:2d:2e:b9:1d:0a:16:66:25:ad:32:6b:b2:e2:
a3:d6:e4:db:60:74:02:d0:2f
publicExponent: 65537 (0x10001)
privateExponent:
11:bc:bb:27:a0:9c:01:01:13:5c:8e:dd:1a:2d:24:
从私钥中提取公钥
$ openssl rsa -in private.pem -pubout -out public.pem
writing RSA key
$ cat public.pem
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQNiXkM7Sw3EwCHp1TPEFvKLe5
kP7MWr+N/mf4NDlgEZa08xIThtAI7T7I/e6rW6Ho7HAgbucCb/cx1GEx+kH0ldRC
KZ7NxS4Ueo9YjqArbsRlQDx5w5cVj58g5E1ZuIvR600uXWYZXAK9LS65HQoWZiWt
Mmuy4qPW5NtgdALQLwIDAQAB
-----END PUBLIC KEY-----
通过公钥加密数据
$ openssl rsautl -encrypt -in a.txt -inkey public.pem -pubin -out enc.txt
$ cat enc.txt
1��,~��~Dn�P�Q�
]X
��wa�؆���ޅ��T���sJ��z���,l쩨�l��,Y�i�����vD9^Y��)D�:�
RSA 非对称式加解演算法因为先天的限制,无法加密过大的档案,若遇到这个问题时,OpenSSL 会输出如下的错误讯息
RSA operation error
140736003920840:error:0406D06E:rsa routines:RSA_padding_add_PKCS1_type_2:data too large for key size:/BuildRoot/Library/Caches/com。apple。xbs/Sources/libressl/libressl-22.50。3/libressl/crypto/rsa/rsa_pk1.c:158:
通过私钥解密数据
$ openssl rsautl -decrypt -in enc.txt -inkey private.pem -out dec.txt
$ cat dec.txt
11111111111111
11111111111111
11111111111111
11111111111111
通过私钥加密数据
$ openssl rsautl -sign -in dec.txt -inkey private.pem -out enc2.txt
$ cat enc2.txt
]n�&h`�,ܪ8ۭ��`��X�fL8。�^����G
\��3��P����t�Xj���&�f��_7�K�[2wK7@ʼ�_�Qh�N
�x��。
�uɮ�i����@����ݛ���ɧ]l�
通过公钥解密数据
$ openssl rsautl -verify -in enc2.txt -inkey public.pem -pubin -out dec2.txt
$ cat dec2.txt
11111111111111
11111111111111
11111111111111
11111111111111
加密特点
- 加密的安全性非常高,加密解密使用不一样的密钥;
- 运算的效率非常低,一般只加密小数据,用于数字签名。
二、数字签名
数字信息的识别码。
用户在支付宝付费 10 元
直接传递数据是不安全的,黑客可以随意将“消费 10 元”改成“消费 100 元”,支付宝无法验证用户的数据是否被篡改,考虑后,决定将“消费 10 元”的数据连同它的 hash 值一起发送给服务器,服务器端通过对数据进行 hash 运算,与携带的 hash 值进行比较,相同则没有被篡改过。
以为这样就安全了吗?黑客通过中间拦截,将“消费 10 元”及其 hash 值一并修改。
有没有方式可以让 hash 值无法被修改呢?答案是对 hash 值数据进行非对称(RSA)加密,这就是数字签名。
三、代码签名
代码签名(Code signing)是对可执行文件或脚本进行数字签名,用来确认软件在签名后未被修改或损坏的措施。和数字签名原理一样,只不过签名的数据是代码。
3.1 简单的代码签名
在 iOS 出来之前,以前的主流操作系统(Mac/Windows)软件随便从哪里下载都能运行,系统安全存在隐患,盗版软件,病毒入侵,静默安装等等。那么苹果希望解决这样的问题,要保证每一个安装到 iOS 上的 APP 都是经过苹果官方允许的,怎样保证呢?就是通过代码签名。
如果要实现验证,其实最简单的方式就是通过苹果官方生成非对称加密的一对公私钥。在 iOS 的系统中内置一个公钥,私钥由苹果后台保存,我们传 APP 到 AppStore 时,苹果后台用私钥对 App 数据进行签名,iOS 系统下载这个 APP 后,用公钥验证这个签名,若签名正确,这个 App 肯定是由苹果后台认证的,并且没有被修改过,也就达到了苹果的需求:保证安装的每一个 App 都是经过苹果官方允许的。
如果我们 iOS 设备安装 App 只从 App Store 这一个入口这件事就简单解决了,没有任何复杂的东西,一个数字签名搞定。但是实际上 iOS 安装 App 还有其他渠道:比如在开发 App 时直接真机调试的,而且苹果还开放了企业内部分发的渠道,企业证书签名的 App 也是需要顺利安装的。
苹果需要开放这些方式安装APP,这些需求就无法通过简单的代码签名来办到了。那么我们来分析一下,它有些什么需求。
- 安装包不需要上传到 App Store,可以直接安装到手机上;
- 苹果为了保证系统的安全性,又必须对安装的 App 有绝对的控制权
- 经过苹果允许才可以安装
- 不能被滥用,导致非开发 App 也能被安装
为了实现这些需求,iOS 签名的复杂度也就开始增加了,苹果这里给出的方案是双层签名。
3.2 iOS 的双层代码签名
iOS 的双层代码签名流程这里简单梳理一下,这也不是最终的 iOS 签名原理。iOS 的最终签名在这个基础上还要稍微加点东西,文末会讲。
首先这里有两个角色:
- iOS 系统
- Mac 系统
因为 iOS 的 App 开发环境在 Mac 系统下,所以这个依赖关系成为了苹果双层签名的基础。
在 Mac 系统中生成非对称加密算法的一对公钥/私钥(Xcode 代办了)。这里称为公钥 M、私钥 M。
苹果自己有固定的一对公私钥,跟之前 App Store 原理一样,私钥在苹果后台,公钥在每个 iOS 系统中。这里称为公钥 A,私钥 a.
把公钥 M 以及一些你开发者的信息,传到苹果后台(这个就是 CSR 文件),用苹果后台里的私钥 A 去签名公钥 M。得到一份数据包含了公钥 M 以及其签名,把这份数据称为证书。
在开发时,编译完一个 APP 后,用本地的私钥 M(今后你导出的P12) 对这个 APP 进行签名,同时把第三步得到的证书一起打包进 APP 里,安装到手机上。
在安装时,iOS 系统取得证书,通过系统内置的公钥 A,去验证证书的数字签名是否正确。
验证证书后确保了公钥 M 是苹果认证过的,再用公钥 M 去验证 APP 的签名,这里就间接验证了这个 APP 安装行为是否经过苹果官方允许。(这里只验证安装行为,不验证 APP 是否被改动,因为开发阶段 APP 内容总是不断变化的,苹果不需要管。)
有了上面的过程,已经可以保证开发者的认证,和程序的安全性了。 但是,你要知道 iOS 的程序,主要渠道是要通过 APP Store 才能分发到用户设备的,如果只有上述的过程,那岂不是只要申请了一个证书,就可以安装到所有 iOS 设备了?那么为了防止滥用,苹果再加了几个限制。
四、描述文件
应用签名方式并不能解决应用滥用的问题,所以苹果又加了两个限制:
- 在苹果后台注册过的设备才可以安装
- 签名只能针对某一个具体的 App
并且苹果还想控制 App 里面的 iCloud/PUSH/后台运行/调试器附加这些权限,所以苹果把这些权限开关统一称为 Entitlements(授权文件)。并将这个文件放在了一个叫做 Provisioning Profile(描述文件)文件中。描述文件是在 AppleDevelop 网站创建的(在 Xcode 中填上 AppleID 它会代办创建),Xcode 运行时会打包进入 APP 内。
所以我们使用 CSR 申请证书时,我们还要申请描述文件。流程如下:
这个描述文件里面就是描述:
- 可以安装的设备有哪些
- APP 的 ID 是什么
- 权限有哪些
在开发时,编译完一个 APP 后,用本地的私钥 M 对这个 APP 进行签名,同时把从苹果服务器得到的 Provisioning Profile 文件打包进 APP 里,文件名为 embedded.mobileprovision,把 APP 安装到手机上。
我们可以利用 $security cms -D -i embedded.mobileprovision
命令查看 Provisioning profile 内容,这些 Xcode 创建的 Profile 文件都存放在 ~/Library/MobileDevice/Provisioning Profiles/
目录下
注意:每次我们新建项目其实会生成一个描述文件,选择运行到手机上,我们只需要编译一下,在 App 包里面就可以看到。
那么为了便于我们查看信息! 我们可以通过 Xcode 来查看!!
当然,Provisioning profile 本身也是通过签名认证的,所以别想着你可以更改里面的东西来达到扩充权限或者设备的目的。只有老老实实的去网站向 Apple 申请一份更多权限、设备的 profile。
五、整体的流程
首先总结一下刚才的一些名词
证书:内容是公钥或者私钥,由认证机构对其签名组成的数据包。可以使用钥匙串访问看到
P12:就是本地私钥,可以导入到其他电脑
Entitlements:权限文件,包含了 App 一些权限的 plist 文件
CertificateSigningRequest:CSR 文件包含了本地公钥的数据文件
Provisioning Profile:描述文件,包含了证书、Entitlements 等数据,并由苹果后台私钥签名的数据包。
流程如下:
- keychain 里的 “从证书颁发机构请求证书”,这里就本地生成了一对公私钥,保存的 CertificateSigningRequest 里面就包含公钥,私钥保存在本地电脑里。
- 向苹果申请对应把 CSR 传到苹果后台生成证书。
把证书下载到本地。这时本地有两个证书。一个是第 1 步生成的私钥,一个是这里下载回来的证书,keychain 会把这两个证书关联起来,因为他们公私钥是对应的,在 XCode 选择下载回来的证书时,实际上会找到 keychain 里对应的私钥去签名。这里私钥只有生成它的这台 Mac 有,如果别的 Mac 也要编译签名这个 App 怎么办?答案是把私钥导出给其他 Mac 用,在 keychain 里导出私钥,就会存成 .p12 文件,其他 Mac 打开后就导入了这个私钥。
在苹果网站上操作,配置 AppID/权限/设备等,最后下载 Provisioning Profile 文件。
XCode 会通过第 3 步下载回来的证书(存着公钥),在本地找到对应的私钥(第一步生成的),用本地私钥去签名 App,并把 Provisioning Profile 文件命名为 embedded.mobileprovision 一起打包进去。所以任何本地调试的 App,都会有一个 embedded.mobileprovision(描述文件)从 App Store 下载的没有。
六、APP签名的数据
这里对 App 的签名数据保存分两部分
Mach-O 可执行文件会把签名直接写入文件里
其他资源文件则会保存在 _CodeSignature 目录下在 App 包里。
文章
逻辑教育视频:
逻辑教育视频:双向验证
请叫我Hank - iOS应用签名(上)、iOS应用签名(下)
iOS 应用签名的更多相关文章
- iOS代码签名理解
前言 做了几年iOS app coder了,对于证书的生成.使用流程烂熟于心,然而对于这套机制的原理却一直不甚理解.近来由于工作需要仔细研究了一下,特将自己的学习经验记录于此,以供大家学习指正. 问题 ...
- iOS App签名的原理
前言 相信很多同学对于iOS的真机调试,App的打包发布等过程中的各种证书.Provisioning Profile. CertificateSigningRequest.p12的概念是模糊的,导致在 ...
- 【腾讯Bugly干货分享】iOS App 签名的原理
本文来自 WeRead 团队博客: http://wereadteam.github.io/ iOS 签名机制挺复杂,各种证书,Provisioning Profile,entitlements,Ce ...
- iOS app签名原理
基本原理: 公钥能够验证私钥的签名是否正确. Apple后台有一个私钥A,iOS内置一个公钥A,与私钥A对应.(A:代表Apple,即苹果) 本地产生一对公钥L.私钥L,(L:代表Local,即本地) ...
- iOS 应用签名原理&重签名
在苹果的日常开发中,真机测试与打包等很多流程都会牵扯到各种证书,CertificateSigningRequest,p12等.但是很多相应的开发者并不理解iOS App应用签名的原理和流程.今天着重讲 ...
- iOS 超级签名详解
一.原理 把安装设备当做开发设备进行分发.说的明白一些,开发者可以在开发者后台添加手机的UDID,然后重新打包一个IPA文件,分发平台,然后被添加的UDID就可以下载. 二.优缺点 优势: 直接分发, ...
- ios企业签名为什么会掉签?
我们都知道ios用户无法直接安装App Store之外的应用,对于那些无法上架苹果应用商店的APP,开发者们一般会选择苹果签名的形式. 目前的苹果签名有ios企业签名.超级签名和TF上架这三种 ...
- iOS的签名机制
1.从keychain里“从这证书颁发机构请求证书”,这样就在本地生成了一对公私钥,保存的CertificateSigningRequest就是公钥,私钥保存在本地电脑里. 2.苹果自己有一对固定的公 ...
- iOS自动签名网站
node.js作为服务端,调用shell脚本进行iOS包重签名. 需要安装:nodejs ,forever 安装环境: 安装nodejs 安装forever: npm install forever ...
随机推荐
- CVE-2019-0708 远程桌面漏洞复现
漏洞影响Windows版本: Windows XP SP3 x86Windows XP Professional x64 Edition SP2Windows XP Embedded SP3 x86W ...
- 如何优雅地删除 Linux 中的垃圾文件
不知道大家是否也跟我一样,是一只要把的自己电脑文件安排的条理有序,把没用的文件会及时删掉的程序猿呢?如果是的话,那么我们可以愉快地探讨下文章的内容.如果不是的话,你也可以留下来凑凑热闹嘛(>-& ...
- 【每日一包0017】pretty-ms
[github地址:https://github.com/ABCDdouyae...] pretty-ms 将毫秒转换为容易读取的时间:1337000000 → 15d 11h 23m 20s 普通用 ...
- Web 认证配置流程
AC配置 Radius配置 Portal配置
- Sequence to Sequence Learning with Neural Networks论文阅读
论文下载 作者(三位Google大佬)一开始提出DNN的缺点,DNN不能用于将序列映射到序列.此论文以机器翻译为例,核心模型是长短期记忆神经网络(LSTM),首先通过一个多层的LSTM将输入的语言序列 ...
- Notepad++远程连接Linux
为方便编辑Linux上的文件,我们可以用Notepad++的NppFTP插件 工具:Notepad++.CentOS 1.通过ifconfig命令找到主机ip 2.打开Notepad++插件NppFT ...
- plantUML最佳实践
plantUML 使用plantUML中的活动图用来画流程图很好用; 但类图等就不很好用; 个人体会如下: • 时序图 推荐 • 用例图 一般 • 类 图 不推荐, 用Visual Paradigm或 ...
- JsonFormat 日期少了8个小时?还我
JsonFormat 后日期少了8个小时什么鬼? 前言 今天测试的时候发现时间对不上,比数据库里的时间少了8个小时?测试小姐姐一顿狂轰乱炸,一点都不温柔. 什么鬼?哪里出了问题?数据库显示的是下面
- 建议8:恰当选用if和switch
相对来说下面几种情况更适合switch结构 枚举表达式的值.这种枚举是可以期望的,平行逻辑关系的 表达式的值具有离散性,不具有线性的非连续的区间值 表达式的值是固定的,不是动态变化的 表达式的值是有限 ...
- rimraf node_modules 突然不能用了 怀疑是yarn的问题,从环境变量将yarn删掉,能用了
rimraf node_modules 突然不能用了 怀疑是yarn的问题,从环境变量将yarn删掉,能用了