Sok más informatikussal egyetemben én is elborzadva olvastam azokat az "ötleteket" ami szerint a kormány tiltaná azokat az alkalmazásokat melyek olyan titkosítást alkalmaznak, melyet a készítője nem tud feloldani. Azt, hogy ez miért borzalmas ötlet már sokan mások is leírták, ezért erre nem is pazarolnám a betűket. Viszont a többség még úgy hiszi, hogy egy ilyen alkalmazást összerakni csak kivételes emberek tudnak. Ezzel szemben az igazság az, hogy a titkosításokhoz szükséges algoritmusok mára annyira kiforrottak, hogy minimális hozzáértéssel pillanatok alatt össze lehet dobni egy új alkalmazást.
Gondoltam ezt a gyakorlatban is kipróbálom, és megnézem mennyi idő összeütni egy end-to-end titkosító chat alkalmazást.
Elsőnek is kell egy chat alkalmazás. Ezt például a nodejs alapú socket.io-val nem nagy dolog összerakni, van rá kész tutorial is. Az egyszerűség kedvéért letöltöttem a kész oktató anyagot, és telepítettem:
Már csak el kell indítani:
Hoppá, máris van egy működő chat szolgáltatásom:
Már ezt önmagában is elég nehéz lenne megtalálni, hiszen bárki, bárhol elindíthat egy chat szervert. Viszont itt még nem használunk semmilyen titkosítást, így ha a hatóságok megtalálták akkor probléma nélkül le is tudják hallgatni.
Mivel azt szeretnénk, hogy csak a két fél tudja a titkosítást megfejteni ezért a végpontokon (a böngészőben) kel az adatokat titkosítani. Bár még nem végleges, de már szépen halad a HTML5 Crypto szabványa, ami pont ezt teszi számunkra egyszerűen elérhetővé.
A példa kedvéért elég lesz egy szimmetrikus kulcsú titkosítás is, azaz minden félnek ugyanazt a jelszót kell majd ismernie, ha hozzá akar férni az üzenetekhez. Ehhez tegyünk be egy jelszó mezőt az oldal tetejére:
Ezzel párhuzamosan az alsó form kapott egy "bottom" class-t. Pár apró css beállítás után meg is van az új képernyőnk:
Következő lépés az, hogy a beírt jelszóból generáljunk egy titkosító kulcsot. A jelszó önmagában gyakran nem annyira összetett, hogy egy brute force támadásnak ellenálljon, ezért a Crypto API deriveKey() metódusával kicsit "megerősítjük" (egyszerűen kimásoltam a példakódokat az MDN cikkéből):
Megjegyzés: mivel a titkosított chatünk arab magyar felhasználóknak készül, ezért gondolnunk kell az ékezetes karakterekre is. Fogadjuk meg az MDN tanácsát, és a karakter műveletekre használjuk az Unibabel csomagot.
Miután a .zip fájlt letöltöttük a socket.io szerver kódjába (index.js) be kellett rakni, hogy ezt is kiszolgálja. Ehhez ez a néhány sor kell, és ezután már be lehet szúrni a script taget az index.html-be.
Más dolgunk nincs is, mint titkosítani az üzenetet elküldés előtt. Ehhez az index.html-ben a korábbi socket.emit sort erre a kódra kell lecserélnünk:
Hoppá, már titkosított üzeneteket küldözgetünk, igaz elolvasni még nem tudjuk őket:
Most akkor próbáljuk meg dekódolni! Az AES-CBC esetében ehhez az Initialization Vectorra (IV) is szükségünk van, tehát az üzeneten kívül ezt is el kell küldeni. Mivel itt csak az a megkötés, hogy mindig egyedi legyen, ezért nyugodtan átküldhetjük kódolatlanul is. Ezért a socket.emitnek átadott adatstruktúrát kicsit kibővítjük:
Ezután a fogadó oldalon az üzenet eseménybe berakhatjuk a dekódolást:
És már működik is a chatünk: amint a jó jelszót adjuk meg megkapjuk a dekódolt üzeneteket:
A hálózat ablakban is látszik, hogy az üzenetek titkosítva jönnek-mennek, mi viszont már csak a dekódoltat látjuk - feltéve, hogy ismerjük a jelszót.
Ezt a kódot már csak el kell indítani egy publikus szerveren, és már van is egy működő "szolgáltatásunk". Nekem nagyjából két-három órába telt összerakni. Nyilván ez egy "fapados" alkalmazás, de jól szemlélteti, hogy a titkosítást behúzni alig pár sor kódot jelent.
Az alkalmazás jelenleg modern asztali chrome és firefox böngészőkön fut, de vélhetően hamarosan elérhetőek lesznek ezek az API-k a mobil böngészőkön is.
A teljes kód némi finomításokkal elérhető githubon, kipróbálni pedig itt lehet.