Ini Readme menuntun Anda melalui langkah-langkah untuk menghidupkan aplikasi Android E2EE NEXMO In-Apping. Ini juga mencoba menjelaskan perubahan kunci pada kode NEXMO asli di GitHub.
Pertama, mari kita mulai dengan penyegaran cepat tentang apa E2EE (enkripsi ujung-ke-ujung) dan bagaimana cara kerjanya. E2EE Sederhana: Ketika Anda mengetik pesan obrolan, itu akan dienkripsi di perangkat seluler Anda (atau di browser Anda) dan hanya didekripsi ketika mitra obrolan Anda menerimanya dan ingin menampilkannya di jendela obrolan.
Catatan: Gambar perlu diperbarui, itu langsung dirujuk dari proyek Back4app
Pesannya tetap dienkripsi saat bepergian melalui Wi-Fi dan Internet, melalui server cloud / web, ke dalam database, dan dalam perjalanan kembali ke mitra obrolan Anda. Dengan kata lain, tidak ada jaringan atau server yang memiliki petunjuk tentang apa yang Anda berdua mengobrol.
Catatan: Gambar perlu diperbarui, itu langsung dirujuk dari proyek Back4app
Yang sulit dalam enkripsi ujung ke ujung adalah tugas mengelola kunci enkripsi dengan cara yang hanya pengguna yang terlibat dalam obrolan yang dapat mengaksesnya dan tidak ada orang lain. Dan ketika saya menulis "tidak ada orang lain", saya benar -benar bersungguh -sungguh: bahkan orang dalam penyedia cloud Anda atau bahkan Anda, pengembang, keluar; [Tidak ada kesalahan yang tidak disengaja] [_ Kesalahan] atau mengintip secara hukum dimungkinkan. Menulis crypto, terutama untuk beberapa platform itu sulit: menghasilkan angka acak yang sebenarnya, memilih algoritma yang tepat, dan memilih mode enkripsi yang tepat hanyalah beberapa contoh yang membuat sebagian besar pengembang melambaikan tangan mereka di udara dan akhirnya tidak melakukannya.
Teknologi enkripsi end-to-end Virgil memungkinkan pengembang NEXMO untuk mengabaikan semua detail yang menjengkelkan ini dan hanya dengan cepat dan sekadar mengenkripsi pesan obrolan dalam aplikasi pengguna mereka.
Untuk intro, ini adalah bagaimana kami akan meningkatkan aplikasi Android NEXMO untuk dienkripsi ujung ke ujung:
Catatan: Gambar perlu diperbarui, itu langsung dirujuk dari proyek Back4app
Kami akan menerbitkan kunci publik pengguna ke layanan kartu Virgil sehingga pengguna obrolan dapat saling memandang dan dapat mengenkripsi pesan untuk satu sama lain. Kunci pribadi akan tetap di perangkat pengguna.
Oke, cukup berbicara: mari kita mulai lakukan!
Aplikasi API Server sudah diinstal dan tersedia oleh tautan
Buka kelas Virgilfacade dan tentukan konstanta dari tabel di bawah ini
| Nama konstan | Keterangan |
|---|---|
| Virgil_access_token | Token Akses Aplikasi Virgil Anda. Anda harus menghasilkan token ini di dasbor atau menggunakan yang sudah ada |
| Virgil_app_public_key | Aplikasi Virgil Anda kunci publik sebagai string yang dikodekan basis64 |
| Virgil_auth_public_key | Kunci Publik Server Otentikasi Virgil sebagai string yang dikodekan Base64 |
| AUTH_SERVER_URL | URL Server API Aplikasi |
Dua istilah penting di sini:
Dalam versi E2EE dari aplikasi pesan dalam aplikasi, kami akan menghasilkan kunci pribadi untuk setiap pengguna pada waktu pendaftaran. Kami kemudian akan menghasilkan kunci publik pengguna dan menerbitkannya dalam bentuk kartu Virgil baru untuk pengguna, sehingga pengguna lain dapat menemukannya dan mengenkripsi pesan untuk kami.
// Generate private key
val virgilKey = virgilApi.keys.generate()
// Create Virgil Card
val customFields = HashMap < String , String >()
customFields.put( " deviceId " , Settings . Secure . ANDROID_ID )
val virgilCard = virgilApi.getCards().create(userName, virgilKey,
" name " , customFields)Untuk membuat kartu Virgil, Anda akan memerlukan kunci pribadi aplikasi Virgil Anda (jika tidak, siapa pun dapat mempublikasikan kartu untuk aplikasi Anda tanpa kendali Anda). Karena Anda tidak boleh menyimpan kunci ini di perangkat seluler, kami akan menyimpannya di aplikasi web Anda dan membuat aplikasi web Anda memverifikasi pengguna sebelum pembuatan kartu.
val csr = CSR (virgilCard.export())
val response = NexmoApp .instance.serverClient.signup(csr).execute()
var registrationData = response.body() !! RegistrationData juga berisi JWT yang harus digunakan untuk login Nexmo dengan ConversationClient .
Aplikasi seluler Anda adalah satu -satunya tempat di mana kunci pribadi Anda disimpan. Jadi, Anda harus menyimpan kunci pribadi untuk penggunaan di masa depan. Jika Anda kehilangan kunci pribadi, Anda tidak akan dapat mendekripsi pesan yang dikirimkan kepada Anda.
NexmoApp .instance.db.userDao().insert( User (registrationData.user.id,
userName, registrationData.user.href, createdVirgilCard.id,
registrationData.user.virgilCard, virgilKey.privateKey.value)) Inisialisasi SecureChat dan hasilkan kunci satu kali untuk penggunaan di masa depan.
crypto = VirgilCrypto ()
keyStorage = JsonFileKeyStorage (
context.getFilesDir().getAbsolutePath(), userName + " .ks " )
userDataStorage = JsonFileUserDataStorage (
context.getFilesDir().getAbsolutePath(), userName + " .ds " )
// Configure PFS
var chatContext = SecureChatContext (virgilCard, privateKey,
crypto, VIRGIL_ACCESS_TOKEN )
chatContext.keyStorage = keyStorage
chatContext.deviceManager = DefaultDeviceManager ()
chatContext.userDataStorage = userDataStorage
secureChat = SecureChat (chatContext)
secureChat?.rotateKeys( 10 )Setelah login, kami mendapatkan token otentikasi Virgil dari server. Lihat detail aliran oleh tautan.
// Get challenge message
val challengeMessage = this .authClient.getChallengeMessage(cardId)
// Decode encrypted message
val decodedMessage = this .crypto.decrypt(
ConvertionUtils .base64ToBytes(challengeMessage.encryptedMessage),
this .privateKey)
// Encrypt decoded message with application public key
val appPublicKey = this .crypto.importPublicKey(
ConvertionUtils .base64ToBytes( VIRGIL_AUTH_PUBLIC_KEY ))
val newEncryptedMessage =
this .crypto.encrypt(decodedMessage, appPublicKey)
val message = ConvertionUtils .toBase64String(newEncryptedMessage)
// Send acknowledge to auth server
val code = this .authClient.acknowledge(
challengeMessage.authorizationGrantId, message)
// Obtain access token
val accessTokenResponse = this .authClient.obtainAccessToken(code)
val virgilToken = accessTokenResponse.accessToken Masuk Nexmo dengan ConversationClient .
val response = NexmoApp .instance.serverClient
.jwt( " Bearer ${virgilToken} " ).execute()
val jwt = response.body() !! .jwtMari kita muat daftar pengguna terdaftar.
val virgilToken = VirgilFacade .instance.getVirgilToken()
val response = NexmoApp .instance.serverClient
.getUsers( " Bearer ${virgilToken} " ).execute()
var users = response.body()Mulailah percakapan.
conversationClient.newConversation( true , userName,
object : RequestHandler < Conversation > {
override fun onError ( apiError : NexmoAPIError ? ) {
closeWithError( " Conversation is not created " , apiError)
}
override fun onSuccess ( result : Conversation ? ) {
Log .d( TAG , " Created conversation ${result?.conversationId} for user ${userName} " )
mConversation = result
mConversation?.invite(userName, object : RequestHandler < Member > {
override fun onError ( apiError : NexmoAPIError ? ) {
closeWithError( " Can't invite user ${userName} into conversation " , apiError)
}
override fun onSuccess ( result : Member ? ) {
Log .d( TAG , " User ${result?.name} invited into conversation " )
mMemberCard = VirgilFacade .instance.virgilApi.cards.find(result?.name).firstOrNull()?.model
// initizlize conversation
.. .
}
})
}
})Anda akan membutuhkan kartu Virgil dari pengguna yang Anda mulai percakapan.
val userName = NexmoUtils .getConversationPartner(mConversation !! )?.name
mMemberCard = VirgilFacade .instance.virgilApi.cards.find(userName).firstOrNull()?.modelSekarang Anda dapat mengirim dan menerima pesan.
// Get active session
var secureSession = secureChat !! .activeSession(recipientCard.getId());
// If no session, start a new one
if (secureSession == null ) {
secureSession = secureChat !! .startNewSession(recipientCard, null );
}
// Encrypt message text
val encryptedText = secureSession.encrypt(text);Anda tidak dapat mendekripsi pesan yang Anda terenkripsi. Karena itu, Anda harus menyimpan pesan asli secara lokal. Untuk memastikan bahwa pesan itu tidak dirusak, buat kode hash dari teks terenkripsi.
mConversation?.sendText(encryptedMessage,
object : RequestHandler < Event > {
override fun onSuccess ( result : Event ? ) {
// Save message in database
val hash = encryptedMessage.hashCode().toString()
val msg = Message (hash, mConversation !! .conversationId, result !! .member.userId, text)
messageDao.insert(msg)
}
override fun onError ( apiError : NexmoAPIError ? ) {
Log .e( TAG , " Send message error " , apiError)
}
})Mari kita identifikasi pengirim pesan terlebih dahulu.
if (conversationClient.user.userId.equals(textMessage.member.userId)) {
// This message was sent by myself. Find in database
....
} else {
// Message from another conversation member
.. .
}Jika itu pesan Anda sendiri, cukup dapatkan dari database dengan kode hash teks terenkripsi.
val hash = textMessage.text.hashCode().toString()
val message = messageDao.getMessage(mConversation !! .conversationId, hash)
val decryptedText = message.textJika pesan dikirim oleh orang lain, mari kita dekripsi.
// Loadup user session
var secureSession = secureChat !! .loadUpSession(senderCard, encryptedMessage, null )
val decryptedText = secureSession.decrypt(encryptedMessage)