Ini adalah perpustakaan untuk menyederhanakan pengiriman pesan push end-to-end (E2E) terenkripsi dari server aplikasi berbasis Java ke klien Android. Silakan periksa instruksi di bawah ini dan demo untuk lebih jelasnya.
Untuk menambahkan ketergantungan menggunakan Maven:
Untuk server berbasis Java:
< dependency >
< groupId >com.google.capillary</ groupId >
< artifactId >lib</ artifactId >
< version >1.0.0</ version >
</ dependency >
Untuk Android:
< dependency >
< groupId >com.google.capillary</ groupId >
< artifactId >lib-android</ artifactId >
< version >1.0.0</ version >
</ dependency >
Untuk menambahkan ketergantungan menggunakan Gradle:
dependencies {
compile 'com.google.capillary:lib:1.0.0'
}
dependencies {
compile 'com.google.capillary:lib-android:1.0.0'
}
Untuk menggunakan layanan Push Messaging untuk mengirim pesan ke perangkat yang terhubung, pengembang harus mengirimkannya melalui layanan pesan pihak ketiga, seperti Firebase Cloud Messaging (FCM). Sangat mudah untuk mengenkripsi konten pesan antara pengembang dan layanan pesan menggunakan HTTPS. Layanan pesan utama, termasuk FCM, juga mengenkripsi pesan antara server dan perangkat klien mereka.
Namun, pesan antara server pengembang dan perangkat pengguna tidak dienkripsi ujung ke ujung (E2E):
Enkripsi E2E dapat dicapai dengan menghasilkan pasangan kunci enkripsi asimetris pada klien, mendaftarkan kunci publik dengan layanan pesan pengembang, mengenkripsi pesan keluar dengan kunci publik, dan mendekripsi pesan pada klien menggunakan kunci pribadi:
Kapiler menangani operasi ini untuk layanan pesan push yang digunakan oleh aplikasi Android. Itu termasuk:
Fungsionalitas crypto dan manajemen kunci di semua versi Android kembali ke Kitkat (API level 19).
Alur kerja generasi kunci dan pendaftaran.
Enkripsi pesan (di server) dan dekripsi (pada klien).
Perlindungan integritas untuk mencegah modifikasi pesan.
Cases tepi, seperti pengguna yang menambahkan/mengatur ulang kunci perangkat setelah menginstal aplikasi, pengguna mengatur ulang penyimpanan aplikasi, dll.
Sebagai bonus, ini juga memungkinkan pengembang untuk mensyaratkan bahwa perangkat tidak dikunci sebelum pesan yang dipilih dapat didekripsi. Ini termasuk pesan pada perangkat yang menggunakan enkripsi berbasis file (FBE): Pesan terenkripsi di-cache dalam penyimpanan perangkat dan tombol dekripsi pesan yang dienkripsi (DE) disimpan di android keystore yang membutuhkan otentikasi pengguna. Hal ini memungkinkan pengembang untuk menentukan pesan dengan konten sensitif untuk tetap dienkripsi dalam formulir yang di -cache sampai pengguna membuka kunci dan mendekripsi perangkat mereka.
Dorongan web
Pro: Mengikuti IETF RFC 8291, oleh karena itu memungkinkan pengembang untuk berbagi kode dan infrastruktur penyimpanan utama dengan implementasi dorong web yang ada. Protokol Push Web didasarkan pada algoritma pertukaran kunci elips-kurve diffie-hellman (ECDH), yang sangat efisien untuk perangkat yang dibatasi kinerja. Perhatikan bahwa aplikasi (sebagai lawan dari browser) tidak dapat menerima pesan dorong web mentah melalui FCM, tetapi pesan dorong web dapat dengan mudah dibungkus dalam FCM JSON yang sesuai dengan implementasi proxy, memungkinkan Anda untuk menggunakan infrastruktur yang sama dengan modifikasi kecil.
Con: Android Keystore tidak mendukung operasi kunci ECDH. Kunci dienkripsi hibrida dengan kunci RSA yang disimpan di keystore yang berarti bahwa EC Private Key Plaintext tersedia dalam memori pengguna selama operasi crypto.
RSA-ECDSA
Pro: Hybrid-enkripsi pesan dengan kunci publik RSA yang dihasilkan klien (untuk kerahasiaan) dan menandatangani ciphertext dengan kunci publik ECDSA yang dihasilkan pengembang (untuk integritas). Operasi Crypto RSA (Encrypt, Decrypt) didukung oleh Android Keystore dari SDK Version 18 (Jelly Bean) dan di atasnya, yang berarti materi kunci tidak tersedia di luar lingkungan eksekusi tepercaya. Ini berarti bahkan penyerang canggih dengan akses ke memori perangkat tidak dapat mengakses materi kunci pribadi (misalnya, untuk mendekripsi pesan masa depan yang tiba dalam mode boot langsung).
Con: Kurang efisien daripada ECDH dan kunci tidak kompatibel dengan standar pesan push push.
Kunci terikat auth memastikan bahwa pesan tidak dapat dibaca oleh pengguna ketika perangkat mereka terkunci, artinya konten sensitif tidak akan dapat dibaca oleh para penyurvei bahu atau jika perangkat hilang atau dicuri.
Capillary menyediakan fungsionalitas crypto inti yang diperlukan untuk mengirim (dari server aplikasi) dan menerima pesan push terenkripsi di aplikasi Android. Ini sampul:
Menghasilkan dan menyimpan kunci pada klien.
Mengenkripsi dan menandatangani pesan di server.
Mendekripsi dan memverifikasi pesan terenkripsi pada klien.
Mengidentifikasi pesan terenkripsi yang harus disimpan untuk nanti jika diterima saat perangkat dikunci.
Karena arsitektur sisi-server dan dorongan pesan penggunaan pesan banyak dan beragam, tidak praktis untuk menyediakan API sisi server untuk menangani semua implementasi pesan push yang mungkin. Oleh karena itu, kami telah memisahkan fungsi crypto di atas dari transmisi pesan dan fungsi penyimpanan/pengambilan kunci sisi server. Namun, kami telah memberikan implementasi full-stack yang menggunakan Capillary untuk mengirim pesan push yang dienkripsi E2E dari server berbasis Java ke klien Android di aplikasi demo. Singkatnya, Anda perlu menerapkan aspek -aspek solusi berikut ini sendiri (menggunakan aplikasi demo dan instruksi di bawah ini untuk panduan jika diperlukan):
Ikuti langkah -langkah berikut untuk berintegrasi dengan Perpustakaan Kapiler.
Sebelum perpustakaan kapiler dapat digunakan, harus diinisialisasi saat runtime sebagai berikut:
import com . google . capillary . Config ;
Config . initialize ();
Jika Anda menggunakan algoritma RSA-ECDSA, Anda perlu menghasilkan pasangan kunci publik/pribadi ECDSA dan membuat kunci publik tersedia untuk aplikasi Android Anda (misalnya, sebagai sumber daya mentah) dan kunci pribadi yang tersedia untuk server aplikasi Anda. Gunakan program utilitas yang telah kami berikan untuk menghasilkan pasangan kunci ECDSA seperti itu:
$ ./gradlew tools:installDist
$ ./tools/build/install/tools/bin/ecdsa-key-pair-generator
> --ecdsa_public_key_path= < path to new public key >
> --ecdsa_private_key_path= < path to new private key >
Perpustakaan Capillary menggunakan metode antarmuka CapillaryHandler
untuk memberikan respons, seperti kunci publik, plaintext yang didekripsi, dll., Kembali ke aplikasi Android. Oleh karena itu, langkah pertama dalam mengintegrasikan aplikasi Android dengan perpustakaan kapiler adalah mengimplementasikan antarmuka CapillaryHandler
dengan logika khusus aplikasi Anda untuk menangani respons yang disebutkan di atas. Anda dapat melihat bagaimana aplikasi Android Demo Capillary Library mengimplementasikan antarmuka CapillaryHandler
di kelas DemoCapillaryHandler
.
Setiap pasangan kunci kapiler diidentifikasi oleh ID pasangan kunci (alias Keychain ID), yang merupakan string sewenang -wenang yang terserah Anda untuk memutuskan. Untuk menghasilkan pasangan kunci:
import android . content . Context ;
import com . google . capillary . android . RsaEcdsaKeyManager ;
import com . google . capillary . android . WebPushKeyManager ;
import java . io . InputStream ;
Context context = ... // The current app context.
String keychainId = ... // Some identifier for the key pair.
boolean isAuth = ... // Whether the private key usage should be guarded by the device lock.
// To generate an RSA-ECDSA key pair.
InputStream senderVerificationKey = ... // The ECDSA public key of the server.
RsaEcdsaKeyManager . getInstance ( context , keychainId , senderVerificationKey ). generateKeyPair ( isAuth );
// To generate a Web Push key pair.
WebPushKeyManager . getInstance ( context , keychainId ). generateKeyPair ( isAuth );
Ada juga metode generatePeyPairs untuk menghasilkan kunci auth dan noauth dalam satu panggilan metode.
Setelah menghasilkan pasangan kunci kapiler, Anda dapat mengambil kunci publik yang dihasilkan dalam array byte sebagai berikut:
import android . content . Context ;
import com . google . capillary . android . CapillaryHandler ;
import com . google . capillary . android . RsaEcdsaKeyManager ;
import com . google . capillary . android . WebPushKeyManager ;
import java . io . InputStream ;
Context context = ... // The current app context.
String keychainId = ... // The identifier for the key pair.
boolean isAuth = ... // Whether the private key usage is guarded by the device lock.
CapillaryHandler handler = ... // An implementation of CapillaryHandler interface.
Object extra = ... // Any extra information to be passed back to the handler.
// To obtain an RSA-ECDSA public key.
InputStream senderVerificationKey = ... // The ECDSA public key of the server.
RsaEcdsaKeyManager . getInstance ( context , keychainId , senderVerificationKey )
. getPublicKey ( isAuth , handler , extra );
// To obtain a Web Push public key.
WebPushKeyManager . getInstance ( context , keychainId ). getPublicKey ( isAuth , handler , extra );
// The Capillary library returns a byte array representing the Capillary public key via the
// handlePublicKey method of the CapillaryHandler instance.
Setelah menerima ciphertext yang dihasilkan menggunakan kunci publik kapiler, Anda dapat mendekripsi sebagai berikut:
import android . content . Context ;
import com . google . capillary . android . CapillaryHandler ;
import com . google . capillary . android . RsaEcdsaKeyManager ;
import com . google . capillary . android . WebPushKeyManager ;
import java . io . InputStream ;
byte [] ciphertext = ... // The ciphertext received through FCM.
Context context = ... // The current app context.
String keychainId = ... // The identifier for the key pair.
CapillaryHandler handler = ... // An implementation of CapillaryHandler interface.
Object extra = ... // Any extra information to be passed back to the handler.
// To decrypt a ciphertext and pass the plaintext to the CapillaryHandler instance,
// (e.g. for display to the user):
// For RSA-ECDSA:
InputStream senderVerificationKey = ... // The ECDSA public key of the server.
RsaEcdsaKeyManager . getInstance ( context , keychainId , senderVerificationKey )
. getDecrypterManager (). decrypt ( ciphertext , handler , extra );
// For Web Push:
WebPushKeyManager . getInstance ( context , keychainId )
. getDecrypterManager (). decrypt ( ciphertext , handler , extra );
// The Capillary library returns a byte array representing the plaintext via the handleData
// method of the CapillaryHandler instance.
Perlu diingat bahwa selama dekripsi, perpustakaan kapiler dapat secara otomatis menghasilkan kembali pasangan kunci kapiler yang mendasarinya jika pasangan kunci tersebut rusak secara tidak terputus, yang dapat terjadi, misalnya, ketika pengguna menambahkan/mengatur ulang kunci perangkat, mengatur ulang penyimpanan aplikasi, dll . Kunci publik yang baru dihasilkan bersama dengan byte ciphertext kapiler yang memicu generasi kunci akan diteruskan ke aplikasi Android melalui metode yang sesuai dari CapillaryHandler
.
Jika ciphertext telah dihasilkan menggunakan kunci AUTH tetapi perangkat Android dalam konteks yang tidak otentikasi, pustaka kapiler secara internal menyimpan cipherText yang akan didekripsi nanti dan menginformasikan aplikasi Android melalui metode AuthCiphertextSavedForlater. Ini memungkinkan aplikasi Android untuk menangani ciphertext yang di -cache, misalnya dengan memberi tahu pesan pengguna tersedia saat dibuka. Setelah pengguna membuka kunci perangkat, Anda dapat meminta perpustakaan kapiler mendekripsi ciphertext yang disimpan sebagai berikut:
import android . content . Context ;
import com . google . capillary . android . CapillaryHandler ;
import com . google . capillary . android . RsaEcdsaKeyManager ;
import com . google . capillary . android . WebPushKeyManager ;
import java . io . InputStream ;
Context context = ... // The current app context.
String keychainId = ... // The identifier for the key pair.
CapillaryHandler handler = ... // An implementation of CapillaryHandler interface.
Object extra = ... // Any extra information to be passed back to the handler.
// To decrypt saved ciphertexts and pass the plaintexts to the CapillaryHandler instance,
// (e.g. for display to the user):
// For RSA-ECDSA:
InputStream senderVerificationKey = ... // The ECDSA public key of the server.
RsaEcdsaKeyManager . getInstance ( context , keychainId , senderVerificationKey )
. getDecrypterManager (). decryptSaved ( handler , extra );
// For Web Push:
WebPushKeyManager . getInstance ( context , keychainId )
. getDecrypterManager (). decryptSaved ( handler , extra );
// For each decrypted ciphertext, the Capillary library returns a byte array representing the
// plaintext via the handleData method of the CapillaryHandler instance.
Ada beberapa cara untuk memicu pawang untuk ciphertext yang di -cache di atas perangkat. Pendekatan yang digunakan oleh aplikasi Android Demo Perpustakaan Capillary adalah mendengarkan niat siaran Action_user_Present. Lihat DeviceUnlockedBroadcastReceiver
untuk lebih jelasnya.
Untuk menghapus pasangan kunci kapiler:
import android . content . Context ;
import com . google . capillary . android . RsaEcdsaKeyManager ;
import com . google . capillary . android . WebPushKeyManager ;
import java . io . InputStream ;
Context context = ... // The current app context.
String keychainId = ... // The identifier for the key pair.
boolean isAuth = ... // Whether the private key usage is guarded by the device lock.
// To delete an RSA-ECDSA key pair.
InputStream senderVerificationKey = ... // The ECDSA public key of the server.
RsaEcdsaKeyManager . getInstance ( context , keychainId , senderVerificationKey ). deleteKeyPair ( isAuth );
// To delete a Web Push key pair.
WebPushKeyManager . getInstance ( context , keychainId ). deleteKeyPair ( isAuth );
Perpustakaan Capillary menyediakan fungsionalitas untuk mengenkripsi pesan di server aplikasi berbasis Java.
Untuk mengenkripsi pesan menggunakan kunci publik kapiler:
import com . google . capillary . EncrypterManager ;
import com . google . capillary . RsaEcdsaEncrypterManager ;
import com . google . capillary . WebPushEncrypterManager ;
import java . io . InputStream ;
byte [] recipientPublicKey = ... // The Capillary public key of the client.
byte [] message = ... // The message to be sent to the client.
// To create an RSA-ECDSA ciphertext.
InputStream senderSigningKey = ... // The ECDSA private key of the server.
EncrypterManager rsaEcdsaEncrypterManager = new RsaEcdsaEncrypterManager ( senderSigningKey );
rsaEcdsaEncrypterManager . loadPublicKey ( recipientPublicKey );
byte [] ciphertext = rsaEcdsaEncrypterManager . encrypt ( message );
// This step is not strictly necessary, but it ensures that the EncrypterManager releases the
// stored public key for garbage collection.
rsaEcdsaEncrypterManager . clearPublicKey ();
// To create a Web Push ciphertext.
EncrypterManager webPushEncrypterManager = new WebPushEncrypterManager ();
webPushEncrypterManager . loadPublicKey ( recipientPublicKey );
byte [] ciphertext = webPushEncrypterManager . encrypt ( message );
webPushEncrypterManager . clearPublicKey ();
Perpustakaan Kapiler dikelola oleh Googler berikut: