מקשים עטופים בחומרה

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

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

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

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

עיצוב

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

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

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

עטיפת מפתחות

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

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

כל המפתחות שמועברים לליבה (kernel) של 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 פרטים נוספים זמינים במאמר מטא-נתונים מסמכים להצפנה.