Acest articol despre criptarea end-to-End a MTProto este destinat utilizatorilor avansați.Dacă doriți să aflați mai multe despre chat-urile secrete dintr-o sursă mai puțin intimidantă, consultați Întrebările frecvente generale.
rețineți că începând cu versiunea 4.6, principalii clienți Telegram folosesc MTProto 2.0.MTProto v. 1.0 este învechit și este în prezent eliminat treptat.
chaturile secrete sunt chaturi individuale în care mesajele sunt criptate cu o cheie deținută doar de participanții la chat. Rețineți că schema pentru aceste chat-uri secrete criptate end-to-end este diferită de cea utilizată pentru chat-urile cloud:
o notă despre MTProto 2.0
Acest articol descrie stratul de criptare end-to-end din Protocolul MTProto versiunea 2.0.Principalele diferențe față de versiunea 1.0 (descrise aici pentru referință) sunt următoarele:
- SHA-256 este utilizat în loc de SHA-1;
- octeții de umplutură sunt implicați în calculul msg_key;
- msg_key depinde nu numai de mesajul care trebuie criptat, ci și de o porțiune a cheii secrete de chat;
- 12..Se folosesc 1024 octeți de umplutură în loc de 0..15 octeți de umplutură în V. 1. 0.
vezi și: MTProto 2.0: chat-uri Cloud, criptare server-client
generarea cheilor
cheile sunt generate folosind protocolul Diffie-Hellman.
să luăm în considerare următorul scenariu: utilizatorul A ar dori să inițieze comunicarea criptată end-to-end cu utilizatorul B.
trimiterea unei cereri
Utilizatorul a execută mesaje.getDhConfig pentru a obține parametrii Diffie-Hellman: un prim p și un element de ordin înalt g.
executarea acestei metode înainte de fiecare nouă procedură de generare a cheilor este de o importanță vitală. Este logic să memorați în cache valorile parametrilor împreună cu versiunea pentru a evita să primiți toate valorile de fiecare dată. Dacă versiunea stocată pe client este încă actualizată, serverul va returna mesajele constructorului.dhConfigNotModified.
Clientul este de așteptat să verifice dacă p este un prim sigur pe 2048 biți (ceea ce înseamnă că atât p, cât și (p-1)/2 sunt prime și că 2^2047 < p < 2^2048) și că g generează un subgrup ciclic de prim ordin (p-1) / 2, adică. este un reziduu pătratic mod p. deoarece G este întotdeauna egal cu 2, 3, 4, 5, 6 sau 7, Acest lucru se face cu ușurință folosind legea reciprocității pătratice, rezultând o condiție simplă pe p mod 4G-și anume, p mod 8 = 7 pentru G = 2; p mod 3 = 2 Pentru g = 3; nicio condiție suplimentară pentru G = 4; p mod 5 = 1 sau 4 Pentru g = 5; p mod 24 = 19 sau 23 pentru G = 6; și p mod 7 = 3, 5 sau 6 pentru g = 7. După ce g și p au fost verificate de către client, este logic să cache rezultatul, astfel încât să se evite repetarea calculelor lungi în viitor. Această memorie cache poate fi partajată cu una utilizată pentru generarea cheilor de autorizare.
dacă clientul are un generator de numere aleatoare inadecvat, este logic să treacă parametrul random_length (random_length> 0) astfel încât serverul generează propria secvență aleatorie aleatorie a lungimii corespunzătoare.Important: utilizarea secvenței aleatoare a serverului în forma sa brută poate fi nesigură. Acesta trebuie combinat cu o secvență client, de exemplu, prin generarea unui număr aleatoriu client de aceeași lungime (client_random) și folosind final_random := random XOR client_random
.
Clientul a calculează un număr de 2048 biți a (folosind suficientă entropie sau Aleatoriu al serverului; vezi mai sus) și execută mesaje.requestEncryption după trecerea în g_a := pow(g, a) mod dh_prime
.
utilizatorul B primește actualizarea updateEncryption pentru toate cheile de autorizare asociate (toate dispozitivele autorizate) cu constructorul de chat encryptedChatRequested. Utilizatorului trebuie să i se arate informații de bază despre utilizatorul A și trebuie să i se solicite să accepte sau să respingă solicitarea.
ambii clienți trebuie să verifice dacă g, g_a și g_b sunt mai mari decât unu și mai mici decât p-1. Vă recomandăm să verificați dacă g_a și g_b sunt între 2 ^ {2048-64} și p – 2^{2048-64} de asemenea.
acceptarea unei cereri
după ce utilizatorul B confirmă crearea unui chat secret cu A în interfața client, clientul B primește, de asemenea, parametri de configurare actualizați pentru metoda Diffie-Hellman. Ulterior, generează un număr aleatoriu de 2048 de biți, b, folosind reguli similare cu cele pentru a.
după ce a primit g_a de la actualizarea cu encryptedChatRequested, se poate genera imediat cheia partajată finală:key = (pow(g_a, b) mod dh_prime)
. Dacă lungimea cheii< 256 octeți, adăugați mai mulți octeți zero ca umplutură — astfel încât cheia să aibă exact 256 octeți. Amprenta sa, key_fingerprint, este egală cu ultimii 64 de biți ai SHA1 (cheie).
Nota 1: în acest caz special SHA1 este folosit aici chiar și pentru MTProto 2.0 chat-uri secrete.
Nota 2: această amprentă este utilizată ca o verificare a sănătății pentru procedura de schimb de chei pentru a detecta erorile la dezvoltarea software — ului client-nu este conectată la vizualizarea cheii utilizată pe clienți ca mijloc de autentificare externă în chat-urile secrete. Vizualizările cheie ale clienților sunt generate folosind primii 128 de biți de SHA1(cheie intială) urmată de primii 160 de biți de SHA256 (cheie utilizată atunci când chat-ul secret a fost actualizat la stratul 46).
clientul B execută mesaje.acceptEncryption după trecerea acestuia g_b := pow(g, b) mod dh_prime
și key_fingerprint.
pentru toate dispozitivele autorizate ale clientului B, cu excepția celui curent, actualizările updateEncryption sunt trimise cu constructorul encryptedChatDiscarded. Ulterior, singurul dispozitiv care va putea accesa chatul secret este dispozitivul B, care a efectuat apelul la mesaje.acceptcryption.
Utilizatorul a va primi o actualizare updateEncryption cu constructorul encryptedChat, pentru cheia de autorizare care a inițiat chatul.
cu g_b din actualizare, clientul A poate calcula și cheia partajatăkey = (pow(g_b, a) mod dh_prime)
. Dacă lungimea cheii< 256 octeți, adăugați mai mulți octeți zero ca umplutură — astfel încât cheia să aibă exact 256 octeți. Dacă amprenta pentru cheia primită este identică cu cea care a fost transmisă către encryptedChat, mesajele primite pot fi trimise și procesate. În caz contrar, mesaje.discardEncryption trebuie executat și utilizatorul notificat.
Perfect Forward Secret
pentru a păstra în siguranță comunicațiile anterioare, clienții oficiali Telegram vor iniția re-tastarea odată ce o cheie a fost utilizată pentru a decripta și cripta mai mult de 100 de mesaje sau a fost utilizată mai mult de o săptămână, cu condiția ca cheia să fi fost utilizată pentru a cripta cel puțin un mesaj. Cheile vechi sunt apoi aruncate în siguranță și nu pot fi reconstruite, chiar și cu acces la noile chei utilizate în prezent.
protocolul de re-tastare este descris în continuare în acest articol: secretul perfect înainte în chaturile secrete.
vă rugăm să rețineți că clientul dvs. trebuie să susțină secretul înainte în chat-urile secrete pentru a fi compatibil cu clienții oficiali Telegram.
trimiterea și primirea mesajelor într-un Chat Secret
serializarea și criptarea mesajelor trimise
un obiect TL de tip DecryptedMessage este creat și conține mesajul în text simplu. Pentru compatibilitate înapoi, obiectul trebuie să fie înfășurat în constructorul decriptatmessagelayer cu o indicație a stratului acceptat (începând cu 46).
Schema TL pentru conținutul mesajelor criptate end-to-end este disponibilă aici „
construcția rezultată este serializată ca o serie de octeți folosind reguli TL generice. Matricea rezultată este prefixată de 4 octeți care conțin lungimea matricei fără a număra acești 4 octeți.
matricea de octeți este căptușită cu 12 până la 1024 octeți de umplutură aleatori pentru a-și face lungimea divizibilă cu 16 octeți. (În criptarea MTProto 1.0 mai veche, au fost utilizați doar 0 până la 15 octeți de umplutură.)
cheie mesaj, msg_key, este calculat ca 128 biți de mijloc de SHA256 a datelor obținute în etapa anterioară, prepended de 32 octeți din cheia partajată cheie. (Pentru criptarea MTProto 1.0 mai veche, msg_key a fost calculat diferit, ca cei 128 de biți inferiori ai SHA1 ai datelor obținute în etapele anterioare, excluzând octeții de umplutură.)
pentru MTProto 2.0, cheia AES aes_key și vectorul de inițializare aes_iv sunt calculate (cheia este cheia partajată obținută în timpul generării cheii) după cum urmează:
- msg_key_large = SHA256 (substr (cheie, 88 + x, 32) + plaintext + random_padding);
- msg_key = substr (msg_key_large, 8, 16);
- sha256_a = SHA256 (msg_key + substr (cheie, x, 36));
- sha256_b = SHA256 (substr (cheie, 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);
pentru MTProto 2.0, x=0 pentru mesaje de la inițiatorul chat-ului Secret, x=8 pentru mesajele din direcția opusă.
pentru MTProto învechit 1.0, msg_key, aes_key și aes_iv au fost calculate diferit (consultați acest document pentru referință).
datele sunt criptate cu o cheie de 256 de biți, aes_key și un vector de inițializare de 256 de biți, AES-iv, folosind criptarea AES-256 cu infinite garble extension (IGE). Cheie de criptare amprentă key_fingerprint și cheia de mesaj msg_key sunt adăugate în partea de sus a matricei de octeți rezultate.
datele criptate sunt încorporate într-un mesaj.sendEncrypted apel API și a trecut la serverul de Telegramă pentru livrare la cealaltă parte a Chat-ul Secret.
actualizarea la MTProto 2.0 de la MTProto 1.0
de îndată ce ambele părți dintr-un chat secret folosesc cel puțin stratul 73, ar trebui să utilizeze MTProto 2.0 numai pentru toate mesajele trimise. Unele dintre primele mesaje primite pot utiliza MTProto 1.0, dacă un strat de pornire suficient de ridicat nu a fost negociat în timpul creării chatului secret. După primirea primului mesaj criptat cu MTProto 2.0 (sau primul mesaj cu stratul 73 sau mai mare), toate mesajele cu numere de secvență mai mari trebuie să fie criptate și cu MTProto 2.0.
atâta timp cât stratul curent este mai mic decât 73, fiecare parte ar trebui să încerce să decripteze mesajele primite cu MTProto 1.0, iar dacă acest lucru nu este de succes (msg_key nu se potrivește), încercați MTProto 2.0. Odată ce primul mesaj criptat MTProto 2.0 sosește (sau stratul este actualizat la 73), nu este nevoie să încercați decriptarea MTProto 1.0 Pentru oricare dintre mesajele ulterioare (cu excepția cazului în care clientul încă așteaptă ca unele lacune să fie închise).
decriptarea unui mesaj primit
pașii de mai sus se efectuează în ordine inversă. Când se primește un mesaj criptat, trebuie să verificați dacă msg_key este de fapt egal cu cei 128 de biți de mijloc ai hash-ului SHA256 al mesajului decriptat, prepended de 32 de octeți preluați din cheia partajată.Dacă stratul de mesaje este mai mare decât cel acceptat de client, utilizatorul trebuie să fie notificat că versiunea client este depășită și să i se solicite actualizarea.
numere de secvență
este necesar să interpretați toate mesajele în ordinea lor inițială pentru a vă proteja împotriva posibilelor manipulări. Chaturile secrete acceptă un mecanism special pentru manipularea contoarelor seq_no independent de server.
manipularea corectă a acestor contoare este descrisă în continuare în acest articol: numere de secvență în chat-uri secrete.
vă rugăm să rețineți că clientul dvs. trebuie să accepte numere de secvență în chat-uri secrete pentru a fi compatibil cu clienții oficiali Telegram.
trimiterea fișierelor criptate
toate fișierele trimise la chaturile secrete sunt criptate cu chei unice care nu sunt în niciun fel legate de cheia partajată a chatului. Înainte de a trimite un fișier criptat, se presupune că adresa fișierului criptat va fi atașată la exteriorul unui mesaj criptat folosind parametrul fișier al mesajelor.metoda sendEncryptedFile și că cheia pentru decriptarea directă va fi trimisă în corpul mesajului (parametrul cheie din Constructorii decryptedMessageMediaPhoto, decryptedMessageMediaVideo și decryptedMessageMediaFile.
înainte ca un fișier să fie trimis într-un chat secret, sunt calculate 2 numere aleatorii pe 256 de biți, care vor servi drept cheie AES și vector de inițializare utilizat pentru criptarea fișierului. Criptarea AES-256 cu extensie garble infinită (IGE) este utilizată în mod similar.
amprenta cheie este calculată după cum urmează:
- digest = md5(cheie + iv)
- amprentă = substr(digest, 0, 4) XOR substr(digest, 4, 4)
conținutul criptat al unui fișier este stocat pe server în același mod ca și cel al unui fișier în chat-urile cloud: bucată cu bucată folosind apeluri pentru încărcare.salveazăfilepart.Un apel ulterior la mesaje.sendEncryptedFile va atribui un identificator fișierului stocat și va trimite adresa împreună cu mesajul. Destinatarul va primi o actualizare cu criptaremesaj, iar parametrul fișier va conține informații despre fișier.
fișierele criptate de intrare și ieșire pot fi redirecționate către alte chat-uri secrete folosind constructorul inputEncryptedFile pentru a evita salvarea aceluiași conținut pe server de două ori.
lucrul cu o casetă de actualizare
chaturile secrete sunt asociate cu dispozitive specifice (sau mai degrabă cu chei de autorizare), nu cu utilizatori. O casetă de mesaje convențională, care utilizează pts pentru a descrie starea clientului, nu este potrivită, deoarece este proiectată pentru stocarea mesajelor pe termen lung și accesul la mesaje de pe diferite dispozitive.
o coadă suplimentară de mesaje temporare este introdusă ca soluție la această problemă. Când se trimite o actualizare cu privire la un mesaj dintr-un chat secret, se trimite o nouă valoare a qts, care ajută la reconstituirea diferenței dacă a existat o pauză lungă în conexiune sau în cazul pierderii unei actualizări.
pe măsură ce numărul de evenimente crește, valoarea qts crește cu 1 cu fiecare eveniment nou. Valoarea inițială nu poate (și nu va fi) egală cu 0.
faptul că evenimentele din coada temporară au fost primite și stocate de client este recunoscut în mod explicit printr-un apel către mesaje.metoda receivedQueue sau implicit printr-un apel la actualizări.getdiference (valoarea qts a trecut, nu starea finală). Toate mesajele recunoscute ca fiind livrate de client, precum și orice mesaje mai vechi de 7 zile, pot (și vor) fi șterse de pe server.
la dezautorizare, coada de evenimente a dispozitivului corespunzător va fi ștearsă forțat, iar valoarea qts va deveni irelevantă.
actualizarea la noi straturi
clientul dvs. ar trebui să stocheze întotdeauna stratul maxim despre care se știe că este acceptat de client pe cealaltă parte a unui chat secret. Când chat-ul secret este creat pentru prima dată, această valoare ar trebui inițializată la 46. Această valoare a stratului la distanță trebuie întotdeauna actualizată imediat după primirea oricărui pachet care conține informații ale unui strat superior, adică.:
- orice mesaj secret de chat care conține layer_no în
decryptedMessageLayer
cu strat>=46 sau - un mesaj de serviciu decriptatmessageactionnotifylayer, înfășurat ca și cum ar fi constructorul decriptatmessageservice al stratului învechit 8 (constructor
decryptedMessageService#aa48327d
).
notificarea clientului la distanță despre stratul local
pentru a notifica clientul la distanță despre stratul local, clientul dvs. trebuie să trimită un mesaj de tipdecryptedMessageActionNotifyLayer
. Această notificare trebuie să fie înfășurată într-un constructor al unui strat adecvat.
există două cazuri în care clientul dvs. trebuie să notifice clientul la distanță despre stratul său local:
- De îndată ce a fost creat un nou chat secret, imediat după ce cheia secretă a fost schimbată cu succes.
- imediat după ce clientul local a fost actualizat pentru a sprijini un nou strat de chat secret. În acest caz, notificările trebuie trimise tuturor chat-urilor secrete existente în prezent. Rețineți că acest lucru este necesar numai atunci când actualizați la noi straturi tematice care conțin modificări în implementarea chaturilor secrete (de ex. nu trebuie să faceți acest lucru atunci când clientul dvs. este actualizat de la stratul 46 la stratul 47).