E2EE (End-To-End Encryption) voor Delphi

· Componenten

Vanaf versie 2026.1.0 wordt E2EE (End-To-End Encryption) ondersteund (alleen voor eSeGeCe All-Access-abonnees).

End-to-end-encryptie (E2EE) zorgt ervoor dat alleen de communicerende peers de inhoud van uitgewisselde berichten kunnen lezen. Zelfs de server die de berichten doorstuurt, kan ze niet ontsleutelen. Dit artikel legt uit hoe E2EE werkt tussen twee peers met behulp van public-key-cryptografie om berichten veilig uit te wisselen.

E2EE uitgelegd

Kernprincipes van E2EE

In een E2EE-systeem met twee peers:


Overzicht sleutelmateriaal

Elke peer (bijvoorbeeld Alice en Bob) heeft:

Publieke en privé-sleutels zijn wiskundig met elkaar verbonden, maar het kennen van de publieke sleutel onthult niet de privé-sleutel.


Stap 1: uitwisseling van publieke sleutels

Voordat versleutelde communicatie kan plaatsvinden, moeten Alice en Bob elkaars publieke sleutels kennen.

Typische benaderingen:

Deze uitwisseling brengt de veiligheid niet in gevaar, omdat publieke sleutels niet geheim zijn.


Stap 2: een gedeeld geheim opzetten (ECDH)

Om berichten efficiënt te versleutelen, leiden Alice en Bob eerst een gedeeld geheim af met behulp van Elliptic Curve Diffie–Hellman (ECDH).

Hoe ECDH conceptueel werkt

Vanwege de wiskundige eigenschappen van elliptische krommen produceren beide berekeningen dezelfde geheime waarde, ook al stuurt geen van beide partijen dat geheim ooit door.

Op geen enkel moment wordt het gedeelde geheim over het netwerk verstuurd.


Stap 3: een symmetrische encryptiesleutel afleiden

Het ruwe ECDH-gedeelde geheim wordt niet rechtstreeks gebruikt voor encryptie. In plaats daarvan wordt het verwerkt via een Key Derivation Function (KDF), doorgaans een cryptografische hash zoals SHA-256.

Doel van sleutelafleiding:


Het resultaat is een symmetrische encryptiesleutel die alleen bij Alice en Bob bekend is.


Stap 4: het bericht versleutelen

Wanneer Alice een bericht naar Bob wil sturen:

  1. Alice converteert het bericht naar bytes.
  2. Alice versleutelt het bericht met een symmetrische cipher (meestal AES-GCM) met:
    • De afgeleide symmetrische sleutel
    • Een willekeurige initialisatievector (IV)
  3. Alice stuurt het versleutelde bericht en de IV via de server naar Bob.

AES-GCM wordt vaak gebruikt omdat het het volgende biedt:



Stap 5: het bericht ontsleutelen

Wanneer Bob het versleutelde bericht ontvangt:

  1. Bob leidt onafhankelijk dezelfde symmetrische sleutel af via ECDH en dezelfde KDF.
  2. Bob ontsleutelt het bericht met de symmetrische sleutel en de IV.
  3. Als de authenticatie slaagt, krijgt Bob de oorspronkelijke leesbare tekst.

Als het bericht is gewijzigd of de verkeerde sleutel wordt gebruikt, mislukt de decryptie.


Rol van de server

In deze architectuur:


De server kan:


Dit is de bepalende eigenschap van end-to-end-encryptie.


Samenvatting

End-to-end-encryptie tussen twee peers werkt door het combineren van:

  1. Public-key-cryptografie (voor sleutelovereenkomst)
  2. Symmetrische cryptografie (voor efficiënte berichtversleuteling)
  3. Key Derivation Functions (voor veiligheid en correctheid)

Het resultaat is een systeem waarin:


Dit model is de cryptografische ruggengraat van moderne veilige berichtensystemen. 

E2EE-voorbeeld

// ... Create the Server
WSServer := TsgcWebSocketHTTPServer.Create(nil);
WSServer.Port := 80;
WSPE2EE := TsgcWSPServer_E2EE.Create(nil);
WSPE2EE.Server := WSServer;
WSServer.Active := True;
// ... Create 2 clients
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 send a message to client-2
E2EE1.SendDirectMessage('client-2', 'Hello Client-2');
// ... read the message in the OnE2EEMessageText event
procedure OnE2EEMessageText(Sender: TObject; const aFrom, aText: string);
begin
  DoLog('#direct_message: ' + aText);
end;