סקירה כללית על אמולציית כרטיסים מבוססת-מארח

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

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

הדמיית כרטיס באמצעות רכיב מאובטח

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

תרשים עם קורא NFC שמחובר למתג NFC כדי לאחזר מידע מרכיב מאובטח
איור 1. הדמיה של כרטיס NFC עם רכיב מאובטח.

הרכיב המאובטח עצמו מבצע את התקשורת עם מסוף ה-NFC, ואף אפליקציה ל-Android לא מעורבת בעסקה. אחרי השלמת העסקה, אפליקציה ל-Android יכולה לשלוח שאילתות ישירות לרכיב המאובטח כדי לבדוק את סטטוס העסקה ולהודיע למשתמש.

אמולציה של כרטיסים מבוססי מארח

כשכרטיס NFC מומר באמצעות אמולציה של כרטיס מבוססת-מארח, הנתונים מנותבים ישירות ל-CPU של המארח במקום לעבור לרכיב מאובטח. איור 2 ממחיש איך פועלת אמולציה של כרטיסים מבוססי מארח:

תרשים עם קורא NFC שעובר דרך בקר NFC כדי לאחזר מידע מה-CPU
איור 2. הדמיה של כרטיס NFC ללא רכיב מאובטח.

כרטיסי NFC ופרוטוקולים נתמכים

תרשים שבו מוצג סטאק הפרוטוקול של HCE
איור 3. סטאק הפרוטוקולים של HCE ב-Android.

תקני ה-NFC תומכים בפרוטוקולים רבים ושונים, ויש סוגים שונים של כרטיסים שאפשר לחקות.

מערכת ההפעלה Android מגרסה 4.4 ואילך תומכת בכמה פרוטוקולים נפוצים בשוק כיום. כרטיסים רבים שכבר קיימים מבוססים על הפרוטוקולים האלה, כמו כרטיסי תשלום ללא מגע. הפרוטוקולים האלה נתמכים גם על ידי הרבה קוראי NFC בשוק היום, כולל מכשירי NFC של Android שפועלים כקוראים בעצמם (ראו את הכיתה IsoDep). כך תוכלו ליצור ולפרוס פתרון NFC מקצה לקצה שמבוסס על HCE, ולהשתמש רק במכשירים עם Android.

באופן ספציפי, Android מגרסה 4.4 ואילך תומך בהדמיה של כרטיסים שמבוססים על מפרט ISO-DEP של NFC-Forum (מבוסס על ISO/IEC 14443-4) ועל עיבוד יחידות נתונים של Application Protocol (APDUs) כפי שמוגדרות במפרט ISO/IEC 7816-4. מערכת Android מחייבת הדמיה של ISO-DEP רק מעל הטכנולוגיה Nfc-A‏ (ISO/IEC 14443-3 Type A). התמיכה בטכנולוגיית Nfc-B‏ (ISO/IEC 14443-4 Type B) היא אופציונלית. איור 3 ממחיש את השכבות של כל המפרטים האלה.

שירותי HCE

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

בחירת שירות

כשהמשתמש מכה במכשיר על קורא NFC, מערכת Android צריכה לדעת איזה שירות HCE קורא ה-NFC רוצה לתקשר איתו. במפרט ISO/IEC 7816-4 מוגדר אופן לבחירת אפליקציות, שמתמקד במזהה אפליקציה (AID). מזהה AID מורכב מ-16 בייטים לכל היותר. אם אתם מבצעים הדמיה של כרטיסים בתשתית קיימת של קורא NFC, מזהי ה-AID שהקוראים האלה מחפשים הם בדרך כלל מזהי AID ידועים ורשומים באופן ציבורי (לדוגמה, מזהי ה-AID של רשתות תשלומים כמו Visa ו-MasterCard).

אם רוצים לפרוס תשתית קוראים חדשה לאפליקציה משלכם, צריך לרשום את מזהי ה-AID שלכם. תהליך הרישום של מזהי AID מוגדר במפרט ISO/IEC 7816-5. אם אתם פורסים אפליקציית HCE ל-Android, מומלץ לרשום AID בהתאם ל-7816-5 כדי למנוע התנגשויות עם אפליקציות אחרות.

קבוצות AID

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

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

  • כל מזהי ה-AID בקבוצה מנותבים לשירות ה-HCE הזה.
  • אף מזהה AID בקבוצה לא מנותב לשירות ה-HCE הזה (לדוגמה, כי המשתמש העדיף שירות אחר שביקשו ממנו גם מזהה AID אחד או יותר בקבוצה).

במילים אחרות, אין מצב ביניים שבו חלק מ-AIDs בקבוצה יכולים לעבור לשירות HCE אחד וחלק לשירות אחר.

קבוצות וקטגוריות של סיוע בינלאומי

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

במכשירי Android מגרסה 4.4 ואילך יש תמיכה בשתי קטגוריות:

הטמעת שירות HCE

כדי לדמות כרטיס NFC באמצעות אמולציה של כרטיס מבוסס-מארח, צריך ליצור רכיב Service שמטפל בעסקאות ה-NFC.

בדיקת התמיכה ב-HCE

האפליקציה יכולה לבדוק אם מכשיר תומך ב-HCE על ידי בדיקה של התכונה FEATURE_NFC_HOST_CARD_EMULATION. משתמשים בתג <uses-feature> במניפסט של האפליקציה כדי להצהיר שהאפליקציה משתמשת בתכונה HCE, ולהצהיר אם היא נדרשת לצורך הפעלת האפליקציה או לא.

הטמעת שירותים

ב-Android מגרסה 4.4 ואילך יש מחלקה נוחה בשם Service שאפשר להשתמש בה כבסיס להטמעת שירות HCE: המחלקה HostApduService.

השלב הראשון הוא להרחיב את HostApduService, כפי שמתואר בדוגמת הקוד הבאה:

Kotlin

class MyHostApduService : HostApduService() {

    override fun processCommandApdu(commandApdu: ByteArray, extras: Bundle?): ByteArray {
       ...
    }

    override fun onDeactivated(reason: Int) {
       ...
    }
}

Java

public class MyHostApduService extends HostApduService {
    @Override
    public byte[] processCommandApdu(byte[] apdu, Bundle extras) {
       ...
    }
    @Override
    public void onDeactivated(int reason) {
       ...
    }
}

HostApduService מכריז על שתי שיטות מופשטות שצריך לבטל את הגדרת ברירת המחדל שלהן ולהטמיע אותן. אחד מהם, processCommandApdu(), נקרא בכל פעם שקורא NFC שולח לשירות יחידת נתונים של פרוטוקול אפליקציה (APDU). הודעות APDU מוגדרות במפרט ISO/IEC 7816-4. חבילות APDU הן החבילות ברמת האפליקציה שמתחלפות בין קורא ה-NFC לבין שירות ה-HCE. הפרוטוקול ברמת האפליקציה הוא חצי דופלקס: קורא ה-NFC שולח לכם פקודת APDU, וממתין שתשלחו לו תשובה ב-APDU.

כפי שצוין קודם, Android משתמש ב-AID כדי לקבוע איזה שירות HCE הקורא רוצה ליצור איתו קשר. בדרך כלל, ה-APDU הראשון שקורא ה-NFC שולח למכשיר הוא SELECT AID APDU. ה-APDU הזה מכיל את ה-AID שקורא ה-NFC רוצה לתקשר איתו. מערכת Android מחלצת את ה-AID הזה מה-APDU, פותרת אותו לשירות HCE ואז מעבירה את ה-APDU לשירות המטופל.

כדי לשלוח APDU תגובה, מחזירים את הבייטים של APDU התגובה מ-processCommandApdu(). חשוב לזכור שהשיטה הזו נקראת בשרשור הראשי של האפליקציה, ואסור לחסום אותו. אם אי אפשר לחשב ולשלוח תשובה APDU באופן מיידי, צריך להחזיר null. לאחר מכן תוכלו לבצע את העבודה הנדרשת בשרשור אחר ולהשתמש ב-method‏ sendResponseApdu() שמוגדר בכיתה HostApduService כדי לשלוח את התשובה בסיום.

Android ממשיך להעביר APDU חדשים מהקורא לשירות שלכם, עד שאחד מהאירועים הבאים מתרחש:

  • קורא ה-NFC שולח APDU נוסף של SELECT AID, שמערכות ההפעלה מתייחסות אליו כאל שירות אחר.
  • הקישור של ה-NFC בין קורא ה-NFC לבין המכשיר שלכם לא תקין.

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

אם אתם עובדים עם תשתית קיימת של קורא, עליכם להטמיע את הפרוטוקול הקיים ברמת האפליקציה שהקוראים מצפים לו בשירות ה-HCE.

אם אתם פורסים תשתית חדשה של קורא שבשליטתכם, תוכלו להגדיר את הפרוטוקול ואת רצף ה-APDU שלכם. כדאי להגביל את כמות ה-APDU ואת גודל הנתונים להחלפה: כך המשתמשים יצטרכו להחזיק את המכשיר מעל קורא ה-NFC רק למשך זמן קצר. גבול עליון סביר הוא כ-1KB של נתונים, שבדרך כלל אפשר להעביר תוך 300ms.

הצהרה על מניפסט השירות ורישום AID

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

  1. כדי להודיע לפלטפורמה שמדובר בשירות HCE שמטמיע ממשק HostApduService, מוסיפים למוצהר השירות מסנן Intent לפעולה SERVICE_INTERFACE.

  2. כדי להודיע לפלטפורמה אילו קבוצות של AIDs השירות הזה מבקש, צריך לכלול את התג SERVICE_META_DATA <meta-data> בהצהרה על השירות, כך שיצביע על משאב XML עם מידע נוסף על שירות ה-HCE.

  3. מגדירים את המאפיין android:exported לערך true, ומחייבים את ההרשאה android.permission.BIND_NFC_SERVICE בהצהרת השירות. האפשרות הראשונה מבטיחה שאפשר יהיה לאגד את השירות לאפליקציות חיצוניות. לאחר מכן, השירות אוכף שרק אפליקציות חיצוניות עם ההרשאה android.permission.BIND_NFC_SERVICE יכולות לקשר אליו. מכיוון ש-android.permission.BIND_NFC_SERVICE היא הרשאת מערכת, כך אפשר לאכוף ביעילות שרק מערכת Android תוכל לקשר את השירות.

דוגמה להצהרת מניפסט של HostApduService:

<service android:name=".MyHostApduService" android:exported="true"
         android:permission="android.permission.BIND_NFC_SERVICE">
    <intent-filter>
        <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
    </intent-filter>
    <meta-data android:name="android.nfc.cardemulation.host_apdu_service"
               android:resource="@xml/apduservice"/>
</service>

תג המטא-נתונים הזה מפנה לקובץ apduservice.xml. לפניכם דוגמה לקובץ כזה עם הצהרה אחת על קבוצת AID שמכילה שני AIDs קנייניים:

<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
           android:description="@string/servicedesc"
           android:requireDeviceUnlock="false">
    <aid-group android:description="@string/aiddescription"
               android:category="other">
        <aid-filter android:name="F0010203040506"/>
        <aid-filter android:name="F0394148148100"/>
    </aid-group>
</host-apdu-service>

התג <host-apdu-service> חייב לכלול מאפיין <android:description> שמכיל תיאור ידידותי למשתמש של השירות, שאפשר להציג בממשק המשתמש של האפליקציה. אפשר להשתמש במאפיין requireDeviceUnlock כדי לציין שהמכשיר נעול לפני שמפעילים את השירות הזה לטיפול ב-APDU.

התווית <host-apdu-service> חייבת להכיל תג <aid-group> אחד לפחות. כל תג <aid-group> חייב לבצע את הפעולות הבאות:

  • מכילה מאפיין android:description שמכיל תיאור ידידותי למשתמש של קבוצת ה-AID, שמתאים להצגה בממשק המשתמש.
  • מגדירים את המאפיין android:category כך שיציין את הקטגוריה שאליה משתייכת קבוצת ה-AID, למשל קבועי המחרוזות שמוגדרים על ידי CATEGORY_PAYMENT או CATEGORY_OTHER.
  • מכילים תג <aid-filter> אחד או יותר, שכל אחד מהם מכיל מזהה AID יחיד. מציינים את ה-AID בפורמט הקסדצימלי ומוודאים שהוא מכיל מספר תווים אי זוגי.

בנוסף, לאפליקציה צריכה להיות ההרשאה NFC כדי להירשם כשירות HCE.

פתרון סכסוכים ב-AID

אפשר להתקין כמה רכיבי HostApduService במכשיר אחד, ואותו מזהה AID יכול להיות רשום על ידי יותר משירות אחד. מערכת Android קובעת איזה שירות להפעיל לפי השלבים הבאים:

  1. אם אפליקציית הארנק שמוגדרת כברירת מחדל של המשתמש רשמה את ה-AID, המערכת תפעיל את האפליקציה הזו.
  2. אם אפליקציית הארנק שמוגדרת כברירת מחדל לא רשמה את ה-AID, המערכת תפעיל את השירות שרשם את ה-AID.
  3. אם יותר משירות אחד רשם את ה-AID, מערכת Android תשאל את המשתמש איזה שירות להפעיל.

העדפה לשירות שפועל בחזית

אפליקציות בחזית יכולות להפעיל את setPreferredService כדי לציין איזה שירות של הדמיית כרטיס עדיף להשתמש בו בזמן שפעילות ספציפית פועלת בחזית. העדפת האפליקציה בחזית מבטלת את פתרון הסכסוך של AID. מומלץ להשתמש בשיטה הזו כשהאפליקציה צופה שהמשתמש עשוי להשתמש בסימולציה של כרטיס NFC.

‫Android מגרסה 13 ואילך

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

Android מגרסה 12 ומטה

מגדירים את הגודל של באנר השירות ל-260x96dp, ואז מגדירים את הגודל של באנר השירות בקובץ ה-XML של המטא-נתונים על ידי הוספת המאפיין android:apduServiceBanner לתג <host-apdu-service>, שמצביע על המשאב שניתן לציור. דוגמה:

<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
        android:description="@string/servicedesc"
        android:requireDeviceUnlock="false"
        android:apduServiceBanner="@drawable/my_banner">
    <aid-group android:description="@string/aiddescription"
               android:category="payment">
        <aid-filter android:name="F0010203040506"/>
        <aid-filter android:name="F0394148148100"/>
    </aid-group>
</host-apdu-service>

אפליקציות Wallet

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

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

אפליקציות יכולות לבדוק אם הן מוגדרות כברירת מחדל לאפליקציית הארנק על ידי העברת הערך RoleManager.ROLE_WALLET אל RoleManager.isRoleHeld().

אם האפליקציה שלכם היא לא ברירת המחדל, תוכלו לבקש את תפקיד ברירת המחדל של הארנק על ידי העברת RoleManager.ROLE_WALLET אל RoleManager.createRequestRoleIntent().

נכסים נדרשים לאפליקציות Wallet

כדי לספק חוויית משתמש חזותית מושכת יותר, אפליקציות ארנק HCE נדרשות לספק באנר שירות.

מצב תצפית

ב-Android 15 נוספה התכונה Observe Mode. כשהאפשרות מופעלת, מצב התצפית מאפשר למכשיר לעקוב אחרי לולאות הסקרים של NFC ולשלוח התראות עליהן לרכיבי HostApduService המתאימים, כדי שיוכלו להתכונן לאינטראקציה עם מסוף NFC נתון. HostApduService יכול להעביר את המכשיר למצב תצפית על ידי העברת true אל setObserveModeEnabled(). ההגדרה הזו מורה ל-NFC stack לא לאפשר עסקאות NFC, ובמקום זאת לעקוב באופן פסיבי אחרי לולאות הסקרים.

מסננים של לולאת הסקרים

אפשר לרשום מסננים של לולאת סקרים ל-HostApduService באמצעות אחת מהשיטות הבאות:

כשמסנן של לולאת סקרים תואם למסגרות סקרים לא סטנדרטיות, סטאק ה-NFC מפנה את מסגרות הסקרים האלה ל-HostApduService התואם על ידי קריאה ל-method‏ processPollingFrames() שלו. כך השירות יכול לבצע את כל הפעולות הנדרשות כדי לוודא שהמשתמש מוכן לבצע עסקה ויש לו כוונה לעשות זאת – למשל, אימות המשתמש. אם קורא ה-NFC משתמש רק בפריימים רגילים בלולאת הבדיקה שלו, סטאק ה-NFC מנווט את פריימים הבדיקה האלה לשירות המועדף בחזית, אם השירות הזה נמצא בחזית, או לבעלים של תפקיד הארנק שמוגדר כברירת מחדל, במקרה אחר.

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

תגובה ללופים של סקרים ומעבר ממצב תצפית

כשהשירות מוכן לבצע עסקה, הוא יכול לצאת ממצב התצפית על ידי העברת הערך false אל setObserveModeEnabled(). לאחר מכן, מקבץ ה-NFC יאפשר להמשיך בעסקאות.

רכיבי HostApduService יכולים לציין שצריך להפעיל את מצב התצפית בכל פעם שהם שירות התשלומים המועדף, על ידי הגדרת shouldDefaultToObserveMode לערך true במניפסט או על ידי קריאה ל-CardEmulation.setShouldDefaultToObserveModeForService().

אפשר גם להשתמש ברכיבים HostApduService ו-OffHostApduService כדי לציין שמסננים של לולאות סקירה שתואמים למסגרות של לולאות סקירה שהתקבלו צריכים להשבית באופן אוטומטי את מצב התצפית ולאפשר לעסקאות להמשיך, על ידי הגדרת autoTransact לערך true בהצהרה PollingLoopFilter במניפסט.

העדפה לשירות שפועל בחזית

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

התנהגות המסך כשהוא כבוי וכשהמסך נעול

ההתנהגות של שירותי HCE משתנה בהתאם לגרסה של Android שפועלת במכשיר.

Android מגרסה 15 ואילך

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

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

Android מגרסה 12 ואילך

באפליקציות שמטרגטות את Android 12 (רמת API 31) ואילך, אפשר להפעיל תשלומים ב-NFC בלי שהמסך של המכשיר יהיה דלוק. לשם כך, מגדירים את requireDeviceScreenOn לערך false.

Android מגרסה 10 ואילך

במכשירים עם Android מגרסה 10 (רמת API‏ 29) ואילך יש תמיכה ב-NFC מאובטח. כשה-NFC המאובטח מופעל, כל אמולרטורים של כרטיסים (אפליקציות מארח ואפליקציות מחוץ למארח) לא זמינים כשמסך המכשיר כבוי. כשה-NFC המאובטח מושבת, אפליקציות מחוץ למארח זמינות כשמסך המכשיר כבוי. אפשר לבדוק אם יש תמיכה ב-NFC מאובטח באמצעות isSecureNfcSupported().

במכשירים עם Android מגרסה 10 ואילך, אותה פונקציונליות של הגדרת android:requireDeviceUnlock ל-true חלה גם על מכשירי Android מגרסה 9 ומטה, אבל רק כש-Secure NFC מושבת. כלומר, אם Secure NFC מופעל, שירותי HCE לא יכולים לפעול מסך הנעילה, ללא קשר להגדרה של android:requireDeviceUnlock.

Android מגרסה 9 ומטה

במכשירים עם Android 9 (רמת API 28) ומטה, בקר ה-NFC ומעבד האפליקציות מושבתים לחלוטין כשהמסך של המכשיר כבוי. לכן, שירותי HCE לא פועלים כשהמסך כבוי.

בנוסף, ב-Android 9 ומטה, שירותי HCE יכולים לפעול ממסך הנעילה. עם זאת, האפשרות הזו נשלטת על ידי המאפיין android:requireDeviceUnlock בתג <host-apdu-service> של שירות ה-HCE. כברירת מחדל, לא נדרש לבטל את נעילת המכשיר, והשירות מופעל גם אם המכשיר נעול.

אם תגדירו את המאפיין android:requireDeviceUnlock לערך true בשירות ה-HCE, מערכת Android תבקש מהמשתמש לבטל את נעילת המכשיר במקרים הבאים:

  • המשתמש מכה על קורא NFC.
  • קורא ה-NFC בוחר מזהה AID שמשויך לשירות שלכם.

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

יכולת לדור בכפיפה עם כרטיסים עם רכיב מאובטח

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

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

כשקורא ה-NFC שולח APDU עם SELECT AID, בקר ה-NFC מנתח אותו ובודק אם מזהי ה-AID תואמים למזהי AID כלשהם בטבלת הניתוב שלו. אם הוא תואם, ה-APDU הזה וכל ה-APDUs הבאים אחריו נשלחים ליעד שמשויך ל-AID, עד שמתקבל APDU נוסף של SELECT AID או שהקישור ל-NFC נקטע.

איור 4 ממחיש את הארכיטקטורה הזו:

תרשים שבו קורא NFC מתקשר עם רכיב מאובטח ועם המעבד
איור 4. מכשירי Android שפועלים עם רכיב מאובטח ועם אמולציה של כרטיס מארח.

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

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

בקטע הבא מוסבר איך להצהיר על מזהי AID לאפליקציות שמשתמשות ברכיב מאובטח להדמיית כרטיס.

רישום AID של רכיב מאובטח

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

  • הפעולה שמשמשת במסנן הכוונה צריכה להיות מוגדרת כ-SERVICE_INTERFACE.
  • צריך להגדיר את מאפיין השם של המטא-נתונים לערך SERVICE_META_DATA.
  • קובץ ה-XML של המטא-נתונים חייב להשתמש בתג הבסיס (root) <offhost-apdu-service>.

    <service android:name=".MyOffHostApduService" android:exported="true"
           android:permission="android.permission.BIND_NFC_SERVICE">
      <intent-filter>
          <action android:name="android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE"/>
      </intent-filter>
      <meta-data android:name="android.nfc.cardemulation.off_host_apdu_service"
                 android:resource="@xml/apduservice"/>
    </service>

דוגמה לקובץ apduservice.xml התואם שמירשם שני מזהי AID:

<offhost-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
           android:description="@string/servicedesc">
    <aid-group android:description="@string/subscription" android:category="other">
        <aid-filter android:name="F0010203040506"/>
        <aid-filter android:name="F0394148148100"/>
    </aid-group>
</offhost-apdu-service>

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

המאפיין android:apduServiceBanner נדרש לשירותים מחוץ למארח שהם אפליקציות תשלומים, וכדי שאפשר יהיה לבחור אותם כאפליקציית תשלומים שמוגדרת כברירת מחדל.

קריאה לשירות מחוץ למארח

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

HCE ואבטחה

ארכיטקטורת HCE מספקת רכיב אבטחה מרכזי אחד: השירות מוגן על ידי הרשאת המערכת BIND_NFC_SERVICE, ולכן רק מערכת ההפעלה יכולה לקשר את השירות ולתקשר איתו. כך אפשר לוודא שכל APDU שאתם מקבלים הוא למעשה APDU שהמערכת הפעלה קיבלה מבקר ה-NFC, ושכל APDU שאתם שולחים בחזרה עובר רק למערכת ההפעלה, שמעבירה את ה-APDU ישירות לבקר ה-NFC.

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

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

פרטים ופרמטרים של פרוטוקול

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

פרוטוקול Nfc-A (ISO/IEC 14443 type A) למניעת התנגשויות והפעלה

כחלק מהפעלת פרוטוקול Nfc-A, מתבצעת החלפה של כמה פריימים.

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

לאחר מכן, קורא ה-NFC יכול לבחור את מכשיר ה-HCE על ידי שליחת הפקודה SEL_REQ. בתגובה SEL_RES של מכשיר ה-HCE מוגדר לפחות הביט השישי (0x20), שמציין שהמכשיר תומך ב-ISO-DEP. שימו לב שיכול להיות שגם ביטים אחרים ב-SEL_RES מוגדרים, למשל כדי לציין תמיכה בפרוטוקול NFC-DEP‏ (p2p). מכיוון שיכול להיות שביטים אחרים מוגדרים, קוראים שרוצים לקיים אינטראקציה עם מכשירי HCE צריכים לבדוק באופן מפורש את הביט השישי בלבד, ולא להשוות את SEL_RES המלא לערך 0x20.

הפעלת ISO-DEP

אחרי הפעלת פרוטוקול Nfc-A, קורא ה-NFC מפעיל את הפעלת פרוטוקול ISO-DEP. הוא שולח פקודה מסוג RATS (בקשה לתשובה לבחירה). בקר ה-NFC יוצר את תגובת ה-RATS, ה-ATS. לא ניתן להגדיר את ה-ATS באמצעות שירותי HCE. עם זאת, הטמעות של HCE חייבות לעמוד בדרישות של NFC Forum לתגובה של ATS, כך שקוראי NFC יכולים לסמוך על כך שהפרמטרים האלה מוגדרים בהתאם לדרישות של NFC Forum לכל מכשיר HCE.

בקטע הבא מופיעים פרטים נוספים על הבייטים הנפרדים בתשובה של ATS שמספק בקר ה-NFC במכשיר HCE:

  • TL: אורך התגובה של מערכת ATS. אסור לציין אורך של יותר מ-20 בייט.
  • T0: צריך להגדיר את הביטים 5, 6 ו-7 בכל מכשירי ה-HCE, כדי לציין ש-TA(1), ‏ TB(1) ו-TC(1) כלולים בתגובה של ATS. הביטים 1 עד 4 מציינים את FSCI, שמקודד את גודל המסגרת המקסימלי. במכשירי HCE, הערך של FSCI צריך להיות בין 0h ל-8h.
  • T(A)1: הגדרת קצב הנתונים בין הקורא לבין המהדר, והאם הוא יכול להיות אסימטרי. אין דרישות או הבטחות לגבי קצב העברת הנתונים במכשירי HCE.
  • T(B)1: הביטים 1 עד 4 מציינים את המספר השלם של זמן ההגנה על מסגרת ההתחלה (SFGI). במכשירי HCE, הערך של SFGI חייב להיות פחות מ-8 שעות. הביטים 5 עד 8 מציינים את המספר המלא של זמן ההמתנה לפרסום פריים (FWI) ומקודדים את זמן ההמתנה לפרסום פריים (FWT). במכשירי HCE, הערך של FWI חייב להיות קטן מ-8 שעות.
  • T(C)1: ביט 5 מציין תמיכה ב'תכונות פרוטוקול מתקדמות'. יכול להיות שמכשירי HCE יתמכו בתכונות הפרוטוקול המתקדמות, ויכול להיות שלא. ביט 2 מציין תמיכה ב-DID. יכול להיות שמכשירי HCE תומכים ב-DID ויכול להיות שלא. ביט 1 מציין תמיכה ב-NAD. מכשירים עם HCE לא יכולים לתמוך ב-NAD ולהגדיר את ביט 1 לאפס.
  • בייטים היסטוריים: מכשירים עם HCE עשויים להחזיר עד 15 בייטים היסטוריים. קוראי NFC שרוצים לקיים אינטראקציה עם שירותי HCE לא צריכים להניח דבר לגבי התוכן של הבייטים ההיסטוריים או נוכחותם.

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

  • הערך של FSCI ב-T0 חייב להיות בין 2 שעות ל-8 שעות.
  • צריך להגדיר את T(A)1 לערך 0x80, כדי לציין שרק קצב העברת הנתונים של 106kbit/s נתמך, ושאין תמיכה בקצב העברת נתונים אסימטרי בין הקורא לבין המהדר.
  • הערך של FWI ב-T(B)1 חייב להיות 7 שעות לכל היותר.

החלפת נתונים ב-APDU

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