Dies ist eine Bibliothek, um das Senden von End-to-End (E2E) verschlüsselten Push-Nachrichten von Java-basierten Anwendungsservern an Android-Clients zu vereinfachen. Bitte überprüfen Sie die folgenden Anweisungen und die Demo für weitere Informationen.
Um eine Abhängigkeit mit Maven hinzuzufügen:
Für einen Java-basierten Server:
< dependency >
< groupId >com.google.capillary</ groupId >
< artifactId >lib</ artifactId >
< version >1.0.0</ version >
</ dependency >
Für Android:
< dependency >
< groupId >com.google.capillary</ groupId >
< artifactId >lib-android</ artifactId >
< version >1.0.0</ version >
</ dependency >
Um eine Abhängigkeit mit Gradle hinzuzufügen:
dependencies {
compile 'com.google.capillary:lib:1.0.0'
}
dependencies {
compile 'com.google.capillary:lib-android:1.0.0'
}
Um Push -Messaging -Dienste zu verwenden, um Nachrichten an verbundene Geräte zu senden, müssen Entwickler sie über einen Messaging -Dienst von Drittanbietern wie Firebase Cloud Messaging (FCM) senden. Es ist einfach, den Nachrichteninhalt zwischen dem Entwickler und dem Messaging -Dienst mithilfe von HTTPS zu verschlüsseln. Große Messaging -Dienste, einschließlich FCM, verschlüsseln auch Nachrichten zwischen ihren Servern und Client -Geräten.
Nachrichten zwischen dem Entwicklerserver und den Benutzergeräten sind jedoch nicht von End-to-End (E2E) verschlüsselt:
Die E2E -Verschlüsselung kann erreicht werden, indem ein asymmetrisches Verschlüsselungsschlüsselpaar auf dem Kunden generiert wird, den öffentlichen Schlüssel mit dem Entwickler -Messaging -Service registriert, ausgehende Nachrichten mit dem öffentlichen Schlüssel verschlüsselt und Nachrichten über den Kunden über den privaten Schlüssel entschlüsselt werden:
Kapillare behandelt diese Operationen für Push -Messaging -Dienste, die von Android Apps verwendet werden. Es enthält:
Kryptofunktionalität und Schlüsselmanagement in allen Versionen von Android zurück zu KitKat (API -Stufe 19).
Schlüsselgenerierungs- und Registrierungsworkflows.
Nachrichtenverschlüsselung (auf dem Server) und Entschlüsselung (auf dem Client).
Integritätsschutz, um die Änderung der Nachrichten zu verhindern.
Kantenwagen wie Benutzer, die nach der Installation der App die Gerätesperrung hinzufügen/zurücksetzen, haben Benutzer den App-Speicher von Apps usw. zurücksetzen, usw.
Als Bonus können Entwickler auch verlangen, dass Geräte entsperrt werden, bevor ausgewählte Nachrichten entschlüsselt werden können. Dies umfasst Nachrichten auf Geräten, die die dateibasierte Verschlüsselung (FBE) verwenden: Verschlüsselte Nachrichten werden in Geräteverschlüsselung (DE) Speicher- und Nachrichtenentschlüsselungsschlüssel zwischengespeichert. Auf diese Weise können Entwickler Nachrichten mit sensiblen Inhalten angeben, um in zwischengespeicherter Form verschlüsselt zu bleiben, bis der Benutzer sein Gerät entsperrt und entsperrt hat.
Web -Push
Pro: Folgt dem IETF RFC 8291 und ermöglicht es den Entwicklern daher, Code und wichtige Speicherinfrastruktur mit vorhandenen Web -Push -Implementierungen zu teilen. Das Web-Push-Protokoll basiert auf dem Schlüsselaustauschalgorithmus des Elliptic-Kurve Diffie-Hellman (ECDH), der für leistungsbezogene Geräte hocheffizient ist. Beachten Sie, dass Apps (im Gegensatz zu Browsern) keine RAW -Web -Push -Nachrichten über FCM empfangen können. Web -Push -Nachrichten können jedoch durch eine Proxy -Implementierung problemlos in den entsprechenden FCM JSON eingewickelt werden, sodass Sie dieselbe Infrastruktur mit geringfügigen Änderungen verwenden können.
CON: Android Keystore unterstützt keine ECDH -Schlüsselvorgänge. Tasten sind mit einem in Keystore gespeicherten RSA-Taste mit einem hybridverschlüsselten RSA-Taste, was bedeutet, dass der private Taste der EC-Klartext während der Krypto-Operationen im Benutzerspeicher verfügbar ist.
RSA-ECDSA
PRO: Hybrid-Crymypts Eine Nachricht mit einem von Kunden erstellten RSA-öffentlichen Schlüssel (für die Vertraulichkeit) und unterzeichnet den Chiffretext mit einem von Entwickler generierten ECDSA Public Key (für Integrität). RSA Crypto Operations (Encrypt, Decrypt) werden von Android Keystore von SDK -Versionen 18 (Jelly Bean) und oben unterstützt, was bedeutet, dass Schlüsselmaterial außerhalb der vertrauenswürdigen Ausführungsumgebung nicht verfügbar ist. Dies bedeutet, dass selbst ein ausgefeilter Angreifer mit Zugriff auf den Gerätspeicher nicht auf private Schlüsselmaterial zugreifen kann (z. B. um zukünftige Nachrichten zu entschlüsseln, die im Direktstartmodus ankommen).
CON: Weniger effizient als ECDH und Schlüssel sind nicht mit dem Web -Push -Messaging -Standard kompatibel.
Authgebundene Tasten stellt sicher, dass Nachrichten nicht von Benutzern gelesen werden können, wenn ihr Gerät gesperrt ist, was bedeutet, dass der sensible Inhalt nicht durch Schulterläufer lesbar ist oder wenn das Gerät verloren geht oder gestohlen wird.
Die Kapillary bietet die für das Senden erforderliche Kernkrypto -Funktionen (von einem Anwendungsserver) und empfangen verschlüsselte Push -Nachrichten in Android -Apps. Dies deckt:
Erzeugen und Speichern von Schlüssel für den Kunden.
Verschlüsseln und Signieren von Nachrichten auf dem Server.
Entschlüsseln und Überprüfung verschlüsselter Nachrichten im Client.
Identifizieren verschlüsselter Nachrichten, die für später gespeichert werden sollten, wenn das Gerät gesperrt ist.
Da serverseitige Architekturen und Push-Messaging-Anwendungskräfte vielfältig sind und vielfältig sind, ist es nicht praktisch, eine serverseitige API bereitzustellen, um alle möglichen Push-Nachrichten-Implementierungen zu verarbeiten. Daher haben wir die obige Krypto-Funktionalität aus der Nachrichtenübertragung und der serverseitigen Schlüsselspeicher-/Abruffunktionen entkoppelt. Wir haben jedoch eine Vollstapel-Implementierung zur Verfügung gestellt, in der die Kapillare in der Demo-Anwendung von einem Java-basierten Server an Android-Clients an Android-Clients senden. Zusammenfassend müssen Sie die folgenden Aspekte der Lösung selbst implementieren (unter Verwendung der Demo -Anwendung und den folgenden Anweisungen, um nach Bedarf Anleitungen zu erhalten):
Bitte befolgen Sie die folgenden Schritte, um in die Kapillarbibliothek zu integrieren.
Bevor die Kapillarbibliothek verwendet werden kann, muss sie wie folgt zur Laufzeit initialisiert werden:
import com . google . capillary . Config ;
Config . initialize ();
Wenn Sie den RSA-ECDSA-Algorithmus verwenden, müssen Sie ein ECDSA-Paar/privates Schlüsselpaar generieren und den öffentlichen Schlüssel Ihrer Android-App (z. B. als ROW-Ressource) und privatem Schlüssel für Ihren Anwendungsserver zur Verfügung stellen. Verwenden Sie das Dienstprogramm, das wir bereitgestellt haben, um solche ECDSA -Schlüsselpaare zu generieren:
$ ./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 >
Die Kapillarbibliothek verwendet Methoden der CapillaryHandler
-Schnittstelle, um Antworten wie öffentliche Schlüssel, entschlüsselte Klartext usw. zurück zur Android -App zu liefern. Der erste Schritt bei der Integration einer Android-App in die Kapillarbibliothek besteht darin, die CapillaryHandler
Schnittstelle mit Ihrer App-spezifischen Logik zu implementieren, um die oben genannten Antworten zu verarbeiten. Sie können sehen, wie die Demo -Android -App der Kapillarbibliothek die CapillaryHandler
-Schnittstelle in der DemoCapillaryHandler
-Klasse implementiert.
Jedes Kapillarschlüsselpaar wird durch eine Schlüsselpaar -ID (auch bekannt als Keychain -ID) identifiziert, bei der es sich um eine willkürliche Zeichenfolge handelt, die bei Ihnen zu entscheiden ist. Um ein Schlüsselpaar zu generieren:
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 );
Es gibt auch eine GenerateKeypairs -Methode, um sowohl Auth- als auch NoAuth -Schlüssel in einem einzelnen Methodenaufruf zu generieren.
Nachdem Sie ein Kapillarschlüsselpaar generiert haben, können Sie den generierten öffentlichen Schlüssel in einem Byte -Array wie folgt abrufen:
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.
Nachdem Sie einen Chiffretext erhalten haben, der mit einem Capillary Public Key erzeugt wurde, können Sie ihn wie folgt entschlüsseln:
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.
Beachten Sie, dass die Kapillarbibliothek während der Entschlüsselung die zugrunde liegenden Kapillarschlüsselpaare automatisch neu generieren kann, wenn diese Schlüsselpaare unwiderruflich beschädigt sind, was beispielsweise auftreten kann, wenn der Benutzer die Gerätesperrung, die App-Speicher usw. zurücksetzt CapillaryHandler
Wenn der Chiffretext unter Verwendung eines Auth -Schlüssels generiert wurde, das Android -Gerät jedoch in einem nicht authentifizierten Kontext befindet, speichert die Kapillarbibliothek den späteren Ciphertext, der später entschlüsselt wird, und informiert die Android -App über die AuthciphertextsavedForlater -Methode. Auf diese Weise kann die Android -App zwischengespeicherte Chiffretetexte verarbeiten, z. B. durch Angaben, dass die Benutzernachrichten beim Entsperren verfügbar sind. Wenn der Benutzer das Gerät entsperrt, können Sie die Kapillarbibliothek alle gespeicherten Chiffretexte wie folgt entschlüsseln lassen:
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.
Es gibt verschiedene Möglichkeiten, den Handler für zwischengespeicherte Chiffretext beim Entsperren von Geräten auszulösen. Der Ansatz, der von der Demo -Android -App der Kapillarbibliothek verwendet wird, besteht darin, auf die Sendung Action_User_Present zu hören. Weitere Informationen finden Sie unter DeviceUnlockedBroadcastReceiver
.
So löschen Sie ein Kapillarschlüsselpaar:
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 );
Die Kapillarbibliothek bietet die Funktionalität, Nachrichten auf Java-basierten Anwendungsservern zu verschlüsseln.
Um eine Nachricht mit einem Kapillar -öffentlichen Schlüssel zu verschlüsseln:
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 ();
Die Kapillarbibliothek wird von den folgenden Googlers gepflegt: