הצפנת מטא-נתונים

‫Android מגרסה 7.0 ואילך תומך בהצפנה מבוססת-קובץ (FBE). הצפנה כזו מאפשרת להצפין קבצים שונים באמצעות מפתחות שונים, כך שיהיה אפשר לבטל את הנעילה שלהם בנפרד. המפתחות האלה משמשים להצפנה של תוכן הקובץ וגם של שמות הקבצים. כשמשתמשים ב-FBE, מידע אחר, כמו פריסות של ספריות, גדלים של קבצים, הרשאות וזמני יצירה או שינוי, לא מוצפן. ביחד, המידע הנוסף הזה נקרא מטא-נתונים של מערכת הקבצים.

ב-Android 9 נוספה תמיכה בהצפנת מטא-נתונים. בהצפנת מטא-נתונים, מפתח יחיד שקיים בזמן האתחול מצפין את כל התוכן שלא מוצפן על ידי FBE. המפתח הזה מוגן על ידי KeyMint (לשעבר Keymaster), שמוגן על ידי Verified Boot.

הצפנת מטא-נתונים תמיד מופעלת באחסון שניתן להתאמה כשהצפנת FBE מופעלת. אפשר גם להפעיל הצפנת מטא-נתונים באחסון הפנימי. במכשירים שהושקו עם Android מגרסה 11 ואילך, צריך להפעיל הצפנת מטא-נתונים באחסון הפנימי.

הטמעה באחסון פנימי

כדי להגדיר הצפנת מטא-נתונים באחסון הפנימי של מכשירים חדשים, צריך להגדיר את מערכת הקבצים metadata, לשנות את רצף ההפעלה ולהפעיל את הצפנת המטא-נתונים בקובץ fstab של המכשיר.

דרישות מוקדמות

אפשר להגדיר הצפנת מטא-נתונים רק כשמפרמטים את מחיצת הנתונים בפעם הראשונה. לכן התכונה הזו מיועדת רק למכשירים חדשים, ולא מיועדת לשינוי באמצעות עדכון OTA.

כדי להצפין מטא-נתונים, צריך להפעיל את המודול dm-default-key בליבה. ב-Android מגרסה 11 ואילך,‏ dm-default-key נתמך בליבות הנפוצות של Android, מגרסה 4.14 ואילך. בגרסה הזו של dm-default-key נעשה שימוש במסגרת הצפנה שאינה תלויה בחומרה או בספק, שנקראת blk-crypto.

כדי להפעיל את dm-default-key, משתמשים בפקודה:

CONFIG_BLK_INLINE_ENCRYPTION=y
CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y
CONFIG_DM_DEFAULT_KEY=y

dm-default-key משתמש בחומרה להצפנה מוטמעת (חומרה שמצפינה או מפענחת את הנתונים בדרך אל מכשיר האחסון או ממנו) כשהיא זמינה. אם לא משתמשים בחומרה להצפנה מוטבעת, צריך גם להפעיל חזרה ל-API של ההצפנה של ליבת המערכת:

CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y

אם לא משתמשים בחומרה להצפנה מוטמעת, מומלץ להפעיל גם האצה מבוססת-CPU, כמו שמומלץ במסמכי התיעוד בנושא FBE.

ב-Android בגרסה 10 ומטה, לא הייתה תמיכה ב-dm-default-key בליבת Android הנפוצה. לכן, היה על הספקים להטמיע את dm-default-key.

הגדרת מערכת קבצים של מטא-נתונים

מכיוון שאי אפשר לקרוא שום דבר במחיצת נתוני המשתמשים עד שמפתח ההצפנה של המטא-נתונים קיים, בטבלת המחיצות צריך להקצות מחיצה נפרדת שנקראת מחיצת המטא-נתונים לאחסון של ה-blob של KeyMint שמגן על המפתח הזה. מחיצת המטא-נתונים צריכה להיות בגודל 16MB.

fstab.hardware חייב לכלול רשומה של מערכת קבצים של מטא-נתונים שנמצאת במחיצה הזו, ולבצע אתחול שלה ב-/metadata, כולל הדגל formattable כדי לוודא שהיא מעוצבת בזמן האתחול. מערכת הקבצים f2fs לא פועלת במחיצות קטנות יותר, ולכן מומלץ להשתמש במערכת ext4 במקום זאת. לדוגמה:

/dev/block/bootdevice/by-name/metadata              /metadata          ext4        noatime,nosuid,nodev,discard                          wait,check,formattable

כדי לוודא שנקודת הצירוף /metadata קיימת, מוסיפים את השורה הבאה ל-BoardConfig-common.mk:

BOARD_USES_METADATA_PARTITION := true

שינויים ברצף ההפעלה

כשמשתמשים בהצפנת מטא-נתונים, צריך להפעיל את vold לפני שמפעילים את /data. כדי לוודא שההפעלה תתבצע מספיק זמן מראש, מוסיפים את הפסקה הבאה ל-init.hardware.rc:

# We need vold early for metadata encryption
on early-fs
    start vold

המערכת צריכה להפעיל את KeyMint ולהכין אותה לפני שהיא מנסה להפעיל את /data.

init.hardware.rc צריך כבר להכיל הוראה mount_all שמפעילה את /data עצמו בקטע on late-fs. לפני השורה הזו, מוסיפים את ההוראה להפעיל את השירות wait_for_keymaster:

on late-fs
    
    # Wait for Keymaster
    exec_start wait_for_keymaster

    # Mount RW partitions which need run fsck
    mount_all /vendor/etc/fstab.${ro.boot.hardware.platform} --late

הפעלת הצפנת מטא-נתונים

לבסוף, מוסיפים את keydirectory=/metadata/vold/metadata_encryption לעמודה fs_mgr_flags ברשומה fstab של userdata. לדוגמה, שורה מלאה ב-fstab יכולה להיראות כך:

/dev/block/bootdevice/by-name/userdata              /data              f2fs        noatime,nosuid,nodev,discard,inlinecrypt latemount,wait,check,fileencryption=aes-256-xts:aes-256-cts:inlinecrypt_optimized,keydirectory=/metadata/vold/metadata_encryption,quota,formattable

כברירת מחדל, אלגוריתם הצפנת המטא-נתונים באחסון הפנימי הוא AES-256-XTS. אפשר לבטל את ההגדרה הזו על ידי הגדרת האפשרות metadata_encryption, גם היא בעמודה fs_mgr_flags:

  • במכשירים שאין בהם האצת AES, אפשר להפעיל הצפנת Adiantum על ידי הגדרת metadata_encryption=adiantum.
  • במכשירים שתומכים במפתחות שעטופים בחומרה, אפשר לעטוף את מפתח ההצפנה של המטא-נתונים בחומרה על ידי הגדרת metadata_encryption=aes-256-xts:wrappedkey_v0 (או metadata_encryption=:wrappedkey_v0, כי aes-256-xts הוא אלגוריתם ברירת המחדל).

ממשק הליבה של dm-default-key השתנה ב-Android 11, ולכן צריך לוודא שהגדרתם את הערך הנכון של PRODUCT_SHIPPING_API_LEVEL ב-device.mk. לדוגמה, אם המכשיר מופעל עם Android 11 (רמת API‏ 30), הקובץ device.mk צריך לכלול:

PRODUCT_SHIPPING_API_LEVEL := 30

אפשר גם להגדיר את מאפיין המערכת הבא כדי לאלץ את השימוש ב-API החדש dm-default-key, ללא קשר לרמת ה-API של המשלוח:

PRODUCT_PROPERTY_OVERRIDES += \
    ro.crypto.dm_default_key.options_format.version=2

אימות

כדי לוודא שהצפנת המטא-נתונים מופעלת ופועלת בצורה תקינה, מריצים את הבדיקות שמתוארות בהמשך. חשוב לשים לב גם לבעיות הנפוצות שמתוארות בהמשך.

בדיקות

כדי לוודא שההצפנה של המטא-נתונים מופעלת באחסון הפנימי, מריצים את הפקודה הבאה:

adb root
adb shell dmctl table userdata

הפלט אמור להיראות כך:

Targets in the device-mapper table for userdata:
0-4194304: default-key, aes-xts-plain64 - 0 252:2 0 3 allow_discards sector_size:4096 iv_large_sectors

אם ביטלתם את הגדרות ההצפנה שמוגדרות כברירת מחדל על ידי הגדרת האפשרות metadata_encryption בfstab של המכשיר, הפלט יהיה שונה מעט מהפלט שלמעלה. לדוגמה, אם הפעלתם הצפנת Adiantum, השדה השלישי יהיה xchacha12,aes-adiantum-plain64 במקום aes-xts-plain64.

לאחר מכן, מריצים את vts_kernel_encryption_test כדי לוודא שהצפנת המטא-נתונים וה-FBE נכונים:

atest vts_kernel_encryption_test

או:

vts-tradefed run vts -m vts_kernel_encryption_test

בעיות נפוצות

במהלך הקריאה ל-mount_all, שמתקינה את המחיצה /data שמוצפנת במטא-נתונים, init מפעיל את הכלי vdc. הכלי vdc מתחבר אל vold דרך binder כדי להגדיר את המכשיר עם מטא-נתונים מוצפנים ולהעלות את המחיצה. במהלך השיחה הזו, init חסום, וניסיונות לקרוא או להגדיר מאפיינים של init נחסמים עד ש-mount_all מסתיים. אם בשלב הזה, חלק כלשהו בעבודה של vold נחסם באופן ישיר או עקיף בקריאה או בהגדרת מאפיין, מתרחש מצב של קיפאון. חשוב לוודא ש-vold יכול להשלים את הפעולות של קריאת המפתחות, אינטראקציה עם KeyMint והרכבת ספריית הנתונים בלי אינטראקציה נוספת עם init.

אם KeyMint לא מופעל באופן מלא כשמריצים את mount_all, הוא לא מגיב ל-vold עד שהוא קורא מאפיינים מסוימים מ-init, וכתוצאה מכך נוצר בדיוק מצב הקיפאון שמתואר. הצבת exec_start wait_for_keymaster מעל הקריאה הרלוונטית ל-mount_all כפי שמוגדרת מבטיחה ש-KeyMint יפעל באופן מלא מראש, וכך נמנעת חסימה.

הגדרה באחסון שניתן להתאמה

מאז Android 9, הצפנה של מטא-נתונים מופעלת תמיד באחסון שניתן להתאמה כש-FBE מופעל, גם אם הצפנה של מטא-נתונים לא מופעלת באחסון הפנימי.

ב-AOSP, יש שתי הטמעות של הצפנת מטא-נתונים באחסון שניתן להתאמה: הטמעה שהוצאה משימוש שמבוססת על dm-crypt, והטמעה חדשה יותר שמבוססת על dm-default-key. כדי לוודא שההטמעה הנכונה נבחרה למכשיר שלכם, צריך לוודא שהגדרתם את הערך הנכון של PRODUCT_SHIPPING_API_LEVEL ב-device.mk. לדוגמה, אם המכשיר מופעל עם Android 11 (רמת API‏ 30), הקובץ device.mk צריך להכיל:

PRODUCT_SHIPPING_API_LEVEL := 30

אפשר גם להגדיר את מאפייני המערכת הבאים כדי לאלץ את השימוש בשיטת ההצפנה החדשה של מטא-נתונים של נפח (ובגרסה החדשה של מדיניות ברירת המחדל של FBE), ללא קשר לרמת ה-API של המשלוח:

PRODUCT_PROPERTY_OVERRIDES += \
    ro.crypto.volume.metadata.method=dm-default-key \
    ro.crypto.dm_default_key.options_format.version=2 \
    ro.crypto.volume.options=::v2

השיטה הנוכחית

במכשירים שהושקו עם Android מגרסה 11 ואילך, הצפנת מטא-נתונים באחסון שניתן להתאמה משתמשת במודול הליבה dm-default-key, בדיוק כמו באחסון הפנימי. בדרישות המוקדמות שלמעלה מוסבר אילו אפשרויות של הגדרת ליבת המערכת צריך להפעיל. שימו לב: יכול להיות שחומרה להצפנה מוטמעת שפועלת באחסון הפנימי של המכשיר לא תהיה זמינה באחסון שניתן להתאמה, ולכן יכול להיות שיהיה צורך ב-CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y.

כברירת מחדל, שיטת ההצפנה של המטא-נתונים של עוצמת הקול dm-default-key משתמשת באלגוריתם ההצפנה AES-256-XTS עם מגזרים קריפטוגרפיים של 4,096 בייט. אפשר לשנות את האלגוריתם על ידי הגדרת מאפיין המערכת ro.crypto.volume.metadata.encryption. התחביר של הערך של המאפיין הזה זהה לזה של אפשרות ה-fstab‏ metadata_encryption שמתוארת למעלה. לדוגמה, במכשירים שאין בהם האצת AES, אפשר להפעיל הצפנת Adiantum על ידי הגדרת ro.crypto.volume.metadata.encryption=adiantum.

שיטה מדור קודם

במכשירים שהושקו עם Android מגרסה 10 ומטה, הצפנת המטא-נתונים באחסון שניתן להתאמה משתמשת במודול הליבה dm-crypt ולא ב-dm-default-key:

CONFIG_DM_CRYPT=y

בניגוד לשיטה dm-default-key, בשיטה dm-crypt התוכן של הקובץ מוצפן פעמיים: פעם אחת באמצעות מפתח FBE ופעם אחת באמצעות מפתח הצפנת המטא-נתונים. ההצפנה הכפולה הזו פוגעת בביצועים ולא נדרשת כדי להשיג את יעדי האבטחה של הצפנת המטא-נתונים, כי מערכת Android מבטיחה שמפתחות ה-FBE יהיו לפחות קשים לפריצה כמו מפתח הצפנת המטא-נתונים. ספקים יכולים לבצע התאמות אישיות בקרנל כדי להימנע מהצפנה כפולה, במיוחד על ידי הטמעה של האפשרות allow_encrypt_override שאנדרואיד מעבירה אל dm-crypt כשמאפיין המערכת ro.crypto.allow_encrypt_override מוגדר לערך true. ההתאמות האישיות האלה לא נתמכות על ידי ליבת Android הנפוצה.

כברירת מחדל, שיטת ההצפנה של מטא-נתונים של נפח dm-crypt משתמשת באלגוריתם ההצפנה AES-128-CBC עם ESSIV ועם מגזרים קריפטוגרפיים של 512 בייט. אפשר לשנות את ההגדרה הזו על ידי הגדרת מאפייני המערכת הבאים (שמשמשים גם להצפנת נתונים מלאה):

  • ro.crypto.fde_algorithm בוחרים את אלגוריתם ההצפנה של המטא-נתונים. האפשרויות הן aes-128-cbc ו-adiantum. אפשר להשתמש ב-Adiantum רק אם במכשיר אין האצת AES.
  • ro.crypto.fde_sector_size בוחרת את גודל הסקטור המוצפן. האפשרויות הן 512,‏ 1024,‏ 2048 ו-4096. להצפנת Adiantum, משתמשים ב-4096.