筆者接觸打包已經一段時間了,但一直對簽名都是似懂非懂,最近從加密數論知識起回看這部分知識,感覺還是有很多不懂的地方。先簡單說明一哈數學原理,然后說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>生成一份非對稱加密的公鑰和私鑰,私鑰保留,公鑰公布出去。
對一份數據,算出摘要 后,用私鑰加密 這個摘要,得到一份加密后的數據,稱為原始數據的簽名。把它跟原始數據一起發送給用戶。
-
用戶收到數據和簽名后,用公鑰解密得到摘要。同時用同樣的算法計算原始數據的摘要,對比這里計算出來的摘要和用公鑰解密簽名得到的摘要是否相等,若相等則表示這份數據中途沒有被篡改過,因為如果篡改過,摘要會變化 。
image
最簡單的簽名
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 。所以能拓展整個流程圖如下。image
- 在你的 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]http://www.lxweimin.com/p/95ca850e7ece
[3]https://juejin.im/post/5be2e07fe51d454d5c7c2b9