Esta é uma biblioteca para simplificar o envio de mensagens push criptografadas de ponta a ponta (E2E) de servidores de aplicativos baseados em Java para clientes Android. Verifique as instruções abaixo e a demonstração para obter mais detalhes.
Para adicionar uma dependência usando o maven:
Para um servidor baseado em Java:
< dependency >
< groupId >com.google.capillary</ groupId >
< artifactId >lib</ artifactId >
< version >1.0.0</ version >
</ dependency >
Para Android:
< dependency >
< groupId >com.google.capillary</ groupId >
< artifactId >lib-android</ artifactId >
< version >1.0.0</ version >
</ dependency >
Para adicionar uma dependência usando o gradle:
dependencies {
compile 'com.google.capillary:lib:1.0.0'
}
dependencies {
compile 'com.google.capillary:lib-android:1.0.0'
}
Para usar os serviços de mensagens Push para enviar mensagens para dispositivos conectados, os desenvolvedores devem enviá -los através de um serviço de mensagens de terceiros, como Firebase Cloud Messaging (FCM). É simples criptografar o conteúdo da mensagem entre o desenvolvedor e o serviço de mensagens usando HTTPS. Os principais serviços de mensagens, incluindo o FCM, também criptografam mensagens entre seus servidores e dispositivos clientes.
No entanto, as mensagens entre o servidor de desenvolvedor e os dispositivos de usuário não são criptografados de ponta a ponta (E2E):
A criptografia E2E pode ser alcançada gerando um par de teclas de criptografia assimétrica no cliente, registrando a chave pública no serviço de mensagens do desenvolvedor, criptografando mensagens de saída com a chave pública e descriptografando mensagens no cliente usando a chave privada:
O capilar lida com essas operações para os serviços de mensagens push usados pelos aplicativos Android. Inclui:
Funcionalidade criptográfica e gerenciamento de chaves em todas as versões do Android de volta ao kitkat (API Nível 19).
Fluxos de trabalho de geração e registro -chave.
Criptografia de mensagem (no servidor) e descriptografia (no cliente).
Proteção de integridade para impedir a modificação da mensagem.
Casos de borda, como usuários adicionando/redefinição de trava após instalar o aplicativo, os usuários redefinindo o armazenamento de aplicativos, etc.
Como bônus, também permite que os desenvolvedores exigem que os dispositivos sejam desbloqueados antes que as mensagens selecionadas possam ser descriptografadas. Isso inclui mensagens em dispositivos usando a criptografia baseada em arquivo (FBE): as mensagens criptografadas são armazenadas em cache nas teclas de decreto de armazenamento e mensagem criptografadas e de mensagens do dispositivo são armazenadas no Android Keystore que requer autenticação do usuário. Isso permite que os desenvolvedores especifiquem mensagens com conteúdo sensível para permanecer criptografado em forma de cache até que o usuário tenha desbloqueado e descriptografado seu dispositivo.
Push da web
PRO: segue o IETF RFC 8291, portanto, permite que os desenvolvedores compartilhem o código e a infraestrutura de armazenamento com as implementações existentes do Press Press. O Protocolo da Web Push é baseado no algoritmo de troca de chave de curva elíptica Diffie-Hellman (ECDH), que é altamente eficiente para dispositivos com restrição de desempenho. Observe que os aplicativos (em oposição aos navegadores) não podem receber mensagens de push da Web em FCM, mas as mensagens de push da Web podem ser facilmente envolvidas no FCM JSON apropriado por uma implementação proxy, permitindo que você use a mesma infraestrutura com pequenas modificações.
CON: Android KeyStore não suporta operações -chave do ECDH. As chaves são criptografadas com uma chave RSA armazenada no Keystore, o que significa que o texto simples da CEC de CE está disponível na memória do usuário durante as operações de criptografia.
RSA-ECDSA
Pro: criptografa híbrida com uma mensagem com uma chave pública da RSA gerada pelo cliente (para confidencialidade) e assina o texto Cipher com uma chave pública ECDSA gerada pelo desenvolvedor (para integridade). As operações RSA Crypto (Encrypt, descriptografaram) são suportadas pelo Android Keystore das versões SDK 18 (Jelly Bean) e acima, o que significa que o material -chave não está disponível fora do ambiente de execução confiável. Isso significa que mesmo um atacante sofisticado com acesso à memória do dispositivo não pode acessar o material de chave privada (por exemplo, para descriptografar mensagens futuras que chegam no modo de inicialização direta).
CON: menos eficiente que o ECDH e as teclas não são compatíveis com o padrão de mensagens da Web Push.
As teclas ligadas a auth garantem que as mensagens não possam ser lidas pelos usuários quando o dispositivo estiver bloqueado, o que significa que o conteúdo sensível não será legível por surfistas ombros ou se o dispositivo for perdido ou roubado.
O Capillary fornece a funcionalidade principal de criptografia necessária para enviar (de um servidor de aplicativos) e receber mensagens push criptografadas em aplicativos Android. Isso cobre:
Gerando e armazenando chaves no cliente.
Criptografar e assinar mensagens no servidor.
Descriptografar e verificar mensagens criptografadas no cliente.
Identificando mensagens criptografadas que devem ser armazenadas posteriormente se recebidas enquanto o dispositivo estiver bloqueado.
Como as arquiteturas do lado do servidor e as fases de uso de mensagens são muitas e variadas, não é prático fornecer uma API do lado do servidor para lidar com todas as implementações possíveis de mensagens. Portanto, dissociamos a funcionalidade criptográfica acima da transmissão de mensagens e das funções de armazenamento/recuperação do lado do servidor. No entanto, fornecemos uma implementação de pilha completa que usa o capilar para enviar mensagens de push criptografadas de E2E de um servidor baseado em Java para clientes Android no aplicativo Demo. Em resumo, você precisará implementar os seguintes aspectos da solução (usando o aplicativo de demonstração e as instruções abaixo para orientação, quando necessário):
Siga as etapas a seguir para se integrar à biblioteca capilar.
Antes que a biblioteca capilar possa ser usada, ela deve ser inicializada em tempo de execução da seguinte forma:
import com . google . capillary . Config ;
Config . initialize ();
Se você estiver usando o algoritmo RSA-ECDSA, precisará gerar um par de chaves públicas/privadas do ECDSA e disponibilizar a chave pública para o seu aplicativo Android (por exemplo, como um recurso bruto) e a chave privada disponível para o seu servidor de aplicativos. Use o programa de utilitário que fornecemos para gerar esses pares de chaves 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 >
A biblioteca capilar usa métodos da interface CapillaryHandler
para fornecer respostas, como chaves públicas, texto sem graça, etc., de volta ao aplicativo Android. Portanto, a primeira etapa na integração de um aplicativo Android com a biblioteca capilar é implementar a interface CapillaryHandler
com sua lógica específica do aplicativo para lidar com as respostas mencionadas acima. Você pode ver como o aplicativo Android da Demo Android da Biblioteca Capilar implementa a interface CapillaryHandler
na classe DemoCapillaryHandler
.
Cada par de teclas capilares é identificado por um ID do par de teclas (também conhecido como ID do chaveiro), que é uma sequência arbitrária que depende de você decidir. Para gerar um par chave:
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 );
Há também um método GenerateKeypairs para gerar teclas AUTH e NOAUTH em uma única chamada de método.
Depois de gerar um par de chaves capilares, você pode recuperar a chave pública gerada em uma matriz de bytes da seguinte forma:
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.
Depois de receber um texto cifrado gerado usando uma chave pública capilar, você pode descriptografá -la da seguinte forma:
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.
Lembre-se de que, durante a descriptografia, a biblioteca capilar pode re-generar automaticamente os pares de chaves capilares subjacentes se esses pares de chaves estiverem irrecuivelmente corrompidos, o que pode acontecer, por exemplo, quando o usuário adicionar/redefine o bloqueio do dispositivo, redefine o armazenamento do aplicativo, etc. CapillaryHandler
Se o texto cifrado foi gerado usando uma chave de autenticação, mas o dispositivo Android estiver em um contexto não autenticado, a biblioteca capilar salva internamente o texto cifrado a ser descriptografado posteriormente e informará o aplicativo Android através do método AuthcipherTextSavedforlater. Isso permite que o aplicativo Android lida com o CipherTexts em cache, por exemplo, dizendo que as mensagens do usuário estão disponíveis após o desbloqueio. Após o usuário que desbloqueia o dispositivo, você pode descriptografar a biblioteca capilar de todos os textos cifrões salvos da seguinte forma:
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.
Existem várias maneiras de acionar o manipulador para o texto cifrado em cache no desbloqueio do dispositivo. A abordagem usada pelo aplicativo Android da Demo Android da Biblioteca Capilar é ouvir a intenção de transmissão action_user_presente. Consulte DeviceUnlockedBroadcastReceiver
para obter mais detalhes.
Para excluir um par de chaves capilares:
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 );
A biblioteca capilar fornece a funcionalidade para criptografar mensagens em servidores de aplicativos baseados em Java.
Para criptografar uma mensagem usando uma chave pública capilar:
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 ();
A biblioteca capilar é mantida pelos seguintes Googlers: