全磁碟加密

全磁碟加密是使用 加密金鑰裝置經過加密後,所有使用者建立的資料都會受到 自動加密後再將檔案提交至磁碟和所有讀取作業 就會自動解密資料,再將資料傳回呼叫程序。

Android 是在 4.4 版中加入全磁碟加密功能,Android 5.0 才推出這項功能 這些新功能:

  • 建立快速加密,只對已使用的資料分區加密的區塊加密 可避免初次啟動花費太多時間僅限 ext4 和 f2fs 檔案系統 請注意,目前也支援快速加密
  • 已新增 forceencrypt fstab 旗標,藉此在首次啟動時加密。
  • 開始支援無密碼的模式和加密功能。
  • 新增採用「可信任」機制的加密金鑰儲存空間硬體支援儲存空間 執行環境 (TEE) 簽署能力 (例如 TrustZone 中)。 詳情請參閱儲存加密金鑰 詳細資料。

注意:先升級至 Android 5.0 的裝置 恢復原廠設定後,任何加密狀態可能會還原為未加密狀態。全新 Android 5.0 無法在首次啟動時加密的裝置回到未加密狀態。

Android 全磁碟加密功能的運作方式

Android 全磁碟加密是以 dm-crypt 為基礎,這是核心 可以在封鎖裝置層運作因為 加密技術適用於內嵌式 MultiMediaCard (eMMC) 和 自行在核心中顯示為區塊的類似 Flash 裝置 裝置。YAFFS 無法直接加密原始模型, NAND 快閃晶片。

加密演算法採用 128 Advanced Encryption Standard (AES), 加密區塊鏈結 (CBC) 和 ESSIV:SHA256。主要金鑰是以 128 位元 AES,透過呼叫 OpenSSL 程式庫。您必須使用 128 位元以上的 鍵 (256 為選用)。

注意:原始設備製造商 (OEM) 可使用 128 位元以上將主金鑰加密。

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

  • 預設
  • PIN 碼
  • 密碼
  • 圖案

初次啟動時,裝置會建立隨機產生的 128 位元主金鑰 然後使用預設密碼和儲存的鹽字串進行雜湊處理。預設密碼為:「default_password」 不過,結果雜湊會透過 TEE (例如 TrustZone) 簽署。 使用簽章的雜湊值加密主金鑰。

您可以在 Android 開放原始碼計畫 cryptfs.cpp 中找到定義的預設密碼 檔案。

使用者在裝置上設定 PIN 碼/密碼或密碼時,只能輸入 128 位元金鑰 會重新加密並儲存(也就是說,使用者 PIN 碼/票證/圖案變更並「不會」造成原因) 重新加密使用者資料)。請注意, 受管理的裝置 可能受到 PIN 碼、解鎖圖案或密碼的限制。

加密功能是由「init」和「vold」管理。 init 呼叫 vold,而且 vold 集會觸發要觸發的屬性 初始化事件。系統的其他部分 也會檢視資源來執行報表狀態等工作 密碼。如果發生重大錯誤,手機會提示遭恢復原廠設定。叫用 加密功能,系統將會使用指令列工具 (vold) vdccryptfs 指令:checkpwrestartenablecryptochangepwcryptocompleteverifypwsetfieldgetfieldmountdefaultencryptedgetpwtypegetpwclearpw

如要加密、解密或抹除/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。 以下詳細說明每個流程。

使用強制加密功能加密新裝置

這是 Android 5.0 裝置的一般啟動程序。

  1. 使用 forceencrypt 旗標偵測未加密的檔案系統

    /data 未加密,但必須負起「forceencrypt」的規定。 卸載 /data

  2. 開始加密 /data

    vold.decrypt = "trigger_encryption" 觸發了 init.rc, 因此 vold 會在不使用密碼的情況下為 /data 加密。 (未設定,因為這應該是新裝置)。

  3. 掛接 tmpfs

    vold 會掛接 tmpfs /data (使用 ro.crypto.tmpfs_options),並將 vold.encrypt_progress 屬性設為 0。 vold 準備 tmpfs /data 來啟動加密系統,並設定 資源「vold.decrypt」改為:trigger_restart_min_framework

  4. 建立架構以顯示進度

    由於裝置幾乎沒有可加密的資料,因此進度列會顯示 但通常不會實際顯示,因為加密速度非常快。詳情請見 將現有裝置加密以瞭解詳情 進度 UI 的詳細資料

  5. /data 加密之後,移除架構

    voldvold.decrypt設為 trigger_default_encryption,這會啟動 「defaultcrypto」服務。(系統會開始下列流程來掛接 預設加密使用者資料)。trigger_default_encryption 會檢查 加密類型,檢查 /data 是否使用 密碼。由於 Android 5.0 裝置會在首次啟動時加密,因此應有 未設定密碼;因此我們會解密並掛接 /data

  6. 掛接 /data

    init 接著使用以下程式碼,在 tmpfs RAMDisk 上掛接 /data: 系統從 ro.crypto.tmpfs_options 擷取的參數 位置:init.rc

  7. 開始使用架構

    voldvold.decrypt設為 trigger_restart_framework,會繼續正常啟動 上傳資料集之後,您可以運用 AutoML 自動完成部分資料準備工作

加密現有裝置

將未加密的 Android K 以下版本加密,會有什麼影響? 已轉移到 L 的裝置。

這項程序是由使用者所啟動,在 程式碼使用者選擇加密裝置時,UI 會確保 電池已充飽電,且 AC 變壓器已接上電源,確保有足夠的電力 才能完成加密程序。

警告:裝置沒電,並在結束前關機 加密時,檔案資料會處於部分加密狀態。裝置必須 恢復原廠設定,所有資料都遺失。

如要啟用內置加密,vold 會啟動迴圈讀取每個機制 然後將解碼器寫入 傳送至加密區塊裝置vold 會檢查特定產業是否位於 讀取及寫入資料 在新裝置上加密的效率大幅提升。

裝置狀態:設定 ro.crypto.state = "unencrypted" 然後執行 on nonencrypted init 觸發條件來繼續啟動程序。

  1. 檢查密碼

    UI 會使用 cryptfs enablecrypto inplace 指令呼叫 vold 其中 passwd 是使用者的螢幕鎖定密碼。

  2. 移除架構

    vold 會檢查錯誤,如果無法加密,則會傳回 -1;以及 在記錄中顯示原因。如果可加密,則會設定 vold.decrypt 屬性。 至 trigger_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,系統就會顯示進度列 UI,會每隔五秒就查詢該屬性,並更新進度列。 加密迴圈每次都會更新 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.decrypt設為 trigger_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.decrypt設為 trigger_restart_min_framework,因為/data是 使用密碼加密

  2. 掛接 tmpfs

    init 會設定五項屬性儲存初始掛接選項 為 /data 提供,且其參數是從 init.rc 傳遞。 vold 會利用下列屬性設定加密編譯對應:

    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 (ASCII 8 位數十六進位數字,前面加上 0x)
  3. 開始架構以提示密碼

    架構會啟動,並發現 vold.decrypt 已設為 trigger_restart_min_framework。讓架構機構知道 在 tmpfs /data 磁碟上開機,該磁碟需要取得使用者密碼。

    不過,首先必須確認磁碟已妥善加密。這項服務 傳送 cryptfs cryptocomplete 指令至 vold。 如果加密順利完成,vold 會傳回 0;發生內部錯誤時會傳回 -1;或 -2 表示加密未順利完成。vold:決定 藉由查看 CRYPTO_ENCRYPTION_IN_PROGRESS 的加密中繼資料 旗標。如果設定這項政策,加密程序就會中斷,而且未發生 裝置可用的資料如果 vold 傳回錯誤,UI 應該 顯示訊息向使用者顯示重新啟動裝置、將裝置恢復原廠設定,然後 而使用者按下該按鈕進行這類操作

  4. 使用密碼解密資料

    cryptfs cryptocomplete 成功後,架構 會顯示一個 UI,要求提供磁碟密碼。UI 會藉由 傳送 cryptfs checkpw 指令至 vold。如果 密碼正確 (由成功掛接的 已在臨時位置解密 /data,然後將其卸載); vold 會將已解密的封鎖裝置名稱儲存在屬性中 ro.crypto.fs_crypto_blkdev 且將狀態 0 傳回 UI。如果 密碼不正確,UI 會傳回 -1。

  5. 停止架構

    UI 會顯示加密啟動圖形,然後利用以下內容呼叫 vold: 輸入 cryptfs restart 指令vold 會設定屬性 vold.decrypttrigger_reset_main,這會導致 需init.rc執行 class_reset main。這會停止所有服務 位於主要類別中,這可讓系統卸載 tmpfs /data

  6. 掛接 /data

    vold 接著會掛接解密的實際 /data 分區 並準備新的分區 (如果 已透過清除選項加密,但這個選項尚未支援 版本)。這會將屬性 vold.post_fs_data_done 設為 0,然後 將 vold.decrypt 設為 trigger_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 表示開機後第一次使用。

  7. 開始使用完整架構

    現在架構會使用解密的 /data 啟動所有服務 即可開始使用

失敗

無法解密的裝置可能會因某些原因而產生故障。裝置 請從一般的啟動步驟開始:

  1. 使用密碼偵測已加密的裝置
  2. 掛接 tmpfs
  3. 開始建立提示以輸入密碼

但架構開啟後,裝置可能會發生一些錯誤:

  • 密碼相符,但無法解密資料
  • 使用者輸入錯誤密碼 30 次

如果這些錯誤仍未解決,請提示使用者恢復原廠設定

如果 vold 在加密程序期間偵測到錯誤,且 尚未刪除任何資料,架構也已建立,共 vold 組 將屬性 vold.encrypt_progress 寫入 error_not_encrypted。 UI 提示使用者重新啟動,並提醒使用者加密程序 並未開始如果在架構破壞後發生錯誤,但 進度列 UI 開始前,vold 會重新啟動系統。如果 重新啟動失敗,這會將 vold.encrypt_progress 設為 error_shutting_down 並傳回 -1;但這不會 擷取錯誤。這並不預期發生。

如果 vold 在加密過程中偵測到錯誤,就會進行以下設定: vold.encrypt_progresserror_partially_encrypted 並傳回 -1。接著,UI 應會顯示一則訊息 ,並提供按鈕讓使用者將裝置恢復原廠設定。

儲存加密金鑰

加密金鑰會儲存在加密編譯中繼資料中。硬體備份是 透過使用受信任的執行環境 (TEE) 簽署功能實作。 我們先前是使用套用加密機制所產生的金鑰來加密主金鑰 密碼和資料儲存的鹽。為了確保金鑰的彈性 藉由簽署最終金鑰來擴充這個演算法 擷取 TEE 金鑰然後,產生的簽章會轉換成適當的 再套用一次 scrypt這組金鑰接著會用於加密 並解密主金鑰。如何儲存這組金鑰:

  1. 隨機產生 16 位元組磁碟加密金鑰 (DEK) 和 16 位元組的鹽。
  2. 為使用者密碼和鹽,產生 32 位元組的中繼資訊 鍵 1 (IK1)。
  3. 為硬體繫結私密金鑰 (HBK) 大小提供零位元組的 Pad IK1。 具體而言,我們會調成:00 ||IK1 ||00..00;一個零位元組、32 IK1 個位元組、223 零位元組
  4. 使用 HBK 簽署已填充的 IK1,以產生 256 位元組的 IK2。
  5. 套用 IK2 和鹽 (與步驟 2 相同的鹽) 以產生 32 位元組 IK3。
  6. 使用 IK3 的前 16 個位元組做為 KEK,最後一個 16 個位元組做為 IV。
  7. 使用 AES_CBC 加密 DEK,並使用金鑰 KEK 和初始化向量 IV 加密。

變更密碼

使用者在設定中選擇變更或移除密碼時,使用者介面會傳送 將 cryptfs changepw 指令傳送至 vold,以及 vold 會使用新的密碼重新加密磁碟主金鑰。

加密屬性

voldinit 透過以下方式相互通訊 設定屬性。下方是可用於加密的屬性清單。

固定屬性

資源 說明
vold.decrypt trigger_encryption 將磁碟加密,不使用 密碼。
vold.decrypt trigger_default_encryption 檢查雲端硬碟,確認檔案是否經過密碼加密。 如果是,請解密並掛接 否則請將 vold.decrypt 設為 trigger_restart_min_framework。
vold.decrypt trigger_reset_main 設為關閉要求提供磁碟密碼的 UI。
vold.decrypt trigger_post_fs_data 設定前提為 /data 準備必要的目錄等等。
vold.decrypt trigger_restart_framework 由 轉變為啟動實際架構和所有服務。
vold.decrypt trigger_shutdown_framework 設為關閉完整架構,啟動加密作業。
vold.decrypt trigger_restart_min_framework 設定到啟動 加密進度列 UI 提示輸入密碼 ro.crypto.state 的值。
vold.encrypt_progress 架構啟動後 如果已設定此屬性,請輸入 進度列 UI 模式
vold.encrypt_progress 0 to 100 進度列 UI 應該 就會顯示設定的百分比值
vold.encrypt_progress error_partially_encrypted 進度列使用者介面應會顯示加密失敗的訊息, 為使用者提供 將裝置恢復原廠設定。
vold.encrypt_progress error_reboot_failed 進度列 UI 應顯示加密訊息 完成後,請提供可重新啟動裝置的按鈕。這個錯誤 表示無需發生
vold.encrypt_progress error_not_encrypted 進度列 UI 應該 顯示錯誤訊息。 發生、未加密任何資料,或 ,並為使用者提供重新啟動系統的按鈕。
vold.encrypt_progress error_shutting_down 進度列使用者介面並未執行,因此無法確定回應者是誰 。而這個情況應該永遠不會發生。
vold.post_fs_data_done 0 請先由vold設定,再設定vold.decrypttrigger_post_fs_data
vold.post_fs_data_done 1 由「init.rc」設定或 init.rc 會在完成工作 post-fs-data 後立即生效。

init 屬性

資源 說明
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

這五項屬性 當伺服器嘗試透過傳入的參數掛接 /data 時,系統會傳回 init init.rcvold 會使用這些資訊設定加密對應。
ro.crypto.tmpfs_options init.rc 設定,並使用 init 在下列情況中應使用的選項 正在掛接 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