這是一個庫,可以簡化從基於Java的應用程序服務器到Android客戶端的端到端(E2E)發送加密推送消息。請檢查下面的說明和演示以獲取更多詳細信息。
使用maven添加依賴性:
對於基於Java的服務器:
< dependency >
< groupId >com.google.capillary</ groupId >
< artifactId >lib</ artifactId >
< version >1.0.0</ version >
</ dependency >
對於Android:
< dependency >
< groupId >com.google.capillary</ groupId >
< artifactId >lib-android</ artifactId >
< version >1.0.0</ version >
</ dependency >
使用gradle添加依賴性:
dependencies {
compile 'com.google.capillary:lib:1.0.0'
}
dependencies {
compile 'com.google.capillary:lib-android:1.0.0'
}
要使用推送消息服務將消息發送給連接的設備,開發人員必須通過第三方消息傳遞服務(例如Firebase Cloud Messaging(FCM))發送它們。使用HTTPS在開發人員和消息服務之間加密消息內容非常簡單。包括FCM在內的主要消息傳遞服務還加密了其服務器和客戶端設備之間的消息。
但是,開發人員服務器和用戶設備之間的消息未加密端到端(E2E):
可以通過在客戶端上生成非對稱加密密鑰對,在開發人員消息傳輸服務上註冊公共密鑰,使用公共密鑰加密消息,並使用私有密鑰上的客戶在客戶端上解密消息來實現E2E加密。
毛細管處理Android應用程序使用的推送消息服務的這些操作。它包括:
加密功能和鍵管理的所有版本的Android返回到Kitkat(API級別19)。
關鍵的一代和註冊工作流程。
消息加密(在服務器上)和解密(在客戶端上)。
完整性保護以防止消息修改。
Edge-Case,例如在安裝應用程序後添加/重置設備鎖定的用戶,用戶重置應用程序存儲等。
作為獎勵,它還允許開發人員要求在解密選定的消息之前解鎖設備。這包括使用基於文件的加密(FBE)上的設備上的消息:在設備加密(DE)存儲(DE)中,將加密消息存儲在需要用戶身份驗證的Android密鑰庫中。這使開發人員可以指定具有敏感內容的消息,以保持緩存的形式加密,直到用戶解鎖和解密其設備為止。
網絡推動
PRO:遵循IETF RFC 8291,因此允許開發人員與現有的Web推動實現共享代碼和密鑰存儲基礎結構。 Web Push協議基於橢圓形曲線差異 - 赫爾曼(ECDH)密鑰交換算法,該算法對於性能受限的設備高效。請注意,應用程序(與瀏覽器相反)無法通過FCM接收原始的Web推動消息,但是通過代理實現,可以輕鬆地將Web推動消息包裹在適當的FCM JSON中,從而使您可以使用少量修改的相同基礎結構。
CON: Android密鑰店不支持ECDH密鑰操作。密鑰與密鑰庫中存儲的RSA密鑰進行混合加密,這意味著在加密操作過程中,在用戶內存中可以使用EC私有密鑰授權。
RSA-ECDSA
專業: Hybrid-contrypt通過客戶生成的RSA公共密鑰(用於機密性)的消息,並通過開發人員生成的ECDSA公共密鑰(用於誠信)簽名密文。 RSA加密操作(加密,解密)由SDK版本18(Jelly Bean)及更高版本的Android密鑰店支持,這意味著關鍵材料在受信任的執行環境之外不可用。這意味著即使是具有訪問設備內存的複雜攻擊者也無法訪問私鑰材料(例如,以直接啟動模式解密未來消息)。
CON:不如ECDH和鍵效率與Web推送消息標準不兼容。
Auth Bound Bound Keys確保用戶鎖定設備時無法讀取消息,這意味著肩膀彎曲器或設備丟失或竊取的敏感內容將無法讀取。
毛細管提供了發送(從應用程序服務器)發送並在Android應用中接收加密推送消息所需的核心加密功能。這涵蓋了:
在客戶端生成和存儲密鑰。
在服務器上加密和簽名消息。
解密和驗證客戶端上的加密消息。
識別設備被鎖定時收到的加密消息,以便以後存儲。
由於服務器端體系結構和推動消息傳遞用例且多樣化,因此提供服務器端API以處理所有可能的推送消息實現是不切實際的。因此,我們已將上述加密功能與消息傳輸和服務器端密鑰存儲/檢索功能解耦。但是,我們提供了一個全堆棧實現,該實現使用毛細管將E2E加密的推送消息從基於Java的服務器發送到Demo應用程序中的Android客戶端。總而言之,您將需要自己實施解決方案的以下方面(在需要時使用以下演示應用程序和指導以進行指導):
請按照以下步驟與毛細管庫集成。
在使用毛細管庫之前,必須在運行時初始化它,如下所示:
import com . google . capillary . Config ;
Config . initialize ();
如果您使用的是RSA-ECDSA算法,則需要生成ECDSA公共/私有密鑰對,並使您的Android應用程序(例如,作為原始資源)和應用程序服務器可用於私有密鑰。使用我們提供的實用程序來生成此類ECDSA密鑰對:
$ ./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 >
毛細管庫使用CapillaryHandler
接口的方法來提供響應,例如公共鑰匙,解密的明文等,返回到Android應用程序。因此,將Android應用程序與毛細管庫集成的第一步是與您的應用程序特定邏輯實現CapillaryHandler
接口,以處理上述響應。您可以看到毛細管庫的演示Android應用如何在DemoCapillaryHandler
類中實現CapillaryHandler
接口。
每個毛細管鑰匙對通過一個密鑰對ID(又稱鍵鏈ID)標識,這是一個任意的字符串,由您決定。生成一個密鑰對:
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 );
還有一種生成鍵盤方法可以在單個方法調用中同時生成auth和noauth鍵。
生成毛細管密鑰對後,您可以在字節數組中檢索生成的公共密鑰,如下所示:
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.
收到使用毛細管公共密鑰生成的密文後,您可以將其解密如下:
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.
請記住,在解密期間,毛細管庫可以自動重新生成基礎毛細管鑰匙對,如果這些密鑰對不可損壞,例如,當用戶添加/重置設備鎖定,重置應用程序存儲等時,可能會發生這種情況,例如這樣一個新生成的公共密鑰,以及觸發密鑰再生的毛細血管密碼字節,將通過CapillaryHandler
的適當方法傳遞給Android應用。
如果使用auth鍵生成了密文,但是Android設備處於未經驗證的上下文中,則毛細管庫內部可以保存稍後解密的密文,並通過authciphertextsavedforlater方法通知Android App。這允許Android應用程序處理緩存的密文,例如通過告訴Unlock時可用用戶消息。用戶解鎖設備後,您可以讓毛細管庫解密任何保存的密文,如下所示:
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.
有幾種方法可以在設備解鎖時觸發緩存密文的處理程序。毛細管庫的演示Android應用程序使用的方法是聆聽Action_user_present廣播意圖。有關更多詳細信息,請參見DeviceUnlockedBroadcastReceiver
。
刪除毛細管鑰匙對:
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 );
毛細管庫提供了在基於Java的應用程序服務器上加密消息的功能。
使用毛細管公鑰加密消息:
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 ();
毛細管庫由以下Googles維護: