GOSTIM: P2P F2F E2EE IM sa usa ka gabii nga adunay GOST cryptography
Pagkahimong usa ka developer PyGOST mga librarya (GOST cryptographic primitives sa purong Python), kanunay kong makadawat og mga pangutana kon unsaon pagpatuman ang pinakasimple nga luwas nga mensahe sa tuhod. Daghang mga tawo ang nag-isip sa gipadapat nga cryptography nga yano ra, ug ang pagtawag sa .encrypt() sa usa ka block cipher igo na aron ipadala kini nga luwas sa usa ka channel sa komunikasyon. Ang uban nagtuo nga ang gipadapat nga cryptography mao ang kapalaran sa pipila, ug gidawat nga ang mga adunahan nga kompanya sama sa Telegram nga adunay mga olympiad-mathematician. dili ma implementar luwas nga protocol.
Kining tanan nag-aghat kanako sa pagsulat niini nga artikulo aron ipakita nga ang pagpatuman sa cryptographic protocol ug luwas nga IM dili ingon ka lisud nga buluhaton. Bisan pa, dili kini angayan nga mag-imbento sa imong kaugalingon nga pag-authenticate ug mga protocol sa panguna nga kasabutan.
Ang artikulo mosulat -aw-sa-peer, higala-sa-higala, end-to-end nga gi-encrypt instant messenger uban sa SIGMA-I authentication ug key agreement protocol (base sa kung asa kini gipatuman IPsec IKE), gamit ang eksklusibong GOST cryptographic algorithms PyGOST library ug ASN.1 message encoding library PyDERASN (mahitungod niini ako na misulat kaniadto). Usa ka kinahanglanon: kini kinahanglan nga yano kaayo nga kini mahimong isulat gikan sa wala sa usa ka gabii (o adlaw sa trabaho), kung dili kini usa ka yano nga programa. Tingali kini adunay mga sayup, wala kinahanglana nga mga komplikasyon, mga kakulangan, ug kini ang akong una nga programa gamit ang asyncio library.
IM nga disenyo
Una, kinahanglan natong masabtan kung unsa ang hitsura sa atong IM. Alang sa kayano, himoa nga kini usa ka peer-to-peer nga network, nga walay bisan unsang pagdiskobre sa mga partisipante. Personal namong ipaila kung asa nga adres: pantalan nga makonektar aron makigkomunikar sa interlocutor.
Akong nasabtan nga, niining panahona, ang pangagpas nga ang direktang komunikasyon anaa sa taliwala sa duha ka arbitraryong mga kompyuter usa ka mahinungdanong limitasyon sa paggamit sa IM sa praktis. Apan kon mas daghan nga mga developers ang nagpatuman sa tanang matang sa NAT-traversal crutches, mas dugay nga kita magpabilin sa IPv4 Internet, nga adunay makapaguol nga posibilidad sa komunikasyon tali sa arbitraryong mga kompyuter. Hangtod kanus-a nimo maagwanta ang kakulang sa IPv6 sa balay ug trabaho?
Kita adunay usa ka higala-sa-higala nga network: ang tanan nga posible nga mga interlocutors kinahanglan nga mahibal-an daan. Una, gipasimple kaayo niini ang tanan: gipaila namo ang among kaugalingon, nakit-an o wala makit-an ang ngalan / yawe, giputol o nagpadayon sa pagtrabaho, nahibal-an ang interlocutor. Ikaduha, sa kinatibuk-an, kini luwas ug nagwagtang sa daghang mga pag-atake.
Ang IM interface mahimong duol sa klasiko nga mga solusyon walay pulos nga mga proyekto, nga ganahan kaayo ko sa ilang minimalism ug Unix-way nga pilosopiya. Ang programa sa IM nagmugna og usa ka direktoryo nga adunay tulo ka Unix domain sockets alang sa matag interlocutor:
saβmga mensahe nga gipadala ngadto sa interlocutor girekord niini;
out - ang mga mensahe nga nadawat gikan sa interlocutor gibasa gikan niini;
estado - pinaagi sa pagbasa gikan niini, atong mahibal-an kung ang interlocutor sa pagkakaron konektado, ang koneksyon address/port.
Dugang pa, ang usa ka conn socket gihimo, pinaagi sa pagsulat sa host port diin kami nagsugod sa usa ka koneksyon sa hilit nga interlocutor.
|-- alice
| |-- in
| |-- out
| `-- state
|-- bob
| |-- in
| |-- out
| `-- state
`- conn
Kini nga pamaagi nagtugot kanimo sa paghimo sa mga independente nga pagpatuman sa IM transport ug user interface, tungod kay walay higala, dili nimo mapahimut-an ang tanan. Paggamit tmux ug / o daghang ikog, mahimo kang makakuha og multi-window interface nga adunay syntax highlighting. Ug uban sa tabang rlwrap makakuha ka ug GNU Readline-compatible message input line.
Sa tinuud, ang mga proyekto nga walaβy sipsip naggamit sa mga file sa FIFO. Sa personal, dili nako masabtan kung giunsa pagtrabaho ang mga file nga kompetisyon sa asyncio nga walaβy sinulat sa kamot nga background gikan sa gipahinungod nga mga hilo (Gigamit nako ang sinultian alang sa ingon nga mga butang sa dugay nga panahon Go). Busa, nakahukom ko nga buhaton ang Unix domain sockets. Ikasubo, kini naghimo nga imposible nga buhaton ang echo 2001: 470: patay:: babe 6666 > conn. Gisulbad nako kini nga problema gamit ang socat: echo 2001:470:patay::babe 6666 | socat - UNIX-CONNECT:conn, socat READLINE UNIX-CONNECT:alice/in.
Ang orihinal nga dili sigurado nga protocol
Ang TCP gigamit isip transportasyon: gigarantiyahan niini ang pagpadala ug ang order niini. UDP dili garantiya (nga mahimong mapuslanon kon cryptography gigamit), apan suporta SCTP Ang Python dili mogawas sa kahon.
Ikasubo, sa TCP walay konsepto sa usa ka mensahe, usa lamang ka sapa sa bytes. Busa, kinahanglan nga maghimo ug usa ka pormat alang sa mga mensahe aron kini mapaambit sa ilang kaugalingon niini nga hilo. Mahimo kaming magkauyon nga gamiton ang karakter sa feed sa linya. Maayo kini alang sa mga nagsugod, apan sa higayon nga magsugod kami sa pag-encrypt sa among mga mensahe, kini nga karakter mahimong makita bisan asa sa ciphertext. Sa mga network, busa, ang mga sikat nga protocol mao ang una nga nagpadala sa gitas-on sa mensahe sa mga byte. Pananglitan, gikan sa kahon ang Python adunay xdrlib, nga nagtugot kanimo sa pagtrabaho sa susama nga format XDR.
Dili kami molihok sa husto ug episyente sa pagbasa sa TCP - among pasimplehon ang code. Gibasa namo ang datos gikan sa socket sa walay katapusan nga loop hangtud nga among gi-decode ang kompleto nga mensahe. Ang JSON nga adunay XML mahimo usab nga magamit ingon usa ka format alang niini nga pamaagi. Apan kung idugang ang kriptograpiya, kinahanglan nga pirmahan ug pamatud-an ang datos - ug magkinahanglan kini usa ka byte-for-byte nga parehas nga representasyon sa mga butang, nga wala gihatag sa JSON/XML (mahimong magkalainlain ang mga resulta sa dump).
Ang XDR angay alang niini nga buluhaton, bisan pa niana gipili nako ang ASN.1 nga adunay DER encoding ug PyDERASN librarya, tungod kay kita adunay taas nga lebel nga mga butang nga magamit diin kini kanunay nga labi ka makapahimuot ug kombenyente sa pagtrabaho. Dili sama sa schemaless bencode, MessagePack o CBOR, ASN.1 awtomatik nga susihon ang datos batok sa usa ka hard-coded schema.
Ang nadawat nga mensahe mao ang Msg: bisan usa ka text MsgText (nga adunay usa ka text field sa pagkakaron) o usa ka MsgHandshake handshake message (nga adunay ngalan sa interlocutor). Karon kini morag sobra ka komplikado, apan kini usa ka pundasyon alang sa umaabot.
Ibutang ang imong kaugalingong ngalan (--our-name alice). Ang tanan nga gipaabot nga mga interlocutor gilista nga gibulag sa mga koma (βilang-ngalan bob, eve). Alang sa matag usa sa mga interlocutors, usa ka direktoryo nga adunay mga socket sa Unix gihimo, ingon man usa ka coroutine alang sa matag sulod, gawas, estado:
Kung nagbasa gikan sa usa ka socket sa estado, ang programa nangita alang sa adres sa interlocutor sa PEER_ALIVE nga diksyonaryo. Kung wala pa'y koneksyon sa interlocutor, unya usa ka walay sulod nga linya ang gisulat.
async def unixsock_state_processor(reader, writer, peer_name: str) -> None:
peer_writer = PEER_ALIVES.get(peer_name)
writer.write(
b"" if peer_writer is None else (" ".join([
str(i) for i in peer_writer.get_extra_info("peername")[:2]
]).encode("utf-8") + b"n")
)
await writer.drain()
writer.close()
Sa pagsulat sa usa ka adres sa usa ka conn socket, ang koneksyon nga "initiator" function gilunsad:
async def unixsock_conn_processor(reader, writer) -> None:
data = await reader.read(256)
writer.close()
host, port = data.decode("utf-8").split(" ")
await initiator(host=host, port=int(port))
Atong tagdon ang initiator. Una kini klaro nga nagbukas sa usa ka koneksyon sa piho nga host / port ug nagpadala usa ka mensahe sa handshake nga adunay ngalan niini:
Unya, naghulat kini og tubag gikan sa hilit nga partido. Naningkamot sa pag-decode sa umaabot nga tubag gamit ang Msg ASN.1 scheme. Kami nagtuo nga ang tibuok nga mensahe ipadala sa usa ka bahin sa TCP ug ato kining madawat sa atomikong paagi sa pagtawag sa .read(). Among gisusi nga nadawat namo ang mensahe sa handshake.
Gisusi namo nga nahibal-an namo ang nadawat nga ngalan sa interlocutor. Kung dili, nan among giputol ang koneksyon. Among susihon kung nakatukod na ba kami og koneksyon uban kaniya (ang interlocutor mihatag na usab ug sugo nga makonektar kanamo) ug isira kini. Ang IN_QUEUES nga pila nagkupot sa Python nga mga kuwerdas nga adunay teksto sa mensahe, apan adunay espesyal nga kantidad nga Wala nga nagsenyas sa msg_sender coroutine nga mohunong sa pagtrabaho aron makalimtan ang bahin sa magsusulat niini nga adunay kalabotan sa kabilin nga koneksyon sa TCP.
159 msg_handshake = msg.value
160 peer_name = str(msg_handshake["peerName"])
161 if peer_name not in THEIR_NAMES:
162 logging.warning("unknown peer name: %s", peer_name)
163 writer.close()
164 return
165 logging.info("%s: session established: %s", _id, peer_name)
166 # Run text message sender, initialize transport decoder {{{
167 peer_alive = PEER_ALIVES.pop(peer_name, None)
168 if peer_alive is not None:
169 peer_alive.close()
170 await IN_QUEUES[peer_name].put(None)
171 PEER_ALIVES[peer_name] = writer
172 asyncio.ensure_future(msg_sender(peer_name, writer))
173 # }}}
Gidawat sa msg_sender ang mga outgoing messages (gipila gikan sa in socket), gi-serialize kini sa usa ka mensahe sa MsgText ug gipadala kini pinaagi sa koneksyon sa TCP. Mahimong maguba kini bisan unsang orasa - klaro namon nga gipugngan kini.
async def msg_sender(peer_name: str, writer) -> None:
in_queue = IN_QUEUES[peer_name]
while True:
text = await in_queue.get()
if text is None:
break
writer.write(Msg(("text", MsgText((
("text", UTF8String(text)),
)))).encode())
try:
await writer.drain()
except ConnectionResetError:
del PEER_ALIVES[peer_name]
return
logging.info("%s: sent %d characters message", peer_name, len(text))
Sa katapusan, ang initiator mosulod sa usa ka walay katapusan nga loop sa pagbasa sa mga mensahe gikan sa socket. Susihon kung kini nga mga mensahe mga text message ug ibutang kini sa OUT_QUEUES nga pila, diin sila ipadala sa gawas nga socket sa katugbang nga interlocutor. Ngano nga dili nimo mahimo ang .read() ug i-decode ang mensahe? Tungod kay posible nga daghang mga mensahe gikan sa tiggamit ang matipon sa buffer sa operating system ug ipadala sa usa ka bahin sa TCP. Mahimo natong decode ang una, ug ang bahin sa sunod mahimong magpabilin sa buffer. Sa kaso sa bisan unsa nga dili normal nga sitwasyon, atong isira ang TCP nga koneksyon ug ihunong ang msg_sender coroutine (pinaagi sa pagpadala sa Wala sa OUT_QUEUES nga pila).
174 buf = b""
175 # Wait for test messages {{{
176 while True:
177 data = await reader.read(MaxMsgLen)
178 if data == b"":
179 break
180 buf += data
181 if len(buf) > MaxMsgLen:
182 logging.warning("%s: max buffer size exceeded", _id)
183 break
184 try:
185 msg, tail = Msg().decode(buf)
186 except ASN1Error:
187 continue
188 buf = tail
189 if msg.choice != "text":
190 logging.warning("%s: unexpected %s message", _id, msg.choice)
191 break
192 try:
193 await msg_receiver(msg.value, peer_name)
194 except ValueError as err:
195 logging.warning("%s: %s", err)
196 break
197 # }}}
198 logging.info("%s: disconnecting: %s", _id, peer_name)
199 IN_QUEUES[peer_name].put(None)
200 writer.close()
66 async def msg_receiver(msg_text: MsgText, peer_name: str) -> None:
67 text = str(msg_text["text"])
68 logging.info("%s: received %d characters message", peer_name, len(text))
69 await OUT_QUEUES[peer_name].put(text)
Balik ta sa main code. Human sa paghimo sa tanang coroutine sa panahon nga magsugod ang programa, atong sugdan ang TCP server. Alang sa matag natukod nga koneksyon, nagmugna kini usa ka coroutine sa pagtubag.
logging.basicConfig(
level=logging.INFO,
format="%(levelname)s %(asctime)s: %(funcName)s: %(message)s",
)
loop = asyncio.get_event_loop()
server = loop.run_until_complete(asyncio.start_server(responder, args.bind, args.port))
logging.info("Listening on: %s", server.sockets[0].getsockname())
loop.run_forever()
Ang responder susama sa initiator ug nagsalamin sa tanan nga parehas nga mga aksyon, apan ang walay katapusan nga loop sa pagbasa sa mga mensahe magsugod dayon, alang sa kayano. Sa pagkakaron, ang protocol sa handshake nagpadala usa ka mensahe gikan sa matag kilid, apan sa umaabot adunay duha gikan sa initiator sa koneksyon, pagkahuman ang mga text message mahimong ipadala dayon.
Panahon na aron masiguro ang among komunikasyon. Unsa ang atong gipasabut sa seguridad ug unsa ang atong gusto:
kompidensyal sa gipasa nga mga mensahe;
pagkakasaligan ug integridad sa gipasa nga mga mensahe - ang ilang mga pagbag-o kinahanglan mahibal-an;
panalipod batok sa mga pag-atake sa replay - ang kamatuoran sa nawala o gibalikbalik nga mga mensahe kinahanglan mahibal-an (ug kami nakahukom nga tapuson ang koneksyon);
identification ug authentication sa mga interlocutors gamit ang pre-entered public keys - nakadesisyon na mi sa sayo pa nga naghimo mi ug friend-to-friend network. Human lamang sa pag-authentication atong masabtan kon kinsa ang atong gipakigsultihan;
pagkabaton hingpit nga sekreto sa unahan mga kabtangan (PFS) - ang pagkompromiso sa among dugay na nga pagpirma nga yawe kinahanglan dili mosangpot sa abilidad sa pagbasa sa tanan nga nangaging mga sulat. Ang pagrekord sa natanggong nga trapiko nahimong walay kapuslanan;
balido/balido sa mga mensahe (transportasyon ug handshake) sulod lang sa usa ka sesyon sa TCP. Ang pagsal-ot sa husto nga gipirmahan/authenticated nga mga mensahe gikan sa laing sesyon (bisan sa parehas nga interlocutor) dili mahimo;
ang usa ka passive observer kinahanglan nga dili makakita sa bisan hain sa user identifiers, transmitted long-lived public keys, o hash gikan kanila. Usa ka piho nga anonymity gikan sa usa ka passive observer.
Katingad-an, hapit tanan gusto nga adunay kini nga minimum sa bisan unsang protocol sa handshake, ug gamay ra sa mga nahisgutan sa katapusan ang nahimamat alang sa "homegrown" nga mga protocol. Karon dili na kami mag-imbento og bisan unsang bag-o. Ako siguradong morekomendar sa paggamit Balay sa kasaba para sa pagtukod og mga protocol, pero pilion ta og mas simple.
Ang duha ka labing popular nga mga protocol mao ang:
TLS - usa ka komplikado kaayo nga protocol nga adunay taas nga kasaysayan sa mga bug, jambs, vulnerabilities, dili maayo nga panghunahuna, pagkakomplikado ug mga kakulangan (bisan pa, kini walaβy kalabotan sa TLS 1.3). Apan dili nato kini tagdon tungod kay kini sobra ka komplikado.
IPsec Ρ Ike β walaβy seryoso nga mga problema sa cryptographic, bisan kung dili usab kini yano. Kung nagbasa ka bahin sa IKEv1 ug IKEv2, nan ang gigikanan niini STS, ISO/IEC IS 9798-3 ug SIGMA (SIGn-and-MAc) nga mga protocol - igo ra nga ipatuman sa usa ka gabii.
Unsa ang maayo bahin sa SIGMA, ingon ang pinakabag-o nga link sa pagpauswag sa mga protocol sa STS / ISO? Nagtagbo kini sa tanan namong mga kinahanglanon (lakip ang "pagtago" sa mga identifier sa interlocutor) ug walay nahibal-an nga mga problema sa cryptographic. Kini minimalistic - ang pagtangtang sa labing menos usa ka elemento gikan sa mensahe sa protocol mosangpot sa pagkawalay kasiguruhan niini.
Gikan sa pinakasimple nga protocol sa panimalay ngadto sa SIGMA. Ang labing sukaranan nga operasyon nga interesado kami mao yawe nga kasabutan: Usa ka function nga nagpagawas sa duha ka partisipante sa samang bili, nga mahimong gamiton isip simetriko nga yawe. Sa walay pag-adto sa mga detalye: ang matag usa sa mga partido makamugna og usa ka ephemeral (gigamit lamang sulod sa usa ka sesyon) nga pares nga yawe (publiko ug pribado nga mga yawe), pagbayloay sa mga yawe sa publiko, pagtawag sa function sa kasabutan, ngadto sa input diin ilang gipasa ang ilang pribadong yawe ug ang publiko yawe sa interlocutor.
Bisan kinsa mahimong moambak sa tunga ug pulihan ang mga yawe sa publiko sa ilang kaugalingon - walaβy panghimatuud sa mga interlocutors sa kini nga protocol. Magdugang ta og pirma nga adunay taas nga kinabuhi nga mga yawe.
Ang ingon nga pirma dili molihok, tungod kay wala kini gihigot sa usa ka piho nga sesyon. Ang ingon nga mga mensahe "angay" usab alang sa mga sesyon sa ubang mga partisipante. Ang tibuok konteksto kinahanglang mag-subscribe. Kini nagpugos kanato sa pagdugang usab og laing mensahe gikan sa A.
Dugang pa, hinungdanon nga idugang ang imong kaugalingon nga identifier sa ilawom sa pirma, tungod kay kung dili mahimo naton ilisan ang IdXXX ug pirmahan pag-usab ang mensahe gamit ang yawe sa lain nga nailhan nga interlocutor. Aron mapugngan mga pag-atake sa pagpamalandong, gikinahanglan nga ang mga elemento ubos sa pirma anaa sa tin-aw nga gihubit nga mga dapit sumala sa ilang kahulogan: kung A ang mga timailhan (PubA, PubB), nan ang B kinahanglan nga mopirma (PubB, PubA). Naghisgot usab kini sa kamahinungdanon sa pagpili sa istruktura ug format sa serialized data. Pananglitan, ang mga set sa ASN.1 DER encoding gisunod-sunod: SET OF(PubA, PubB) mahimong parehas sa SET OF(PubB, PubA).
Bisan pa, wala gihapon kami "napamatud-an" nga nakamugna kami sa parehas nga gipaambit nga yawe alang sa kini nga sesyon. Sa prinsipyo, mahimo naton kung wala kini nga lakang - ang una nga koneksyon sa transportasyon mahimong dili balido, apan gusto namon nga kung mahuman ang paglamano, sigurado kami nga ang tanan nauyonan. Sa pagkakaron aduna kitay ISO/IEC IS 9798-3 nga protocol sa kamot.
Mahimo natong pirmahan ang namugna nga yawe mismo. Delikado kini, tungod kay posible nga adunay mga pagtulo sa pirma nga algorithm nga gigamit (bisan pa nga mga bit-per-pirma, apan nag-leak gihapon). Posible nga mopirma og hash sa derivation key, apan ang pag-leak bisan sa hash sa derivated key mahimong bililhon sa usa ka brute-force attack sa derivation function. Ang SIGMA naggamit ug MAC function nga nagpamatuod sa nagpadala ID.
Isip usa ka pag-optimize, ang uban tingali gusto nga gamiton pag-usab ang ilang mga ephemeral nga yawe (nga, siyempre, dili maayo alang sa PFS). Pananglitan, naghimo kami usa ka yawe nga pares, misulay sa pagkonektar, apan ang TCP wala magamit o nabalda bisan diin sa tunga-tunga sa protocol. Makauulaw ang pag-usik sa nausik nga entropy ug mga kapanguhaan sa processor sa usa ka bag-ong pares. Busa, among ipaila ang gitawag nga cookie - usa ka pseudo-random nga kantidad nga manalipod batok sa posible nga random replay nga mga pag-atake kung gamiton pag-usab ang ephemeral public key. Tungod sa pagbugkos tali sa cookie ug sa ephemeral nga yawe sa publiko, ang publiko nga yawe sa kaatbang nga partido mahimong tangtangon gikan sa pirma ingon nga wala kinahanglana.
Sa katapusan, gusto namon nga makuha ang pribasiya sa among mga kauban sa pag-istoryahanay gikan sa usa ka passive observer. Aron mahimo kini, ang SIGMA nagsugyot nga una nga magbinayloay sa mga ephemeral nga yawe ug maghimo usa ka sagad nga yawe kung diin i-encrypt ang pag-authenticate ug pag-ila sa mga mensahe. Gihulagway sa SIGMA ang duha ka kapilian:
SIGMA-I - nanalipod sa initiator gikan sa aktibo nga mga pag-atake, ang responder gikan sa mga pasibo: ang initiator nagpamatuod sa responder ug kon adunay usa ka butang nga dili motakdo, nan kini dili paghatag sa iyang pag-ila. Ang akusado naghatag sa iyang identipikasyon kung adunay usa ka aktibong protocol nga gisugdan uban kaniya. Ang pasibo nga tigpaniid walay makat-onan;
SIGMA-R - nanalipod sa responder gikan sa aktibo nga mga pag-atake, ang initiator gikan sa mga pasibo. Ang tanan sukwahi gyud, apan sa kini nga protocol upat ka mga mensahe sa handshake ang gipasa na.
Gipili namo ang SIGMA-I tungod kay mas susama kini sa among gipaabot gikan sa pamilyar nga mga butang sa kliyente-server: ang kliyente giila lamang sa gipamatud-an nga server, ug ang tanan nakaila na sa server. Dugang pa nga kini mas sayon ββnga ipatuman tungod sa mas diyutay nga mga mensahe sa handshake. Ang tanan nga among idugang sa protocol mao ang pag-encrypt sa bahin sa mensahe ug pagbalhin sa identifier A sa na-encrypt nga bahin sa katapusang mensahe:
GOST R gigamit alang sa pirma 34.10-2012 algorithm nga adunay 256-bit nga mga yawe.
Aron makamugna ang publikong yawe, gigamit ang 34.10/2012/XNUMX VKO.
Ang CMAC gigamit isip MAC. Sa teknikal, kini usa ka espesyal nga paagi sa operasyon sa block cipher, nga gihulagway sa GOST R 34.13-2015. Isip usa ka encryption function alang niini nga mode β Balingkingpus (34.12-2015).
Ang hash sa iyang public key gigamit isip identifier sa interlocutor. Gigamit ingon usa ka hash Stribog-256 (34.11/2012/256 XNUMX ka gamay).
Human sa handshake, magkasabot mi sa gipaambit nga yawe. Magamit namo kini alang sa authenticated encryption sa mga mensahe sa transportasyon. Kini nga bahin yano kaayo ug lisud nga masayop: gidugangan namon ang counter sa mensahe, gi-encrypt ang mensahe, gi-authenticate (MAC) ang counter ug ciphertext, ipadala. Kung makadawat usa ka mensahe, among susihon nga ang counter adunay gipaabut nga kantidad, pamatud-an ang ciphertext gamit ang counter, ug i-decrypt kini. Unsa nga yawe ang akong gamiton sa pag-encrypt sa mga mensahe sa handshake, pagdala sa mga mensahe, ug unsaon pag-authenticate niini? Ang paggamit sa usa ka yawe alang sa tanan niini nga mga buluhaton peligroso ug dili maalamon. Gikinahanglan ang pagmugna og mga yawe gamit ang espesyal nga mga gimbuhaton Ang KDF (key nga derivation function). Pag-usab, dili ta magbahin sa buhok ug mag-imbento og usa ka butang: HKDF dugay na nga nahibal-an, maayo nga gisiksik ug walay nahibal-an nga mga problema. Ikasubo, ang lumad nga librarya sa Python wala niini nga function, mao nga among gigamit hkdf plastik nga bag. Ang HKDF sa sulod gigamit Ang HMAC, nga sa baylo naggamit ug hash function. Usa ka pananglitan nga pagpatuman sa Python sa panid sa Wikipedia nagkinahanglan lang og pipila ka linya sa code. Sama sa kaso sa 34.10/2012/256, atong gamiton ang Stribog-XNUMX isip hash function. Ang output sa among key agreement function tawgon nga session key, diin ang mga nawala nga simetriko mamugna:
HandshakeTBS ang pirmahan. HandshakeTBE - unsa ang ma-encrypt. Gidani nako ang imong atensyon sa natad sa ukm sa MsgHandshake1. 34.10 VKO, alang sa mas dako nga randomization sa namugna nga mga yawe, naglakip sa UKM (user keying material) parameter - dugang nga entropy.
Pagdugang sa Cryptography sa Code
Atong tagdon lamang ang mga pagbag-o nga gihimo sa orihinal nga code, tungod kay ang gambalay nagpabilin nga pareho (sa pagkatinuod, ang katapusan nga pagpatuman gisulat una, ug unya ang tanan nga cryptography giputol gikan niini).
Tungod kay ang panghimatuud ug pag-ila sa mga interlocutor himuon gamit ang mga yawe sa publiko, kinahanglan na sila nga itago sa usa ka lugar sa dugay nga panahon. Alang sa kayano, gigamit namo ang JSON nga sama niini:
among - among key pares, hexadecimal pribado ug publikong yawe. ilang β mga ngalan sa mga interlocutors ug ilang mga yawe sa publiko. Atong usbon ang mga argumento sa command line ug idugang ang post-processing sa JSON data:
from pygost import gost3410
from pygost.gost34112012256 import GOST34112012256
CURVE = gost3410.GOST3410Curve(
*gost3410.CURVE_PARAMS["GostR3410_2001_CryptoPro_A_ParamSet"]
)
parser = argparse.ArgumentParser(description="GOSTIM")
parser.add_argument(
"--keys-gen",
action="store_true",
help="Generate JSON with our new keypair",
)
parser.add_argument(
"--keys",
default="keys.json",
required=False,
help="JSON with our and their keys",
)
parser.add_argument(
"--bind",
default="::1",
help="Address to listen on",
)
parser.add_argument(
"--port",
type=int,
default=6666,
help="Port to listen on",
)
args = parser.parse_args()
if args.keys_gen:
prv_raw = urandom(32)
pub = gost3410.public_key(CURVE, gost3410.prv_unmarshal(prv_raw))
pub_raw = gost3410.pub_marshal(pub)
print(json.dumps({
"our": {"prv": hexenc(prv_raw), "pub": hexenc(pub_raw)},
"their": {},
}))
exit(0)
# Parse and unmarshal our and their keys {{{
with open(args.keys, "rb") as fd:
_keys = json.loads(fd.read().decode("utf-8"))
KEY_OUR_SIGN_PRV = gost3410.prv_unmarshal(hexdec(_keys["our"]["prv"]))
_pub = hexdec(_keys["our"]["pub"])
KEY_OUR_SIGN_PUB = gost3410.pub_unmarshal(_pub)
KEY_OUR_SIGN_PUB_HASH = OctetString(GOST34112012256(_pub).digest())
for peer_name, pub_raw in _keys["their"].items():
_pub = hexdec(pub_raw)
KEYS[GOST34112012256(_pub).digest()] = {
"name": peer_name,
"pub": gost3410.pub_unmarshal(_pub),
}
# }}}
Ang pribadong yawe sa 34.10 algorithm usa ka random nga numero. 256-bit nga gidak-on alang sa 256-bit elliptic curves. Ang PyGOST wala magtrabaho sa usa ka set sa bytes, apan uban sa dako nga numero, mao nga ang atong pribadong yawe (urandom(32)) kinahanglang i-convert sa numero gamit ang gost3410.prv_unmarshal(). Ang publiko nga yawe determinado nga deterministiko gikan sa pribadong yawe gamit ang gost3410.public_key(). Ang public key 34.10 kay duha ka dagkong numero nga kinahanglan usab nga i-convert ngadto sa byte sequence para sa kasayon ββsa pagtipig ug transmission gamit ang gost3410.pub_marshal().
Human mabasa ang JSON file, ang publiko nga mga yawe sumala niana kinahanglan nga mabag-o balik gamit ang gost3410.pub_unmarshal(). Tungod kay makadawat kami sa mga identifier sa mga interlocutors sa porma sa usa ka hash gikan sa publiko nga yawe, kini mahimo dayon nga kalkulado nga daan ug ibutang sa usa ka diksyonaryo alang sa dali nga pagpangita. Ang Stribog-256 hash mao ang gost34112012256.GOST34112012256(), nga hingpit nga nagtagbaw sa hashlib interface sa hash functions.
Sa unsang paagi nausab ang initiator coroutine? Ang tanan sumala sa laraw sa paglamano: naghimo kami usa ka cookie (daghan ang 128-bit), usa ka ephemeral key pair 34.10, nga gamiton alang sa function sa VKO key agreement.
Ang UKM usa ka 64-bit nga numero (urandom(8)), nga nagkinahanglan usab og deserialization gikan sa byte nga representasyon niini gamit ang gost3410_vko.ukm_unmarshal(). Ang VKO function alang sa 34.10/2012/256 3410-bit mao ang gost34102012256_vko.kek_XNUMX() (KEK - encryption key).
Ang namugna nga yawe sa sesyon kay usa na ka 256-bit pseudo-random byte sequence. Busa, kini magamit dayon sa mga gimbuhaton sa HKDF. Tungod kay ang GOST34112012256 nakatagbaw sa hashlib interface, mahimo kini dayon nga gamiton sa Hkdf nga klase. Wala namo ipiho ang asin (ang unang argumento sa Hkdf), tungod kay ang namugna nga yawe, tungod sa ephemerality sa mga nag-apil nga mga pares nga yawe, magkalahi alang sa matag sesyon ug adunay igo nga entropy. kdf.expand() pinaagi sa default naghimo na sa 256-bit nga mga yawe nga gikinahanglan alang sa Grasshopper sa ulahi.
Sunod, ang TBE ug TBS nga mga bahin sa umaabot nga mensahe gisusi:
ang MAC sa umaabot nga ciphertext gikalkula ug gisusi;
ang ciphertext gi-decrypted;
Ang istruktura sa TBE gi-decode;
ang identifier sa interlocutor gikuha gikan niini ug kini gisusi kon siya nakaila kanato sa tanan;
MAC sa ibabaw niini nga identifier kalkulado ug gisusi;
ang pirma sa TBS nga istruktura gipamatud-an, nga naglakip sa cookie sa duha ka partido ug ang publiko nga ephemeral nga yawe sa kaatbang nga partido. Ang pirma gipamatud-an sa dugay na nga pirma nga yawe sa interlocutor.
Sama sa akong gisulat sa ibabaw, 34.13/2015/XNUMX naghulagway sa lain-laing pag-block sa mga mode sa operasyon sa cipher gikan sa 34.12/2015/3413. Lakip kanila adunay usa ka mode alang sa pagmugna imitasyon pagsal-ot ug MAC kalkulasyon. Sa PyGOST kini mao ang gost34.12.mac(). Kini nga mode nagkinahanglan sa pagpasa sa encryption function (pagdawat ug pagbalik sa usa ka block sa data), ang gidak-on sa encryption block ug, sa pagkatinuod, ang data mismo. Nganong dili nimo ma-hardcode ang gidak-on sa encryption block? 2015/128/64 naghulagway dili lamang sa XNUMX-bit Grasshopper cipher, apan usab sa XNUMX-bit Magma - usa ka gamay nga giusab GOST 28147-89, gimugna balik sa KGB ug sa gihapon adunay usa sa mga labing taas nga safety thresholds.
Ang Kuznechik gisugdan pinaagi sa pagtawag sa gost.3412.GOST3412Kuznechik(key) ug gibalik ang usa ka butang nga adunay .encrypt()/.decrypt() nga mga pamaagi nga angay para sa pagpasa sa 34.13 functions. Ang MAC kalkulado sama sa mosunod: gost3413.mac(GOST3412Kuznechik(key).encrypt, KUZNECHIK_BLOCKSIZE, ciphertext). Aron itandi ang kalkulado ug nadawat nga MAC, dili nimo magamit ang naandan nga pagtandi (==) sa mga kuwerdas sa byte, tungod kay kini nga operasyon nag-leak sa oras sa pagtandi, nga, sa kinatibuk-ang kaso, mahimong mosangpot sa makamatay nga mga kahuyangan sama sa MANANAP pag-atake sa TLS. Ang Python adunay espesyal nga function, hmac.compare_digest, alang niini.
Ang block cipher function mahimo ra maka-encrypt sa usa ka block sa data. Alang sa mas dako nga gidaghanon, ug bisan dili usa ka multiple sa gitas-on, gikinahanglan nga gamiton ang encryption mode. 34.13-2015 naghulagway sa mosunod: ECB, CTR, OFB, CBC, CFB. Ang matag usa adunay kaugalingon nga madawat nga mga lugar sa aplikasyon ug mga kinaiya. Ikasubo, wala gihapon mi na-standardize gipamatud-an nga mga mode sa pag-encrypt (sama sa CCM, OCB, GCM ug uban pa) - napugos kami sa pagdugang sa MAC sa among kaugalingon. pilion ko kontra mode (CTR): wala kini magkinahanglan og padding sa block nga gidak-on, mahimong parallelize, naggamit lamang sa encryption function, mahimong luwas nga gamiton sa pag-encrypt sa daghang mga mensahe (dili sama sa CBC, nga adunay mga bangga nga medyo dali).
Sama sa .mac(), .ctr() nagkuha ug susamang input: ciphertext = gost3413.ctr(GOST3412Kuznechik(key).encrypt, KUZNECHIK_BLOCKSIZE, plaintext, iv). Gikinahanglan nga ipiho ang usa ka inisyal nga vector nga eksaktong katunga sa gitas-on sa block sa pag-encrypt. Kung ang among encryption nga yawe gigamit lamang sa pag-encrypt sa usa ka mensahe (bisan gikan sa daghang mga bloke), nan luwas nga magbutang ug zero initialization vector. Aron ma-encrypt ang mga mensahe sa handshake, mogamit kami usa ka bulag nga yawe matag higayon.
Ang pag-verify sa pirma nga gost3410.verify() kay trivial: gipasa namo ang elliptic curve diin kami nagtrabaho (girekord lang namo kini sa among GOSTIM protocol), ang public key sa nagpirma (ayaw kalimti nga kini kinahanglan nga usa ka tuple sa duha dako nga numero, ug dili usa ka byte string), 34.11/2012/XNUMX hash ug ang pirma mismo.
Sunod, sa initiator nag-andam kami ug nagpadala usa ka mensahe sa handshake sa handshake2, nga gihimo ang parehas nga mga aksyon sama sa among gibuhat sa panahon sa pag-verify, simetrikal lang: pagpirma sa among mga yawe imbis nga susihon, ug uban pa...
Kung natukod ang sesyon, ang mga yawe sa transportasyon namugna (usa ka lahi nga yawe alang sa pag-encrypt, alang sa pag-authenticate, alang sa matag usa sa mga partido), ug ang Grasshopper gisugdan aron ma-decrypt ug susihon ang MAC:
Ang msg_sender coroutine karon nag-encrypt sa mga mensahe sa dili pa ipadala kini sa koneksyon sa TCP. Ang matag mensahe adunay monotonically increase nonce, nga mao usab ang initialization vector kung ma-encrypt sa counter mode. Ang matag mensahe ug bloke sa mensahe gigarantiyahan nga adunay lahi nga kantidad sa counter.
Ang GOSTIM gituyo nga gamiton lamang alang sa mga katuyoan sa edukasyon (tungod kay dili kini sakop sa mga pagsulay, labing menos)! Ang source code sa programa mahimong ma-download dinhi (Π‘ΡΡΠΈΠ±ΠΎΠ³-256 Ρ ΡΡ: 995bbd368c04e50a481d138c5fa2e43ec7c89bc77743ba8dbabee1fde45de120). ΠΠ°ΠΊ ΠΈ Π²ΡΠ΅ ΠΌΠΎΠΈ ΠΏΡΠΎΠ΅ΠΊΡΡ, ΡΠΈΠΏΠ° GoGOST, PyDERASN, NCCP, GoVPN, GOSTIM mao ang bug-os libre nga softwaregiapod-apod ubos sa mga termino GPLv3 +.