E2EE (Criptografia de Ponta a Ponta) para Delphi

· Componentes

A partir da versão 2026.1.0 o E2EE (End-To-End Encryption) é suportado (apenas para assinantes eSeGeCe All-Access).

A Criptografia de Ponta a Ponta (E2EE) garante que apenas os pares em comunicação possam ler o conteúdo das mensagens trocadas. Nem mesmo o servidor que roteia as mensagens consegue descriptografá-las. Este artigo explica como o E2EE funciona entre dois pares usando criptografia de chave pública para trocar mensagens com segurança.

E2EE explicado

Princípios fundamentais do E2EE

Em um sistema E2EE com dois pares:


Visão geral do material de chaves

Cada par (por exemplo, Alice e Bob) tem:

As chaves pública e privada são matematicamente vinculadas, mas conhecer a chave pública não revela a chave privada.


Passo 1: troca de chaves públicas

Antes que a comunicação criptografada possa ocorrer, Alice e Bob precisam conhecer as chaves públicas um do outro.

Abordagens típicas:

Essa troca não compromete a segurança, porque as chaves públicas não são secretas.


Passo 2: estabelecendo um segredo compartilhado (ECDH)

Para criptografar mensagens de forma eficiente, Alice e Bob primeiro derivam um segredo compartilhado usando Elliptic Curve Diffie–Hellman (ECDH).

Como o ECDH funciona conceitualmente

Por causa das propriedades matemáticas das curvas elípticas, ambos os cálculos produzem o mesmo valor secreto, mesmo que nenhum dos lados transmita esse segredo.

Em nenhum momento o segredo compartilhado é enviado pela rede.


Passo 3: derivando uma chave de criptografia simétrica

O segredo compartilhado ECDH bruto não é usado diretamente para criptografia. Em vez disso, ele é processado por uma Key Derivation Function (KDF), normalmente um hash criptográfico como o SHA-256.

Finalidade da derivação de chave:


O resultado é uma chave de criptografia simétrica conhecida apenas por Alice e Bob.


Passo 4: criptografando a mensagem

Quando Alice quer enviar uma mensagem para Bob:

  1. Alice converte a mensagem em bytes.
  2. Alice criptografa a mensagem usando uma cifra simétrica (geralmente AES-GCM) com:
    • A chave simétrica derivada
    • Um vetor de inicialização (IV) aleatório
  3. Alice envia a mensagem criptografada e o IV para Bob por meio do servidor.

O AES-GCM é comumente usado porque fornece:



Passo 5: descriptografando a mensagem

Quando Bob recebe a mensagem criptografada:

  1. Bob deriva independentemente a mesma chave simétrica usando ECDH e a mesma KDF.
  2. Bob descriptografa a mensagem usando a chave simétrica e o IV.
  3. Se a autenticação for bem-sucedida, Bob obtém o plaintext original.

Se a mensagem tiver sido alterada ou a chave errada for usada, a descriptografia falha.


Papel do servidor

Nessa arquitetura, o servidor:


O servidor não pode:


Essa é a propriedade definidora da Criptografia de Ponta a Ponta.


Resumo

A Criptografia de Ponta a Ponta entre dois pares funciona combinando:

  1. Criptografia de chave pública (para acordo de chave)
  2. Criptografia simétrica (para criptografia eficiente de mensagens)
  3. Funções de derivação de chave (para segurança e correção)

O resultado é um sistema em que:


Esse modelo é a espinha dorsal criptográfica dos sistemas modernos de mensageria segura. 

Exemplo de E2EE

// ... Cria o Servidor
WSServer := TsgcWebSocketHTTPServer.Create(nil);
WSServer.Port := 80;
WSPE2EE := TsgcWSPServer_E2EE.Create(nil);
WSPE2EE.Server := WSServer;
WSServer.Active := True;
// ... Cria 2 clientes
WSClient1 := TsgcWebSocketClient.Create(nil);
WSClient1.Host := '127.0.0.1';
WSClient1.Port := 80;
E2EE1 := TsgcWSPClient_E2EE.Create(nil);
E2EE1.Client := WSClient1;
E2EE1.E2EE_Otpions.UserId := 'client-1';
WSClient1.Active := True;
WSClient2 := TsgcWebSocketClient.Create(nil);
WSClient2.Host := '127.0.0.1';
WSClient2.Port := 80;
E2EE2 := TsgcWSPClient_E2EE.Create(nil);
E2EE2.OnE2EEMessageText := OnE2EEMessageTextEvent;
E2EE2.E2EE_Otpions.UserId := 'client-2';
E2EE2.Client := WSClient2;
WSClient2.Active := True;
// ... client-1 envia uma mensagem para client-2
E2EE1.SendDirectMessage('client-2', 'Hello Client-2');
// ... lê a mensagem no evento OnE2EEMessageText
procedure OnE2EEMessageText(Sender: TObject; const aFrom, aText: string);
begin
  DoLog('#direct_message: ' + aText);
end;