Android सिस्टम की कुंजी की पुष्टि करने वाला प्रोग्राम

Android के लिए Key Verifier, उपयोगकर्ताओं को एक जैसा और सुरक्षित तरीका उपलब्ध कराता है. इससे वे यह पुष्टि कर पाते हैं कि वे एंड-टू-एंड एन्क्रिप्शन (E2EE) वाले आपके ऐप्लिकेशन में सही व्यक्ति से बातचीत कर रहे हैं. यह उपयोगकर्ताओं को मैन-इन-द-मिडल हमलों से बचाता है. इसके लिए, यह उन्हें भरोसेमंद और एक जैसे सिस्टम यूज़र इंटरफ़ेस (यूआई) के ज़रिए, किसी संपर्क के सार्वजनिक एन्क्रिप्शन पासकोड की पुष्टि करने की अनुमति देता है.

यह सुविधा, Key Verifier की मदद से उपलब्ध कराई जाती है. यह एक सिस्टम सेवा है, जो Google System Services का हिस्सा है. इसे Play Store का इस्तेमाल करके डिस्ट्रिब्यूट किया जाता है. यह E2EE की सार्वजनिक कुंजियों के लिए, डिवाइस पर मौजूद एक सेंट्रलाइज़्ड रिपॉज़िटरी के तौर पर काम करता है.

आपको Key Verifier के साथ इंटिग्रेट क्यों करना चाहिए

  • एक जैसा यूज़र एक्सपीरियंस दें: पुष्टि करने के लिए अपना फ़्लो बनाने के बजाय, सिस्टम के स्टैंडर्ड यूज़र इंटरफ़ेस (यूआई) को लॉन्च किया जा सकता है. इससे उपयोगकर्ताओं को उनके सभी ऐप्लिकेशन पर एक जैसा और भरोसेमंद अनुभव मिलता है.
  • उपयोगकर्ताओं का भरोसा बढ़ता है: सिस्टम की मदद से पुष्टि की स्थिति के बारे में साफ़ तौर पर बताने से, उपयोगकर्ताओं को भरोसा होता है कि उनकी बातचीत सुरक्षित और निजी है.
  • डेवलपमेंट के खर्च को कम करें: कुंजी की पुष्टि करने वाले यूज़र इंटरफ़ेस (यूआई), स्टोरेज, और स्टेटस मैनेजमेंट की जटिलता को सिस्टम सर्विस पर ऑफ़लोड करें.

मुख्य शब्द

  • lookupKey: यह संपर्क के लिए एक ओपेक और स्थायी आइडेंटिफ़ायर होता है. इसे संपर्क की जानकारी देने वाली सेवा के LOOKUP_KEY कॉलम में सेव किया जाता है. contact ID के उलट, lookupKey में संपर्क की जानकारी बदलने या मर्ज करने पर भी कोई बदलाव नहीं होता. इसलिए, किसी संपर्क को रेफ़र करने के लिए, lookupKey का इस्तेमाल करने का सुझाव दिया जाता है.
  • accountId: यह किसी डिवाइस पर उपयोगकर्ता के खाते के लिए, ऐप्लिकेशन के हिसाब से तय किया गया आइडेंटिफ़ायर होता है. इस आईडी को आपका ऐप्लिकेशन तय करता है. इससे, एक ही उपयोगकर्ता के कई खातों के बीच अंतर करने में मदद मिलती है. यह यूज़र इंटरफ़ेस में उपयोगकर्ता को दिखता है. हमारा सुझाव है कि आप फ़ोन नंबर, ईमेल पता या उपयोगकर्ता हैंडल जैसे काम के कॉन्टेंट का इस्तेमाल करें
  • deviceId: यह किसी उपयोगकर्ता के खाते से जुड़े किसी डिवाइस का यूनीक आइडेंटिफ़ायर होता है. इससे उपयोगकर्ता के पास कई डिवाइस हो सकते हैं. हर डिवाइस के लिए, क्रिप्टोग्राफ़िक कुंजियों का अपना सेट होता है. यह ज़रूरी नहीं है कि यह किसी डिवाइस का नाम हो. हालांकि, इसका इस्तेमाल एक ही खाते के लिए इस्तेमाल की गई कई कुंजियों के बीच अंतर करने के लिए किया जा सकता है

शुरू करना

शुरू करने से पहले, KeyVerifier सेवा के साथ कम्यूनिकेट करने के लिए अपना ऐप्लिकेशन सेट अप करें.

अनुमतियां तय करें: AndroidManifest.xml में, ये अनुमतियां तय करें. आपको रनटाइम के दौरान भी उपयोगकर्ता से इनके लिए अनुरोध करना होगा.

<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />

क्लाइंट इंस्टेंस पाएं: ContactKeys का इंस्टेंस पाएं. यह एपीआई का आपका एंट्री पॉइंट है.

import com.google.android.gms.contactkeys.ContactKeys

val contactKeyClient = ContactKeys.getClient(context)

मैसेजिंग ऐप्लिकेशन डेवलपर के लिए दिशा-निर्देश

मैसेजिंग ऐप्लिकेशन के डेवलपर के तौर पर, आपकी मुख्य भूमिका यह है कि आप Key Verifier सेवा पर, अपने उपयोगकर्ताओं की सार्वजनिक कुंजियां और उनके संपर्कों की कुंजियां पब्लिश करें.

किसी उपयोगकर्ता की सार्वजनिक कुंजियां पब्लिश करना

अगर आपको अन्य लोगों को अपना उपयोगकर्ता नाम ढूंढने और उसकी पुष्टि करने की अनुमति देनी है, तो डिवाइस पर मौजूद रिपॉज़िटरी में अपनी सार्वजनिक कुंजी पब्लिश करें. बेहतर सुरक्षा के लिए, Android Keystore में कुंजियां बनाएं.

import com.google.android.gms.contactkeys.ContactKeyClient
import com.google.android.gms.tasks.Tasks

suspend fun publishSelfKey(
    contactKeyClient: ContactKeyClient,
    accountId: String,
    deviceId: String,
    publicKey: ByteArray
) {
    try {
        Tasks.await(
          contactKeyClient.updateOrInsertE2eeSelfKey(
            deviceId,
            accountId,
            publicKey
          )
        )
        // Self key published successfully.
    } catch (e: Exception) {
        // Handle error.
    }
}

संपर्कों के साथ सार्वजनिक कुंजियां जोड़ना

जब आपके ऐप्लिकेशन को उपयोगकर्ता के किसी संपर्क के लिए सार्वजनिक पासकोड मिलता है, तो आपको उसे सेव करना होगा. साथ ही, उसे सेंट्रल रिपॉज़िटरी में उस संपर्क से जोड़ना होगा. इससे कुंजी की पुष्टि की जा सकती है. साथ ही, अन्य ऐप्लिकेशन को संपर्क के लिए पुष्टि की स्थिति दिखाने की अनुमति मिलती है. इसके लिए, आपको Android Contacts Provider से संपर्क का lookupKey चाहिए. यह आम तौर पर तब ट्रिगर होता है, जब आपके कुंजी डिस्ट्रिब्यूशन सर्वर से कोई कुंजी फ़ेच की जा रही हो या स्थानीय कुंजियों को समय-समय पर सिंक किया जा रहा हो.

import com.google.android.gms.contactkeys.ContactKeyClient
import com.google.android.gms.tasks.Tasks

suspend fun storeContactKey(
    contactKeyClient: ContactKeyClient,
    contactLookupKey: String,
    contactAccountId: String,
    contactDeviceId: String,
    contactPublicKey: ByteArray
) {
    try {
        Tasks.await(
            contactKeyClient.updateOrInsertE2eeContactKey(
                contactLookupKey,
                contactDeviceId,
                contactAccountId,
                contactPublicKey
            )
        )
        // Contact's key stored successfully.
    } catch (e: Exception) {
        // Handle error.
    }
}

कुंजियां और पुष्टि की स्थिति वापस पाना

कुंजियां पब्लिश करने के बाद, उपयोगकर्ता व्यक्ति के सामने मौजूद क्यूआर कोड को स्कैन करके उनकी पुष्टि कर सकते हैं. आपके ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) में यह दिखना चाहिए कि बातचीत में पुष्टि की गई कुंजी का इस्तेमाल किया जा रहा है या नहीं. हर कुंजी के लिए, पुष्टि होने की स्थिति होती है. इसका इस्तेमाल करके, अपने यूज़र इंटरफ़ेस (यूआई) को सूचना दी जा सकती है.

पुष्टि की स्थितियों के बारे में जानें:

  • UNVERIFIED: यह हर नई कुंजी के लिए डिफ़ॉल्ट स्थिति होती है. इसका मतलब है कि कुंजी मौजूद है, लेकिन उपयोगकर्ता ने अभी तक इसकी पुष्टि नहीं की है. अपने यूज़र इंटरफ़ेस (यूआई) में, इसे सामान्य स्थिति के तौर पर माना जाना चाहिए. साथ ही, आम तौर पर कोई खास इंडिकेटर नहीं दिखाना चाहिए.

  • VERIFIED: इस स्टेटस से पता चलता है कि इस पर ज़्यादा भरोसा किया जा सकता है. इसका मतलब है कि उपयोगकर्ता ने पुष्टि करने की प्रोसेस (जैसे, क्यूआर कोड स्कैन करना) पूरी कर ली है. साथ ही, उसने पुष्टि की है कि कुंजी, उस संपर्क से जुड़ी है जिसके लिए उसे शेयर किया गया था. अपने यूज़र इंटरफ़ेस (यूआई) में, आपको साफ़ तौर पर सकारात्मक इंडिकेटर दिखाना चाहिए. जैसे, हरे रंग का सही का निशान या शील्ड.

  • VERIFICATION_FAILED: यह चेतावनी की स्थिति है. इसका मतलब है कि संपर्क से जुड़ी कुंजी, पहले पुष्टि की गई कुंजी से मेल नहीं खाती. ऐसा तब हो सकता है, जब किसी संपर्क को नया डिवाइस मिलता है. हालांकि, इससे सुरक्षा से जुड़े संभावित खतरे का भी पता चल सकता है. अपने यूज़र इंटरफ़ेस (यूआई) में, उपयोगकर्ता को प्रमुखता से चेतावनी दें. साथ ही, उसे संवेदनशील जानकारी भेजने से पहले फिर से पुष्टि करने का सुझाव दें.

किसी संपर्क से जुड़ी सभी कुंजियों के लिए, कुल स्थिति वापस पाई जा सकती है. हमारा सुझाव है कि एक से ज़्यादा कुंजियां मौजूद होने पर, स्थिति को ठीक करने के लिए VerificationState.leastVerifiedFrom() का इस्तेमाल करें. इससे VERIFIED के मुकाबले VERIFICATION_FAILED को सही तरीके से प्राथमिकता दी जाएगी.

  • संपर्क लेवल पर एग्रीगेट स्टेटस पाना
import com.google.android.gms.contactkeys.ContactKeyClient
import com.google.android.gms.contactkeys.constants.VerificationState
import com.google.android.gms.tasks.Tasks

suspend fun displayContactVerificationStatus(
    contactKeyClient: ContactKeyClient,
    contactLookupKey: String
) {
    try {
        val keysResult = Tasks.await(contactKeyClient.getAllE2eeContactKeys(contactLookupKey))
        val states =
          keysResult.keys.map { VerificationState.fromState(it.localVerificationState) }
        val contactStatus = VerificationState.leastVerifiedFrom(states)
        updateUi(contactLookupKey, contactStatus)
    } catch (e: Exception) {
        // Handle error.
    }
}
  • खाता लेवल पर एग्रीगेट स्टेटस पाना
import com.google.android.gms.contactkeys.ContactKeyClient
import com.google.android.gms.contactkeys.constants.VerificationState
import com.google.android.gms.tasks.Tasks

suspend fun displayAccountVerificationStatus(
    contactKeyClient: ContactKeyClient,
    accountId: String
) {
    try {
        val keys = Tasks.await(contactKeyClient.getE2eeAccountKeysForAccount(accountId))
        val states = keys.map { VerificationState.fromState(it.localVerificationState) }
        val accountStatus = VerificationState.leastVerifiedFrom(states)
        updateUi(accountId, accountStatus)
    } catch (e: Exception) {
        // Handle error.
    }
}

मुख्य बदलावों को रीयल टाइम में देखना

यह पक्का करने के लिए कि आपके ऐप्लिकेशन का यूज़र इंटरफ़ेस हमेशा भरोसेमंद होने की सही स्थिति दिखाए, आपको अपडेट के लिए सुनना चाहिए. हमारा सुझाव है कि फ़्लो-आधारित एपीआई का इस्तेमाल करें. यह एपीआई, सदस्यता लिए हुए खाते के लिए कोई कुंजी जोड़े जाने, हटाए जाने या उसके पुष्टि करने की स्थिति में बदलाव होने पर, कुंजियों की नई सूची जारी करता है. यह खास तौर पर, ग्रुप बातचीत में शामिल सदस्यों की सूची को अपडेट रखने के लिए काम आता है. किसी कुंजी की पुष्टि की स्थिति तब बदल सकती है, जब:

  • उपयोगकर्ता पुष्टि करने की प्रोसेस पूरी कर लेता है. जैसे, क्यूआर कोड स्कैन करना.
  • किसी संपर्क की कुंजी में बदलाव किया गया है. इसलिए, अब यह पुष्टि की गई पिछली वैल्यू से मेल नहीं खाती.
fun observeKeyUpdates(contactKeyClient: ContactKeyClient, accountIds: List<String>) {
    lifecycleScope.launch {
        contactKeyClient.getAccountContactKeysFlow(accountIds)
            .collect { updatedKeys ->
                // A key was added, removed, or updated.
                // Refresh your app's UI and internal state.
                refreshUi(updatedKeys)
            }
    }
}

व्यक्तिगत तौर पर कुंजी की पुष्टि करना

उपयोगकर्ताओं के लिए, किसी कुंजी की पुष्टि करने का सबसे सुरक्षित तरीका, व्यक्ति के तौर पर पुष्टि करना है. इसके लिए, अक्सर क्यूआर कोड स्कैन किया जाता है या संख्याओं के क्रम की तुलना की जाती है. Key Verifier ऐप्लिकेशन, इस प्रोसेस के लिए स्टैंडर्ड यूज़र इंटरफ़ेस (यूआई) फ़्लो उपलब्ध कराता है. आपका ऐप्लिकेशन इन्हें लॉन्च कर सकता है. पुष्टि करने की कोशिश के बाद, एपीआई अपने-आप कुंजी की पुष्टि की स्थिति को अपडेट करता है. साथ ही, अगर कुंजी के अपडेट पर नज़र रखी जा रही है, तो आपके ऐप्लिकेशन को इसकी सूचना दी जाएगी.

  • उपयोगकर्ता के चुने गए संपर्क के लिए, कुंजी की पुष्टि करने की प्रोसेस शुरू करें चुने गए संपर्क के lookupKey का इस्तेमाल करके, getScanQrCodeIntent की ओर से उपलब्ध कराया गया PendingIntent लॉन्च करें. यूज़र इंटरफ़ेस (यूआई) की मदद से, उपयोगकर्ता दिए गए संपर्क के लिए सभी कुंजियों की पुष्टि कर सकता है.
import android.app.ActivityOptions
import android.app.PendingIntent
import com.google.android.gms.contactkeys.ContactKeyClient
import com.google.android.gms.tasks.Tasks

suspend fun initiateVerification(contactKeyClient: ContactKeyClient, lookupKey: String) {
    try {
        val pendingIntent = Tasks.await(contactKeyClient.getScanQrCodeIntent(lookupKey))
        val options =
          ActivityOptions.makeBasic()
            .setPendingIntentBackgroundActivityStartMode(
              ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
            )
            .toBundle()
        pendingIntent.send(options)
    } catch (e: Exception) {
        // Handle error.
    }
}
  • उपयोगकर्ता के चुने गए खाते के लिए, कुंजी की पुष्टि करने की प्रोसेस शुरू करें अगर उपयोगकर्ता को किसी ऐसे खाते की पुष्टि करनी है जो किसी संपर्क से सीधे तौर पर लिंक नहीं है (या किसी संपर्क के किसी खास खाते की पुष्टि करनी है), तो getScanQrCodeIntentForAccount की ओर से PendingIntent लॉन्च किया जा सकता है. आम तौर पर, इसका इस्तेमाल आपके अपने ऐप्लिकेशन के पैकेज के नाम और खाता आईडी के लिए किया जाता है.
import android.app.ActivityOptions
import android.app.PendingIntent
import com.google.android.gms.contactkeys.ContactKeyClient
import com.google.android.gms.tasks.Tasks

suspend fun initiateVerification(contactKeyClient: ContactKeyClient, packageName: String, accountId: String) {
    try {
        val pendingIntent = Tasks.await(contactKeyClient.getScanQrCodeIntentForAccount(packageName, accountId))
        // Allow activity start from background on Android SDK34+
        val options =
          ActivityOptions.makeBasic()
            .setPendingIntentBackgroundActivityStartMode(
              ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
            )
            .toBundle()
        pendingIntent.send(options)
    } catch (e: Exception) {
        // Handle error.
    }
}