Security & Privacy
Crie Apps de Chat Criptografado com Back4app + Virgil SDK
52 min
como fazer um aplicativo de chat compatível com o gdpr introdução ahoy comunidade back4app! este é um tutorial de convidado da equipe da virgil security, inc https //virgilsecurity com/?utm source=back4app\&utm medium=blog\&utm campaign=e2eechat nós somos a tecnologia criptográfica por trás de mensagens criptografadas de ponta a ponta da twilio https //www twilio com/blog/2016/05/introducing end to end encryption for twilio ip messaging with virgil security html nossos amigos @ back4app nos pediram para mostrar como construir um aplicativo de chat criptografado de ponta a ponta em cima do back4app neste post, vamos guiá lo pelos passos para fazer um simples aplicativo messenger android back4app ser criptografado de ponta a ponta! você está pronto? ps se você não se importa com os detalhes, simplesmente pule para o final do post e baixe o produto final o que é criptografia de ponta a ponta? primeiro, vamos começar com um rápido lembrete do que é e2ee (criptografia de ponta a ponta) e como funciona e2ee é simples quando você digita uma mensagem de chat, ela é criptografada em seu dispositivo móvel (ou em seu navegador) e é descriptografada apenas quando seu parceiro de chat a recebe e deseja exibi la na janela de chat a mensagem permanece criptografada enquanto viaja pela wi fi e pela internet, através da nuvem / servidor web, em um banco de dados, e no caminho de volta para seu parceiro de chat em outras palavras, nenhuma das redes ou servidores tem ideia do que vocês dois estão conversando o que é difícil na criptografia de ponta a ponta é a tarefa de gerenciar as chaves de criptografia de uma maneira que apenas os usuários envolvidos no chat possam acessá las e ninguém mais e quando eu escrevo “ninguém mais”, eu realmente quero dizer isso até mesmo os insiders do seu provedor de nuvem ou mesmo você, o desenvolvedor, estão fora; nenhum erro acidental https //techcrunch com/2017/11/29/meet the man who deactivated trumps twitter account/ ou espiadas legalmente forçadas são possíveis escrever criptografia, especialmente para várias plataformas, é difícil gerar números verdadeiramente aleatórios, escolher os algoritmos certos e escolher os modos de criptografia corretos são apenas alguns exemplos que fazem a maioria dos desenvolvedores levantar as mãos no ar e acabar apenas não fazendo isso este post do blog mostrará como ignorar todos esses detalhes irritantes e rapidamente e simplesmente criptografar de ponta a ponta usando o sdk da virgil para uma introdução, é assim que vamos atualizar o aplicativo de mensagens do back4app para ser criptografado de ponta a ponta durante o cadastro geraremos as chaves privadas e públicas individuais para novos usuários (lembre se a chave pública do destinatário criptografa mensagens e a chave privada correspondente do destinatário as descriptografa) antes de enviar mensagens, você criptografará as mensagens de chat com a chave pública do destinatário após receber mensagens, você descriptografará as mensagens de chat com a chave privada do destinatário publicaremos as chaves públicas dos usuários no serviço de cartões da virgil para que os usuários de chat possam se localizar e criptografar mensagens uns para os outros as chaves privadas permanecerão nos dispositivos dos usuários mantenha simples esta é a implementação mais simples possível de um chat e2ee e funciona perfeitamente para aplicativos de chat simples entre 2 usuários onde as conversas são de curta duração e está tudo bem perder o histórico de mensagens se um dispositivo for perdido com a chave privada nele ok, chega de conversa! vamos ao código começaremos guiando você pela configuração do aplicativo android, depois, adicionaremos algum código para tornar o aplicativo criptografado de ponta a ponta pré requisitos para completar este tutorial, você precisa android studio um aplicativo criado no back4app siga o tutorial criar novo app para aprender como criar um aplicativo no back4app inscreva se para uma conta da virgil security (criaremos o aplicativo mais tarde) vamos configurar o aplicativo de mensagens “limpo” do back4app 1 configure seu servidor de aplicativos vamos começar implantando a função em nuvem para isso, você precisará de encontre main js main js e package json package json no diretório scripts scripts ; abra main js main js com seu editor favorito 1 1) obtenha as credenciais do back4app abra dashboard dashboard do seu aplicativo > configurações do aplicativo configurações do aplicativo > segurança e chaves segurança e chaves em main js main js , substitua parse app id parse app id pelo seu id da aplicação id da aplicação e parse rest api key parse rest api key pela sua chave da api rest chave da api rest 1 2) obtenha credenciais virgil crie uma aplicação em painel virgil https //dashboard virgilsecurity com/ abra seu novo aplicativo virgil, navegue até a seção e3kit e gere um env env arquivo na seção e3kit na barra lateral esquerda copie os valores de app id app id , app key app key , e app key id app key id do arquivo env env substitua os valores copiados no seu main js main js arquivo nos campos correspondentes ( main js main js de scripts scripts diretório) 1 3) implantar função de código em nuvem abra o “dashboard” do back4app do seu aplicativo > “core” > funções de código em nuvem; clique em +adicionar e selecione seu main js e package json (do diretório de scripts), depois mova ambos para a pasta na nuvem; clique em deploy 2 inicie o aplicativo de demonstração back4app kotlin limpo não se esqueça de configurar a função de código em nuvem do back4app primeiro é uma parte obrigatória desta demonstração depois disso, siga os seguintes passos 2 1) importar projeto no android studio abra o android studio > arquivo arquivo > novo novo > projeto do controle de versão projeto do controle de versão > git git url do repositório git https //github com/virgilsecurity/chat back4app android verifique a clean chat kt clean chat kt branch importante! selecione o tipo de árvore de arquivos “projeto” ele será usado durante todo o tutorial 2 2) configurar credenciais do back4app no projeto abra o “painel” do back4app do seu aplicativo > “configurações do aplicativo” > “segurança e chaves”; vá para /app/src/main/res/values/strings xml /app/src/main/res/values/strings xml arquivo no seu projeto android e substitua your back4app app id your back4app app id pelo seu id da aplicação id da aplicação e your back4app client key your back4app client key pelo seu chave do cliente chave do cliente 2 3) configurar db abra o back4app “dashboard” > “core” > “database browser” > “criar uma classe” e crie classes do tipo personalizado personalizado nomeado mensagem mensagem e chatthread chatthread ; 2 4) configurar consulta ao vivo volte para sua conta back4app https //dashboard back4app com/apps/#!/admin pressione o configurações do servidor configurações do servidor botão em sua aplicação encontre o bloco “hospedagem web e consulta ao vivo” abra as configurações de consulta ao vivo e verifique a ativar hospedagem ativar hospedagem opção escolha um nome para seu subdomínio para ativar a consulta ao vivo para as 2 classes que você criou mensagem mensagem e chatthread chatthread copie o nome do seu novo subdomínio e clique no botão salvar retorne para /app/src/main/res/values/strings xml /app/src/main/res/values/strings xml e cole o “nome do subdomínio” que você inseriu acima no back4app live query url back4app live query url em vez de “seunomedesubdomínio” após essas etapas, você poderá clicar no botão executar no android studio e fazer o exemplo funcionar use um emulador ou um dispositivo real para testá lo 3 execute a demonstração limpa para ver o resultado da execução da versão limpa da demonstração, você precisará cadastrar 2 usuários; iniciar uma conversa entre eles e enviar algumas mensagens; 3\ abra o back4app “dashboard” > “core” > “database browser” > “message” se tudo funcionou, você deve ver o aplicativo de mensagens de chat aparecendo registre dois usuários e envie algumas mensagens um para o outro você deve ver novos dados aparecendo na mensagem mensagem classe observe que você pode ver no servidor sobre o que seus usuários estão conversando próximo feche sua interface de chat e passe para a próxima etapa – adicionando criptografia e2ee agora, vamos criptografar essas mensagens de ponta a ponta! ao final desta parte, é assim que suas mensagens de chat parecerão no servidor você consegue notar a diferença? como chegamos lá? obviamente, precisamos implementar a criptografia de ponta a ponta, o que significa que nosso aplicativo precisa gerar o par de chaves privada e pública como parte do cadastro armazenar a chave privada no armazenamento de chaves no dispositivo do usuário publicar a chave pública no serviço de cartões da virgil como um “cartão virgil” para outros usuários baixarem e criptografarem mensagens com ele criptografar mensagens com a chave pública e assinar com a chave privada; descriptografar mensagens com a chave privada e verificar com a chave pública para isso, precisaremos adicionar o e3kit ao nosso aplicativo de demonstração limpo e mais código para implementar tudo o que foi descrito acima mas antes de começarmos, vamos esclarecer dois termos importantes para você o que é um cartão virgil e uma chave privada? cartão virgil os cartões virgil carregam as chaves privadas dos usuários os cartões virgil são publicados no serviço de cartões da virgil (imagine que este serviço é como uma lista telefônica) para que outros usuários possam recuperá los alice precisa recuperar a chave pública de bob para criptografar uma mensagem para bob usando essa chave chave privada uma parte privada da chave de criptografia lembre se, chaves privadas podem descriptografar dados que foram criptografados usando a chave pública correspondente 1 adicione o e3kit à demonstração limpa do e3kit back4app kotlin no nível do aplicativo ( módulo app módulo app ) gradle em /app/build gradle /app/build gradle adicione (mas não sincronize os scripts gradle ainda) adicione o seguinte ao final do seu nível de projeto /build gradle /build gradle ( projeto chat back4app android projeto chat back4app android ) agora você pode sincronizar os scripts gradle; atualize sua appvirgil appvirgil classe adicionando novos campos pressione alt+ enter alt+ enter para importar as bibliotecas necessárias na classe 2 autenticar usuários com o back4app cloud code no /virgilsecurity/virgilback4app/model/ /virgilsecurity/virgilback4app/model/ diretório, crie classes de dados authenticateresponse authenticateresponse e virgiljwtresponse virgiljwtresponse que representam respostas das funções do cloud code no /virgilsecurity/virgilback4app/util/ /virgilsecurity/virgilback4app/util/ crie um authrx authrx objeto que implementa chamadas para funções do cloud code (não se esqueça de importar todas as bibliotecas necessárias depois) 1 object authrx { 2 3 / 4 you can call it only after successful \[authenticate] 5 / 6 fun virgiljwt(sessiontoken string) = single create\<string> { emitter > 7 val requestparams = mutablemapof\<string, string>() apply { 8 put("sessiontoken", sessiontoken) 9 } 10 11 parsecloud callfunctioninbackground\<map\<string, any>>( 12 key virgil jwt, 13 requestparams 14 ) { virgiljwt, exception > 15 if (exception == null) 16 emitter onsuccess(virgiljwt\[key token] tostring()) 17 else 18 emitter onerror(exception) 19 20 } 21 } 22 23 private const val key virgil jwt = "virgil jwt" 24 private const val key token = "token" 25 } 3 armazenar o virgil jwt localmente o token virgil recebido das funções do cloud code precisa ser armazenado localmente vamos atualizar preferências preferências a classe em /virgilsecurity/virgilback4app/util/ /virgilsecurity/virgilback4app/util/ defina a constante adicione as funções setvirgiltoken setvirgiltoken , virgiltoken virgiltoken e clearvirgiltoken clearvirgiltoken kotlin fun setvirgiltoken(virgiltoken string) { with(sharedpreferences edit()) { putstring(key virgil token, virgiltoken) apply() } } fun virgiltoken() string? { with(sharedpreferences) { return getstring(key virgil token, null) } } fun clearvirgiltoken() { with(sharedpreferences edit()) { remove(key virgil token) apply() } } 1 virgil token should be reset on logout let's add `preferences instance(this) clearvirgiltoken()` line into `initdrawer` function of `threadslistactivity` class (in ` /virgilsecurity/virgilback4app/chat/contactslist/`) 2 kotlin 3 private fun initdrawer() { 4 5 nvnavigation setnavigationitemselectedlistener { item > 6 r id itemlogout > { 7 dldrawer closedrawer(gravitycompat start) 8 presenter disposeall() 9 showbaseloading(true) 10 // new code >> 11 preferences instance(this) clearvirgiltoken() 12 // << new code 13 14 } 15 } 16 } 4 modificar o registro do usuário e3kit cuida das suas chaves privadas e públicas para gerá las durante o processo de registro, precisaremos fazer o seguinte em /virgilsecurity/virgilback4app/util/ /virgilsecurity/virgilback4app/util/ crie a rxethree rxethree classe agora, adicione initethree initethree função que inicializa a instância do e3kit em rxethree rxethree classe 1 import com virgilsecurity android common model ethreeparams 2 import com virgilsecurity android ethree interaction ethree 3 4 5 fun initethree(identity string, verifyprivatekey boolean = false) 6single\<ethree> = single create { e > 6 val params = ethreeparams(identity, {preferences virgiltoken()!!}, context) 7 val ethree = ethree(params) 8 if (verifyprivatekey) { 9 if (ethree haslocalprivatekey()) { 10 e onsuccess(ethree) 11 } else { 12 e onerror(keyentrynotfoundexception()) 13 } 14 } else { 15 e onsuccess(ethree) 16 } 17 } adicione registerethree registerethree função que registra um novo usuário na rxethree rxethree classe e3kit gera um par de chaves durante o cadastro a chave privada gerada é então armazenada no armazenamento local, e a chave pública é publicada nos serviços virgil como um cartão virgil 1 import com android virgilsecurity virgilback4app appvirgil 2 import com virgilsecurity common callback oncompletelistener 3 import io reactivex completable 4 5 6 fun registerethree() completable = completable create { e > 7 appvirgil ethree register() addcallback(object oncompletelistener { 8 override fun onerror(throwable throwable) { 9 e onerror(throwable) 10 } 11 12 override fun onsuccess() { 13 e oncomplete() 14 } 15 16 }) 17 } vamos fazer algumas atualizações no loginpresenter loginpresenter classe (em /virgilsecurity/virgilback4app/auth/) /virgilsecurity/virgilback4app/auth/) adicionar rxethree rxethree campo 1 private val rxethree = rxethree(context) atualize a requestsignup requestsignup função para executar o registro com e3kit 1 fun requestsignup(identity string, onsuccess () > unit, onerror (throwable) > unit) { 2 val password = generatepassword(identity tobytearray()) 3 4 val disposable = rxparse signup(identity, password) 5 subscribeon(schedulers io()) 6 observeon(schedulers io()) 7 // new code >> 8 tosingle { parseuser getcurrentuser() } 9 flatmap { authrx virgiljwt(it sessiontoken) } 10 map { preferences setvirgiltoken(it) } 11 flatmap { rxethree initethree(identity) } 12 map { appvirgil ethree = it } 13 flatmap { rxethree registerethree() tosingle { unit } } 14 // << new code 15 observeon(androidschedulers mainthread()) 16 // updated code >> 17 subscribeby( 18 onsuccess = { 19 onsuccess() 20 }, 21 onerror = { 22 onerror(it) 23 } 24 ) 25 // << updated code 26 27 compositedisposable += disposable 28 } 5 modificar funções de login agora, vamos fazer alterações no requestsignin requestsignin método da loginpresenter loginpresenter classe (em /virgilsecurity/virgilback4app/auth/) /virgilsecurity/virgilback4app/auth/) 1 fun requestsignin(identity string, 2 onsuccess () > unit, 3 onerror (throwable) > unit) { 4 5 val password = generatepassword(identity tobytearray()) 6 7 val disposable = rxparse login(identity, password) 8 subscribeon(schedulers io()) 9 observeon(schedulers io()) 10 // new code >> 11 flatmap { authrx virgiljwt(it sessiontoken) } 12 map { preferences setvirgiltoken(it) } 13 flatmap { rxethree initethree(identity, true) } 14 map { appvirgil ethree = it } 15 // << new code 16 observeon(androidschedulers mainthread()) 17 // updated code >> 18 subscribeby( 19 onsuccess = { 20 onsuccess() 21 }, 22 onerror = { 23 onerror(it) 24 } 25 ) 26 // << updated code 27 28 compositedisposable += disposable 29 } 6 obter a lista de chats existentes em seguida, adicione funções que tratam a inicialização do e3kit na threadslistfragment threadslistfragment classe (em /virgilsecurity/virgilback4app/chat/contactslist/) /virgilsecurity/virgilback4app/chat/contactslist/) 1 private fun oninitethreesuccess() { 2 presenter requestthreads(parseuser getcurrentuser(), 3 20, 4 page, 5 const tablenames created at criteria, 6 ongetthreadssuccess, 7 ongetthreadserror) 8 } 9 10 private fun oninitethreeerror(throwable throwable) { 11 showprogress(false) 12 if (adapter itemcount == 0) 13 tverror visibility = view\ visible 14 15 utils toast(activity, utils resolveerror(throwable)) 16 } atualizar postcreateinit postcreateinit função para inicializar e3kit 1 override fun postcreateinit() { 2 3 presenter = threadslistfragmentpresenter(activity) 4 5 showprogress(true) 6 // updated code >> 7 if (appvirgil isethreeinitialized()) { 8 presenter requestthreads(parseuser getcurrentuser(), 9 20, 10 page, 11 const tablenames created at criteria, 12 ongetthreadssuccess, 13 ongetthreadserror) 14 } else { 15 presenter requestethreeinit(parseuser getcurrentuser(), oninitethreesuccess, oninitethreeerror) 16 } 17 // << updated code 18 } e adicione o seguinte código na threadslistfragmentpresenter threadslistfragmentpresenter classe em virgilsecurity virgilback4app chat contactslist/ virgilsecurity virgilback4app chat contactslist/ adicionar campo 1 private val rxethree = rxethree(context) e função 1 fun requestethreeinit(currentuser parseuser, onsuccess () > unit, onerror (throwable) > unit) { 2 val disposable = rxethree initethree(currentuser username) 3 subscribeon(schedulers io()) 4 observeon(androidschedulers mainthread()) 5 subscribeby( 6 onsuccess = { 7 appvirgil ethree = it 8 onsuccess() 9 }, 10 onerror = { 11 onerror(it) 12 } 13 ) 14 15 compositedisposable += disposable 16 } neste ponto, conseguimos registrar/login um usuário e criar um novo chat com outro usuário agora vamos adicionar criptografia para nossas mensagens 7 criptografia e descriptografia de mensagens vamos adicionar findcard findcard função para rxethree rxethree classe (em /virgilsecurity/virgilback4app/util/ /virgilsecurity/virgilback4app/util/ ) que nos ajudará a obter o último cartão virgil pelo nome de usuário 1 fun findcard(identity string) single\<card> = single create { e > 2 appvirgil ethree finduser(identity) addcallback(object onresultlistener\<card> { 3 override fun onerror(throwable throwable) { 4 e onerror(throwable) 5 } 6 7 override fun onsuccess(result card) { 8 e onsuccess(result) 9 } 10 11 }) 12 } quando um chat é aberto, devemos obter o cartão virgil do destinatário edite postcreateinit postcreateinit de chatthreadfragment chatthreadfragment classe (em /virgilsecurity/virgilback4app/chat/thread/ /virgilsecurity/virgilback4app/chat/thread/ ) substituindo 1 presenter requestmessages(thread, 2 50, 3 page, 4 const tablenames created at criteria, 5 ongetmessagessuccess, 6 ongetmessageserror) código por um novo 1 presenter requestcard(recipientid, 2 ongetcardsuccess, 3 ongetcarderror) e adicione duas funções 1 private fun ongetcardsuccess(card card) { 2 showprogress(false) 3 adapter interlocutorcard = card 4 presenter requestmessages(thread, 5 50, 6 page, 7 const tablenames created at criteria, 8 ongetmessagessuccess, 9 ongetmessageserror) 10 } 11 12 private fun ongetcarderror(t throwable) { 13 if (t is virgilcardisnotfoundexception || t is virgilcardserviceexception) { 14 utils toast(this, 15 "virgil card is not found \nyou can not chat with user without virgil card") 16 activity onbackpressed() 17 } 18 showprogress(false) 19 srlrefresh isrefreshing = false 20 locksendui(lock = false, lockinput = false) 21 22 utils toast(this, utils resolveerror(t)) 23 } agora vamos mudar chatthreadpresenter chatthreadpresenter adicionar campos 1 private val ethree = appvirgil ethree 2 private lateinit var usercard card 3 private val rxethree = rxethree(context) adicione uma função que obtém um cartão virgil do destinatário 1 fun requestcard(identity string, 2 onsuccess (card) > unit, 3 onerror (throwable) > unit) { 4 5 val disposable = rxethree findcard(identity) 6 subscribeon(schedulers io()) 7 observeon(androidschedulers mainthread()) 8 subscribeby( 9 onsuccess = { 10 usercard = it 11 onsuccess(it) 12 }, 13 onerror = { 14 onerror(it) 15 } 16 ) 17 18 compositedisposable += disposable 19 } adicione a criptografia das mensagens de saída na requestsendmessage requestsendmessage função 1 fun requestsendmessage(text string, 2 thread chatthread, 3 onsuccess () > unit, 4 onerror (throwable) > unit) { 5 6 val encryptedtext = ethree authencrypt(text, usercard) 7 val disposable = rxparse sendmessage(encryptedtext, thread) 8 9 } adicione a descriptografia de todas as mensagens recebidas na chatthreadrvadapter chatthreadrvadapter classe (em /virgilsecurity/virgilback4app/chat/thread/) /virgilsecurity/virgilback4app/chat/thread/) adicionar campos 1 private var ethree ethree = appvirgil ethree 2 lateinit var interlocutorcard card implementar a descriptografia de mensagens na onbindviewholder onbindviewholder função 1 override fun onbindviewholder(viewholder recyclerview\ viewholder, position int) { 2 when (viewholder) { 3 is holdermessageme > { 4 val decryptedtext = ethree authdecrypt(items\[position] body) 5 viewholder bind(decryptedtext) 6 } 7 is holdermessageyou > { 8 val decryptedtext = ethree authdecrypt(items\[position] body, interlocutorcard) 9 viewholder bind(decryptedtext) 10 } 11 } 12 } 8 execute a demonstração completa de criptografia de ponta a ponta agora, para ver o resultado da nossa demonstração totalmente criptografada de ponta a ponta, siga estas etapas novamente desconectar o usuário anterior registrar 2 novos usuários; iniciar uma conversa entre eles e enviar algumas mensagens; abrir back4app “dashboard” > “core” > “database browser” > “message” importante! você precisa desconectar o usuário atual e registrar dois novos usuários, depois disso você pode iniciar um chat e2ee com esses dois novos usuários a razão é que seus dois primeiros usuários não têm virgil card virgil card ’s, então você não pode usar criptografar\descriptografar para eles { blockquote tip} pronto! agora você pode ver que as mensagens dos usuários estão criptografadas e só podem ser acessadas no aplicativo pelos próprios usuários conformidade com hipaa e gdpr a criptografia de ponta a ponta é uma maneira de atender aos requisitos técnicos para hipaa (a lei de portabilidade e responsabilidade de seguros de saúde dos estados unidos de 1996) e gdpr (o regulamento geral sobre a proteção de dados da união europeia) se você precisar de mais detalhes, registre se para uma conta virgil https //developer virgilsecurity com/account/signup?utm source=back4app\&utm medium=blog\&utm campaign=e2eechat , junte se à nossa comunidade no slack e nos avise lá estamos felizes em discutir suas próprias circunstâncias de privacidade e ajudá lo a entender o que é necessário para atender aos requisitos técnicos de hipaa e gdpr para onde ir a partir daqui? projeto final https //github com/virgilsecurity/chat back4app android/ se você perdeu partes do quebra cabeça, abra o branch do projeto e2ee você pode inserir suas credenciais de aplicativo neste código (como fez durante o artigo) e construir o projeto você pode encontrar mais informações sobre o que pode construir com a virgil security aqui https //virgilsecurity com/?utm source=back4app\&utm medium=blog\&utm campaign=e2eechat