GOSTIM: P2P F2F E2EE IM nan yon aswè ak kriptografi GOST
Pou ou kab vin yon pwomotè PyGOST bibliyotèk (GOST primitif kriptografik nan pi Python), mwen souvan resevwa kesyon sou fason pou aplike mesaj ki pi senp an sekirite sou jenou an. Anpil moun konsidere kriptografi aplike yo dwe byen senp, epi rele .encrypt() sou yon chifreman blòk pral ase yo voye li an sekirite sou yon kanal kominikasyon. Gen lòt ki kwè ke kriptografi aplike se desten kèk moun, e li akseptab ke konpayi rich tankou Telegram ak olympiad-matematisyen. pa ka aplike pwotokòl sekirite.
Tout bagay sa a te pouse m 'ekri atik sa a pou montre ke mete ann aplikasyon pwotokòl kriptografik ak IM an sekirite se pa yon travay difisil. Sepandan, li pa vo envante pwòp otantifikasyon ou ak pwotokòl akò kle yo.
Atik la pral ekri kanmarad-a-kanmarad, zanmi-a-zanmi, bout-a-fen chiffres instant messenger ak SIGMA-I otantifikasyon ak pwotokòl akò kle (sou baz li aplike IPsec IKE), lè l sèvi avèk sèlman GOST algoritm kriptografik bibliyotèk PyGOST ak bibliyotèk kodaj mesaj ASN.1. PyDERASN (sou sa mwen deja ekri avan). Yon avantou: li dwe tèlman senp ke li ka ekri nan grafouyen nan yon aswè (oswa jou travay), otreman li pa yon pwogram senp ankò. Li pwobableman gen erè, konplikasyon nesesè, enpèfeksyon, plis sa a se premye pwogram mwen an lè l sèvi avèk bibliyotèk asyncio la.
IM konsepsyon
Premyèman, nou bezwen konprann ki sa IM nou an pral sanble. Pou senplisite, se pou li yon rezo kanmarad-a-kanmarad, san okenn dekouvèt nan patisipan yo. Nou pral pèsonèlman endike ki adrès: pò pou konekte ak kominike ak entèrlokuteur a.
Mwen konprann ke, nan moman sa a, sipozisyon ke kominikasyon dirèk disponib ant de òdinatè abitrè se yon limit enpòtan sou aplikasyon IM nan pratik. Men, plis devlopè yo aplike tout kalite beki NAT-travèsal, se plis n ap rete sou Entènèt IPv4 la, ak yon pwobabilite depresyon pou kominikasyon ant òdinatè abitrè. Konbyen tan ou ka tolere mank IPv6 nan kay la ak nan travay?
Nou pral gen yon rezo zanmi-a-zanmi: tout entèrlokuteur posib yo dwe konnen davans. Premyèman, sa a anpil senplifye tout bagay: nou prezante tèt nou, jwenn oswa pa jwenn non / kle a, dekonekte oswa kontinye travay, konnen entèrlokuteur la. Dezyèmman, an jeneral, li an sekirite epi li elimine anpil atak.
Koòdone IM la pral fèmen nan solisyon klasik pwojè san tete, ki mwen vrèman renmen pou minimalist yo ak filozofi Unix-fason. Pwogram IM kreye yon anyè ak twa sipò domèn Unix pou chak entèrlokuteur:
nan—mesaj yo voye bay entèrlokuteur a anrejistre ladan l;
soti - mesaj yo resevwa nan men entèrlokuteur a li nan li;
eta - pa li nan li, nou chèche konnen si entèrlokuteur a kounye a konekte, adrès la koneksyon / pò.
Anplis de sa, yon priz koneksyon kreye, lè w ekri pò a lame nan ki nou kòmanse yon koneksyon ak entèrlokuteur a aleka.
|-- alice
| |-- in
| |-- out
| `-- state
|-- bob
| |-- in
| |-- out
| `-- state
`- conn
Apwòch sa a pèmèt ou fè aplikasyon endepandan nan transpò IM ak koòdone itilizatè, paske pa gen okenn zanmi, ou pa ka tanpri tout moun. Sèvi ak tmux ak / oswa multi, ou ka jwenn yon koòdone milti-fenèt ak sentaks en. Ak èd la rlwrap ou ka jwenn yon liy antre mesaj GNU Readline ki konpatib.
An reyalite, pwojè suckless itilize FIFO dosye. Pèsonèlman, mwen pa t 'kapab konprann ki jan yo travay ak dosye konpetitif nan asyncio san yon background ekri men nan fil dedye (mwen te itilize lang lan pou bagay sa yo pou yon tan long. Go). Se poutèt sa, mwen deside fè fè ak sipò domèn Unix. Malerezman, sa fè li enposib fè echo 2001:470:dead::babe 6666 > konn. Mwen rezoud pwoblèm sa a lè l sèvi avèk socat: echo 2001:470:mouri::babe 6666 | socat - UNIX-CONNECT:conn, socat READLINE UNIX-CONNECT:alice/in.
Pwotokòl orijinal la ensekirite
TCP yo itilize kòm transpò: li garanti livrezon ak lòd li yo. UDP garanti ni (ki ta itil lè yo itilize kriptografik), men sipò SCTP Python pa soti nan bwat la.
Malerezman, nan TCP pa gen okenn konsèp nan yon mesaj, se sèlman yon kouran nan bytes. Se poutèt sa, li nesesè yo vini ak yon fòma pou mesaj pou yo ka pataje nan mitan tèt yo nan fil sa a. Nou ka dakò pou sèvi ak karaktè liy manje a. Li bon pou kòmanse, men yon fwa nou kòmanse kode mesaj nou yo, karaktè sa a ka parèt nenpòt kote nan chifreman an. Nan rezo, Se poutèt sa, pwotokòl popilè yo se moun ki premye voye longè mesaj la an byte. Pou egzanp, soti nan bwat la Python gen xdrlib, ki pèmèt ou travay ak yon fòma menm jan an XDR.
Nou pa pral travay kòrèkteman ak efikasite ak lekti TCP - nou pral senplifye kòd la. Nou li done ki soti nan priz la nan yon bouk kontinuèl jiskaske nou dekode mesaj la konplè. JSON ak XML ka itilize tou kòm yon fòma pou apwòch sa a. Men, lè yo ajoute kriptografik, done yo pral dwe siyen ak otantifye - e sa pral mande pou yon byte-pou-byte reprezantasyon ki idantik nan objè, ki JSON/XML pa bay (rezilta pil fatra yo ka varye).
XDR se apwopriye pou travay sa a, sepandan mwen chwazi ASN.1 ak DER kodaj ak PyDERASN bibliyotèk, depi nou pral gen objè wo nivo nan men ak ki souvan li se pi bèl ak pratik nan travay. Kontrèman ak schemaless benkode, MessagePack oswa CBOR, ASN.1 pral otomatikman tcheke done yo kont yon chema difisil-kode.
Mesaj resevwa a pral Msg: swa yon tèks MsgText (ak yon sèl jaden tèks pou kounye a) oswa yon mesaj MsgHandshake handshake (ki gen non entèrlokuteur a). Koulye a, li sanble twò konplike, men sa a se yon fondasyon pou lavni an.
Mete pwòp non ou (--non-nou alice). Tout entèrlokuteur espere yo nan lis separe pa vigil (—non-yo bob,eve). Pou chak entèrlokuteur yo, yo kreye yon anyè ak sipò Unix, ansanm ak yon koroutin pou chak nan, soti, eta:
Lè li nan yon priz leta, pwogram nan chèche adrès entèrlokuteur a nan diksyonè PEER_ALIVE la. Si pa gen okenn koneksyon ak entèrlokuteur a ankò, Lè sa a, yon liy vid ekri.
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()
Lè w ap ekri yon adrès nan yon priz koneksyon, fonksyon "inisyatè" koneksyon an lanse:
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))
Ann konsidere inisyatè a. Premyèman, li evidamman ouvè yon koneksyon ak lame / pò a espesifye epi voye yon mesaj lanmen ak non li:
Lè sa a, li tann pou yon repons soti nan pati a aleka. Eseye dekode repons fèk ap rantre lè l sèvi avèk konplo Msg ASN.1 la. Nou sipoze ke tout mesaj la pral voye nan yon sèl segman TCP epi nou pral resevwa li atomik lè w ap rele .read(). Nou tcheke si nou te resevwa mesaj lanmen an.
Nou tcheke si non entèlokutè a te resevwa a konnen nou. Si ou pa, Lè sa a, nou kraze koneksyon an. Nou tcheke si nou te deja etabli yon koneksyon avèk li (entèrlokuteur a ankò te bay lòd la konekte ak nou) epi fèmen li. Keu IN_QUEUES la kenbe kòd Python ak tèks mesaj la, men li gen yon valè espesyal None ki siyal koroutin msg_sender la sispann travay pou li bliye ekriven li ki asosye ak koneksyon TCP eritaj la.
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 # }}}
msg_sender aksepte mesaj sortan (ki nan keu nan yon priz nan), seri yo nan yon mesaj MsgText epi voye yo sou yon koneksyon TCP. Li ka kraze nan nenpòt ki moman - nou klèman entèsepte sa a.
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))
Nan fen a, inisyatè a antre nan yon bouk enfini nan lekti mesaj ki soti nan priz la. Tcheke si mesaj sa yo se mesaj tèks epi mete yo nan keu OUT_QUEUES, kote yo pral voye yo nan priz la soti nan entèrlokuteur ki koresponn lan. Poukisa ou pa ka jis fè .read() ak dekode mesaj la? Paske li posib ke plizyè mesaj ki soti nan itilizatè a pral rasanble nan tanpon sistèm operasyon an epi voye nan yon sèl segman TCP. Nou ka dekode youn nan premye, ak Lè sa a, yon pati nan youn nan ki vin apre a ka rete nan tanpon an. Nan nenpòt sitiyasyon nòmal, nou fèmen koneksyon TCP a epi sispann koroutin msg_sender la (pa voye None nan keu OUT_QUEUES).
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)
Ann retounen nan kòd prensipal la. Apre ou fin kreye tout koroutin yo nan moman pwogram nan kòmanse, nou kòmanse sèvè TCP la. Pou chak koneksyon etabli, li kreye yon koroutin sekouris.
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()
sekouris se menm jan ak inisyatè ak miwa tout aksyon yo menm, men bouk la enfini nan lekti mesaj kòmanse imedyatman, pou senplisite. Kounye a, pwotokòl lanmen voye yon mesaj soti nan chak bò, men nan lavni an pral gen de soti nan inisyatè koneksyon an, apre sa yo ka voye mesaj tèks imedyatman.
Li lè pou sekirize kominikasyon nou yo. Ki sa nou vle di pa sekirite ak sa nou vle:
konfidansyalite mesaj transmèt;
otantisite ak entegrite nan mesaj transmèt - chanjman yo dwe detekte;
pwoteksyon kont atak replay - yo dwe detekte lefèt nan mesaj ki manke oswa repete (epi nou deside mete fen nan koneksyon an);
idantifikasyon ak otantifikasyon entèrlokuteur lè l sèvi avèk kle piblik pre-antre - nou deja deside pi bonè ke nou te fè yon rezo zanmi-a-zanmi. Se sèlman apre otantifikasyon nou pral konprann ki moun nou ap kominike ak;
disponiblite pafè sekrè pou pi devan pwopriyete (PFS) - konpwomèt kle siyen ki dire lontan nou an pa ta dwe mennen nan kapasite nan li tout korespondans anvan yo. Anrejistreman trafik entèsepte vin initil;
validite/validite mesaj (transpò ak lanmen) sèlman nan yon sesyon TCP. Mete mesaj kòrèkteman siyen/otantifye ki soti nan yon lòt sesyon (menm avèk menm entèrlokuteur a) pa ta dwe posib;
yon obsèvatè pasif pa ta dwe wè ni idantifyan itilizatè yo, ni kle piblik ki dire lontan ki te transmèt, ni hache nan men yo. Yon sèten anonimite soti nan yon obsèvatè pasif.
Surprenante, prèske tout moun vle gen minimòm sa a nan nenpòt pwotokòl lanmen, epi anpil ti kras nan pi wo a finalman satisfè pou pwotokòl "homegrown". Koulye a, nou pa pral envante anyen nouvo. Mwen ta definitivman rekòmande pou itilize Fondasyon bri pou bati pwotokòl, men ann chwazi yon bagay ki pi senp.
De pwotokòl ki pi popilè yo se:
tl - yon pwotokòl trè konplèks ak yon istwa long nan pinèz, jambs, vilnerabilite, move panse, konpleksite ak enpèfeksyon (sepandan, sa a gen ti kras fè ak TLS 1.3). Men, nou pa konsidere li paske li twò konplike.
IPsec с Ike — pa gen pwoblèm kriptografik grav, byenke yo tou pa senp. Si ou li sou IKEv1 ak IKEv2, Lè sa a, sous yo se STS, ISO/IEC IS 9798-3 ak SIGMA (SIGn-and-MAc) pwotokòl - ase senp pou aplike nan yon aswè.
Ki sa ki bon sou SIGMA, kòm dènye lyen nan devlopman nan pwotokòl STS / ISO? Li satisfè tout kondisyon nou yo (ki gen ladan "kache" idantifyan entèrlokuteur) epi li pa gen okenn pwoblèm kriptografik li te ye. Li se minimalist - retire omwen yon eleman nan mesaj pwotokòl la ap mennen nan ensekirite li yo.
Ann ale soti nan pwotokòl ki pi senp nan kay la nan SIGMA. Operasyon ki pi fondamantal nou enterese nan se akò kle: Yon fonksyon ki bay tou de patisipan yo menm valè, ki ka itilize kòm yon kle simetrik. San yo pa antre nan detay: chak nan pati yo jenere yon pè kle efemèr (itilize sèlman nan yon sèl sesyon) (kle piblik ak prive), echanj kle piblik, rele fonksyon akò a, nan opinyon nan ki yo pase kle prive yo ak piblik la. kle entèrlokuteur a.
Nenpòt moun ka sote nan mitan an epi ranplase kle piblik ak pwòp yo - pa gen okenn otantifikasyon nan entèrlokuteur nan pwotokòl sa a. Ann ajoute yon siyati ak kle ki dire lontan.
Yon siyati sa a pa pral travay, paske li pa mare nan yon sesyon espesifik. Mesaj sa yo tou "apwopriye" pou sesyon ak lòt patisipan yo. Tout kontèks la dwe abònman. Sa a fòse nou ajoute yon lòt mesaj nan men A.
Anplis de sa, li enpòtan pou ajoute pwòp idantifyan ou anba siyati a, paske otreman nou ka ranplase IdXXX epi re-siyen mesaj la ak kle yon lòt entèrlokuteur li te ye. Pou anpeche atak refleksyon, li nesesè ke eleman ki anba siyati a yo nan kote ki byen defini dapre siyifikasyon yo: si A siy (PubA, PubB), Lè sa a, B dwe siyen (PubB, PubA). Sa a tou pale sou enpòtans ki genyen nan chwazi estrikti a ak fòma nan done seri. Pa egzanp, ansanm nan kodaj ASN.1 DER yo klase: SET OF(PubA, PubB) pral idantik ak SET OF(PubB, PubA).
Sepandan, nou toujou pa "pwouve" ke nou te pwodwi menm kle pataje pou sesyon sa a. Nan prensip, nou ka fè san etap sa a - premye koneksyon transpò a pral envalid, men nou vle ke lè lanmen an fini, nou ta asire w ke tout bagay vrèman dakò sou. Nan moman sa a nou gen pwotokòl ISO/IEC IS 9798-3 nan men.
Nou ta ka siyen kle a pwodwi tèt li. Sa a se danjere, paske li posib ke ka gen fwit nan algorithm siyati yo itilize (kwake Bits-pa-siyati, men yo toujou ap koule). Li posib pou siyen yon hash nan kle derivasyon an, men koule menm hash nan kle derive a ka gen anpil valè nan yon atak fòs brital sou fonksyon an derivasyon. SIGMA sèvi ak yon fonksyon MAC ki otantifye ID moun k ap voye a.
Kòm yon optimize, kèk ka vle reitilize kle efemèr yo (ki se, nan kou, malere pou PFS). Pou egzanp, nou te pwodwi yon pè kle, yo te eseye konekte, men TCP pa t 'disponib oswa yo te entèwonp yon kote nan mitan an nan pwotokòl la. Li se yon wont gaspiye entropi ak resous processeur gaspiye sou yon nouvo pè. Se poutèt sa, nou pral entwodui sa yo rele bonbon an - yon valè pseudo-o aza ki pral pwoteje kont posib atak reparèt o aza lè w ap reitilize kle piblik efemèr. Akòz obligatwa ki genyen ant bonbon an ak kle piblik la efemèr, kle piblik la nan pati opoze a ka retire nan siyati a kòm nesesè.
Finalman, nou vle jwenn konfidansyalite patnè konvèsasyon nou yo nan men yon obsèvatè pasif. Pou fè sa, SIGMA pwopoze premye echanj kle efemèr epi devlope yon kle komen sou ki ankripte mesaj otantifikasyon ak idantifye. SIGMA dekri de opsyon:
SIGMA-I - pwoteje inisyatè a kont atak aktif, sekouris a soti nan atak pasif: inisyatè a otantifye sekouris la epi si yon bagay pa matche, Lè sa a, li pa bay idantifikasyon li yo. Akize a bay idantifikasyon li si yo kòmanse yon pwotokòl aktif avèk li. Obsèvatè pasif la pa aprann anyen;
SIGMA-R - pwoteje sekouris la kont atak aktif, inisyatè a soti nan atak pasif. Tout bagay se egzakteman opoze a, men nan pwotokòl sa a kat mesaj lanmen yo deja transmèt.
Nou chwazi SIGMA-I kòm li pi sanble ak sa nou espere nan bagay ki abitye kliyan-sèvè: kliyan an rekonèt sèlman pa sèvè otantifye a, epi tout moun deja konnen sèvè a. Anplis de sa, li pi fasil pou aplike akòz mwens mesaj lanmen. Tout sa nou ajoute nan pwotokòl la se ankripte yon pati nan mesaj la epi transfere idantifyan an A nan pati a chiffres nan dènye mesaj la:
GOST R yo itilize pou siyati 34.10-2012 algorithm ak kle 256-bit.
Pou jenere kle piblik la, yo itilize 34.10/2012/XNUMX VKO.
CMAC yo itilize kòm MAC la. Teknikman, sa a se yon mòd operasyon espesyal nan yon chifreman blòk, ki dekri nan GOST R 34.13-2015. Kòm yon fonksyon chifreman pou mòd sa a - Sotrèl (34.12-2015).
Yo itilize hash la nan kle piblik li kòm idantifyan entèrlokuteur a. Itilize kòm yon hash Stribog-256 (34.11/2012/256 XNUMX Bits).
Apre lanmen an, nou pral dakò sou yon kle pataje. Nou ka sèvi ak li pou chifreman otantifye nan mesaj transpò. Pati sa a trè senp epi difisil pou fè yon erè: nou ogmante kontwa mesaj la, ankripte mesaj la, otantifye (MAC) kontwa a ak chifretèks, voye. Lè n ap resevwa yon mesaj, nou tcheke si kontwa a gen valè espere, otantifye tèks chifreman an ak kontwa an, epi dechifre li. Ki kle mwen ta dwe itilize pou ankripte mesaj lanmen, transpòte mesaj, ak kijan pou otantifye yo? Sèvi ak yon sèl kle pou tout travay sa yo se danjere e saj. Li nesesè pou jenere kle lè l sèvi avèk fonksyon espesyalize KDF (fonksyon derivasyon kle). Ankò, se pou nou pa fann cheve epi envante yon bagay: HKDF li te konnen depi lontan, byen rechèch epi li pa gen okenn pwoblèm li te ye. Malerezman, bibliyotèk natif natal Python pa gen fonksyon sa a, kidonk nou itilize hkdf sak plastik. HKDF entèn itilize HMAC, ki an vire sèvi ak yon fonksyon hash. Yon egzanp aplikasyon nan Python sou paj Wikipedya a pran jis kèk liy kòd. Kòm nan ka a nan 34.10/2012/256, nou pral sèvi ak Stribog-XNUMX kòm fonksyon an hash. Pwodiksyon fonksyon akò kle nou an pral rele kle sesyon an, ki soti nan ki simetrik ki manke yo pral pwodwi:
HandshakeTBS se sa ki pral siyen. HandshakeTBE - sa ki pral chiffres. Mwen atire atansyon w sou jaden ukm nan MsgHandshake1. 34.10 VKO, pou menm pi gwo randomisation nan kle yo pwodwi, gen ladan UKM (materyèl keying itilizatè) paramèt la - jis antropi adisyonèl.
Ajoute kriptografik nan Kòd
Ann konsidere sèlman chanjman ki fèt nan kòd orijinal la, depi fondasyon an rete menm jan an (an reyalite, aplikasyon final la te ekri an premye, ak Lè sa a, tout kriptografi a te koupe soti nan li).
Depi otantifikasyon ak idantifikasyon entèrlokuteur yo pral fèt lè l sèvi avèk kle piblik, yo kounye a bezwen yo dwe estoke yon kote pou yon tan long. Pou senplisite, nou itilize JSON tankou sa a:
nou - pè kle nou an, kle prive ak piblik egzadesimal. yo — non entèrlokuteur yo ak kle piblik yo. Ann chanje agiman liy kòmand yo epi ajoute apre-pwosesis done JSON:
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),
}
# }}}
Kle prive algorithm 34.10 la se yon nimewo o aza. Gwosè 256-bit pou koub eliptik 256-bit. PyGOST pa travay ak yon seri bytes, men ak gwo kantite, Se konsa, kle prive nou an (urandom(32)) bezwen konvèti nan yon nimewo lè l sèvi avèk gost3410.prv_unmarshal (). Se kle piblik la detèmine detèministic soti nan kle prive a lè l sèvi avèk gost3410.public_key(). Kle piblik 34.10 la se de gwo nimewo ki bezwen tou konvèti nan yon sekans byte pou fasilite depo ak transmisyon lè l sèvi avèk gost3410.pub_marshal().
Apre ou fin li fichye JSON la, kle piblik yo dwe konvèti tounen lè l sèvi avèk gost3410.pub_unmarshal(). Depi nou pral resevwa idantifyan yo nan entèrlokuteur yo nan fòm lan nan yon hash soti nan kle piblik la, yo ka imedyatman kalkile davans epi mete yo nan yon diksyonè pou rechèch rapid. Stribog-256 hash se gost34112012256.GOST34112012256 (), ki konplètman satisfè koòdone nan hashlib nan fonksyon hash.
Ki jan koroutin inisyatè a chanje? Tout bagay se tankou pou chak konplo lanmen: nou jenere yon bonbon (128-bit se anpil), yon pè kle efemèr 34.10, ki pral itilize pou fonksyon an akò kle VKO.
UKM se yon nimewo 64-bit (urandom(8)), ki tou mande pou deserialization soti nan reprezantasyon byte li yo lè l sèvi avèk gost3410_vko.ukm_unmarshal (). Fonksyon VKO pou 34.10/2012/256 3410-bit se gost34102012256_vko.kek_XNUMX () (KEK - kle chifreman).
Kle sesyon pwodwi a se deja yon sekans byte pseudo-o aza 256-bit. Se poutèt sa, li ka imedyatman itilize nan fonksyon HKDF. Depi GOST34112012256 satisfè koòdone hashlib la, li ka imedyatman itilize nan klas Hkdf. Nou pa presize sèl la (premye agiman nan Hkdf), depi kle ki pwodwi a, akòz efemèr nan pè kle k ap patisipe yo, yo pral diferan pou chak sesyon epi li deja gen ase entropi. kdf.expand() pa default deja pwodui kle 256-bit ki nesesè pou Grasshopper pita.
Apre sa, yo tcheke pati TBE ak TBS nan mesaj k ap vini an:
MAC a sou tèks chifreman fèk ap rantre yo kalkile epi tcheke;
se chifreman tèks la dechifre;
estrikti TBE dekode;
yo pran idantifikasyon entèrlokuteur a nan men li epi yo tcheke si nou konnen li ditou;
MAC sou idantifyan sa a kalkile epi tcheke;
siyati sou estrikti TBS la verifye, ki gen ladann bonbon tou de pati yo ak kle piblik efemèr pati opoze a. Siyati a verifye pa kle siyati ki dire lontan entèlokutè a.
Kòm mwen te ekri pi wo a, 34.13/2015/XNUMX dekri divès kalite bloke mòd operasyon chifreman yo soti 34.12/2015/3413. Pami yo gen yon mòd pou jenere imitasyon foure ak kalkil MAC. Nan PyGOST sa a se gost34.12.mac (). Mòd sa a mande pou pase fonksyon an chifreman (resevwa ak retounen yon blòk nan done), gwosè a nan blòk la chifreman ak, an reyalite, done nan tèt li. Poukisa ou pa ka hardcode gwosè blòk chifreman an? 2015/128/64 dekri non sèlman chifreman Grasshopper XNUMX-bit, men tou XNUMX-bit la. Magma - yon GOST 28147-89 yon ti kras modifye, ki te kreye tounen nan KGB a epi li toujou gen youn nan pi wo papòt sekirite yo.
Kuznechik inisyalize lè w rele gost.3412.GOST3412Kuznechik(kle) epi li retounen yon objè ak metòd .encrypt()/.decrypt() apwopriye pou pase nan fonksyon 34.13. MAC kalkile jan sa a: gost3413.mac(GOST3412Kuznechik(key).encrypt, KUZNECHIK_BLOCKSIZE, ciphertext). Pou konpare MAC kalkile a ak resevwa, ou pa ka itilize konparezon abityèl (==) nan fisèl byte, depi operasyon sa a fwit tan konparezon, ki, nan ka jeneral la, ka mennen nan frajilite fatal tankou BÈT atak sou TLS. Python gen yon fonksyon espesyal, hmac.compare_digest, pou sa.
Fonksyon chifre blòk an ka sèlman ankripte yon blòk done. Pou yon nimewo ki pi gwo, e menm pa yon miltip nan longè a, li nesesè yo sèvi ak mòd nan chifreman. 34.13-2015 dekri sa ki annapre yo: ECB, CTR, OFB, CBC, CFB. Chak gen pwòp zòn akseptab aplikasyon ak karakteristik. Malerezman, nou toujou pa gen estanda mòd chifreman otantifye (tankou CCM, OCB, GCM ak renmen an) - nou oblije omwen ajoute MAC tèt nou. mwen chwazi mòd kontwa (CTR): li pa mande pou padding nan gwosè blòk la, yo ka paralelize, itilize sèlman fonksyon an chifreman, yo ka itilize san danje pou ankripte gwo kantite mesaj (kontrèman ak CBC, ki gen kolizyon relativman byen vit).
Tankou .mac (), .ctr () pran opinyon menm jan an: ciphertext = gost3413.ctr (GOST3412Kuznechik (key). Encrypt, KUZNECHIK_BLOCKSIZE, plaintext, iv). Li oblije presize yon vektè inisyalizasyon ki se egzakteman mwatye longè blòk chifreman an. Si yo itilize kle chifreman nou an sèlman pou ankripte yon mesaj (kwake soti nan plizyè blòk), Lè sa a, li an sekirite pou mete yon vektè inisyalizasyon zewo. Pou ankripte mesaj lanmen, nou itilize yon kle separe chak fwa.
Verifye siyati gost3410.verify() se trivial: nou pase koub eliptik nan kote n ap travay la (nou tou senpleman anrejistre li nan pwotokòl GOSTIM nou an), kle piblik siyatè a (pa bliye ke sa a ta dwe yon tuple de de). gwo nimewo, epi yo pa yon fisèl byte), 34.11/2012/XNUMX hash ak siyati nan tèt li.
Apre sa, nan inisyatè a nou prepare epi voye yon mesaj lanmen bay handshake2, fè menm aksyon nou te fè pandan verifikasyon, sèlman simetrik: siyen sou kle nou yo olye pou yo tcheke, elatriye...
Lè sesyon an etabli, kle transpò yo pwodwi (yon kle separe pou chifreman, pou otantifikasyon, pou chak pati yo), epi Grasshopper la inisyalize pou dechifre epi tcheke MAC la:
Koroutin msg_sender la kounye a ankripte mesaj anvan yo voye yo sou yon koneksyon TCP. Chak mesaj gen yon nonce monotonically ogmante, ki se tou vektè inisyalizasyon an lè chiffres nan mòd kontwa. Chak mesaj ak blòk mesaj garanti gen yon valè kontwa diferan.
GOSTIM fèt pou itilize sèlman pou rezon edikasyon (piske li pa kouvri pa tès yo, omwen)! Kòd sous pwogram lan ka telechaje isit la (Стрибог-256 хэш: 995bbd368c04e50a481d138c5fa2e43ec7c89bc77743ba8dbabee1fde45de120). Как и все мои проекты, типа GoGOST, PyDERASN, NCCP, GoVPN, GOSTIM se konplètman lojisyèl gratis, distribye anba kondisyon yo GPLv3 +.