מאפיינים

בדף הזה מפורט מידע על התכונות הקריפטוגרפיות של Android Keystore, כפי שסופקו על ידי ההטמעה הבסיסית של KeyMint (או Keymaster).

פרימיטיבים קריפטוגרפיים

מערכת Keystore מספקת את הקטגוריות הבאות של פעולות:

  • יצירת מפתחות, שמובילה ליצירת חומר של מפתחות פרטיים או סודיים שרק לסביבה המאובטחת יש גישה אליו. לקוחות יכולים ליצור מפתחות בדרכים הבאות:
    • יצירת מפתחות חדשים
    • ייבוא של חומר מפתחות ללא הצפנה
    • ייבוא של חומר מפתחות מוצפן
  • אימות מפתחות: יצירת מפתח אסימטרי יוצרת אישור שמכיל את החלק של המפתח הציבורי מזוג המפתחות. האישור הזה יכול להכיל גם מידע על המטא-נתונים של המפתח ועל מצב המכשיר, והכול חתום על ידי שרשרת מפתחות שחוזרת ל-root מהימן.
  • פעולות קריפטוגרפיות:
    • הצפנה ופענוח סימטריים (AES, ‏ 3DES)
    • פענוח אסימטרי (RSA)
    • חתימה אסימטרית (ECDSA, ‏ RSA)
    • חתימה ואימות סימטריים (HMAC)
    • הסכם מפתחות אסימטרי (ECDH)

חשוב לזכור ש-Keystore ו-KeyMint לא מטפלים בפעולות של מפתחות ציבוריים למפתחות אסימטריים.

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

הפרימיטיבים והמצבים שצריכים להיות נתמכים בהטמעת KeyMint מתוארים במפרט של ממשק ה-HAL‏ IKeyMintDevice.

ההטמעה הבסיסית של KeyMint חייבת לבצע יצירת מספרים אקראיים כדי לתמוך ביצירת מפתחות וביצירת ווקטורים של אימות או ווקטורים של איפוס (IV) אקראיים. כדי לתמוך בכך, מערכת Android מספקת מדי פעם אנטרופי נוסף להטמעת KeyMint.

בקרת גישה למפתחות

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

אמצעי בקרת הגישה מוגדרים כ'רשימת הרשאות' של צמדי תג/ערך. תגי הרשאה הם מספרים שלמים של 32 ביט, והערכים הם מגוון סוגים. אפשר לחזור על חלק מהתגים כדי לציין כמה ערכים. האפשרות לחזור על תג מצוינה בממשק ה-HAL של KeyMint‏ (לשעבר Keymaster).

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

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

אכיפת מדיניות באמצעות חומרה לעומת אכיפת מדיניות באמצעות תוכנה

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

השדה הזה מוצג ב-KeyMint API באמצעות השדה securityLevel מסוג KeyCharacteristics. החומרה המאובטחת אחראית להציב את ההרשאות ב-KeyCharacteristics עם רמת האבטחה המתאימה, על סמך מה שהיא יכולה לאכוף. המידע הזה מוצג גם ברשומי האימות של מפתחות אסימטריים: מאפייני המפתח של SecurityLevel::TRUSTED_ENVIRONMENT או SecurityLevel::STRONGBOX מופיעים ברשימה hardwareEnforced, והמאפיינים של SecurityLevel::SOFTWARE או SecurityLevel::KEYSTORE מופיעים ברשימה softwareEnforced.

לדוגמה, בדרך כלל הסביבה המאובטחת לא אוכפת אילוצים על תאריך ומרווחי הזמן שבהם אפשר להשתמש במפתח, כי אין לה גישה מהימנה למידע על התאריך והשעה. כתוצאה מכך, הרשאות כמו Tag::ORIGINATION_EXPIRE_DATETIME נאכפות על ידי Keystore ב-Android, ויש להן את הערך SecurityLevel::KEYSTORE.

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

הרשאות ליצירת הודעות קריפטוגרפיות

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

  • Tag::ALGORITHM
  • Tag::KEY_SIZE
  • Tag::BLOCK_MODE
  • Tag::PADDING
  • Tag::CALLER_NONCE
  • Tag::DIGEST
  • Tag::MGF_DIGEST

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

  • Tag::BLOCK_MODE
  • Tag::PADDING
  • Tag::DIGEST
  • Tag::MGF_DIGEST

הערך שבו נעשה שימוש מצוין בזמן הפעולה.

מטרה

למפתחות יש קבוצה משויכת של מטרות, שמתבטאות כרשומת הרשאה אחת או יותר עם התג Tag::PURPOSE, שמגדירה את האופן שבו אפשר להשתמש בהם. המטרות מוגדרות בקובץ KeyPurpose.aidl.

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

ייבוא מפתחות

KeyMint תומך בייבוא של:

  • זוגות מפתחות אסימטריים בפורמט PKCS#8 בקידוד DER (ללא הצפנה מבוססת-סיסמה)
  • מפתחות סימטריים כבייט גולמי

כדי להבטיח שאפשר יהיה להבדיל בין מפתחות מיובאים למפתחות שנוצרו באופן מאובטח, המשתנה Tag::ORIGIN נכלל ברשימת ההרשאות המתאימה למפתחות. לדוגמה, אם מפתח נוצר בחומרה מאובטחת, הערך Tag::ORIGIN עם הערך KeyOrigin::GENERATED נמצא ברשימת hw_enforced של מאפייני המפתח, ואילו למפתח שיובאו לחומרה מאובטחת יש את הערך KeyOrigin::IMPORTED.

אימות משתמשים

הטמעות מאובטחות של KeyMint לא מטמיעות אימות משתמשים, אלא מסתמכות על אפליקציות מהימנות אחרות שמטמיעות אימות משתמשים. הממשק שהאפליקציות האלה מטמיעות מתואר בדף Gatekeeper.

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

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

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

  • הערך Tag::NO_AUTHENTICATION_REQUIRED מציין שאין צורך באימות משתמש, אבל הגישה למפתח עדיין מוגבלת לאפליקציה הבעלים (ולכל האפליקציות שהיא מעניקה להן גישה).
  • Tag::AUTH_TIMEOUT הוא ערך מספרי שמציין, בשניות, את רמת העדכניות הנדרשת של אימות המשתמש כדי לאשר את השימוש במפתח. זמן הקצאת הזמן לא חל על הפעלות מחדש. אחרי הפעלה מחדש, כל האימותים לא תקפים. אפשר להגדיר את הזמן הקצוב לתפוגה לערך גדול כדי לציין שנדרש אימות פעם אחת בכל הפעלה (2^32 שניות הן כ-136 שנים, וכנראה שמכשירי Android מופעלים מחדש בתדירות גבוהה יותר).

דרישה למכשיר לא נעול

אפשר להשתמש במפתחות עם Tag::UNLOCKED_DEVICE_REQUIRED רק כשהמכשיר לא נעול. לסמנטיקה המפורטת, ראו KeyProtection.Builder#setUnlockedDeviceRequired(boolean).

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

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

לכל משתמש (כולל פרופילים) יש שני מפתחות סופר שמשויכים ל-UNLOCKED_DEVICE_REQUIRED:

  • מפתח הסופר הסימטרי UnlockedDeviceRequired. זהו מפתח AES‑256‑GCM. הוא מצפין מפתחות UNLOCKED_DEVICE_REQUIRED שיובאו או נוצרו בזמן שהמכשיר לא נעול למשתמש.
  • מפתח הסופר האסימטרי UnlockedDeviceRequired. זהו זוג מפתחות ECDH‏ P‑521. הוא מצפין מפתחות UNLOCKED_DEVICE_REQUIRED שמיובאים או נוצרים בזמן שהמכשיר נעול למשתמש. מפתחות שמאובטחים באמצעות המפתח האסימטרי הזה מוצפנים מחדש באמצעות המפתח הסימטרי בשימוש הראשון (שיכול להתרחש רק כשהמכשיר לא נעול).

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

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

  • אם המשתמש הפעיל רק קוד אימות, קו ביטול נעילה או סיסמה, המערכת של Keystore ממירה לאפס את החלקים הסודיים של מפתחות הסופר שנשמרו במטמון. כך אפשר לשחזר את המפתחות הסופר רק באמצעות העותק המוצפן במסד הנתונים, שאפשר לפענח רק באמצעות קוד אימות, קו ביטול נעילה או סיסמה מקבילים.
  • אם למשתמש יש רק מידע ביומטרי מסוג 3 ('חזק') וקוד אימות, קו ביטול נעילה או סיסמה מופעלים, המערכת של Keystore תסדיר את שחזור מפתחות הסופר באמצעות כל אחד מהמאפיינים הביומטריים של המשתמש שנרשמו כמידע מסוג 3 (בדרך כלל טביעת אצבע), כחלופה לקוד אימות, לקו ביטול נעילה או לסיסמה. לשם כך, המערכת יוצרת מפתח AES‑256‑GCM חדש, מצפינה באמצעותו את החלקים הסודיים של מפתחות הסופר, מייבאת את מפתח ה-AES‑256‑GCM ל-KeyMint כמפתח שמקושר למידע ביומטרי, שמחייב אימות ביומטרי שהצליח ב-15 השניות האחרונות, ומוחקת את העותק של כל המפתחות האלה בטקסט ללא הצפנה.
  • אם למשתמש יש זיהוי ביומטרי מסוג 1 ('נוחות'), זיהוי ביומטרי מסוג 2 ('חלש') או סוכן אמון פעיל לביטול נעילה, מפתחות הסופר נשמרים במטמון של Keystore כטקסט ללא הצפנה. במקרה כזה, לא קיימת אבטחה קריפטוגרפית למפתחות UNLOCKED_DEVICE_REQUIRED. כדי להימנע מהשימוש בחלופה הפחות מאובטחת הזו, המשתמשים יכולים לא להפעיל את שיטות הנעילה האלה. שיטות הביטול הנפוצות ביותר של הנעילה בקטגוריות האלה הן ביטול נעילה באמצעות זיהוי הפנים במכשירים רבים וביטול נעילה באמצעות שעון חכם מותאם.

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

כבילת לקוח

קישור לקוח, כלומר שיוך של מפתח לאפליקציית לקוח מסוימת, מתבצע באמצעות מזהה לקוח אופציונלי ונתוני לקוח אופציונליים מסוימים (Tag::APPLICATION_ID ו-Tag::APPLICATION_DATA, בהתאמה). מערכת Keystore מתייחסת לערכים האלה כ-blobs אטומים, ומוודאת רק שאותם blobs שמוצגים במהלך יצירת המפתח או הייבוא שלו מוצגים בכל שימוש, ושהם זהים בייט אחרי בייט. נתוני הקישור של הלקוח לא מוחזרים על ידי KeyMint. מבצע הקריאה החוזרת צריך לדעת אותו כדי להשתמש במפתח.

התכונה הזו לא חשופה לאפליקציות.

תפוגה

ב-Keystore יש תמיכה בהגבלת השימוש במפתחות לפי תאריך. אפשר לשייך למפתח את תאריך ההתחלה ואת תאריך התפוגה שלו, ו-Keystore לא יבצע פעולות על המפתח אם התאריך/השעה הנוכחיים לא נמצאים בטווח התוקף. טווח התוקף של המפתח מצוין באמצעות התגים Tag::ACTIVE_DATETIME,‏ Tag::ORIGINATION_EXPIRE_DATETIME ו-Tag::USAGE_EXPIRE_DATETIME. ההבחנה בין 'יצירה' לבין 'שימוש' מבוססת על כך שהמפתח משמש ליצירה של טקסט מוצפן/חתימה/וכו' חדשים, או לשימוש בטקסט מוצפן/חתימה/וכו' קיימים. שימו לב שההבחנה הזו לא מוצגת לאפליקציות.

התגים Tag::ACTIVE_DATETIME,‏ Tag::ORIGINATION_EXPIRE_DATETIME ו-Tag::USAGE_EXPIRE_DATETIME הם אופציונליים. אם התגים לא נמצאים, ההנחה היא שאפשר תמיד להשתמש במפתח המדובר כדי לפענח או לאמת הודעות.

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

קישור של Root of Trust

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

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

יצירת מקור נתונים מחדש במחולל מספרים אקראיים

מכיוון שחומרה מאובטחת יוצרת מספרים אקראיים לחומר מפתח ולווקטורים של אתחול (IV), ומכיוון שיצרני מספרים אקראיים בחומרה לא תמיד מהימנים לחלוטין, ממשק ה-HAL של KeyMint מספק ממשק שמאפשר ל-Keystore לספק אנטרופיה נוספת, שמעורבת במספרים האקראיים שנוצרים.

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