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

‫Android 7.0 ואילך תומך בהצפנה מבוססת-קבצים (FBE). הצפנה ברמת הקובץ (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 ולהכין אותו לפני שהיא מנסה להפעיל את init /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. התחביר של הערך של המאפיין הזה זהה לתחביר של האפשרות metadata_encryptionfstab שמתוארת למעלה. לדוגמה, במכשירים שאין בהם האצת 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.