מפתחות עטופים בחומרה

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

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

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

הערה: מנוע הצפנה מוטמע (או חומרה להצפנה מוטמעת) הוא חומרה שמצפינה או מפענחת נתונים בזמן שהם בדרך אל מכשיר האחסון או ממנו. בדרך כלל זהו מארח UFS או eMMC שמטמיע את תוספות הקריפטו שמוגדרות על ידי מפרט JEDEC.

עיצוב

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

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

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

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

היררכיית מפתחות

אפשר להפיק מפתחות ממפתחות אחרים באמצעות פונקציית נגזרת מפתחות (KDF) כמו HKDF. התוצאה היא היררכיית מפתחות.

בתרשים הבא מוצגת היררכיית מפתחות אופיינית של FBE כאשר לא נעשה שימוש במפתחות עטופים בחומרה:

היררכיית מפתחות של FBE (רגילה)
איור 1. היררכיית מפתחות של FBE (רגילה)

מפתח הכיתה של FBE הוא מפתח ההצפנה הגולמי שמערכת Android מעבירה לליבה של Linux כדי לפתוח קבוצה מסוימת של ספריות מוצפנות, כמו האחסון של פרטי הכניסה של משתמש מסוים ב-Android. (במעבד, המפתח הזה נקרא מפתח מאסטר של fscrypt). מהמפתח הזה, הליבה נגזרת את מפתחות המשנה הבאים:

  • מזהה המפתח. הוא לא משמש להצפנה, אלא הוא ערך שמזהה את המפתח שבו מוגן קובץ או ספרייה מסוימים.
  • מפתח ההצפנה של תוכן הקובץ
  • מפתח ההצפנה של שמות הקבצים

לעומת זאת, בתרשים הבא מוצגת היררכיית המפתחות של FBE כשמשתמשים במפתחות ארוזים בחומרה:

היררכיית מפתחות FBE (עם מפתח עטוף חומרה)
איור 2. היררכיית מפתחות FBE (עם מפתח עטוף בחומרה)

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

  • ממשק אחד להפקת inline_encryption_key וישירות לתכנת אותו לחריץ מפתח של מנוע ההצפנה המוטבע. כך אפשר להצפין או לפענח את תוכן הקבצים בלי שתוכנה תקבל גישה למפתח הגולמי. בליבות הנפוצות של Android, הממשק הזה תואם לפעולה blk_crypto_ll_ops::keyslot_program, שחייבת להיות מוטמעת על ידי מנהל האחסון.
  • ממשק אחד להפקה והחזרה של sw_secret ("תוכנה סודי" -- נקרא גם "הסוד הגולמי" במקומות מסוימים), המערכת של Linux משתמשת בכל מה שצריך כדי להפיק את מפתחות המשנה לכל דבר מלבד תוכן הקבצים הצפנה. בליבות הנפוצות של Android, הממשק הזה תואם לפעולה blk_crypto_ll_ops::derive_sw_secret, שחייבת להיות מוטמעת על ידי מנהל האחסון.

כדי להפיק את inline_encryption_key ו-sw_secret מתוך מפתח אחסון גולמי, החומרה חייבת להשתמש ב-KDF חזק מבחינה קריפטוגרפית. ה-KDF חייב לפעול בהתאם לשיטות המומלצות לקריפטוגרפיה, וחוזק האבטחה שלו צריך להיות לפחות 256 ביט, כלומר מספיק לכל אלגוריתם שמיושם בשלב מאוחר יותר. בנוסף, צריך להשתמש תווית נפרדת, הקשר ומחרוזת מידע ספציפית לאפליקציה כאשר שמפיקות כל סוג של מפתח משנה כדי להבטיח שמפתחות המשנה שמתקבלים מבודדים מבחינה קריפטוגרפית. כלומר, הידע של אחד מהם לא חושף שום אחר. אין צורך בהארכת מפתחות, כי מפתח האחסון הגולמי הוא כבר מפתח אקראי אחיד.

מבחינה טכנית, אפשר להשתמש בכל KDF שעומד בדרישות האבטחה. עם זאת, למטרות בדיקה, צריך להטמיע מחדש את אותו KDF בקוד הבדיקה. נכון לעכשיו, נבדקה והוטמעה פונקציית KDF אחת. אפשר למצוא אותה בקוד המקור של vts_kernel_encryption_test. מומלץ שהחומרה תשתמש ב-KDF הזה, שמשתמש ב-NIST SP 800-108 "KDF במצב מונה" עם AES-256-CMAC כ-PRF. לתשומת ליבכם: כדי להבטיח תאימות, חלקים באלגוריתם חייבים להיות זהים, כולל הבחירה בהקשרים של KDF ואת התוויות לכל מפתח משנה.

אריזה של מפתחות

כדי לעמוד ביעדים של אבטחת מפתחות באריזת חומרה, מוגדרים שני סוגים של אריזת מפתחות:

  • אריזה זמנית: החומרה מצפינה את המפתח הגולמי באמצעות מפתח שנוצר באופן אקראי בכל הפעלה ולא חשוף ישירות מחוץ לחומרה.
  • אריזה לטווח ארוך: החומרה מצפינה את המפתח הגולמי באמצעות מפתח קבוע וייחודי שמובנה בחומרה שאינו ישיר חשיפה מחוץ לחומרה.

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

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

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

  • ממשקים ליצירה ולייבוא של מפתחות אחסון, והחזרתם באריזת לטווח ארוך. הגישה לממשקים האלה מתבצעת באופן עקיף דרך KeyMint, והם תואמים לתג KeyMint‏ TAG_STORAGE_KEY. היכולת 'יצירה' משמשת את vold ליצירת מפתחות אחסון חדשים לשימוש ב-Android, והיכולת 'ייבוא' משמשת את vts_kernel_encryption_test לייבוא מפתחות בדיקה.
  • ממשק להמרת מפתח אחסון ארוך טווח באריזת זמן לטווח קצר. זה תואם לשיטה convertStorageKeyToEphemeral של KeyMint. השיטה הזו בשימוש לפי vold וגם vts_kernel_encryption_test לפי הסדר כדי לבטל את הנעילה של האחסון.

האלגוריתם לאריזת המפתחות הוא פרטי הטמעה, אבל צריך להשתמש פרוטוקול AEAD חזק כמו AES-256-GCM עם מערכות IV אקראיות.

נדרשים שינויים בתוכנה

ל-AOSP כבר יש מסגרת בסיסית לתמיכה במפתחות שמוגדרים בחומרה. הזה כוללת את התמיכה ברכיבי מרחב משתמשים כמו vold, וגם כתמיכה בליבה (kernel) של Linux ב-blk-crypto, ב-fscrypt וב- dm-default-key.

עם זאת, יש צורך לבצע כמה שינויים ספציפיים להטמעה.

שינויים ב-KeyMint

צריך לשנות את ההטמעה של KeyMint במכשיר כך שתתמוך ב-TAG_STORAGE_KEY ותטמיע את השיטה convertStorageKeyToEphemeral.

ב-Keymaster, נעשה שימוש ב-exportKey במקום ב- convertStorageKeyToEphemeral.

שינויים בליבה (kernel) של Linux

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

בשביל android14 בליבות גבוהות יותר, הגדרת BLK_CRYPTO_KEY_TYPE_HW_WRAPPED ב-blk_crypto_profile::key_types_supported, יצרן blk_crypto_ll_ops::keyslot_program ו-blk_crypto_ll_ops::keyslot_evict תמיכה בתכנות/בפינוי מפתחות עטופים בחומרה, וליישם את blk_crypto_ll_ops::derive_sw_secret.

לליבות android12 ו-android13, הגדרה של BLK_CRYPTO_FEATURE_WRAPPED_KEYS בעוד blk_keyslot_manager::features, ליצור blk_ksm_ll_ops::keyslot_program ו-blk_ksm_ll_ops::keyslot_evict תמיכה בתכנות/בפינוי מפתחות עטופים בחומרה, ולהטמיע את blk_ksm_ll_ops::derive_raw_secret.

בליבות android11, מגדירים את BLK_CRYPTO_FEATURE_WRAPPED_KEYS ב-keyslot_manager::features, מוסיפים ל-keyslot_mgmt_ll_ops::keyslot_program ול-keyslot_mgmt_ll_ops::keyslot_evict תמיכה בתכנות או בהוצאה של מפתחות עטופים בחומרה, ומטמיעים את keyslot_mgmt_ll_ops::derive_raw_secret.

בדיקה

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

atest -v vts_kernel_encryption_test

קוראים את יומן הבדיקות ומוודאים שמקרי הבדיקה של מפתחות עטופים בחומרה (לדוגמה, FBEPolicyTest.TestAesInlineCryptOptimizedHwWrappedKeyPolicy והקבוצה DmDefaultKeyTest.TestHwWrappedKey) לא דילגת על התהליך עקב התמיכה עבור מפתחות עטופים בחומרה שלא זוהו, כי תוצאות הבדיקה עדיין 'עבר' במקרה כזה.

הפעלת המפתחות

אחרי שתראו שהתמיכה במפתחות עטופים בחומרה פועלת כמו שצריך, תוכלו לבצע את השינויים הבאים בקובץ fstab של המכשיר כדי לאפשר ל-Android להשתמש בו ל-FBE ולצפנת מטא-נתונים:

  • FBE: מוסיפים את הדגל wrappedkey_v0 לפרמטר fileencryption. לדוגמה, השתמשו fileencryption=::inlinecrypt_optimized+wrappedkey_v0 עבור לפרטים נוספים, ראו FBE תיעוד.
  • הצפנת מטא-נתונים: מוסיפים את הדגל wrappedkey_v0 אל metadata_encryption. לדוגמה, השתמשו metadata_encryption=:wrappedkey_v0 פרטים נוספים זמינים במאמר מטא-נתונים מסמכים להצפנה.