Mensagens pessoais criptografadas

Gostaríamos de encomendar um plugin que permita mensagens privadas e criptografadas entre usuários finais.

:mega: Este plugin já existe e é oficialmente suportado. Veja em Discourse Encrypt (deprecated)

Atualmente, há muito poucos ambientes online para comunicação segura, privada e de longo prazo. As ferramentas existentes geralmente são bastante complexas e exigem habilidades técnicas extremas para uso. Como resultado, a maioria da comunicação “privada” é feita de forma “curta” no Telegram, Skype ou WhatsApp. Além disso, esse modo de comunicação em massa não é adequadamente auditável, pois se baseia em ferramentas de código fechado e frequentemente em protocolos também fechados.

Gostaríamos de construir uma solução altamente utilizável e auditável para mensagens criptografadas em um plugin dedicado do Discourse.

Para isso, gostaríamos de nos basear em alguns princípios:

  1. Construir a solução sobre a Web Crypto API.

  2. Fazer com que o servidor armazene uma chave privada criptografada e uma chave pública por usuário.

  3. Fazer com que o servidor armazene uma chave de conversa criptografada por participante em mensagens privadas (criptografada usando a chave privada do usuário final).

  4. Armazenar todo o conteúdo em Markdown e os títulos na forma crua e criptografada por mensagem (criptografada usando a chave da conversa).

  5. Aceitar a limitação de que o servidor sabe quem conversou com quem e quando (estamos protegendo apenas o “o quê”). Aceitar também que a busca não funcionará para esse conteúdo.

Experiência proposta para o usuário final

Jane acessa sua página de usuário e clica no botão “habilitar mensagens criptografadas”. Ao clicar, ela é solicitada a inserir uma senha secreta. A interface explica claramente que, se ela esquecer essa senha, NUNCA mais terá acesso às suas mensagens criptografadas.

Uma vez que as mensagens criptografadas estiverem habilitadas, um novo [ ] aparecerá na interface de criação de mensagens com o texto [ ] criptografar mensagem. Isso só será clicável se todos os destinatários tiverem a opção “habilitar mensagens criptografadas” ativada. Se alguns não tiverem chaves públicas, ao tentar clicar, será exibida a mensagem: “Desculpe, mas alguns dos participantes não têm mensagens criptografadas habilitadas”.

Jane decide conversar privadamente com Pete. Ela o adiciona à lista de participantes, clica em criptografar mensagem e envia uma mensagem para ele.

Pete recebe uma notificação informando que Jane enviou uma mensagem criptografada. Não há título, apenas a informação de que existe uma mensagem criptografada, com links para a mensagem (tanto na notificação por e-mail quanto na web).

Se Pete estiver no mesmo dispositivo onde habilitou as mensagens criptografadas, sua senha secreta já foi inserida e as credenciais já estão armazenadas no IndexedDB. Se ele estiver em um novo dispositivo, será solicitado que ele insira sua senha secreta para ativar as mensagens criptografadas.

A interface exibirá claramente uma sobreposição ou indicador visual para mostrar que a mensagem está criptografada.

Uma vez iniciada a comunicação entre Jane e Pete, qualquer um deles pode convidar novas pessoas para a conversa, desde que possuam chaves públicas.

Pete ou Jane podem alterar a senha secreta sempre que desejarem. Se fizerem isso, a chave privada será recriptografada usando a nova senha e enviada ao servidor. (Para a versão 1, não serão permitidas alterações na chave privada em si, apenas na senha.)

Detalhes técnicos

Em nenhum momento qualquer conversa privada não criptografada ou credenciais privadas serão enviadas ao servidor. A única confiança depositada no servidor será de que ninguém manipulou o payload JavaScript enviado ao cliente.

Os pares de chaves pública e privada serão gerados 100% no lado do cliente. Em seguida, a chave privada será criptografada usando criptografia simétrica AES antes de ser entregue ao servidor para guarda segura. A senha será estendida usando um sal gerado aleatoriamente e armazenado no servidor. O estiramento da senha será feito no cliente usando PBKDF2 (disponível na Web Crypto API). O par de chaves privada/pública será armazenado no cliente no IndexedDB usando um objeto CryptoKey não exportável. Dados de CryptoKey exportáveis serão removidos da memória o mais rápido possível.

A chave privada criptografada e a chave pública serão armazenadas em campos personalizados do usuário. Apenas o current_user poderá ler/gravar a chave privada criptografada; todos os usuários logados poderão ler as chaves públicas de todos os usuários.

As chaves de conversa serão geradas no lado do cliente no início da conversa ou ao convidar alguém, e serão criptografadas usando todas as chaves públicas envolvidas na conversa. Esses dados serão armazenados em uma tabela dedicada (user_id, topic_id, encrypted_conversation_key). Essa linha poderá ser criada por qualquer usuário da conversa, mas somente será legível quando current_user == user_id.

Será tomado cuidado especial para nunca vazar dados não criptografados para o servidor, incluindo garantir que rascunhos não sejam armazenados sem criptografia.

Para evitar uma grande classe de erros, novos elementos DOM (com novos IDs) serão usados para a edição e visualização do editor. A atual .d-editor-input conterá apenas blobs criptografados, e a visualização tradicional será desabilitada (ou seja, haverá duas áreas de texto: uma criptografada e outra não). A criptografia será fortemente desacoplada (debounced) para evitar problemas de desempenho.

Para a versão 1 (e o escopo deste item de trabalho), estamos dispostos a eliminar certas funcionalidades, incluindo suporte a uploads, oneboxing de conteúdo criptografado e outros casos complexos de borda.

Não temos problema em descriptografar, compilar e passar o HTML por um validador (whitelister) em tempo real ao renderizar esse conteúdo privado.

Requisitos de documentação

Antes da implementação, será criada uma especificação muito detalhada, incluindo mockups web e, mais importante, uma visão geral de segurança detalhada.

Requisitos de teste

Este plugin deve incluir um conjunto abrangente de testes unitários e de integração, tanto no lado do cliente quanto no servidor. Se você aceitar este projeto, escreva os testes desde o início; não espere até o fim do projeto para adicioná-los posteriormente.

Preocupações

Muitas das preocupações mencionadas em: https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/august/javascript-cryptography-considered-harmful/ não são mais relevantes devido à Web Crypto API (geração de bytes aleatórios verdadeiros, armazenamento de chaves privadas e muito mais). O único vetor principal existente é o servidor enviar JavaScript malicioso ao cliente. A curto prazo, os usuários simplesmente precisarão confiar no servidor da mesma forma que confiam no 1Password, LastPass e outras interfaces de segurança web. A longo prazo (versão 3/4 – no próximo ano ou depois), podemos considerar o lançamento de uma extensão de navegador que exibe um cadeado em sites onde todos os hashes de estabilidade dos payloads JavaScript são bem conhecidos.

A WebCrypto API ainda é relativamente nova, mas amplamente suportada. O plugin deve funcionar em todos os navegadores que suportamos.

Mockups simples e rascunhos

* Ao iniciar uma mensagem, o usuário pode optar por criptografar a conversa. Um aviso será exibido se algum dos participantes estiver sem chaves públicas.

* Os usuários podem habilitar mensagens criptografadas clicando nesse botão e seguindo uma interface que gera o par de chaves.

Se as mensagens criptografadas estiverem habilitadas, deve ser exibido simplesmente: “Você tem mensagens criptografadas habilitadas”.

* Um ícone ou sobreposição indicará que uma mensagem está criptografada.

Orçamento

Este é um projeto muito complexo de implementar, que exige integração profunda e revisão cuidadosa. Esperamos que seja extremamente bem testado (usando testes tanto no lado do cliente quanto no servidor). Nosso orçamento atual para um MVP é de 10 mil dólares americanos (USD).

34 curtidas

If the implementation is open source with the rest of discourse I could probably get our lot to throw in £1000 or thereabouts to your budget.

12 curtidas

Cool, yes, this will be open source under the MIT license, with an additional full license assignment to Discourse.

Regarding browser support, we want to make sure it works on every platform: Chrome + Safari is a minimum (so it works on iPhone / Android / Desktop), but my preference is that we hit Firefox as well. Edge is in the nice-to-have and IE11 is in the I don’t really care department, especially if it is missing crypto stuff.

7 curtidas

I’ll get the ball rolling now then, couple of questions though.

  • Is it plausible for this project to accommodate group encrypted chat, even if up to a point?
  • Would “Force every PM encrypted” option be on the cards?

Not for the initial version. Maybe for version 2 or 3, a PM between 20 users should absolutely work for V1.

Yes this is fine as an option. Basically would disallow PM to users that don’t have encryption enabled (but still allow admins to PM them unconditionally). We would need to think this through, but I don’t want to add this to the scope of the spec quite yet.

4 curtidas

Thanks i’m obligated to sample an arbitrarily acceptable number of our PMs and reading people’s intimate conversations if only skimming is not only something I don’t want to do it takes time I haven’t got.

a PM between 20 users should absolutely work for V1.

That’s group chat in my context (Forgot where I am :slight_smile: ) and will be fine. I’d expect strong support from our lot.

Keep in mind with this plugin it is technically impossible for you to read members private conversations provided they have a reasonably strong passphrase.

They are encrypted in the database and only decrypted client side. You would have to add a code exploit to your server for you to be able to swing reading encrypted PMs. Longer term (in v3 / v4) this code exploit would result in a giant red flag on the screen for people who install the “confirm my encrypted discourse conversations have not been exploited” browser plugin.

1 curtida

Yes that’s ideal, i’m obligated to look at them because I can look at them.

1 curtida

This is fascinating. It would be refreshing to do something really technically challenging. But, at least for me, the cost / benefit of taking the time to master (assuming, optimistically, that I could) all the relevant pieces doesn’t make sense right now.

That said, I just did a little reading on cryptography and have a few questions / thoughts:

  • Am I correct in understanding that you would need to generate a new conversation key every time you added or removed a member from the PM?

  • You would need some protection or warning against using other plugins as well. I can imagine a scenario in which you install this plugin, then someone writes another plugin that exposes or stores the entered text in some way before it is encrypted.

  • Wouldn’t you need to also only allow this feature on sites that force https? From the article you linked.

    You can’t simply send a single Javascript file over SSL/TLS. You have to send all the page content over SSL/TLS. Otherwise, attackers will hijack the crypto code using the least-secure connection that builds the page.

    Otherwise, in addition to the issue of the server sending malicious javascript you could also have the issue of ‘hijacking’.

  • Searchable semantic encryption is possible (by no means do I mean to imply that I understand the description in that paper). I assume you’re excluding it as the cost / benefit isn’t worth it, at least for the MVP.

  • Why not use the Signal Protocol? (javascript library).

ps. for whoever takes this on

15 curtidas

Great questions:

The encrypted conversation key does not need to change on add. All members of the conversation have a copy of the decrypted conversation key. So to add a member you would encrypt this conversation key using the “invitee” public key and teach the server about that.

Technically it would be correct to amend the conversation key if you are removing members from a conversation, but we can wait on v2 for that. Cause it would be a very expensive operation from the client side, entire conversation would have to be re-encrypted, or complex multi conversation key systems need to be built.

Yes, the long term V3 / V4 goal here is to have a whitelist of JS integrity hashes stored in a browser extension. That is really the only way a client can know 100% that the “server is not messing with stuff”. However for V1 we trust the server and server operator not to be malicious.

Yes, if SSL is off all bets are off. We do not expect this feature to even remotely work if SSL is off.

Yes search is off the cards for now cause it is just going to be too hard to get right for the MVP.

Maybe, not against leaning on existing standards, but I suspect the Discourse integration work here is going to be enormous regardless.

11 curtidas

Congrats! @dan will be taking this project! We will update here as we make progress!

29 curtidas

Signed up to comment on this because I’m curious on the implementation as a developer myself.

I’m personally no cryptography pro, so forgive me if these are silly questions.

Would it not be viable to encrypt the message on the server-side using the public keys of people currently in the conversation, in this case?
Essentially I guess this would lead to a double layer of encryption - the data is encrypted client-side for true E2E encryption as described with the conversation key, and then encrypted on the way out by the server to only the public keys active in the conversation. At that point, removing a member from the conversation would mean any future messages wouldn’t be decryptable by them.

I’m not too sure on the security implications of nested encryption like that, however.

My second question is how well this would work cross-device? Does it require a private key on the device, or is that handled by the passphrase encrypted private key being stored?

4 curtidas

Interesting idea the “double” encrypting. It does though add more responsibility to the server and a lot of this is about removing responsibility from the server so I am not sure it is a great idea protocol wise.

Cross device is handled by retrieving the encrypted private key from the server and decrypting using the key phrase.

Longer term we can introduce more “security” modes with a super strict one when say the server never even stores the private key encrypted (like say 1 password), but short term this is out of scope.

10 curtidas

Welcome! :discourse: :heart:

Those are not silly questions at all! If you want to dig deeper, I highly recommend Dan Boneh’s courses on Coursera.org.

This depends a lot on the particularities of the system you use. Check out double DES (i.e. vulnerable to meet-in-the-middle) and triple DES.

Let’s say Eve used to be a part of a group discussion with Alice and Bob. Even if Alice or Bob kick Eve out she will still have the conversation key and theoretically, she could intercept the messages before they get to the server and decrypt them.

If the conversation key gets compromised, the safest approach is to revoke it and use a new one for new messages. Ideally, you’d probably want to re-encrypt the old messages.

7 curtidas

That makes sense to me, thanks for the explanation! (@sam too)

So adding or removing users from the conversation would involve decrypting everything client-side, revoking the conversation key and generating a new one, then re-encrypting messages before sending to the server?
Plus encrypting the new conversation key with the user passphrase and storing it.

1 curtida

I’ve been talking to my wife about this feature. While this may raise an eyebrow at mealtime conversation in our family, she’s a security engineer for Thales eSecurity.

She’s of the opinion that the Specification needs some use cases with bad actors and how the system should respond. For example: Malicious Admin, Malicious SysOps.

This would then give rise to a security statement that could be presented to users of the system.

9 curtidas

I would love it if your wife or anyone interested in this problem at her work would pop by and give feedback.

@dan has made tremendous progress here, I am testing v1 with him this week.

To answer your specific question of bad sys admins. Overall if you can commandeer the web site and deliver malicious payloads our current v1 can not offer privacy. This is by design.

Our plans for v3/v4 is to have a browser plugin that validates every single JavaScript file on the page matches a particular hash in the whitelist. That way if you would be running this plugin you would be able to disallow unrecognized JS payloads.

Overall the underlying design means that passwords can not be fished out after the fact even if the server is malicious, but it can trick the client if it wishes to decrypt arbitrary payloads. Native browser plugins or a more refined web standard longer term will help eliminate this

14 curtidas

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.