全磁碟加密是使用 加密金鑰裝置加密後,所有使用者建立的資料都會在寫入磁碟前自動加密,所有讀取作業都會在將資料傳回呼叫程序前自動解密資料。
Android 是在 4.4 版中加入全磁碟加密功能,Android 5.0 才推出這項功能 這些新功能:
- 建立快速加密,只對已使用的資料分區加密的區塊加密 可避免初次啟動花費太多時間目前只有 ext4 和 f2fs 檔案系統支援快速加密功能。
- 已新增
forceencrypt
fstab 旗標,藉此在首次啟動時加密。 - 新增對不含密碼的圖案和加密功能支援。
- 新增採用「可信任」機制的加密金鑰儲存空間硬體支援儲存空間 執行環境 (TEE) 簽署能力 (例如 TrustZone 中)。 詳情請參閱「儲存加密金鑰」。
注意:先升級至 Android 5.0 的裝置 恢復原廠設定後,任何加密狀態都會還原為未加密狀態。在首次啟動時加密的新版 Android 5.0 裝置無法還原為未加密的狀態。
Android 全磁碟加密功能的運作方式
Android 全磁碟加密是以 dm-crypt
為基礎,這是核心
可以在封鎖裝置層運作因此,加密功能可與 Embedded MultiMediaCard (eMMC) 和類似的快閃記憶體裝置搭配使用,這些裝置會將自己呈現給核心,做為區塊裝置。YAFFS 無法直接加密原始模型,
NAND 快閃晶片。
加密演算法採用 128 Advanced Encryption Standard (AES), 加密區塊鏈結 (CBC) 和 ESSIV:SHA256。主金鑰會透過呼叫 OpenSSL 程式庫,以 128 位元 AES 加密。金鑰長度必須為 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
中叫用加密功能,系統會使用指令列工具 vdc
的 cryptfs
指令:checkpw
、restart
、enablecrypto
、changepw
、cryptocomplete
、verifypw
、setfield
、getfield
、mountdefaultencrypted
、getpwtype
、getpw
和 clearpw
。
如要加密、解密或抹除/data
的資料,請/data
。不過,為了顯示任何使用者介面 (UI),架構必須啟動,而架構需要 /data
才能執行。為解決這個難題,我們在 /data
上掛載暫時性檔案系統。這可讓 Android 提示輸入密碼、顯示進度或建議資料
視需要抹除資料。區分從
暫存為真正的 /data
檔案系統,此時系統必須
停止每個暫存檔案系統中開放檔案的程序,然後重新啟動
實際 /data
檔案系統的處理程序所有服務都會這麼做
必須屬於以下三個群組之一:core
、main
和
late_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 裝置的正常首次啟動程序。
- 使用
forceencrypt
標記偵測未加密的檔案系統/data
未加密,但必須加密,因為forceencrypt
有此規定。卸載/data
。 - 開始加密
/data
vold.decrypt = "trigger_encryption"
觸發了init.rc
, 這會導致vold
在不使用密碼的情況下為/data
加密。 (由於這是新裝置,因此未設定任何值)。 - 掛接 tmpfs
vold
會掛接 tmpfs/data
(使用ro.crypto.tmpfs_options
),並將vold.encrypt_progress
屬性設為 0。vold
準備 tmpfs/data
來啟動加密系統,並設定 資源「vold.decrypt
」改為:trigger_restart_min_framework
- 建立架構以顯示進度
由於裝置幾乎沒有可加密的資料,因此進度列不會 經常出現是因為加密非常快速。如要進一步瞭解進度 UI,請參閱「加密現有裝置」。
- 在
/data
加密之後,移除架構vold
將vold.decrypt
設為trigger_default_encryption
,啟動defaultcrypto
服務。(系統會開始下列流程來掛接 預設加密使用者資料)。trigger_default_encryption
會檢查 加密類型,檢查/data
是否使用 密碼。由於 Android 5.0 裝置會在首次開機時進行加密,因此不應設定密碼;因此我們會解密並掛載/data
。 - 掛接
/data
init
接著使用以下程式碼,在 tmpfs RAMDisk 上掛接/data
: 系統從ro.crypto.tmpfs_options
擷取的參數 位置:init.rc
。 - 啟動架構
vold
會將vold.decrypt
設為trigger_restart_framework
,繼續執行一般啟動程序。
加密現有裝置
將未加密的 Android K 以下版本加密,會有什麼影響? 已轉移到 L 的裝置。
這項程序是由使用者所啟動,在 程式碼使用者選擇加密裝置時,UI 會確保 電池已充飽電,且 AC 變壓器已接上電源,確保有足夠的電力 才能完成加密程序。
警告:裝置沒電,並在結束前關機 加密時,檔案資料會處於部分加密狀態。裝置必須恢復原廠設定,且所有資料都會遺失。
如要啟用內置加密,vold
會啟動迴圈讀取每個機制
然後將解碼器寫入
傳送至加密區塊裝置vold
會在讀取和寫入資料之前檢查區段是否已在使用,因此在資料量很少或沒有資料的新裝置上,加密作業的速度會大幅提升。
裝置狀態:設定 ro.crypto.state = "unencrypted"
並執行 on nonencrypted
init
觸發事件,以便繼續啟動。
- 檢查密碼
UI 會使用
cryptfs enablecrypto inplace
指令呼叫vold
其中passwd
是使用者的螢幕鎖定密碼。 - 移除架構
vold
會檢查錯誤,如果無法加密,則會傳回 -1;以及 在記錄中顯示原因。如果可以加密,則會將屬性vold.decrypt
設為trigger_shutdown_framework
。這會導致init.rc
停止在late_start
和main
類別中提供服務。 - 建立加密頁尾
- 建立麵包屑檔案
- 重新啟動
- 偵測導覽標記檔案
- 開始加密
/data
vold
會設定加密編譯對應關係,以便建立虛擬加密區塊裝置 會對應至真實區塊裝置,但會在寫入每個部門時加密, 讀取及解密每個向量。vold
接著會建立並寫入 加密編譯中繼資料 - 在加密期間掛接 tmpfs
vold
會掛載 tmpfs/data
(使用ro.crypto.tmpfs_options
的 tmpfs 選項),並將屬性vold.encrypt_progress
設為 0。vold
會為啟動加密系統準備 tmpfs/data
,並將屬性vold.decrypt
設為:trigger_restart_min_framework
- 建立架構以顯示進度
trigger_restart_min_framework
會導致init.rc
啟動main
類別的服務。架構發現 如果將vold.encrypt_progress
設為 0,系統就會顯示進度列 UI,會每隔五秒就查詢該屬性,並更新進度列。 每次加密分區的百分比時,加密迴圈都會更新vold.encrypt_progress
。 - 將
/data
加密後,請更新加密頁尾/data
成功加密後,vold
就會清除 在中繼資料中加入旗標ENCRYPTION_IN_PROGRESS
。裝置成功解鎖後,系統就會使用密碼加密主金鑰,並更新加密附註。
如果因故重新啟動失敗,
vold
會設定屬性vold.encrypt_progress
到error_reboot_failed
和 UI 應顯示訊息,要求使用者按下按鈕 。這應該不會發生。
啟動使用預設加密機制的加密裝置
如果在沒有密碼的情況下啟動加密裝置,就會發生這種情形。 由於 Android 5.0 裝置會在首次啟動時進行加密,因此不應設定密碼,因此這是預設加密狀態。
- 偵測無密碼的已加密
/data
偵測 Android 裝置已加密,因為無法掛載
/data
,且已設定其中一個標記encryptable
或forceencrypt
。vold
將vold.decrypt
設為trigger_default_encryption
,從 「defaultcrypto
」服務。trigger_default_encryption
檢查加密類型,確認/data
是否已為 不需要密碼 - 解密 /data
在區塊裝置上建立
dm-crypt
裝置,讓裝置可供使用。 - 掛接 /資料
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
類別中的服務。 - 開始使用架構
現在架構會使用解密的
/data
啟動所有服務。 且系統也準備就緒可供使用
啟動未採用預設加密機制的加密裝置
這是在啟動已設定密碼的加密裝置時會發生的情況。裝置的密碼可以是 PIN 碼、解鎖圖案或密碼。
- 偵測使用密碼加密的裝置
偵測 Android 裝置是否已加密,因為標記為
ro.crypto.state = "encrypted"
vold
會將vold.decrypt
設為trigger_restart_min_framework
,因為/data
是使用密碼加密的。 - 掛接 tmpfs
init
會設定五個屬性,用來儲存/data
的初始掛載選項,並透過init.rc
傳遞參數。vold
會利用下列屬性設定加密編譯對應:ro.crypto.fs_type
ro.crypto.fs_real_blkdev
ro.crypto.fs_mnt_point
ro.crypto.fs_options
ro.crypto.fs_flags
(ASCII 8 位元十六進位數字,開頭為 0x)
- 啟動架構,提示輸入密碼
架構會啟動,並發現
vold.decrypt
已設為trigger_restart_min_framework
。讓架構機構知道 在 tmpfs/data
磁碟上開機,該磁碟需要取得使用者密碼。不過,首先必須確認磁碟已妥善加密。這項服務 傳送
cryptfs cryptocomplete
指令至vold
。 如果加密順利完成,vold
會傳回 0;發生內部錯誤時會傳回 -1;或 -2 表示加密未順利完成。vold
:決定 藉由查看CRYPTO_ENCRYPTION_IN_PROGRESS
的加密中繼資料 旗標。如果設定這項政策,加密程序就會中斷,而且未發生 裝置可用的資料如果vold
傳回錯誤,使用者介面應向使用者顯示訊息,要求他們重新啟動裝置並將裝置恢復原廠設定,並提供按鈕供使用者按下執行。 - 使用密碼解密資料
cryptfs cryptocomplete
成功後,架構 會顯示一個 UI,要求提供磁碟密碼。UI 會藉由 傳送cryptfs checkpw
指令至vold
。如果密碼正確 (系統會在暫時位置成功掛載解密的/data
,然後卸載),vold
會在屬性ro.crypto.fs_crypto_blkdev
中儲存解密的區塊裝置名稱,並將狀態 0 傳回至 UI。如果密碼不正確,則會將 -1 傳回至 UI。 - 停止架構
UI 會顯示加密啟動圖形,然後使用
cryptfs restart
指令呼叫vold
。vold
會設定屬性vold.decrypt
到trigger_reset_main
,這會導致 需init.rc
執行class_reset main
。這會停止所有服務 位於主要類別中,這可讓系統卸載 tmpfs/data
。 - Mount
/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
類別中的服務。 - 開始使用完整架構
框架現在會使用已解密的
/data
檔案系統啟動所有服務,系統也已準備就緒。
失敗
無法解密的裝置可能會因某些原因而產生故障。裝置 請從一般的啟動步驟開始:
- 使用密碼偵測已加密的裝置
- 掛接 tmpfs
- 啟動架構,提示輸入密碼
但在架構開啟後,裝置可能會發生一些錯誤:
- 密碼相符,但無法解密資料
- 使用者輸入錯誤密碼 30 次
如果這些錯誤無法解決,請提示使用者恢復原廠設定:
如果 vold
在加密程序期間偵測到錯誤,且尚未銷毀任何資料且架構已啟用,vold
會將屬性 vold.encrypt_progress
設為 error_not_encrypted
。UI 提示使用者重新啟動,並提醒使用者加密程序
並未開始如果錯誤發生在架構解除安裝後,但進度列 UI 顯示前,vold
會重新啟動系統。如果重新啟動失敗,系統會將 vold.encrypt_progress
設為 error_shutting_down
並傳回 -1;但不會有任何東西擷取錯誤。這不是預期的情況。
如果 vold
在加密程序中偵測到錯誤,就會將 vold.encrypt_progress
設為 error_partially_encrypted
並傳回 -1。接著,使用者介面應會顯示加密失敗的訊息,並提供按鈕,讓使用者將裝置恢復原廠設定。
儲存加密金鑰
加密金鑰會儲存在加密中繼資料中。硬體支援功能是透過使用受信任的執行環境 (TEE) 簽署功能實作。先前,我們會使用由 scrypt 套用至使用者密碼和儲存的鹽值所產生的金鑰,加密主金鑰。為了讓金鑰能抵禦外部攻擊,我們會使用儲存的 TEE 金鑰為產生的金鑰簽署,以擴充這項演算法。然後,產生的簽章會轉換成適當的 再套用一次 scrypt這組金鑰接著會用於加密 並解密主金鑰。如何儲存此鍵:
- 隨機產生 16 位元組磁碟加密金鑰 (DEK) 和 16 位元組的鹽。
- 為使用者密碼和鹽,產生 32 位元組的中繼資訊 鍵 1 (IK1)。
- 為硬體繫結私密金鑰 (HBK) 大小提供零位元組的 Pad IK1。 具體來說,我們會以以下方式填充:00 || IK1 || 00..00;一個零位元組、32 個 IK1 位元組、223 個零位元組。
- 使用 HBK 簽署已填充的 IK1,以產生 256 位元組的 IK2。
- 將 scrypt 套用至 IK2 和鹽 (與步驟 2 相同的鹽),產生 32 位元組的 IK3。
- 請使用 IK3 的前 16 位元組做為 KEK,並將最後 16 位元組做為 IV。
- 使用 AES_CBC 加密 DEK,並使用金鑰 KEK 和初始化向量 IV 加密。
變更密碼
使用者在設定中選擇變更或移除密碼時,使用者介面會傳送
將 cryptfs changepw
指令傳送至 vold
,以及
vold
會使用新的密碼重新加密磁碟主金鑰。
加密屬性
vold
和 init
會透過設定屬性來相互通訊。以下列出可用於加密的屬性清單。
Vold 屬性
資源 | 說明 |
---|---|
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.decrypt trigger_shutdown_framework |
由 vold 設定,用於關閉整個架構以啟動加密作業。 |
vold.decrypt trigger_restart_min_framework |
由 vold 設定,視 ro.crypto.state 的值而定,可啟動加密進度列 UI 或密碼提示。 |
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.decrypt 設為 trigger_post_fs_data 之前,由 vold 設定。 |
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 執行。 |
|
當 init 嘗試以 init.rc 傳入的參數掛載 /data 時,會設定這五個屬性。vold 會使用這些值來設定加密對應項目。 |
ro.crypto.tmpfs_options |
init.rc 會在掛接 tmpfs /data 檔案系統時,使用 init.rc 設定的選項。 |
init 動作
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