全盤加密

全盤加密是使用加密密鑰對 Android 設備上的所有用戶數據進行編碼的過程。設備加密後,所有用戶創建的數據在提交到磁盤之前都會自動加密,所有讀取都會在將數據返回到調用進程之前自動解密數據。

Android 4.4 中引入了全盤加密,但 Android 5.0 引入了以下新功能:

  • 創建了快速加密,它只加密數據分區上使用過的塊,以避免首次啟動需要很長時間。目前只有 ext4 和 f2fs 文件系統支持快速加密。
  • 增加了forceencrypt fstab的標誌,以在第一次啟動加密。
  • 添加了對無密碼模式和加密的支持。
  • 添加了使用可信執行環境 (TEE) 簽名功能(例如在 TrustZone 中)的加密密鑰的硬件支持存儲。請參閱存儲加密密鑰的更多細節。

注意:升級到Android 5.0,然後進行加密的設備可以通過恢復出廠設置返回到未加密狀態。首次啟動時加密的新 Android 5.0 設備無法恢復為未加密狀態。

Android 全盤加密的工作原理

的Android全盤加密是基於dm-crypt ,這是一個內核的功能,在塊設備層的作品。正因為如此,加密作品與嵌入式多媒體卡(eMMC的)和類似的閃存設備呈遞自身內核為塊設備。 YAFFS 無法加密,它直接與原始 NAND 閃存芯片對話。

加密算法是具有密碼塊鏈接 (CBC) 和 ESSIV:SHA256 的 128 高級加密標準 (AES)。主密鑰通過調用 OpenSSL 庫使用 128 位 AES 加密。您必須為密鑰使用 128 位或更多位(256 位是可選的)。

注:原始設備製造商可以使用128位或更高加密的主密鑰。

在 Android 5.0 版本中,有四種加密狀態:

  • 默認
  • 別針
  • 密碼
  • 圖案

首次啟動時,設備會創建一個隨機生成的 128 位主密鑰,然後使用默認密碼和存儲的鹽對其進行散列。默認密碼是:“default_password” 但是,生成的散列也是通過 TEE(例如 TrustZone)簽名的,它使用簽名的散列來加密主密鑰。

你可以找到在Android開源項目中定義的默認密碼cryptfs.cpp文件。

當用戶在設備上設置 PIN/pass 或密碼時,只會重新加密和存儲 128 位密鑰。 (即用戶的PIN /通/模式的變化不會導致用戶數據的再加密。)請注意,被管理的設備可能受到PIN,圖案或密碼限制。

加密是通過管理initvoldinit調用vold和vold的套房產為在初始觸發事件。系統的其他部分也會查看屬性以執行諸如報告狀態、要求輸入密碼或在發生致命錯誤時提示恢復出廠設置等任務。要調用在加密功能vold ,系統使用命令行工具vdccryptfs命令: checkpwrestartenablecryptochangepwcryptocompleteverifypwsetfieldgetfieldmountdefaultencryptedgetpwtypegetpw ,和clearpw

為了加密,解密或擦拭/data/data不能安裝。然而,為了顯示的任何用戶界面(UI),該框架必須開始和該框架需要/data來運行。要解決這個難題,一個臨時文件系統安裝在/data 。這允許 Android 根據需要提示輸入密碼、顯示進度或建議數據擦除。它強加的限制,為了從臨時文件系統真正的開關/data文件系統,系統必須停止對臨時文件系統與打開的文件的每個進程,並重新啟動對現實的過程/data文件系統。要做到這一點,所有的服務必須在三組之一: coremainlate_start

  • core :切勿啟動後關閉。
  • main :在輸入硬盤密碼後關機,然後重新啟動。
  • late_start :不會開始後/data已經被解密和安裝。

要觸發這些動作時, vold.decrypt屬性設置為不同的字符串。殺死並重新啟動服務時, init命令是:

  • class_reset :停止服務,但允許其與class_start重新啟動。
  • class_start :重新啟動服務。
  • class_stop :停止服務,並增加了SVC_DISABLED標誌。停止的服務不回應class_start

流量

加密設備有四個流。設備僅加密一次,然後遵循正常的啟動流程。

  • 加密以前未加密的設備:
    • 加密與一個新的設備forceencrypt :強制性加密在第一次啟動(Android中L在開始)。
    • 加密現有設備:用戶啟動的加密(Android K 及更早版本)。
  • 啟動加密設備:
    • 啟動沒有密碼的加密設備:啟動沒有設置密碼的加密設備(與運行 Android 5.0 及更高版本的設備相關)。
    • 使用密碼啟動加密設備:啟動具有設置密碼的加密設備。

除了這些流動,該裝置也可以不加密/data 。下面詳細解釋每個流程。

使用 forceencrypt 加密新設備

這是 Android 5.0 設備的正常首次啟動。

  1. 檢測與未加密的文件系統forceencrypt標誌

    /data是不加密的,但需要是因為forceencrypt任務它。卸載/data

  2. 開始加密/data

    vold.decrypt = "trigger_encryption"觸發器init.rc ,這將導致vold到加密/data沒有密碼。 (沒有設置,因為這應該是一個新設備。)

  3. 掛載 tmpfs

    vold安裝tmpfs的/data (使用TMPFS從選項ro.crypto.tmpfs_options )和集屬性vold.encrypt_progress為0 vold prepepares的TMPFS /data用於引導加密系統和集屬性vold.decrypt到: trigger_restart_min_framework

  4. 提出框架以顯示進展

    因為設備幾乎沒有要加密的數據,所以進度條實際上通常不會出現,因為加密發生得如此之快。見加密現有設備有關的進展UI的更多細節。

  5. /data被加密,取下來的框架

    voldvold.decrypttrigger_default_encryption這將啟動defaultcrypto服務。 (這將啟動以下用於安裝默認加密用戶數據的流程。) trigger_default_encryption檢查的加密類型,看看是否/data被使用或不使用密碼加密。因為 Android 5.0 設備在第一次啟動時是加密的,所以應該沒有設置密碼;因此,我們解密和安裝/data

  6. /data

    init然後安裝/data用參數從拾起上tmpfs的RAMDISK ro.crypto.tmpfs_options ,這是在設置init.rc

  7. 啟動框架

    設置voldtrigger_restart_framework ,繼續平時的開機過程。

加密現有設備

當您加密未加密的 Android K 或更早版本的已遷移到 L 的設備時會發生這種情況。

此過程由用戶啟動,在代碼中稱為“就地加密”。當用戶選擇對設備進行加密時,UI 會確保電池已充滿電且交流適配器已插入,以便有足夠的電量來完成加密過程。

警告:如果設備運行功率,並關閉它已完成加密前的了,文件數據保留在部分加密的狀態。設備必須恢復出廠設置,所有數據都將丟失。

為了實現就地加密, vold開始循環讀取實際塊設備的每個扇區,然後將其寫入加密塊設備。 vold檢查,看是否有部門在使用閱讀和寫作之前,這使得加密快得多有很少或幾乎沒有數據的新設備上。

設備的國家:設置ro.crypto.state = "unencrypted" ,並執行on nonencrypted init觸發繼續引導。

  1. 檢查密碼

    該UI調用vold用命令cryptfs enablecrypto inplace其中passwd是用戶的鎖屏密碼。

  2. 取下框架

    vold檢查錯誤,返回-1,如果它不能加密,並打印記錄的原因。如果它可以加密,它設置屬性vold.decrypttrigger_shutdown_framework 。這將導致init.rc停在服務類late_startmain

  3. 創建加密頁腳
  4. 創建麵包屑文件
  5. 重啟
  6. 檢測麵包屑文件
  7. 開始加密/data

    vold然後建立的加密映射,它創建了一個虛擬的密碼塊裝置,其映射到實際塊裝置,但是加密,因為它被寫入每個扇區,並且當它被讀取解密每個扇區。 vold然後創建並寫入了加密的元數據。

  8. 在加密時,掛載 tmpfs

    vold安裝tmpfs的/data (使用TMPFS從選項ro.crypto.tmpfs_options )和集屬性vold.encrypt_progress為0 vold準備TMPFS /data用於引導加密系統,並設置屬性vold.decrypt到: trigger_restart_min_framework

  9. 提出框架以顯示進展

    trigger_restart_min_framework導致init.rc啟動main類的服務。當看到框架是vold.encrypt_progress設置為0,它帶來了進度條界面,用於查詢該屬性每五秒鐘,並更新進度條。加密循環更新vold.encrypt_progress每次加密分區的另一個%的時間。

  10. /data被加密,更新加密頁腳

    /data被成功加密, vold清除該標誌ENCRYPTION_IN_PROGRESS在元數據中。

    當設備成功解鎖後,密碼將用於加密主密鑰並更新加密頁腳。

    如果重新啟動由於某種原因失敗, vold設置屬性vold.encrypt_progresserror_reboot_failed和UI應該顯示一條消息,要求用戶按一個按鈕來重新啟動。這預計永遠不會發生。

使用默認加密啟動加密設備

當您啟動沒有密碼的加密設備時會發生這種情況。由於Android 5.0設備在第一次啟動加密,應該不存在設置的密碼,因此,這是默認加密狀態。

  1. 檢測加密/data沒有密碼

    檢測到的Android裝置加密,因為/data不能被安裝和標誌中的一個encryptableforceencrypt被設置。

    voldvold.decrypttrigger_default_encryption ,這將啟動defaultcrypto服務。 trigger_default_encryption檢查加密類型,看看是否/data被使用或不使用密碼加密。

  2. 解密/數據

    創建dm-crypt在塊設備裝置,使該裝置準備好使用。

  3. 掛載/數據

    vold並裝入解密真實/data分區,然後準備新的分區。它設置屬性vold.post_fs_data_done為0,然後設置vold.decrypttrigger_post_fs_data 。這將導致init.rc運行它post-fs-data的命令。他們將創建任何必需的目錄或鏈接,然後設置vold.post_fs_data_done為1。

    一旦vold該財產看到1,它設置屬性vold.decrypt到: trigger_restart_framework.這將導致init.rc啟動類服務main一次也是在類開始服務late_start為開機以來的第一次。

  4. 啟動框架

    現在的框架靴使用解密的所有服務/data ,系統就可以使用了。

啟動沒有默認加密的加密設備

當您啟動具有設置密碼的加密設備時,就會發生這種情況。設備的密碼可以是 pin、圖案或密碼。

  1. 使用密碼檢測加密設備

    檢測,由於該標誌的Android設備被加密ro.crypto.state = "encrypted"

    voldvold.decrypttrigger_restart_min_framework因為/data進行加密的口令。

  2. 掛載 tmpfs

    init套五個屬性保存在給定的初始安裝選項/data與從傳遞的參數init.rcvold使用這些屬性來設置加密映射:

    1. ro.crypto.fs_type
    2. ro.crypto.fs_real_blkdev
    3. ro.crypto.fs_mnt_point
    4. ro.crypto.fs_options
    5. ro.crypto.fs_flags (以0x開頭ASCII 8位十六進制數)
  3. 啟動框架以提示輸入密碼

    該框架啟動並看到vold.decrypt設置為trigger_restart_min_framework 。這告訴它tmpfs的上引導框架/data磁盤,它需要獲得用戶的密碼。

    但是,首先需要確保磁盤已正確加密。它發出的命令cryptfs cryptocompletevoldvold返回0,如果加密已成功完成,-1內部錯誤,或如果-2加密沒有成功完成。 vold通過查看用於對加密的元數據確定此CRYPTO_ENCRYPTION_IN_PROGRESS標誌。如果已設置,則加密過程已中斷,並且設備上沒有可用數據。如果vold返回一個錯誤,用戶界面顯示一個消息給用戶,以重新啟動和工廠重置設備,並且給用戶一個按鈕以按這樣做。

  4. 用密碼解密數據

    一旦cryptfs cryptocomplete是成功的,該框架顯示UI要求磁盤密碼。所述UI檢查通過發送該命令的密碼cryptfs checkpwvold 。如果密碼是正確的(這是由解密成功安裝確定/data在一個臨時位置,然後將其卸載), vold保存在屬性解密的塊設備的名稱ro.crypto.fs_crypto_blkdev並返回狀態0到UI .如果密碼不正確,它會向 UI 返回 -1。

  5. 停止框架

    該UI搭設密碼啟動的圖形,然後調用vold用命令cryptfs restartvold設置屬性vold.decrypttrigger_reset_main ,這將導致init.rcclass_reset main 。這將停止所有服務的主類,它允許的tmpfs /data被卸載。

  6. /data

    vold並裝入解密真實/data分區,並準備新的分區(其可以,如果它是與該擦拭選項,它不支持第一加密釋放永遠不會被製備)。它設置屬性vold.post_fs_data_done為0,然後設置vold.decrypttrigger_post_fs_data 。這將導致init.rc運行它post-fs-data的命令。他們將創建任何必需的目錄或鏈接,然後設置vold.post_fs_data_done至1。一旦vold該財產看到1,它設置屬性vold.decrypttrigger_restart_framework 。這將導致init.rc啟動類服務main一次也是在類開始服務late_start為開機以來的第一次。

  7. 啟動完整框架

    現在的框架靴使用解密的所有服務/data文件系統,該系統就可以使用了。

失敗

由於一些原因,無法解密的設備可能出錯。設備以一系列正常的啟動步驟啟動:

  1. 使用密碼檢測加密設備
  2. 掛載 tmpfs
  3. 啟動框架以提示輸入密碼

但是框架打開後,設備可能會遇到一些錯誤:

  • 密碼匹配但無法解密數據
  • 用戶輸入錯誤密碼 30 次

如果這些錯誤不解決,提示用戶工廠擦拭

如果vold在加密過程中檢測到錯誤,如果沒有數據是否已經被破壞,這個框架後, vold設置屬性vold.encrypt_progresserror_not_encrypted 。 UI 會提示用戶重新啟動並提醒他們加密過程從未開始。如果後框架已經拆除,但在此之前的進度條UI是向上,出現錯誤vold將重新啟動系統。如果重新啟動失敗,它設置vold.encrypt_progresserror_shutting_down並返回-1;但不會有任何東西可以捕獲錯誤。這不會發生。

如果vold在加密過程中檢測到一個錯誤時,它設置vold.encrypt_progresserror_partially_encrypted並返回-1。然後 UI 應顯示一條消息,指出加密失敗,並提供一個按鈕供用戶將設備恢復出廠設置。

存儲加密密鑰

加密的密鑰存儲在加密元數據中。硬件支持是通過使用可信執行環境 (TEE) 簽名功能實現的。以前,我們使用通過將 scrypt 應用於用戶密碼和存儲的鹽生成的密鑰來加密主密鑰。為了使密鑰能夠抵禦開箱攻擊,我們通過使用存儲的 TEE 密鑰對結果密鑰進行簽名來擴展此算法。然後再通過一次 scrypt 應用將得到的簽名轉換為適當長度的密鑰。然後使用此密鑰來加密和解密主密鑰。要存儲此密鑰:

  1. 生成隨機的 16 字節磁盤加密密鑰 (DEK) 和 16 字節鹽。
  2. 將 scrypt 應用於用戶密碼和鹽以生成 32 字節的中間密鑰 1 (IK1)。
  3. 用零字節填充 IK1 到硬件綁定私鑰 (HBK) 的大小。具體來說,我們填充為:00 || IK1 || 00..00;一個零字節,32 個 IK1 字節,223 個零字節。
  4. 使用 HBK 符號填充 IK1 以生成 256 字節的 IK2。
  5. 將 scrypt 應用於 IK2 和鹽(與步驟 2 相同的鹽)以生成 32 字節的 IK3。
  6. 將 IK3 的前 16 個字節用作 KEK,將後 16 個字節用作 IV。
  7. 使用 AES_CBC、密鑰 KEK 和初始化向量 IV 加密 DEK。

更改密碼

當用戶選擇改變或設置中刪除他們的密碼時,UI將命令發送cryptfs changepwvold ,和vold重新加密用新密碼磁盤主密鑰。

加密屬性

voldinit通過設置屬性彼此通信。以下是加密的可用屬性列表。

伏地屬性

財產描述
vold.decrypt trigger_encryption無需密碼即可加密驅動器。
vold.decrypt trigger_default_encryption檢查驅動器以查看它是否在沒有密碼的情況下加密。如果是,解密和安裝它,否則設置vold.decrypt到trigger_restart_min_framework。
vold.decrypt trigger_reset_main由 vold 設置以關閉要求磁盤密碼的 UI。
vold.decrypt trigger_post_fs_data通過設置到vold的準備/data有必要的目錄等。
vold.decrypt trigger_restart_framework通過vold設置啟動真正的框架和所有服務。
vold.decrypt trigger_shutdown_framework由vold 設置以關閉完整框架以開始加密。
vold.decrypt trigger_restart_min_framework通過vold的根據的值設置為啟動加密進度條UI或提示輸入密碼, ro.crypto.state
vold.encrypt_progress框架啟動時,如果設置了該屬性,則進入進度條UI模式。
vold.encrypt_progress 0 to 100進度條 UI 應顯示設置的百分比值。
vold.encrypt_progress error_partially_encrypted進度條 UI 應顯示加密失敗的消息,並為用戶提供恢復出廠設置的選項。
vold.encrypt_progress error_reboot_failed進度條 UI 應顯示一條消息,說明加密已完成,並為用戶提供一個重啟設備的按鈕。預計不會發生此錯誤。
vold.encrypt_progress error_not_encrypted進度條 UI 應該顯示一條消息,指出發生了錯誤,沒有數據被加密或丟失,並為用戶提供一個重啟系統的按鈕。
vold.encrypt_progress error_shutting_down進度條 UI 未運行,因此不清楚誰將響應此錯誤。而且無論如何都不應該發生。
vold.post_fs_data_done 0通過設置vold只是設置之前vold.decrypttrigger_post_fs_data
vold.post_fs_data_done 1設置由init.rcinit.rc剛剛完成任務後post-fs-data

初始化屬性

財產描述
ro.crypto.fs_crypto_blkdev通過設置vold命令checkpw由以後使用vold命令restart
ro.crypto.state unencrypted通過設置init說這個系統是未加密的運行/data ro.crypto.state encrypted 。通過設置init說這個系統與加密運行/data

ro.crypto.fs_type
ro.crypto.fs_real_blkdev
ro.crypto.fs_mnt_point
ro.crypto.fs_options
ro.crypto.fs_flags

這五個性質通過設置init時它會嘗試掛載/data與來自傳遞的參數init.rcvold使用這些來設置加密映射。
ro.crypto.tmpfs_options設置由init.rc與安裝tmpfs的初始化時,應使用的選項/data文件系統。

初始化動作

on post-fs-data
on nonencrypted
on property:vold.decrypt=trigger_reset_main
on property:vold.decrypt=trigger_post_fs_data
on property:vold.decrypt=trigger_restart_min_framework
on property:vold.decrypt=trigger_restart_framework
on property:vold.decrypt=trigger_shutdown_framework
on property:vold.decrypt=trigger_encryption
on property:vold.decrypt=trigger_default_encryption