E2EE (End-To-End Encryption) for Delphi

· Komponenty

Od wersji 2026.1.0 obsługiwane jest E2EE (szyfrowanie End-To-End) (tylko dla subskrybentów eSeGeCe All-Access).

Szyfrowanie End-To-End (E2EE) zapewnia, że tylko komunikujące się strony mogą odczytać treść wymienianych wiadomości. Nawet serwer, który routuje wiadomości, nie może ich odszyfrować. Artykuł wyjaśnia, jak E2EE działa między dwoma partnerami z użyciem kryptografii klucza publicznego do bezpiecznej wymiany wiadomości.

E2EE — wyjaśnienie

Podstawowe zasady E2EE

W systemie E2EE między dwoma partnerami:


Przegląd materiału kluczowego

Każdy partner (np. Alicja i Bob) posiada:

Klucze publiczne i prywatne są matematycznie powiązane, ale znajomość klucza publicznego nie ujawnia klucza prywatnego.


Krok 1: Wymiana kluczy publicznych

Zanim będzie możliwa komunikacja szyfrowana, Alicja i Bob muszą znać swoje klucze publiczne.

Typowe podejścia:

Ta wymiana nie narusza bezpieczeństwa, ponieważ klucze publiczne nie są tajne.


Krok 2: Ustanowienie wspólnego sekretu (ECDH)

Aby efektywnie szyfrować wiadomości, Alicja i Bob najpierw wyprowadzają wspólny sekret za pomocą Elliptic Curve Diffie–Hellman (ECDH).

Jak działa ECDH konceptualnie

Ze względu na matematyczne właściwości krzywych eliptycznych obie operacje dają tę samą tajną wartość, mimo że żadna ze stron nigdy nie przesyła tego sekretu.

W żadnym momencie wspólny sekret nie jest wysyłany przez sieć.


Krok 3: Wyprowadzanie symetrycznego klucza szyfrowania

Surowy wspólny sekret ECDH nie jest używany bezpośrednio do szyfrowania. Zamiast tego jest przetwarzany przez funkcję wyprowadzania klucza (KDF), zazwyczaj kryptograficzny skrót taki jak SHA-256.

Cel wyprowadzania klucza:


Wynikiem jest symetryczny klucz szyfrowania znany tylko Alicji i Bobowi.


Krok 4: Szyfrowanie wiadomości

Gdy Alicja chce wysłać wiadomość do Boba:

  1. Alicja konwertuje wiadomość do bajtów.
  2. Alicja szyfruje wiadomość za pomocą symetrycznego szyfru (zazwyczaj AES-GCM) używając:
    • Wyprowadzonego klucza symetrycznego
    • Losowego wektora inicjalizacji (IV)
  3. Alicja wysyła zaszyfrowaną wiadomość i IV do Boba przez serwer.

AES-GCM jest powszechnie stosowany, ponieważ zapewnia:



Krok 5: Deszyfrowanie wiadomości

Gdy Bob otrzymuje zaszyfrowaną wiadomość:

  1. Bob niezależnie wyprowadza ten sam klucz symetryczny używając ECDH i tej samej KDF.
  2. Bob odszyfrowuje wiadomość za pomocą klucza symetrycznego i IV.
  3. Jeśli uwierzytelnienie się powiedzie, Bob uzyskuje oryginalny tekst jawny.

Jeśli wiadomość została zmieniona lub użyto złego klucza, deszyfrowanie kończy się niepowodzeniem.


Rola serwera

W tej architekturze serwer:


Serwer nie może:


To jest definiująca właściwość szyfrowania End-To-End.


Podsumowanie

Szyfrowanie End-To-End między dwoma partnerami działa poprzez połączenie:

  1. Kryptografii klucza publicznego (do uzgodnienia klucza)
  2. Kryptografii symetrycznej (do efektywnego szyfrowania wiadomości)
  3. Funkcji wyprowadzania klucza (dla bezpieczeństwa i poprawności)

Wynikiem jest system, w którym:


Ten model stanowi kryptograficzny fundament nowoczesnych bezpiecznych systemów przesyłania wiadomości. 

Przykład E2EE

// ... 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;