den här artikeln om Mtprotos end-to-End-kryptering är avsedd för avancerade användare.Om du vill lära dig mer om hemliga chattar från en mindre skrämmande källa, vänligen se vår allmänna FAQ.
Observera att från och med version 4.6 använder stora Telegramklienter MTProto 2.0.MTProto v. 1.0 är föråldrat och håller för närvarande på att fasas ut.
hemliga chattar är en-mot-en-chattar där meddelanden krypteras med en nyckel som endast hålls av chattdeltagarna. Observera att schemat för dessa end-to-end-krypterade hemliga chattar skiljer sig från vad som används för molnchattar:
en anteckning på MTProto 2.0
den här artikeln beskriver end-to-end-krypteringsskiktet i MTProto-protokollet version 2.0.De huvudsakliga skillnaderna från version 1.0 (beskrivs här som referens) är följande:
- SHA-256 används istället för SHA-1;
- Padding bytes är involverade i beräkningen av msg_key;
- msg_key beror inte bara på meddelandet som ska krypteras, utan också på en del av den hemliga chattnyckeln;
- 12..1024 padding bytes används istället för 0..15 utfyllnad byte i v. 1.0.
Se även: MTProto 2.0: Molnchattar, server-klientkryptering
nyckelgenerering
nycklar genereras med Diffie-Hellman-protokollet.
låt oss överväga följande scenario: användare A vill initiera end-to-end krypterad kommunikation med användare B.
skicka en förfrågan
användare a kör meddelanden.getDhConfig för att erhålla Diffie-Hellman-parametrarna: a prime p och ett högordningselement g.
att utföra denna metod före varje ny nyckelgenereringsprocedur är av avgörande betydelse. Det är vettigt att cacha värdena för parametrarna tillsammans med versionen för att undvika att behöva ta emot alla värden varje gång. Om den version som lagras på klienten fortfarande är uppdaterad returnerar servern konstruktormeddelandena.dhConfigNotModified.
klienten förväntas kontrollera om p är en säker 2048-bitars prime (vilket betyder att både p och (p-1)/2 är prime, och att 2^2047< p< 2^2048), och att g genererar en cyklisk undergrupp av prime order (p-1) / 2, dvs. är en kvadratisk restmod p. eftersom g alltid är lika med 2, 3, 4, 5, 6 eller 7, görs detta enkelt med kvadratisk ömsesidighetslag, vilket ger ett enkelt tillstånd på p mod 4G-nämligen p mod 8 = 7 för G = 2; p mod 3 = 2 för G = 3; inget extra villkor för G = 4; p Mod 5 = 1 eller 4 för G = 5; p mod 24 = 19 eller 23 för G = 6; och p mod 7 = 3, 5 eller 6 för g = 7. Efter att g och p har kontrollerats av klienten är det vettigt att cacha resultatet för att undvika att upprepa långa beräkningar i framtiden. Den här cachen kan delas med en som används för generering av Behörighetsnycklar.
om klienten har en otillräcklig slumptalsgenerator är det vettigt att skicka random_length-parametern (random_length> 0) så att servern genererar sin egen slumpmässiga sekvens slumpmässig av lämplig längd.Viktigt: det kan vara osäkert att använda serverns slumpmässiga sekvens i sin råa form. Det måste kombineras med en klientsekvens, till exempel genom att generera ett klientslumpnummer med samma längd (client_random) och använda final_random := random XOR client_random
.
klient a beräknar ett 2048-bitars nummer a (med tillräcklig entropi eller serverns slumpmässiga; se ovan) och kör meddelanden.begärandekryptering efter att ha passerat in g_a := pow(g, a) mod dh_prime
.
användare b tar emot uppdateringen updateEncryption för alla tillhörande behörighetsnycklar (alla auktoriserade enheter) med chattkonstruktören encryptedChatRequested. Användaren måste visas grundläggande information om användare A och måste uppmanas att acceptera eller avvisa begäran.
båda klienterna ska kontrollera att g, g_a och g_b är större än en och mindre än p-1. Vi rekommenderar att du kontrollerar att g_a och g_b är mellan 2^{2048-64} och p – 2^{2048-64} också.
Acceptera en begäran
När användare b bekräftar skapandet av en hemlig chatt med A i klientgränssnittet får klient B också uppdaterade konfigurationsparametrar för Diffie-Hellman-metoden. Därefter genererar det ett slumpmässigt 2048-bitars nummer, b, med hjälp av regler som liknar dem för a.
har fått g_a från uppdateringen med encryptedChatRequested, det kan omedelbart generera den slutliga delade nyckeln: key = (pow(g_a, b) mod dh_prime)
. Om nyckellängd < 256 byte, Lägg till flera ledande nollbyte som vaddering — så att nyckeln är exakt 256 byte lång. Dess fingeravtryck, key_fingerprint, är lika med de 64 sista bitarna av SHA1 (nyckel).
Notera 1: i det här fallet används SHA1 här även för MTProto 2.0 hemliga chattar.
Anmärkning 2: detta fingeravtryck används som en sanity check för nyckelutbytesproceduren för att upptäcka buggar när man utvecklar klientprogramvara — den är inte ansluten till nyckelvisualiseringen som används på klienterna som medel för extern autentisering i hemliga chattar. Viktiga visualiseringar på klienterna genereras med de första 128 bitarna av SHA1(intial key) följt av de första 160 bitarna av SHA256 (nyckel som används när hemlig chatt uppdaterades till layer 46).
klient B kör meddelanden.acceptEncryption efter att ha passerat det g_b := pow(g, b) mod dh_prime
och key_fingerprint.
för alla klient B: s auktoriserade enheter, utom den nuvarande, skickas updateEncryption-uppdateringar med konstruktören encryptedchatdiskarded. Därefter är den enda enheten som kommer att kunna komma åt den hemliga chatten enhet B, som ringde till meddelanden.acceptEncryption.
användare A kommer att skickas en updateEncryption-uppdatering med konstruktören encryptedChat, för behörighetsnyckeln som initierade chatten.
med g_b från uppdateringen kan klient A också beräkna den delade nyckeln key = (pow(g_b, a) mod dh_prime)
. Om nyckellängd < 256 byte, Lägg till flera ledande nollbyte som vaddering — så att nyckeln är exakt 256 byte lång. Om fingeravtrycket för den mottagna nyckeln är identiskt med det som skickades till encryptedChat, inkommande meddelanden kan skickas och bearbetas. Annars meddelanden.discardEncryption måste utföras och användaren meddelas.
Perfect Forward Secrecy
för att hålla tidigare kommunikation säker, officiella Telegram klienter kommer att initiera re-keying när en nyckel har använts för att dekryptera och kryptera mer än 100 meddelanden, eller har varit i bruk i mer än en vecka, förutsatt att nyckeln har använts för att kryptera minst ett meddelande. Gamla nycklar kasseras sedan säkert och kan inte rekonstrueras, även med åtkomst till de nya nycklarna som för närvarande används.
re-keying-protokollet beskrivs vidare i den här artikeln: perfekt Framåtsekretess i hemliga chattar.
Observera att din klient måste stödja framåt Sekretess i hemliga chattar för att vara kompatibel med officiella Telegram klienter.
skicka och ta emot meddelanden i en hemlig chatt
serialisering och kryptering av utgående meddelanden
ett TL-objekt av typen DecryptedMessage skapas och innehåller meddelandet i vanlig text. För bakåtkompatibilitet måste objektet vara inslaget i konstruktören dekrypterademessagelayer med en indikation på det stödda lagret (börjar med 46).
TL-schemat för innehållet i end-to-end-krypterade meddelanden finns här”
den resulterande konstruktionen serialiseras som en rad byte med generiska TL-regler. Den resulterande arrayen är prepended av 4 byte som innehåller arraylängden som inte räknar dessa 4 byte.
byte arrayen är vadderad med 12 till 1024 slumpmässiga vadderande byte för att göra dess längd delbar med 16 byte. (I den äldre MTProto 1.0-krypteringen användes endast 0 till 15 vadderande byte.)
Meddelandenyckel, msg_key, beräknas som de 128 mittenbitarna i SHA256 av data som erhållits i föregående steg, prepended av 32 byte från den delade nyckelnyckeln. (För den äldre MTProto 1.0-krypteringen beräknades msg_key annorlunda, som de 128 nedre bitarna av SHA1 av de data som erhållits i föregående steg, exklusive vadderingsbyten.)
För MTProto 2.0 beräknas AES-tangenten aes_key och initialiseringsvektorn aes_iv (nyckeln är den delade nyckeln som erhållits under nyckelgenerering ) enligt följande:
- msg_key_large = SHA256 ( substr (nyckel, 88 + x, 32) + klartext + random_padding);
- msg_key = substr (msg_key_large, 8, 16);
- sha256_a = SHA256 (msg_key + substr (nyckel, x, 36));
- sha256_b = SHA256 (substr (nyckel, 40+x, 36) + msg_key);
- aes_key = substr (sha256_a, 0, 8) + substr (sha256_b, 8, 16) + substr (sha256_a, 24, 8);
- aes_iv = substr (sha256_b, 0, 8) + substr (sha256_a, 8, 16) + substr (sha256_b, 24, 8);
för MTProto 2.0, x=0 för meddelanden från upphovsmannen till den hemliga chatten, x=8 för meddelandena i motsatt riktning.
för den föråldrade MTProto 1.0, msg_key, aes_key och aes_iv beräknades annorlunda (se detta dokument för referens).
Data krypteras med en 256-bitars nyckel, aes_key och en 256-bitars initialiseringsvektor, AES-iv, med AES-256-kryptering med oändlig garble-förlängning (IgE). Krypteringsnyckel fingerprint key_fingerprint och meddelandenyckeln msg_key läggs till högst upp i den resulterande byte-arrayen.
krypterad data är inbäddad i ett meddelande.sendEncrypted API-samtal och skickas till Telegram server för leverans till den andra parten i den hemliga Chatten.
uppgradering till MTProto 2.0 från MTProto 1.0
så snart båda parter i en hemlig chatt använder minst Layer 73, bör de bara använda MTProto 2.0 för alla utgående meddelanden. Några av de första mottagna meddelandena kan använda MTProto 1.0, om ett tillräckligt högt startlager inte har förhandlats fram under skapandet av den hemliga chatten. Efter det första meddelandet krypterat med MTProto 2.0 (eller det första meddelandet med Layer 73 eller högre) tas emot måste alla meddelanden med högre sekvensnummer krypteras med MTProto 2.0 också.
så länge det aktuella lagret är lägre än 73, bör varje part försöka dekryptera mottagna meddelanden med MTProto 1.0, och om detta inte lyckas (msg_key matchar inte), försök MTProto 2.0. När det första MTProto 2.0-krypterade meddelandet anländer (eller lagret uppgraderas till 73) behöver du inte prova MTProto 1.0-dekryptering för något av de ytterligare meddelandena (såvida inte klienten fortfarande väntar på att vissa luckor ska stängas).
dekryptera ett inkommande meddelande
stegen ovan utförs i omvänd ordning. När ett krypterat meddelande tas emot måste du kontrollera att msg_key faktiskt är lika med de 128 mittenbitarna i SHA256-hashen i det dekrypterade meddelandet, tillagt av 32 byte som tagits från den delade nyckeln.Om meddelandelagret är större än det som stöds av klienten måste användaren meddelas att klientversionen är inaktuell och uppmanas att uppdatera.
sekvensnummer
det är nödvändigt att tolka alla meddelanden i sin ursprungliga ordning för att skydda mot eventuella manipuleringar. Hemliga chattar stöder en speciell mekanism för hantering av seq_no-räknare oberoende av servern.
korrekt hantering av dessa räknare beskrivs vidare i den här artikeln: sekvensnummer i hemliga chattar.
Observera att din klient måste stödja sekvensnummer i hemliga chattar för att vara kompatibel med officiella Telegram-klienter.
skicka krypterade filer
alla filer som skickas till hemliga chattar krypteras med engångsnycklar som inte på något sätt är relaterade till chattens delade nyckel. Innan en krypterad fil skickas antas det att den krypterade filens adress kommer att bifogas utsidan av ett krypterat meddelande med hjälp av filparametern för meddelandena.sendEncryptedFile-metoden och att nyckeln för direkt dekryptering kommer att skickas i meddelandets kropp (nyckelparametern i konstruktörerna decryptedMessageMediaPhoto, decryptedMessageMediaVideo och decryptedMessageMediaFile.
innan en fil skickas till en hemlig chatt beräknas 2 slumpmässiga 256-bitarsnummer som kommer att fungera som AES-nyckel och initialiseringsvektor som används för att kryptera filen. AES-256-kryptering med infinite garble extension (IgE) används på samma sätt.
nyckelfingeravtrycket beräknas enligt följande:
- digest = md5(nyckel + iv)
- fingerprint = substr(digest, 0, 4) XOR substr (digest, 4, 4)
det krypterade innehållet i en fil lagras på servern på ungefär samma sätt som i en fil i molnchattar: bit för bit med samtal för att ladda upp.spara fildel.Ett efterföljande samtal till meddelanden.sendEncryptedFile tilldelar en identifierare till den lagrade filen och skickar adressen tillsammans med meddelandet. Mottagaren kommer att få en uppdatering med krypteradmeddelande, och filparametern innehåller filinformation.
inkommande och utgående krypterade filer kan vidarebefordras till andra hemliga chattar med hjälp av constructor inputEncryptedFile för att undvika att spara samma innehåll på servern två gånger.
arbeta med en Uppdateringsruta
hemliga chattar är associerade med specifika enheter (eller snarare med behörighetsnycklar), inte användare. En konventionell meddelanderuta, som använder pts för att beskriva klientens status, är inte lämplig, eftersom den är utformad för långvarig meddelandelagring och meddelandeåtkomst från olika enheter.
en ytterligare tillfällig meddelandekö introduceras som en lösning på detta problem. När en uppdatering om ett meddelande från en hemlig chatt skickas skickas ett nytt värde på qts, vilket hjälper till att rekonstruera skillnaden om det har varit en lång paus i anslutningen eller i händelse av förlust av en uppdatering.
När antalet händelser ökar ökar värdet på qts med 1 för varje ny händelse. Det ursprungliga värdet får inte (och kommer inte) vara lika med 0.
det faktum att händelser från den tillfälliga kön har mottagits och lagrats av klienten bekräftas uttryckligen av ett samtal till meddelandena.mottagenkömetod eller implicit genom ett samtal till uppdateringar.getDifference (värdet av qts passerade, inte det slutliga tillståndet). Alla meddelanden som erkänns som levererade av klienten, liksom alla meddelanden som är äldre än 7 dagar, kan (och kommer) att raderas från servern.
Vid avbehörighet rensas händelsekön för motsvarande enhet med våld och värdet på qts blir irrelevant.
uppdatera till nya lager
din klient ska alltid lagra det maximala lager som är känt för att stödjas av klienten på andra sidan en hemlig chatt. När den hemliga chatten först skapas bör detta värde initieras till 46. Detta fjärrlagervärde måste alltid uppdateras omedelbart efter mottagandet av ett paket som innehåller information om ett övre lager, dvs.:
- varje hemligt chattmeddelande som innehåller layer_no i dess
decryptedMessageLayer
med layer>=46, eller - ett dekrypterat meddelande mess mess actionnotifylayer, inslaget som om det var den decryptedMessageService-konstruktören för det föråldrade lagret 8 (konstruktören
decryptedMessageService#aa48327d
).
meddela fjärrklienten om ditt lokala lager
för att meddela fjärrklienten om ditt lokala lager måste din klient skicka ett meddelande av typen decryptedMessageActionNotifyLayer
. Denna anmälan måste förpackas i en konstruktör av ett lämpligt lager.
det finns två fall när din klient måste meddela fjärrklienten om sitt lokala lager:
- så snart en ny hemlig chatt har skapats, omedelbart efter att den hemliga nyckeln har bytts ut.
- omedelbart efter att den lokala klienten har uppdaterats för att stödja ett nytt hemligt chattlager. I det här fallet måste meddelanden skickas till alla befintliga hemliga chattar. Observera att detta endast är nödvändigt när du uppdaterar till nya lager som innehåller ändringar i implementeringen av hemliga chattar (t. ex. du behöver inte göra detta när din klient uppdateras från lager 46 till lager 47).