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

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

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

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

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

כדי להגדיר הצפנת מטא-נתונים באחסון הפנימי של מכשירים חדשים, צריך להגדיר את מערכת הקבצים metadata, לשנות את רצף ה-init ולהפעיל את הצפנת המטא-נתונים בקובץ 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 ובגרסאות קודמות, הליבה המשותפת של Android לא תמכה ב-dm-default-key. לכן, הספקים היו צריכים להטמיע את dm-default-key.

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

מכיוון שאי אפשר לקרוא שום דבר במחיצה של נתוני המשתמש עד שמופיע מפתח ההצפנה של המטא-נתונים, צריך להקצות מחיצה נפרדת בטבלת המחיצות שנקראת 'מחיצה של מטא-נתונים', כדי לאחסן את ה-blobs של Keymaster שמגינים על המפתח הזה. מחיצת המטא-נתונים צריכה להיות בגודל 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

שינויים ברצף ה-init

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

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

Keymaster צריך לפעול ולהיות מוכן לפני הניסיון לטעון את /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 יוכל להשלים את קריאת המפתחות, אינטראקציה עם Keymaster וטעינת ספריית הנתונים בלי לקיים אינטראקציה נוספת עם init.

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

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

החל מ-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. התחביר של הערך של המאפיין הזה זהה לזה של האפשרות metadata_encryption ב-fstab שמתוארת למעלה. לדוגמה, במכשירים בלי האצת 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 ש-Android מעביר אל dm-crypt כשמאפיין המערכת ro.crypto.allow_encrypt_override מוגדר ל-true. הליבה המשותפת של Android לא תומכת בהתאמות אישיות כאלה.

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

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