Key Verifier untuk Android menyediakan cara terpadu dan aman bagi pengguna untuk memverifikasi bahwa mereka berkomunikasi dengan orang yang tepat di aplikasi pesan terenkripsi end-to-end (E2EE) Anda. Key Verifier melindungi pengguna dari serangan man-in-the-middle dengan memungkinkan mereka mengonfirmasi keaslian kunci enkripsi publik kontak melalui UI sistem yang tepercaya dan konsisten.
Fitur ini disediakan oleh Key Verifier, layanan sistem yang merupakan bagian dari Layanan Sistem Google dan didistribusikan menggunakan Play Store. Layanan ini berfungsi sebagai repositori terpusat di perangkat untuk kunci publik E2EE.
Alasan Anda harus berintegrasi dengan Key Verifier
- Menyediakan UX terpadu: Daripada membuat alur verifikasi sendiri, Anda dapat meluncurkan UI standar sistem, sehingga memberikan pengalaman yang konsisten dan tepercaya kepada pengguna di semua aplikasi mereka.
- Meningkatkan kepercayaan pengguna: Status verifikasi yang jelas dan didukung sistem meyakinkan pengguna bahwa percakapan mereka aman dan bersifat pribadi.
- Mengurangi biaya pengembangan: Menghilangkan kompleksitas UI verifikasi kunci, penyimpanan, dan pengelolaan status ke layanan sistem.
Istilah utama
- lookupKey: ID persisten buram untuk kontak, yang disimpan di kolom
LOOKUP_KEY penyedia kontak. Tidak seperti
contact ID
,lookupKey
tetap stabil meskipun detail kontak pokok diubah atau digabungkan, sehingga menjadikannya cara yang direkomendasikan untuk mereferensikan kontak. - accountId: ID khusus aplikasi untuk akun pengguna di perangkat. ID ini ditentukan oleh aplikasi Anda dan membantu membedakan beberapa akun yang mungkin dimiliki satu pengguna. Informasi ini ditampilkan kepada pengguna di UI, sebaiknya gunakan sesuatu yang bermakna seperti nomor telepon, alamat email, atau nama pengguna
- deviceId: ID unik untuk perangkat tertentu yang terkait dengan akun pengguna. Hal ini memungkinkan pengguna memiliki beberapa perangkat, yang masing-masing memiliki serangkaian kunci kriptografisnya sendiri. Tidak selalu mewakili perangkat fisik, tetapi dapat menjadi cara untuk membedakan beberapa kunci yang digunakan untuk akun yang sama
Memulai
Sebelum memulai, siapkan aplikasi Anda untuk berkomunikasi dengan layanan Key Verifier.
Mendeklarasikan izin: Di AndroidManifest.xml, deklarasikan izin berikut. Anda juga harus memintanya dari pengguna saat runtime.
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
Dapatkan instance klien: Dapatkan instance ContactKeys
, yang merupakan
titik entri Anda ke API.
import com.google.android.gms.contactkeys.ContactKeys
val contactKeyClient = ContactKeys.getClient(context)
Panduan untuk developer aplikasi pesan
Sebagai developer aplikasi pesan, peran utama Anda adalah memublikasikan kunci publik pengguna dan kunci kontak mereka ke layanan Key Verifier.
Memublikasikan kunci publik pengguna
Untuk mengizinkan orang lain menemukan dan memverifikasi pengguna Anda, publikasikan kunci publik mereka ke repositori di perangkat. Untuk keamanan tambahan, pertimbangkan untuk membuat kunci di 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.
}
}
Mengaitkan kunci publik dengan kontak
Saat aplikasi Anda menerima kunci publik untuk salah satu kontak pengguna, Anda harus menyimpannya dan mengaitkannya dengan kontak tersebut di repositori pusat. Hal ini memungkinkan kunci diverifikasi dan aplikasi lain dapat menampilkan status verifikasi untuk kontak. Untuk melakukannya, Anda memerlukan lookupKey kontak dari Penyedia Kontak Android. Hal ini biasanya dipicu saat mengambil kunci dari server distribusi kunci Anda atau selama sinkronisasi berkala kunci lokal.
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.
}
}
Mengambil kunci dan status verifikasi
Setelah Anda memublikasikan kunci, pengguna dapat memverifikasinya melalui pemindaian Kode QR secara langsung. UI aplikasi Anda harus mencerminkan apakah percakapan menggunakan kunci terverifikasi. Setiap kunci memiliki status verifikasi yang dapat Anda gunakan untuk memberi tahu UI Anda.
Memahami status verifikasi:
UNVERIFIED
: Ini adalah status default untuk setiap kunci baru. Artinya, kunci ada, tetapi pengguna belum mengonfirmasi keasliannya. Di UI, Anda harus memperlakukan ini sebagai status netral dan biasanya tidak menampilkan indikator khusus.VERIFIED
: Status ini menunjukkan tingkat kepercayaan yang tinggi. Artinya, pengguna telah berhasil menyelesaikan alur verifikasi (seperti pemindaian Kode QR) dan mengonfirmasi bahwa kunci tersebut milik kontak yang dituju. Di UI, Anda harus menampilkan indikator positif yang jelas, seperti tanda centang atau perisai hijau.VERIFICATION_FAILED
: Ini adalah status peringatan. Hal ini berarti kunci yang terkait dengan kontak tidak cocok dengan kunci yang sebelumnya diverifikasi. Hal ini dapat terjadi jika kontak mendapatkan perangkat baru, tetapi juga dapat mengindikasikan potensi risiko keamanan. Di UI Anda, peringatkan pengguna dengan peringatan yang jelas dan sarankan mereka untuk memverifikasi ulang sebelum mengirim informasi sensitif.
Anda dapat mengambil status gabungan untuk semua kunci yang terkait dengan kontak. Sebaiknya gunakan VerificationState.leastVerifiedFrom()
untuk menyelesaikan status saat ada beberapa kunci, karena akan memprioritaskan VERIFICATION_FAILED
dengan benar daripada VERIFIED
.
- Mendapatkan status gabungan di tingkat kontak
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.
}
}
- Mendapatkan status gabungan di tingkat akun
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.
}
}
Mengamati perubahan utama secara real time
Untuk memastikan UI aplikasi Anda selalu menampilkan status kepercayaan yang benar, Anda harus memantau update. Cara yang direkomendasikan adalah menggunakan Flow-based API, yang memancarkan daftar kunci baru setiap kali kunci untuk akun yang berlangganan ditambahkan, dihapus, atau status verifikasinya berubah. Hal ini sangat berguna untuk menjaga daftar anggota percakapan grup tetap terbaru. Status verifikasi untuk kunci dapat berubah jika:
- Pengguna berhasil menyelesaikan alur verifikasi (misalnya, pemindaian Kode QR).
- Kunci kontak diubah, sehingga tidak lagi cocok dengan nilai yang sebelumnya diverifikasi.
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)
}
}
}
Melakukan verifikasi kunci secara langsung
Cara paling aman bagi pengguna untuk memverifikasi kunci adalah melalui verifikasi secara langsung, sering kali dengan memindai Kode QR atau membandingkan urutan angka. Aplikasi Key Verifier menyediakan alur UI standar untuk proses ini, yang dapat diluncurkan oleh aplikasi Anda. Setelah upaya verifikasi, API akan otomatis memperbarui status verifikasi kunci, dan aplikasi Anda akan diberi tahu jika Anda mengamati update kunci.
- Mulai proses verifikasi kunci untuk kontak yang dipilih pengguna
Luncurkan
PendingIntent
yang disediakan olehgetScanQrCodeIntent
menggunakanlookupKey
kontak yang dipilih. UI memungkinkan pengguna memverifikasi semua kunci untuk kontak tertentu.
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.
}
}
- Mulai proses verifikasi kunci untuk akun yang dipilih pengguna
Jika pengguna ingin memverifikasi akun yang tidak ditautkan langsung ke kontak
(atau akun tertentu dari kontak), Anda dapat meluncurkan
PendingIntent
yang disediakan olehgetScanQrCodeIntentForAccount
. Biasanya digunakan untuk nama paket dan ID akun aplikasi Anda sendiri.
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.
}
}