GOSTIM: P2P F2F E2EE IM trĂĄthnĂłna amhĂĄin le cripteagrafaĂ­ocht GOST

A bheith ina forbrĂłir PyGOST leabharlanna (primitives cripteagrafacha GOST i Python Ă­on), is minic a fhaigheann mĂ© ceisteanna faoi conas na teachtaireachtaĂ­ slĂĄn is simplĂ­ a chur i bhfeidhm ar na glĂșine. Measann go leor daoine go bhfuil cripteagrafaĂ­ocht fheidhmeach simplĂ­ go leor, agus is leor glaoch a chur ar .encrypt() ar bhloc-siffr chun Ă© a sheoladh go slĂĄn thar chainĂ©al cumarsĂĄide. Creideann daoine eile gurb Ă© cripteagrafaĂ­ocht fheidhmeach cinniĂșint an bheagĂĄin, agus tĂĄ sĂ© inghlactha go bhfuil cuideachtaĂ­ saibhre cosĂșil le Telegram le matamaiticeoirĂ­ Oilimpeacha NĂ­ fĂ©idir a chur i bhfeidhm prĂłtacal slĂĄn.

Spreag sĂ© seo go lĂ©ir mĂ© an t-alt seo a scrĂ­obh chun a thaispeĂĄint nach tasc chomh deacair Ă© prĂłtacail cripteagrafacha agus IM slĂĄn a chur i bhfeidhm. Mar sin fĂ©in, nĂ­ fiĂș do phrĂłtacail fĂ­ordheimhnithe agus eochair-chomhaontaithe fĂ©in a chumadh.

GOSTIM: P2P F2F E2EE IM trĂĄthnĂłna amhĂĄin le cripteagrafaĂ­ocht GOST
Beidh an t-alt ag scrĂ­obh piara-to-peer, cara le cara, ceann go deireadh criptithe teachtaire toirt le SIGMA-I prĂłtacal fĂ­ordheimhnithe agus eochair-chomhaontaithe (ar a mbonn an IKE IPsec), ag baint ĂșsĂĄide as halgartaim chripteagrafach GOST go heisiach, leabharlann PyGOST agus leabharlann ionchĂłdaithe teachtaireachta ASN.1 PyDERASN (faoi a bhfuil mĂ© cheana fĂ©in scrĂ­obh roimh). RĂ©amhriachtanas: caithfidh sĂ© a bheith chomh simplĂ­ gur fĂ©idir Ă© a scrĂ­obh Ăłn tĂșs in aon trĂĄthnĂłna amhĂĄin (nĂł lĂĄ oibre), nĂł nĂ­ clĂĄr simplĂ­ Ă© a thuilleadh. Is dĂłcha go bhfuil earrĂĄidĂ­ ann, deacrachtaĂ­ gan ghĂĄ, easnaimh, agus is Ă© seo mo chĂ©ad chlĂĄr ag baint ĂșsĂĄide as an leabharlann asyncio.

Dearadh IM

Ar dtĂșs, nĂ­ mĂłr dĂșinn a thuiscint cad a bheidh ar ĂĄr n-GS cosĂșil. Ar mhaithe le simplĂ­ocht, bĂ­odh gur grĂ©asĂĄn piara le piaraĂ­ Ă©, gan teacht ar rannphĂĄirtithe ar bith. Cuirfimid in iĂșl go pearsanta cĂ©n seoladh: calafort le nascadh leis chun cumarsĂĄid a dhĂ©anamh leis an idirghabhĂĄlaĂ­.

Tuigim, ag an am seo, gur teorannĂș suntasach Ă© an toimhde go bhfuil cumarsĂĄid dhĂ­reach ar fĂĄil idir dhĂĄ rĂ­omhaire treallach ar infheidhmeacht GS i gcleachtas. Ach dĂĄ mhĂ©ad forbrĂłirĂ­ a chuireann gach cineĂĄl crutches trasnaithe NAT i bhfeidhm, is amhlaidh is faide a fhanfaimid ar an IdirlĂ­on IPv4, agus is dĂłcha go mbeidh cumarsĂĄid idir rĂ­omhairĂ­ treallach ann. CĂ© chomh fada is fĂ©idir leat an easpa IPv6 a fhulaingt sa bhaile agus ag an obair?

Beidh lĂ­onra cairde le cara againn: nĂ­ mĂłr fios a bheith ag gach idirghabhĂĄlaĂ­ fĂ©ideartha roimh rĂ©. Ar an gcĂ©ad dul sĂ­os, dĂ©anann sĂ© seo gach rud a shimpliĂș go mĂłr: thugamar isteach muid fĂ©in, fuaireamar nĂł nĂ­or aimsigh an t-ainm/eochair, dĂ­nasctha nĂł lean ar aghaidh ag obair, agus an t-idirghabhĂĄlaĂ­ ar an eolas. Ar an dara dul sĂ­os, go ginearĂĄlta, tĂĄ sĂ© slĂĄn agus cuireann sĂ© deireadh le go leor ionsaithe.

Beidh an comhĂ©adan IM gar do rĂ©itigh clasaiceacha tionscadail gan staonadh, rud a thaitnĂ­onn go mĂłr liom as a gcuid minimalism agus fealsĂșnacht Unix-way. CruthaĂ­onn an clĂĄr IM eolaire le trĂ­ soicĂ©ad fearainn Unix do gach idirghabhĂĄlaĂ­:

  • i—DĂ©antar teachtaireachtaĂ­ a sheoltar chuig an idirghabhĂĄlaĂ­ a thaifeadadh ann;
  • amach - lĂ©itear teachtaireachtaĂ­ a fhaightear Ăłn idirghabhĂĄlaĂ­ uaidh;
  • luaigh - trĂ­ lĂ©amh uaidh, faighimid amach an bhfuil an t-idirghabhĂĄlaĂ­ ceangailte faoi lĂĄthair, an seoladh ceangail/port.

Ina theannta sin, cruthaĂ­tear soicĂ©ad conn, trĂ­d an gcalafort Ăłstach a scrĂ­obh isteach ina gcuirimid tĂșs le nasc leis an gcian-idirghabhĂĄlaĂ­.

|-- alice
|   |-- in
|   |-- out
|   `-- state
|-- bob
|   |-- in
|   |-- out
|   `-- state
`- conn

Ligeann an cur chuige seo duit feidhmiĂș neamhspleĂĄch a dhĂ©anamh ar iompar GS agus comhĂ©adan ĂșsĂĄideora, toisc nach bhfuil aon chara ann, nĂ­ fĂ©idir leat gach duine a shĂĄsamh. Ag baint ĂșsĂĄide as tmux agus / nĂł multitail, is fĂ©idir leat comhĂ©adan ilfhuinneog a fhĂĄil le bĂ©im ar chomhrĂ©ir. Agus le cabhair rlwrap is fĂ©idir leat lĂ­ne ionchuir teachtaireachta atĂĄ comhoiriĂșnach le GNU Readline a fhĂĄil.

Go deimhin, ĂșsĂĄideann tionscadail suckless comhaid FIFO. Go pearsanta, nĂ­ raibh mĂ© in ann a thuiscint conas a bheith ag obair le comhaid iomaĂ­och in asyncio gan cĂșlra lĂĄmhscrĂ­ofa Ăł snĂĄitheanna tiomnaithe (TĂĄ mĂ© ag baint ĂșsĂĄide as an teanga le haghaidh a leithĂ©id de rudaĂ­ le fada an lĂĄ Go). Mar sin, chinn mĂ© dĂ©anamh le soicĂ©id fearainn Unix. Ar an drochuair, fĂĄgann sĂ© seo go bhfuil sĂ© dodhĂ©anta macalla a dhĂ©anamh 2001:470:marbh::babe 6666 > conn. RĂ©itigh mĂ© an fhadhb seo ag baint ĂșsĂĄide as socat: macalla 2001:470:marbh::babe 6666 | socat - UNIX-CONNECT:conn, socat LÉIGHINN UNIX-CONNECT:alice/in.

An prĂłtacal neamhdhaingean bunaidh

ÚsĂĄidtear TCP mar iompar: rĂĄthaĂ­onn sĂ© seachadadh agus a ordĂș. NĂ­ rĂĄthaĂ­onn UDP ceachtar acu (rud a bheadh ​​ĂșsĂĄideach nuair a ĂșsĂĄidtear cripteagrafaĂ­ocht), ach tacaĂ­ocht SCTP NĂ­ thagann Python as an mbosca.

Ar an drochuair, i TCP nĂ­l aon choincheap de theachtaireacht, ach sruth beart. Mar sin, is gĂĄ teacht suas le formĂĄid do theachtaireachtaĂ­ ionas gur fĂ©idir iad a roinnt eatarthu fĂ©in sa snĂĄithe seo. Is fĂ©idir linn aontĂș an carachtar beatha lĂ­ne a ĂșsĂĄid. TĂĄ sĂ© ceart go leor do thosaitheoirĂ­, ach a luaithe a thosaĂ­mid ag criptiĂș ĂĄr dteachtaireachtaĂ­, fĂ©adfaidh an carachtar seo a bheith le feiceĂĄil ĂĄit ar bith sa ciphertext. I lĂ­onraĂ­, mar sin, is iad na prĂłtacail mhĂłrĂ©ilimh iad siĂșd a sheolann fad na teachtaireachta i mbearta den chĂ©ad uair. Mar shampla, as an mbosca tĂĄ xdrlib ag Python, a ligeann duit oibriĂș le formĂĄid den chineĂĄl cĂ©anna XDR.

NĂ­ oibreoimid i gceart agus go hĂ©ifeachtach le lĂ©amh TCP - dĂ©anfaimid an cĂłd a shimpliĂș. LĂ©imid sonraĂ­ Ăłn soicĂ©ad i lĂșb gan teorainn go dtĂ­ go ndĂ©anaimid an teachtaireacht iomlĂĄn a dhĂ­chĂłdĂș. Is fĂ©idir JSON le XML a ĂșsĂĄid mar fhormĂĄid don chur chuige seo freisin. Ach nuair a chuirtear cripteagrafaĂ­ocht leis, nĂ­ mĂłr na sonraĂ­ a shĂ­niĂș agus a fhĂ­ordheimhniĂș - agus beidh gĂĄ le lĂ©iriĂș comhionann beart-ar-beart ar oibiachtaĂ­, rud nach solĂĄthraĂ­onn JSON/XML (d’fhĂ©adfadh go mbeadh Ă©agsĂșlacht ag baint le torthaĂ­ dumpaĂ­).

TĂĄ XDR oiriĂșnach don tasc seo, ach roghnaĂ­onn mĂ© ASN.1 le ionchĂłdĂș DER agus PyDERASN leabharlann, toisc go mbeidh rudaĂ­ ardleibhĂ©il idir lĂĄmha againn a mbĂ­onn sĂ© nĂ­os taitneamhaĂ­ agus nĂ­os ĂĄisiĂșla oibriĂș leo go minic. Murab ionann agus schemaless bencode, MessagePack nĂł CBOR, seiceĂĄlfaidh ASN.1 na sonraĂ­ go huathoibrĂ­och i gcoinne scĂ©imre cĂłdaithe crua.

# Msg ::= CHOICE {
#       text      MsgText,
#       handshake [0] EXPLICIT MsgHandshake }
class Msg(Choice):
    schema = ((
        ("text", MsgText()),
        ("handshake", MsgHandshake(expl=tag_ctxc(0))),
    ))

# MsgText ::= SEQUENCE {
#       text UTF8String (SIZE(1..MaxTextLen))}
class MsgText(Sequence):
    schema = ((
        ("text", UTF8String(bounds=(1, MaxTextLen))),
    ))

# MsgHandshake ::= SEQUENCE {
#       peerName UTF8String (SIZE(1..256)) }
class MsgHandshake(Sequence):
    schema = ((
        ("peerName", UTF8String(bounds=(1, 256))),
    ))

Msg a bheidh sa teachtaireacht a gheofar: tĂ©acs MsgText (le rĂ©imse tĂ©acs amhĂĄin faoi lĂĄthair) nĂł teachtaireacht chroitheadh ​​lĂĄimhe MsgHandshake (ina bhfuil ainm an idirghabhĂĄlaĂ­). Anois tĂĄ cuma rĂł-chasta air, ach is bunĂșs Ă© seo don todhchaĂ­.

     ┌─────┐ ┌─────┐ │ PeerA│ │PeerB│ └──┬───└──┘ └────── ) │ │──────── ─ ────────>│ │ │ │ │ Croitheadh ​​Láimhe(IdB) │ │<──────── ─── │ │ MsgText() │ │─── ─ MsgText() │ │ │

IM gan cripteagrafaĂ­ocht

Mar a dĂșirt mĂ© cheana, ĂșsĂĄidfear an leabharlann asyncio do gach oibrĂ­ocht soicĂ©ad. DĂ©anaimis a bhfuil sĂșil againn a fhĂłgairt ag an seoladh:

parser = argparse.ArgumentParser(description="GOSTIM")
parser.add_argument(
    "--our-name",
    required=True,
    help="Our peer name",
)
parser.add_argument(
    "--their-names",
    required=True,
    help="Their peer names, comma-separated",
)
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()
OUR_NAME = UTF8String(args.our_name)
THEIR_NAMES = set(args.their_names.split(","))

Socraigh d'ainm fĂ©in (--ĂĄr n-ainm alice). TĂĄ na hidirghabhĂĄlaithe go lĂ©ir a bhfuiltear ag sĂșil leo liostaithe scartha le camĂłga ( —a n-ainmneacha bob, oĂ­che). I gcĂĄs gach ceann de na hidirghabhĂĄlaithe, cruthaĂ­tear eolaire le soicĂ©id Unix, chomh maith le coroutine do gach duine isteach, amach, luaigh:

for peer_name in THEIR_NAMES:
    makedirs(peer_name, mode=0o700, exist_ok=True)
    out_queue = asyncio.Queue()
    OUT_QUEUES[peer_name] = out_queue
    asyncio.ensure_future(asyncio.start_unix_server(
        partial(unixsock_out_processor, out_queue=out_queue),
        path.join(peer_name, "out"),
    ))
    in_queue = asyncio.Queue()
    IN_QUEUES[peer_name] = in_queue
    asyncio.ensure_future(asyncio.start_unix_server(
        partial(unixsock_in_processor, in_queue=in_queue),
        path.join(peer_name, "in"),
    ))
    asyncio.ensure_future(asyncio.start_unix_server(
        partial(unixsock_state_processor, peer_name=peer_name),
        path.join(peer_name, "state"),
    ))
asyncio.ensure_future(asyncio.start_unix_server(unixsock_conn_processor, "conn"))

Seoltar teachtaireachtaĂ­ a thagann Ăłn ĂșsĂĄideoir Ăłn soicĂ©ad isteach chuig an scuaine IN_QUEUES:

async def unixsock_in_processor(reader, writer, in_queue: asyncio.Queue) -> None:
    while True:
        text = await reader.read(MaxTextLen)
        if text == b"":
            break
        await in_queue.put(text.decode("utf-8"))

Seoltar teachtaireachtaí a thagann ó idirghabhålaithe chuig scuainí OUT_QUEUES, óna scríobhtar sonraí chuig an soicéad amach:

async def unixsock_out_processor(reader, writer, out_queue: asyncio.Queue) -> None:
    while True:
        text = await out_queue.get()
        writer.write(("[%s] %s" % (datetime.now(), text)).encode("utf-8"))
        await writer.drain()

Agus tĂș ag lĂ©amh Ăł shoicĂ©ad stĂĄit, lorgaĂ­onn an clĂĄr seoladh an idirghabhĂĄlaĂ­ san fhoclĂłir PEER_ALIVE. Mura bhfuil aon nasc leis an idirghabhĂĄlaĂ­ fĂłs, scrĂ­obhtar lĂ­ne fholamh.

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()

Agus seoladh ĂĄ scrĂ­obh chuig soicĂ©ad conn, seoltar an fheidhm “tionscnĂłir” naisc:

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))

DĂ©anaimis machnamh ar an tionscnĂłir. Ar dtĂșs is lĂ©ir go n-osclaĂ­onn sĂ© nasc leis an Ăłsta/port sonraithe agus seolann sĂ© teachtaireacht chroitheadh ​​lĂĄimhe darb ainm:

 130 async def initiator(host, port):
 131     _id = repr((host, port))
 132     logging.info("%s: dialing", _id)
 133     reader, writer = await asyncio.open_connection(host, port)
 134     # Handshake message {{{
 135     writer.write(Msg(("handshake", MsgHandshake((
 136         ("peerName", OUR_NAME),
 137     )))).encode())
 138     # }}}
 139     await writer.drain()

Ansin, fanann sĂ© ar fhreagra Ăłn gcĂłisir iargĂșlta. DĂ©anann sĂ© iarracht an freagra isteach a dhĂ­chĂłdĂș trĂ­ ĂșsĂĄid a bhaint as scĂ©im Msg ASN.1. Glacaimid leis go seolfar an teachtaireacht ar fad i mĂ­r TCP amhĂĄin agus go bhfaighfimid go adamhach Ă© nuair a ghlaoimid ar .read(). DĂ©anaimid seiceĂĄil go bhfuaireamar an teachtaireacht chroitheadh ​​lĂĄimhe.

 141     # Wait for Handshake message {{{
 142     data = await reader.read(256)
 143     if data == b"":
 144         logging.warning("%s: no answer, disconnecting", _id)
 145         writer.close()
 146         return
 147     try:
 148         msg, _ = Msg().decode(data)
 149     except ASN1Error:
 150         logging.warning("%s: undecodable answer, disconnecting", _id)
 151         writer.close()
 152         return
 153     logging.info("%s: got %s message", _id, msg.choice)
 154     if msg.choice != "handshake":
 155         logging.warning("%s: unexpected message, disconnecting", _id)
 156         writer.close()
 157         return
 158     # }}}

DĂ©anaimid seiceĂĄil go bhfuil ainm faighte an idirghabhĂĄlaĂ­ ar eolas againn. Mura bhfuil, ansin briseann muid an nasc. DĂ©anaimid seiceĂĄil an bhfuil nasc bunaithe againn cheana fĂ©in leis (thug an t-idirghabhĂĄlaĂ­ an t-ordĂș arĂ­s chun ceangal a dhĂ©anamh linn) agus Ă© a dhĂșnadh. CoinnĂ­onn an scuaine IN_QUEUES teaghrĂĄin Python le tĂ©acs na teachtaireachta, ach tĂĄ luach ar leith ag None a thugann comhartha don choroutine msg_sender stop a bheith ag obair ionas go ndĂ©anann sĂ© dearmad ar a scrĂ­bhneoir a bhaineann leis an nasc oidhreachta 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     # }}}

glacann msg_sender le teachtaireachtaĂ­ amach (ciĂșĂĄilte Ăł shoicĂ©ad isteach), cuireann sĂ© iad i dteachtaireacht MsgText agus seolann sĂ© thar nasc TCP iad. Is fĂ©idir Ă© a bhriseadh trĂĄth ar bith - tĂĄimid idircheapadh go soilĂ©ir seo.

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))

Ag an deireadh, cuireann an tionscnĂłir lĂșb gan teorainn de teachtaireachtaĂ­ lĂ©itheoireachta Ăłn soicĂ©ad. SeiceĂĄlann cibĂ© acu an teachtaireachtaĂ­ tĂ©acs iad na teachtaireachtaĂ­ seo agus cuireann sĂ© sa scuaine OUT_QUEUES iad, Ăłna seolfar chuig soicĂ©ad amach an idirghabhĂĄlaĂ­ chomhfhreagraigh iad. CĂ©n fĂĄth nach fĂ©idir leat ach .read() a dhĂ©anamh agus an teachtaireacht a dhĂ­chĂłdĂș? Toisc gur fĂ©idir go ndĂ©anfar roinnt teachtaireachtaĂ­ Ăłn ĂșsĂĄideoir a chomhiomlĂĄnĂș i maolĂĄn an chĂłrais oibriĂșchĂĄin agus iad a sheoladh in aon mhĂ­r TCP amhĂĄin. Is fĂ©idir linn an chĂ©ad cheann a dhĂ­chĂłdĂș, agus ansin fĂ©adfaidh cuid den cheann ina dhiaidh sin fanacht sa mhaolĂĄn. I gcĂĄs aon chor neamhghnĂĄch, dĂșnaimid an nasc TCP agus stopaimid an coroutine msg_sender (trĂ­ None a sheoladh chuig an scuaine 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)

Fillfimid ar an bprĂ­omhchĂłd. Tar Ă©is na coroutines go lĂ©ir a chruthĂș ag an am a thosaĂ­onn an clĂĄr, cuirimid tĂșs leis an bhfreastalaĂ­ TCP. I gcĂĄs gach nasc bunaithe, cruthaĂ­onn sĂ© coroutine freagrĂłra.

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()

TĂĄ an freagrĂłir cosĂșil leis an tionscnĂłir agus lĂ©irĂ­onn sĂ© na gnĂ­omhartha cĂ©anna go lĂ©ir, ach tosaĂ­onn lĂșb gan teorainn na dteachtaireachtaĂ­ lĂ©itheoireachta lĂĄithreach, ar mhaithe le simplĂ­ocht. Faoi lĂĄthair, cuireann an prĂłtacal croitheadh ​​lĂĄimhe teachtaireacht amhĂĄin Ăł gach taobh, ach sa todhchaĂ­ beidh dhĂĄ cheann Ăłn tionscnĂłir nasc, agus ina dhiaidh sin is fĂ©idir teachtaireachtaĂ­ tĂ©acs a sheoladh lĂĄithreach.

  72 async def responder(reader, writer):
  73     _id = writer.get_extra_info("peername")
  74     logging.info("%s: connected", _id)
  75     buf = b""
  76     msg_expected = "handshake"
  77     peer_name = None
  78     while True:
  79         # Read until we get Msg message {{{
  80         data = await reader.read(MaxMsgLen)
  81         if data == b"":
  82             logging.info("%s: closed connection", _id)
  83             break
  84         buf += data
  85         if len(buf) > MaxMsgLen:
  86             logging.warning("%s: max buffer size exceeded", _id)
  87             break
  88         try:
  89             msg, tail = Msg().decode(buf)
  90         except ASN1Error:
  91             continue
  92         buf = tail
  93         # }}}
  94         if msg.choice != msg_expected:
  95             logging.warning("%s: unexpected %s message", _id, msg.choice)
  96             break
  97         if msg_expected == "text":
  98             try:
  99                 await msg_receiver(msg.value, peer_name)
 100             except ValueError as err:
 101                 logging.warning("%s: %s", err)
 102                 break
 103         # Process Handshake message {{{
 104         elif msg_expected == "handshake":
 105             logging.info("%s: got %s message", _id, msg_expected)
 106             msg_handshake = msg.value
 107             peer_name = str(msg_handshake["peerName"])
 108             if peer_name not in THEIR_NAMES:
 109                 logging.warning("unknown peer name: %s", peer_name)
 110                 break
 111             writer.write(Msg(("handshake", MsgHandshake((
 112                 ("peerName", OUR_NAME),
 113             )))).encode())
 114             await writer.drain()
 115             logging.info("%s: session established: %s", _id, peer_name)
 116             peer_alive = PEER_ALIVES.pop(peer_name, None)
 117             if peer_alive is not None:
 118                 peer_alive.close()
 119                 await IN_QUEUES[peer_name].put(None)
 120             PEER_ALIVES[peer_name] = writer
 121             asyncio.ensure_future(msg_sender(peer_name, writer))
 122             msg_expected = "text"
 123         # }}}
 124     logging.info("%s: disconnecting", _id)
 125     if msg_expected == "text":
 126         IN_QUEUES[peer_name].put(None)
 127     writer.close()

PrĂłtacal slĂĄn

TĂĄ sĂ© in am againn ĂĄr gcumarsĂĄid a dhaingniĂș. Cad atĂĄ i gceist againn le slĂĄndĂĄil agus cad atĂĄ uainn:

  • rĂșndacht na dteachtaireachtaĂ­ tarchurtha;
  • barĂĄntĂșlacht agus slĂĄine na dteachtaireachtaĂ­ tarchurtha - nĂ­ mĂłr a n-athruithe a bhrath;
  • cosaint i gcoinne ionsaithe athimeartha - nĂ­ mĂłr teachtaireachtaĂ­ ar iarraidh nĂł arĂ­s agus arĂ­s eile a bhrath (agus socraĂ­mid deireadh a chur leis an nasc);
  • aithint agus fĂ­ordheimhniĂș idirghabhĂĄlaithe ag baint ĂșsĂĄide as eochracha poiblĂ­ rĂ©amhiontrĂĄilte - shocraigh muid cheana fĂ©in go raibh muid ag dĂ©anamh lĂ­onra cara le cara. Is tar Ă©is fĂ­ordheimhnithe amhĂĄin a thuigfimid cĂ© leis a bhfuilimid i mbun cumarsĂĄide;
  • infhaighteacht rĂșndacht tosaigh foirfe rĂ©admhaoin (PFS) - nĂ­or cheart go mbeifĂ­ in ann gach comhfhreagras roimhe seo a lĂ©amh mĂĄ chuirtear ĂĄr n-eochair sĂ­nithe fadchĂłnaithe i mbaol. NĂ­ dhĂ©anfaidh aon mhaith trĂĄcht a thaifeadadh;
  • bailĂ­ocht/bailĂ­ocht teachtaireachtaĂ­ (iompar agus croitheadh ​​lĂĄimhe) laistigh de sheisiĂșn TCP amhĂĄin. NĂ­or cheart go mbeadh sĂ© indĂ©anta teachtaireachtaĂ­ sĂ­nithe/fĂ­ordheimhnithe i gceart Ăł sheisiĂșn eile a chur isteach (fiĂș leis an idirghabhĂĄlaĂ­ cĂ©anna);
  • nĂ­or cheart do bhreathnadĂłir Ă©ighnĂ­omhach aitheantĂłirĂ­ ĂșsĂĄideora, eochracha poiblĂ­ fadsaoil a tharchur, nĂł hashes uathu a fheiceĂĄil. Ainm ĂĄirithe Ăł bhreathnadĂłir Ă©ighnĂ­omhach.

Is ĂĄbhar iontais Ă© gur mian le beagnach gach duine an t-Ă­osmhĂ©id seo a bheith acu in aon phrĂłtacal croitheadh ​​lĂĄimhe, agus is beag an mĂ©id thuas a chomhlĂ­ontar i ndeireadh na dĂĄla le haghaidh prĂłtacail “dĂșchais”. Anois nĂ­ dhĂ©anfaimid aon rud nua a chumadh. Ba mhaith liom a mholadh cinnte a ĂșsĂĄid Creat torainn le haghaidh prĂłtacail a thĂłgĂĄil, ach dĂ©anaimis rud Ă©igin nĂ­os simplĂ­ a roghnĂș.

Is iad an dĂĄ phrĂłtacal is coitianta nĂĄ:

  • TLS - prĂłtacal an-chasta le stair fhada de fhabhtanna, subha, leochaileachtaĂ­, droch-mhachnamh, castacht agus easnaimh (ach is beag an bhaint atĂĄ aige seo le TLS 1.3). Ach nĂ­ mheasaimid Ă© toisc go bhfuil sĂ© rĂł-chasta.
  • IPsec с IKE - nach bhfuil fadhbanna cripteagrafacha tromchĂșiseacha acu, cĂ© nach bhfuil siad simplĂ­ freisin. MĂĄ lĂ©ann tĂș faoi IKEv1 agus IKEv2, is Ă© an fhoinse atĂĄ acu STSPrĂłtacail , ISO/IEC IS 9798-3 agus SIGMA (SIGn-agus-MAc) - simplĂ­ go leor le cur i bhfeidhm trĂĄthnĂłna amhĂĄin.

Cad atĂĄ go maith faoi SIGMA, mar an nasc is dĂ©anaĂ­ i bhforbairt prĂłtacail STS/ISO? ComhlĂ­onann sĂ© ĂĄr gcuid riachtanas go lĂ©ir (lena n-ĂĄirĂ­tear aitheantĂłirĂ­ idirghabhĂĄlaĂ­ a “bhfolĂș”) agus nĂ­l aon fhadhbanna cripteagrafacha aitheanta aige. TĂĄ sĂ© Ă­ostach - mĂĄ bhaintear eilimint amhĂĄin ar a laghad as an teachtaireacht prĂłtacail beidh sĂ© ina chĂșis le neamhshlĂĄndĂĄil.

Rachaimid Ăłn bprĂłtacal baile is simplĂ­ go SIGMA. Is Ă© an oibrĂ­ocht is bunĂșsaĂ­ a bhfuil suim againn ann comhaontĂș eochair: Feidhm a aschuireann an dĂĄ rannphĂĄirtĂ­ an luach cĂ©anna, ar fĂ©idir Ă© a ĂșsĂĄid mar eochair shimĂ©adrach. Gan dul isteach i sonraĂ­: gineann gach ceann de na pĂĄirtithe pĂ©ire ephemeral (a ĂșsĂĄidtear ach amhĂĄin laistigh de seisiĂșn amhĂĄin) eochair (eochracha poiblĂ­ agus prĂ­obhĂĄideacha), a mhalartĂș eochracha poiblĂ­, glaoch ar an fheidhm comhaontaithe, chun an t-ionchur a thĂ©ann siad a n-eochair phrĂ­obhĂĄideach agus an phobail. eochair an idirghabhĂĄlaĂ­.

┌─────┐ ┌─────┐ │ PeerA│ │PeerB│ └─────┘ └────── │ ╔══════════ ══════════╗ │──────────────>│ ║(PrvA, PrvA) ─ ─ ════════ ═══════════╝ │ IdB, PubB │ ╔════════════␕␕␂ ───────── ──────│ ║PrvB, PubB = DHgen() ║ │ │ ╚═════════════␕― ─ ──┐ ╔════ ═══╧════════════╗ │ ║ Eochair = DH(PrvA, PubB)║ <───┘ ␕╕ ═══════ ════╝ │ │ │ │

Is fĂ©idir le duine ar bith lĂ©im sa lĂĄr agus a gcuid eochracha poiblĂ­ fĂ©in a athsholĂĄthar - nĂ­l aon fhĂ­ordheimhniĂș idirghabhĂĄlaithe sa phrĂłtacal seo. Cuirimis sĂ­niĂș le heochracha fadsaoil leis.

┌─────┐ ┌─────┐ │ PeerA│ │PeerB│ └──┬──┘ └──┘ ─── SignPrvA, (PubA)) │ ╔═ Cláraigh A = ualach() ║ │ │ ║ PrvA, PubA = DHgen() ║ │ │ ╚════════ ══════ ════════════␂ ═, comhartha (SignPrvB, (PubB)) │ ╔═══════════════ ══════ ══════════ ══════ ════― ‗ ────────── ────────────── ─│ ║ SignPrvB, SignPubB = ualach( )║ │ │ ║ PrvB, PubB │ ║ │ │ ║ PrvB, PubB = ║ ═════════ ═══════════════ ═╝ ────┐ ╔ ══════␕║ ═════╗ │ │ ║fíoraigh( SignPubB, ...) ║ │ <───┘ ║ Eochair = DH(PrvA , PubB) ║ │ │ ╚══════════════ ═ ═╝ │ │ │

NĂ­ oibreoidh sĂ­niĂș den sĂłrt sin, Ăłs rud Ă© nach bhfuil sĂ© ceangailte le seisiĂșn ar leith. TĂĄ teachtaireachtaĂ­ dĂĄ leithĂ©id “oiriĂșnach” freisin do sheisiĂșin le rannphĂĄirtithe eile. NĂ­ mĂłr don chomhthĂ©acs iomlĂĄn sĂ­ntiĂșs a Ă­oc. Cuireann sĂ© seo iallach orainn teachtaireacht eile Ăł A a chur leis freisin.

Ina theannta sin, tĂĄ sĂ© rĂ­thĂĄbhachtach d'aitheantĂłir fĂ©in a chur leis faoin sĂ­niĂș, mar ar shlĂ­ eile is fĂ©idir linn IdXXX a ionadĂș agus an teachtaireacht a athshĂ­niĂș le heochair idirghabhĂĄlaĂ­ aitheanta eile. Chun cosc ​​a chur ionsaithe machnaimh, is gĂĄ go mbeadh na heilimintĂ­ faoin sĂ­niĂș in ĂĄiteanna atĂĄ sainmhĂ­nithe go soilĂ©ir de rĂ©ir a gciall: mĂĄ chomharthaĂ­onn A (PubA, PubB), ansin caithfidh B sĂ­niĂș (PubB, PubA). LabhraĂ­onn sĂ© seo freisin ar a thĂĄbhachtaĂ­ atĂĄ sĂ© struchtĂșr agus formĂĄid na sonraĂ­ sraitheach a roghnĂș. Mar shampla, dĂ©antar tacair in ionchĂłdĂș ASN.1 DER a shĂłrtĂĄil: beidh SET OF(PubA, PubB) comhionann le SET OF(PubB, PubA).

┌─────┐ ┌─────┐ │ PeerA│ │PeerB│ └─────┘ └────── │ ╔══════════ ═════════════════╗ │───────────——————————─ ────────── ─────────────>│ ║ SignPrvA, SignPubA = ualach()║ │ │ ║ PrvA, PubA = DHgen() ║ ║ ─ ═ ══════ ═══════════════╝ │IdB, PubB, comhartha(ComharthaPrvB, (IdB, PubA, PubB)) │ ═ ␕ ╕ ═════ ════════════╗ │<─────────────────────── ───────── ─────────│ ║ SignPrvB, SignPubB = ualach() ║ │ │ ║ PrvB, PubB = DHgen() ║ │ ┐ ╚ │ │ ␕ │ ═ ═══════ ══════════╝ │ comhartha(SignPrvA, (IDA, PubB, PubA)) │ ╔═══════ ═ ═══␐══ ═══╗│─ ────────────────────────────────────────── ──>│ ║fíoraigh(SignPubB, ...) ║ │ │ ║Eochair = DH(PrvA, PubB) ║ │ │ ╚═══════════════␕ ═══ ␂

Mar sin fĂ©in, nĂ­l "cruthĂș" fĂłs againn go bhfuil an eochair chomhroinnte chĂ©anna ginte againn don seisiĂșn seo. I bprionsabal, is fĂ©idir linn a dhĂ©anamh gan an chĂ©im seo - beidh an chĂ©ad nasc iompair neamhbhailĂ­, ach ba mhaith linn nuair a bheidh an croitheadh ​​lĂĄimhe crĂ­ochnaithe, ba mhaith linn a bheith cinnte go bhfuil gach rud aontaithe i ndĂĄirĂ­re. Faoi lĂĄthair tĂĄ an prĂłtacal ISO/IEC IS 9798-3 idir lĂĄmha againn.

D’fhĂ©adfaimis an eochair ghinte fĂ©in a shĂ­niĂș. TĂĄ sĂ© seo contĂșirteach, Ăłs rud Ă© go bhfĂ©adfadh sceitheadh ​​a bheith ann san algartam sĂ­nithe a ĂșsĂĄidtear (cĂ© go giotĂĄn in aghaidh an tsĂ­nithe, ach fĂłs sceitheanna). Is fĂ©idir hash den eochair dĂ­orthaithe a shĂ­niĂș, ach d’fhĂ©adfadh sĂ© a bheith luachmhar mĂĄ sceitheadh ​​fiĂș hash na heochrach dĂ­orthaithe in ionsaĂ­ brĂșidiĂșil ar an bhfeidhm dĂ­orthaithe. ÚsĂĄideann SIGMA feidhm MAC a fhĂ­ordheimhnĂ­onn aitheantas an tseoltĂłra.

┌─────┐ ┌─────┐ │ PeerA│ │PeerB│ └─────┘ └────── │ ╔══════════ ═════════════════╗ │───────────——————————─ ────────── ──────────────────>│ ║ SignPrvA, SignPubA = ualach() ║ │ │ ⚕ Prv = A │ │ ⚕ Prv │ ═ ══════ ═══════════════ ═════╝ │IdB, PubB, comhartha(SignPrvB, (PubA, PubB) ╔) ═══ ════════════════════╗│<────────——————————─ ───────── ─────────────────────│ ║ SignPrvB, SignPubB = ualach() ║ │ │ │ B │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╚════ ═ ══════════════════════╝ │ ╔═════════║ comhartha ════════╗ │ comhartha (ComharthaPrvA, (PubB, PubA)), MAC(IDA) │ ║Eochair = DH(PrvA, PubB) ║ │ ─────────────—————————————————————————— ─ ─ ─────────────────────────>│ ───────────────────>│ ║fíoraigh(Eochair, IdB) │ │ │ │ │ │ │ │ ║ │ │ ╚ ═════════════════════╝ │ │

Mar leas iomlĂĄn a bhaint, b'fhĂ©idir gur mhaith le cuid acu a n-eochracha gearrshaolacha a athĂșsĂĄid (rud atĂĄ, ar ndĂłigh, trua do PFS). Mar shampla, ghin muid eochairphĂ©ire, rinneamar iarracht nascadh, ach nĂ­ raibh TCP ar fĂĄil nĂł cuireadh isteach air ĂĄit Ă©igin i lĂĄr an phrĂłtacail. Is mĂłr an nĂĄire acmhainnĂ­ eantrĂłpachta agus prĂłiseĂĄlaithe a chur amĂș ar phĂ©ire nua. Mar sin, tabharfaimid isteach an fianĂĄn mar a thugtar air - luach brĂ©agach randamach a chosnĂłidh i gcoinne ionsaithe athimeartha randamacha a d'fhĂ©adfadh a bheith ann agus eochracha poiblĂ­ gearrthĂ©armacha ĂĄ n-athĂșsĂĄid. Mar gheall ar an gceangal idir an fianĂĄn agus an eochair phoiblĂ­ ghearrshaolach, is fĂ©idir eochair phoiblĂ­ an phĂĄirtĂ­ eile a bhaint den sĂ­niĂș mar rud nach gĂĄ.

┌─────┐ ┌─────┐ │PeerA│ │PeerB│ └─────────┘ └──┘ └─── A │ ╔════════ ═══════════════════╗ │──────────——————————─ ────────── ────────────────────────────────────────── >│ ║SignPrvA, SignPubA = ualach( )║ │ │ ║ PrvA, PubA = DHgen() ║ │ │ ╚═══════════════␐═══␕ ═ ═╝ │IdB, PubB, CookieB , comhartha(SignPrvB, (CookieA, CookieB, PubB)), MAC(IdB) │ ╔═════════════════␕␕␕␕␕ ╗ │< ────────────────────────────────────────── ───────── ────────────────────│ ║ SignPrvB, SignPubB = ualach() ║ │ │ │ B │ │ │ B │ │ │ B │ │ B │ │ │ B │ │ │ B │ │ ╚══════ ═════════════════════╝ │ │ ╔══════════║ comhartha ══════╗ │ comhartha( SignPrvA, (FianánB, FianánA, PubA)), MAC(IdA) │ ║ Eochair = DH(PrvA, PubB) ║ │────────────————————————————————————————————————————————————─ ─ ────────────────────────────────────────── ──────>│ ║ fíoraigh(Eochair, IdB) ║ │ │ ║fíoraigh(SignPubB,...) ║ │ │ ╚══════════════␕␕␕ │

Ar deireadh, ba mhaith linn prĂ­obhĂĄideacht ĂĄr gcomhphĂĄirtithe comhrĂĄ a fhĂĄil Ăł bhreathnadĂłir Ă©ighnĂ­omhach. Chun seo a dhĂ©anamh, tĂĄ sĂ© beartaithe ag SIGMA eochracha gearrshaolacha a mhalartĂș ar dtĂșs agus eochair choiteann a fhorbairt ar a bhfĂ©adfaĂ­ fĂ­ordheimhniĂș agus aithint teachtaireachtaĂ­ a chriptiĂș. DĂ©anann SIGMA cur sĂ­os ar dhĂĄ rogha:

  • SIGMA-I - cosnaĂ­onn sĂ© an tionscnĂłir Ăł ionsaithe gnĂ­omhacha, an freagrĂłir Ăł ionsaithe Ă©ighnĂ­omhacha: fĂ­ordheimhnĂ­onn an tionscnĂłir an freagrĂłir agus mura n-oireann rud Ă©igin, nĂ­ thugann sĂ© aitheantas dĂł. Tugann an cosantĂłir a aitheantas mĂĄ chuirtear tĂșs le prĂłtacal gnĂ­omhach leis. NĂ­ fhoghlaimĂ­onn an breathnĂłir Ă©ighnĂ­omhach rud ar bith;
    SIGMA-R - a chosnaĂ­onn an freagrĂłir Ăł ionsaithe gnĂ­omhacha, an tionscnĂłir Ăł na cinn Ă©ighnĂ­omhacha. TĂĄ gach rud dĂ­reach ina coinne, ach sa phrĂłtacal seo tĂĄ ceithre theachtaireacht chroitheadh ​​lĂĄimhe tarchurtha cheana fĂ©in.

    Roghnaimid SIGMA-I mar go bhfuil sĂ© nĂ­os cosĂșla leis an mĂ©id a bhfuil sĂșil againn Ăł rudaĂ­ eolach cliant-freastalaĂ­: is Ă© an freastalaĂ­ fĂ­ordheimhnithe amhĂĄin a aithnĂ­tear an cliant, agus tĂĄ a fhios ag gach duine ar an bhfreastalaĂ­ cheana fĂ©in. Ina theannta sin tĂĄ sĂ© nĂ­os Ă©asca Ă© a chur i bhfeidhm mar gheall ar nĂ­os lĂș teachtaireachtaĂ­ croith lĂĄimhe. Is Ă© an t-aon rud a chuirimid leis an bprĂłtacal nĂĄ cuid den teachtaireacht a chriptiĂș agus an t-aitheantĂłir A a aistriĂș go dtĂ­ an chuid criptithe den teachtaireacht dheireanach:

    ┌─────┐ ┌─────┐ │PeerA│ │PeerB│ └──┬──┘ └── ─ ─ ── │ ╔══════════ ═════════════════╗ │───────────——————————─ ────────── ────────────────────────────────────────── ─────>│ ║ SignPrvA , SignPubA = ualach() ║ │ │ ║ PrvA, PubA = DHgen() ║ │ │ ╚═══════════════════════ ════╝ │ PubB, FianánB, Enc((IdB, comhartha(SignPrvB, (CookieA, CookieB, PubB)), MAC(IdB)))) │ ╔ ═ ══ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ␕ ═ ═ ═ ␕ ═ ═══════╗│<─────────────────────────—── ───────── ║SignPrv B, SignPubB = ualach()║ │ │ ║ PrvB, PubB = DHgen() ║ │ │ ╚═════════␐═ ═══════ ═╝ │ │ ╔ ════════ ═════════════╗ │ Enc(Avie, Cook, Sign(Avie), Enc(Avie,Cook) MAC(IDA) )) │ ║Eochair = DH(PrvA, PubB) ║ │────────────────────────── ────── ──── ───────── ──────────────────────────── ─>│ ║fíoraigh(Eochair, IdB) ║ │ │ ║fíoraigh(Cláraigh Tábhairne,...)║ │ │ ╚═════════════════␂
    
    • ÚsĂĄidtear GOST R le haghaidh sĂ­niĂș 34.10-2012 algartam le heochracha 256-giotĂĄn.
    • Chun an eochair phoiblĂ­ a ghiniĂșint, ĂșsĂĄidtear 34.10/2012/XNUMX VKO.
    • ÚsĂĄidtear CMAC mar an MAC. Go teicniĂșil, is modh oibrĂ­ochta speisialta Ă© seo de bhloc-sipher, a thuairiscĂ­tear i GOST R 34.13-2015. Mar fheidhm criptithe don mhĂłd seo - DreoilĂ­n teaspaigh (34.12-2015).
    • ÚsĂĄidtear hash a eochair phoiblĂ­ mar aitheantĂłir an idirghabhĂĄlaĂ­. ÚsĂĄidte mar hash Streachailt-256 (34.11/2012/256 XNUMX giotĂĄn).

    Tar Ă©is an chroitheadh ​​lĂĄimhe, comhaontĂłidh muid ar eochair roinnte. Is fĂ©idir linn Ă© a ĂșsĂĄid chun teachtaireachtaĂ­ iompair a chriptiĂș fĂ­ordheimhnithe. TĂĄ an chuid seo an-simplĂ­ agus deacair botĂșn a dhĂ©anamh: dĂ©anaimid an cuntar teachtaireachta a incrimint, an teachtaireacht a chriptiĂș, an cuntar agus an ciphertext a fhĂ­ordheimhniĂș (MAC), seol. Nuair a fhaigheann muid teachtaireacht, dĂ©anaimid seiceĂĄil go bhfuil an luach ionchais ag an gcuntar, fĂ­ordheimhnigh an ciphertext leis an gcuntar, agus dĂ­chriptigh Ă©. CĂ©n eochair ba cheart dom a ĂșsĂĄid chun teachtaireachtaĂ­ croitheadh ​​lĂĄimhe a chriptiĂș, teachtaireachtaĂ­ a iompar, agus conas iad a fhĂ­ordheimhniĂș? TĂĄ sĂ© contĂșirteach agus mĂ­-chiallmhar ĂșsĂĄid a bhaint as eochair amhĂĄin do na tascanna seo go lĂ©ir. Is gĂĄ eochracha a ghiniĂșint ag baint ĂșsĂĄide as feidhmeanna speisialaithe KDF (feidhm dĂ­orthaithe eochair). ArĂ­s, nĂĄ scoiltimis ribĂ­ agus dĂ©anaimis rud Ă©igin: HKDF le fada an lĂĄ, taighde maith agus nĂ­l aon fadhbanna aitheanta. Ar an drochuair, nĂ­l an fheidhm seo ag leabharlann dĂșchais Python, mar sin ĂșsĂĄidimid hkdf mĂĄla plaisteach. ÚsĂĄideann HKDF go hinmheĂĄnach HMAC, a ĂșsĂĄideann feidhm hash ar a seal. NĂ­ thĂłgann sĂ© ach cĂșpla lĂ­ne cĂłd mar shampla forfheidhmiĂș i Python ar an leathanach VicipĂ©id. Mar a tharla i gcĂĄs 34.10/2012/256, ĂșsĂĄidfimid Stribog-XNUMX mar fheidhm hash. Tabharfar an eochair seisiĂșin ar aschur ĂĄr bprĂ­omhfheidhm comhaontaithe, Ăłna nginfear na cinn simĂ©adracha atĂĄ in easnamh:

    kdf = Hkdf(None, key_session, hash=GOST34112012256)
    kdf.expand(b"handshake1-mac-identity")
    kdf.expand(b"handshake1-enc")
    kdf.expand(b"handshake1-mac")
    kdf.expand(b"handshake2-mac-identity")
    kdf.expand(b"handshake2-enc")
    kdf.expand(b"handshake2-mac")
    kdf.expand(b"transport-initiator-enc")
    kdf.expand(b"transport-initiator-mac")
    kdf.expand(b"transport-responder-enc")
    kdf.expand(b"transport-responder-mac")
    

    StruchtĂșir/ScĂ©imeanna

    BreathnaĂ­mid ar na struchtĂșir ASN.1 atĂĄ againn anois chun na sonraĂ­ seo go lĂ©ir a tharchur:

    class Msg(Choice):
        schema = ((
            ("text", MsgText()),
            ("handshake0", MsgHandshake0(expl=tag_ctxc(0))),
            ("handshake1", MsgHandshake1(expl=tag_ctxc(1))),
            ("handshake2", MsgHandshake2(expl=tag_ctxc(2))),
        ))
    
    class MsgText(Sequence):
        schema = ((
            ("payload", MsgTextPayload()),
            ("payloadMac", MAC()),
        ))
    
    class MsgTextPayload(Sequence):
        schema = ((
            ("nonce", Integer(bounds=(0, float("+inf")))),
            ("ciphertext", OctetString(bounds=(1, MaxTextLen))),
        ))
    
    class MsgHandshake0(Sequence):
        schema = ((
            ("cookieInitiator", Cookie()),
            ("pubKeyInitiator", PubKey()),
        ))
    
    class MsgHandshake1(Sequence):
        schema = ((
            ("cookieResponder", Cookie()),
            ("pubKeyResponder", PubKey()),
            ("ukm", OctetString(bounds=(8, 8))),
            ("ciphertext", OctetString()),
            ("ciphertextMac", MAC()),
        ))
    
    class MsgHandshake2(Sequence):
        schema = ((
            ("ciphertext", OctetString()),
            ("ciphertextMac", MAC()),
        ))
    
    class HandshakeTBE(Sequence):
        schema = ((
            ("identity", OctetString(bounds=(32, 32))),
            ("signature", OctetString(bounds=(64, 64))),
            ("identityMac", MAC()),
        ))
    
    class HandshakeTBS(Sequence):
        schema = ((
            ("cookieTheir", Cookie()),
            ("cookieOur", Cookie()),
            ("pubKeyOur", PubKey()),
        ))
    
    class Cookie(OctetString): bounds = (16, 16)
    class PubKey(OctetString): bounds = (64, 64)
    class MAC(OctetString): bounds = (16, 16)
    

    Is Ă© HandshakeTBS an rud a shĂ­neofar. HandshakeTBE - cad a bheidh criptithe. DĂ­rĂ­m d’aird ar an rĂ©imse ukm in MsgHandshake1. 34.10 ÁirĂ­tear VKO, le haghaidh randamachĂș nĂ­os mĂł fĂłs ar na heochracha ginte, paraimĂ©adar UKM (ĂĄbhar eochrach ĂșsĂĄideora) - gan ach eantrĂłpacht bhreise.

    CripteagrafaĂ­ocht a Chur leis an gCĂłd

    DĂ©anaimis machnamh ach ar na hathruithe a rinneadh ar an gcĂłd bunaidh, Ăłs rud Ă© gur fhan an creat mar an gcĂ©anna (go deimhin, scrĂ­obhadh an cur i bhfeidhm deiridh ar dtĂșs, agus ansin gearradh an cripteagrafaĂ­ocht go lĂ©ir as).

    Ós rud Ă© go ndĂ©anfar fĂ­ordheimhniĂș agus sainaithint idirghabhĂĄlaithe ag baint ĂșsĂĄide as eochracha poiblĂ­, nĂ­ mĂłr iad a stĂłrĂĄil anois in ĂĄit Ă©igin ar feadh i bhfad. Ar mhaithe le simplĂ­ocht, ĂșsĂĄidimid JSON mar seo:

    {
        "our": {
            "prv": "21254cf66c15e0226ef2669ceee46c87b575f37f9000272f408d0c9283355f98",
            "pub": "938c87da5c55b27b7f332d91b202dbef2540979d6ceaa4c35f1b5bfca6df47df0bdae0d3d82beac83cec3e353939489d9981b7eb7a3c58b71df2212d556312a1"
        },
        "their": {
            "alice": "d361a59c25d2ca5a05d21f31168609deeec100570ac98f540416778c93b2c7402fd92640731a707ec67b5410a0feae5b78aeec93c4a455a17570a84f2bc21fce",
            "bob": "aade1207dd85ecd283272e7b69c078d5fae75b6e141f7649ad21962042d643512c28a2dbdc12c7ba40eb704af920919511180c18f4d17e07d7f5acd49787224a"
        }
    }
    

    ĂĄr - ĂĄr bpĂ©ire eochair, eochracha heicsidheacha, prĂ­obhĂĄideacha agus poiblĂ­. — ainmneacha na n-idirghabhĂĄlaithe agus a n-eochracha poiblĂ­. AthraĂ­mis na hargĂłintĂ­ lĂ­ne ordaithe agus cuirimis iarphrĂłiseĂĄil sonraĂ­ JSON leis:

    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),
        }
    # }}}
    

    Is uimhir randamach Ă­ eochair phrĂ­obhĂĄideach an algartam 34.10. MĂ©id 256-giotĂĄn le haghaidh cuair Ă©ilipseacha 256-giotĂĄn. NĂ­ oibrĂ­onn PyGOST le sraith beart, ach le lĂ­on mĂłr, mar sin nĂ­ mĂłr ĂĄr n-eochair phrĂ­obhĂĄideach (urandom(32)) a thiontĂș go huimhir ag baint ĂșsĂĄide as gost3410.prv_unmarshal(). Cinntear an eochair phoiblĂ­ go cinntitheach Ăłn eochair phrĂ­obhĂĄideach ag baint ĂșsĂĄide as gost3410.public_key(). Is Ă© atĂĄ san eochair phoiblĂ­ 34.10 nĂĄ dhĂĄ uimhir mhĂłra ar gĂĄ iad a thiontĂș ina seicheamh beart freisin ar mhaithe le hĂ©ascaĂ­ocht stĂłrĂĄla agus tarchurtha ag baint ĂșsĂĄide as gost3410.pub_marshal().

    Tar Ă©is an comhad JSON a lĂ©amh, nĂ­ mĂłr na heochracha poiblĂ­ a thiontĂș ar ais dĂĄ rĂ©ir sin trĂ­ ĂșsĂĄid a bhaint as gost3410.pub_unmarshal(). Ós rud Ă© go bhfaighfimid aitheantĂłirĂ­ na n-idirghabhĂĄlaithe i bhfoirm hash Ăłn eochair phoiblĂ­, is fĂ©idir iad a rĂ­omh lĂĄithreach roimh rĂ© agus a chur i bhfoclĂłir le haghaidh cuardach tapa. TĂĄ hash Stribog-256 gost34112012256.GOST34112012256(), a shĂĄsaĂ­onn go hiomlĂĄn comhĂ©adan hashlib na bhfeidhmeanna hash.

    Conas a d'athraigh coroutine an tionscnĂłra? TĂĄ gach rud de rĂ©ir na scĂ©ime croith lĂĄimhe: gineann muid fianĂĄn (tĂĄ 128-giotĂĄn go leor), pĂ©ire eochair gearrshaolach 34.10, a ĂșsĂĄidfear le haghaidh feidhm chomhaontaithe eochair VKO.

     395 async def initiator(host, port):
     396     _id = repr((host, port))
     397     logging.info("%s: dialing", _id)
     398     reader, writer = await asyncio.open_connection(host, port)
     399     # Generate our ephemeral public key and cookie, send Handshake 0 message {{{
     400     cookie_our = Cookie(urandom(16))
     401     prv = gost3410.prv_unmarshal(urandom(32))
     402     pub_our = gost3410.public_key(CURVE, prv)
     403     pub_our_raw = PubKey(gost3410.pub_marshal(pub_our))
     404     writer.write(Msg(("handshake0", MsgHandshake0((
     405         ("cookieInitiator", cookie_our),
     406         ("pubKeyInitiator", pub_our_raw),
     407     )))).encode())
     408     # }}}
     409     await writer.drain()
    

    • tĂĄimid ag fanacht le freagra agus dĂ­chĂłdaithe an teachtaireacht Msg isteach;
    • dĂ©an cinnte go bhfaigheann tĂș croitheadh ​​lĂĄimhe1;
    • eochair phoiblĂ­ ghearrshaolach an phĂĄirtĂ­ eile a dhĂ­chĂłdĂș agus eochair an tseisiĂșin a rĂ­omh;
    • Gineann muid eochracha simĂ©adracha atĂĄ riachtanach chun an chuid TBE den teachtaireacht a phrĂłiseĂĄil.

     423     logging.info("%s: got %s message", _id, msg.choice)
     424     if msg.choice != "handshake1":
     425         logging.warning("%s: unexpected message, disconnecting", _id)
     426         writer.close()
     427         return
     428     # }}}
     429     msg_handshake1 = msg.value
     430     # Validate Handshake message {{{
     431     cookie_their = msg_handshake1["cookieResponder"]
     432     pub_their_raw = msg_handshake1["pubKeyResponder"]
     433     pub_their = gost3410.pub_unmarshal(bytes(pub_their_raw))
     434     ukm_raw = bytes(msg_handshake1["ukm"])
     435     ukm = ukm_unmarshal(ukm_raw)
     436     key_session = kek_34102012256(CURVE, prv, pub_their, ukm, mode=2001)
     437     kdf = Hkdf(None, key_session, hash=GOST34112012256)
     438     key_handshake1_mac_identity = kdf.expand(b"handshake1-mac-identity")
     439     key_handshake1_enc = kdf.expand(b"handshake1-enc")
     440     key_handshake1_mac = kdf.expand(b"handshake1-mac")
    

    Is uimhir 64-giotĂĄn Ă­ UKM (urandom(8)), a Ă©ilĂ­onn freisin dĂ­shraithiĂș Ăłna lĂ©iriĂș beart ag baint ĂșsĂĄide as gost3410_vko.ukm_unmarshal(). Is Ă© feidhm VKO le haghaidh 34.10/2012/256 3410-giotĂĄn nĂĄ gost34102012256_vko.kek_XNUMX() (KEK - eochair criptithe).

    Is seicheamh beart randamach randamach 256-giotĂĄn an eochair seisiĂșin a ghintear cheana fĂ©in. Mar sin, is fĂ©idir Ă© a ĂșsĂĄid lĂĄithreach i bhfeidhmeanna HKDF. Ós rud Ă© go sĂĄsaĂ­onn GOST34112012256 an comhĂ©adan hashlib, is fĂ©idir Ă© a ĂșsĂĄid lĂĄithreach sa rang Hkdf. NĂ­ shonraĂ­onn muid an salann (an chĂ©ad argĂłint Hkdf), Ăłs rud Ă© go mbeidh an eochair a ghintear, mar gheall ar thrasfhoirmiĂșlacht na bpĂ©irĂ­ eochair rannphĂĄirteacha, difriĂșil do gach seisiĂșn agus go bhfuil go leor eantrĂłpachta ann cheana fĂ©in. kdf.expand() de rĂ©ir rĂ©amhshocraithe tĂĄirgeann sĂ© na heochracha 256-giotĂĄn atĂĄ ag teastĂĄil le haghaidh DreoilĂ­n teaspaigh nĂ­os dĂ©anaĂ­.

    Ansin, déantar na codanna TBE agus TBS den teachtaireacht isteach a sheiceåil:

    • dĂ©antar an MAC thar an tĂ©acs ciphersa isteach a rĂ­omh agus a sheiceĂĄil;
    • tĂĄ an ciphertext dĂ­chriptithe;
    • TĂĄ struchtĂșr TBE dĂ­chĂłdaithe;
    • tĂłgtar aitheantĂłir an idirghabhĂĄlaĂ­ uaidh agus seiceĂĄiltear an bhfuil sĂ© ar eolas againn ar chor ar bith;
    • DĂ©antar MAC thar an aitheantĂłir seo a rĂ­omh agus a sheiceĂĄil;
    • dĂ©antar an sĂ­niĂș thar an struchtĂșr TBS a fhĂ­orĂș, lena n-ĂĄirĂ­tear fianĂĄn an dĂĄ phĂĄirtĂ­ agus eochair ghearrshaolach phoiblĂ­ an phĂĄirtĂ­ eile. FĂ­oraĂ­tear an sĂ­niĂș le heochair shĂ­nithe fhadtĂ©armach an idirghabhĂĄlaĂ­.

     441     try:
     442         peer_name = validate_tbe(
     443             msg_handshake1,
     444             key_handshake1_mac_identity,
     445             key_handshake1_enc,
     446             key_handshake1_mac,
     447             cookie_our,
     448             cookie_their,
     449             pub_their_raw,
     450         )
     451     except ValueError as err:
     452         logging.warning("%s: %s, disconnecting", _id, err)
     453         writer.close()
     454         return
     455     # }}}
    
     128 def validate_tbe(
     129         msg_handshake: Union[MsgHandshake1, MsgHandshake2],
     130         key_mac_identity: bytes,
     131         key_enc: bytes,
     132         key_mac: bytes,
     133         cookie_their: Cookie,
     134         cookie_our: Cookie,
     135         pub_key_our: PubKey,
     136 ) -> str:
     137     ciphertext = bytes(msg_handshake["ciphertext"])
     138     mac_tag = mac(GOST3412Kuznechik(key_mac).encrypt, KUZNECHIK_BLOCKSIZE, ciphertext)
     139     if not compare_digest(mac_tag, bytes(msg_handshake["ciphertextMac"])):
     140         raise ValueError("invalid MAC")
     141     plaintext = ctr(
     142         GOST3412Kuznechik(key_enc).encrypt,
     143         KUZNECHIK_BLOCKSIZE,
     144         ciphertext,
     145         8 * b"x00",
     146     )
     147     try:
     148         tbe, _ = HandshakeTBE().decode(plaintext)
     149     except ASN1Error:
     150         raise ValueError("can not decode TBE")
     151     key_sign_pub_hash = bytes(tbe["identity"])
     152     peer = KEYS.get(key_sign_pub_hash)
     153     if peer is None:
     154         raise ValueError("unknown identity")
     155     mac_tag = mac(
     156         GOST3412Kuznechik(key_mac_identity).encrypt,
     157         KUZNECHIK_BLOCKSIZE,
     158         key_sign_pub_hash,
     159     )
     160     if not compare_digest(mac_tag, bytes(tbe["identityMac"])):
     161         raise ValueError("invalid identity MAC")
     162     tbs = HandshakeTBS((
     163         ("cookieTheir", cookie_their),
     164         ("cookieOur", cookie_our),
     165         ("pubKeyOur", pub_key_our),
     166     ))
     167     if not gost3410.verify(
     168         CURVE,
     169         peer["pub"],
     170         GOST34112012256(tbs.encode()).digest(),
     171         bytes(tbe["signature"]),
     172     ):
     173         raise ValueError("invalid signature")
     174     return peer["name"]
    

    Mar a scrĂ­obh mĂ© thuas, tĂĄ cur sĂ­os ar 34.13/2015/XNUMX Ă©agsĂșla bloc modhanna oibriĂșchĂĄin cipher Ăłn 34.12/2015/3413. Ina measc tĂĄ modh chun iatĂĄin brĂ©ige agus rĂ­omhanna MAC a ghiniĂșint. I PyGOST is Ă© seo gost34.12.mac(). ÉilĂ­onn an modh seo an fheidhm criptithe a rith (bloc amhĂĄin sonraĂ­ a fhĂĄil agus a thabhairt ar ais), mĂ©id an bhloc criptithe agus, go deimhin, na sonraĂ­ fĂ©in. CĂ©n fĂĄth nach fĂ©idir leat mĂ©id an bhloc criptithe a chĂłdĂș crua? DĂ©anann 2015/128/64 cur sĂ­os nĂ­ amhĂĄin ar an XNUMX-giotĂĄn sifir dreoilĂ­n teaspaigh, ach freisin ar an XNUMX-giotĂĄn Magma - GOST 28147-89 beagĂĄn modhnaithe, a cruthaĂ­odh ar ais sa KGB agus tĂĄ ceann de na tairseacha sĂĄbhĂĄilteachta is airde fĂłs aige.

    Cuirtear tĂșs le Kuznechik trĂ­ ghlao a chur ar gost.3412.GOST3412Kuznechik(eochair) agus cuireann sĂ© rĂ©ad ar ais le modhanna .cript()/.dĂ­chriptiĂș() atĂĄ oiriĂșnach lena chur ar aghaidh chuig 34.13 feidhmeanna. RĂ­omhtar MAC mar seo a leanas: gost3413.mac(GOST3412Kuznechik(eochair).cript, KUZNECHIK_BLOCKSIZE, ciphertext). Chun an MAC rĂ­ofa agus faighte a chur i gcomparĂĄid, nĂ­ fĂ©idir leat an gnĂĄthchomparĂĄid (==) de na teaghrĂĄin bheart a ĂșsĂĄid, Ăłs rud Ă© go sceitheann an oibrĂ­ocht seo am comparĂĄide, rud a d'fhĂ©adfadh, go ginearĂĄlta, leochaileachtaĂ­ marfach a bheith mar thoradh air. Beast ionsaithe ar TLS. TĂĄ feidhm speisialta ag Python, hmac.compare_digest, chuige seo.

    NĂ­ fĂ©idir leis an bhfeidhm bloc-scipĂ©ir ach bloc amhĂĄin sonraĂ­ a chriptiĂș. Le haghaidh lĂ­on nĂ­os mĂł, agus fiĂș nach iolraĂ­ den fhad, is gĂĄ an modh criptithe a ĂșsĂĄid. DĂ©anann 34.13-2015 cur sĂ­os ar na nithe seo a leanas: BCE, CTR, OFB, CBC, CFB. TĂĄ a rĂ©imsĂ­ iarratais agus trĂ©ithe inghlactha fĂ©in ag gach ceann acu. Ar an drochuair, nĂ­l caighdeĂĄnaithe againn fĂłs modhanna criptithe fĂ­ordheimhnithe (cosĂșil le CCM, OCB, GCM agus a leithĂ©id) - tĂĄ iallach orainn ar a laghad MAC a chur orainn fĂ©in. roghnaĂ­m mĂłd cuntair (CTR): nĂ­ Ă©ilĂ­onn sĂ© stuĂĄil le mĂ©id an bhloc, is fĂ©idir Ă© a chomhthreomharĂș, nĂ­ ĂșsĂĄideann sĂ© ach an fheidhm criptithe, is fĂ©idir Ă© a ĂșsĂĄid go sĂĄbhĂĄilte chun lĂ­on mĂłr teachtaireachtaĂ­ a chriptiĂș (murab ionann agus CBC, a bhfuil imbhuailtĂ­ sĂĄch tapa).

    Ar nĂłs .mac(), glacann .ctr() ionchur comhchosĂșil: ciphertext = gost3413.ctr(GOST3412Kuznechik(eochair).cript, KUZNECHIK_BLOCKSIZE, gnĂĄththĂ©acs, iv). TĂĄ sĂ© riachtanach veicteoir tosaigh a shonrĂș atĂĄ dĂ­reach leath fhad an bhloic criptithe. Mura n-ĂșsĂĄidtear ĂĄr n-eochair chriptiĂșchĂĄin ach chun teachtaireacht amhĂĄin a chriptiĂș (cĂ© gur Ăł roinnt bloic), tĂĄ sĂ© sĂĄbhĂĄilte veicteoir tosaigh nialasach a shocrĂș. Chun teachtaireachtaĂ­ croitheadh ​​lĂĄimhe a chriptiĂș, ĂșsĂĄidimid eochair ar leith gach uair.

    Is fĂĄnach an sĂ­niĂș gost3410.verify() a fhĂ­orĂș: tugaimid thar an gcuar Ă©ilipseach ina bhfuilimid ag obair (nĂ­ dhĂ©anaimid ach Ă© a thaifeadadh inĂĄr bprĂłtacal GOSTIM), eochair phoiblĂ­ an sĂ­nitheoir (nĂĄ dĂ©an dearmad gur chĂłir go mbeadh sĂ© seo ina thuple de dhĂĄ lĂ­on mĂłr, agus nĂ­ teaghrĂĄn beart), 34.11/2012/XNUMX hash agus an sĂ­niĂș fĂ©in.

    Ansin, sa thionscnĂłir dĂ©anaimid teachtaireacht chroitheadh ​​lĂĄimhe a ullmhĂș agus a sheoladh chuig handshake2, ag dĂ©anamh na ngnĂ­omhartha cĂ©anna agus a rinneamar le linn an fhĂ­oraithe, go simĂ©adrach amhĂĄin: sĂ­niĂș ar ĂĄr n-eochracha in ionad seiceĂĄil, etc..

     456     # Prepare and send Handshake 2 message {{{
     457     tbs = HandshakeTBS((
     458         ("cookieTheir", cookie_their),
     459         ("cookieOur", cookie_our),
     460         ("pubKeyOur", pub_our_raw),
     461     ))
     462     signature = gost3410.sign(
     463         CURVE,
     464         KEY_OUR_SIGN_PRV,
     465         GOST34112012256(tbs.encode()).digest(),
     466     )
     467     key_handshake2_mac_identity = kdf.expand(b"handshake2-mac-identity")
     468     mac_tag = mac(
     469         GOST3412Kuznechik(key_handshake2_mac_identity).encrypt,
     470         KUZNECHIK_BLOCKSIZE,
     471         bytes(KEY_OUR_SIGN_PUB_HASH),
     472     )
     473     tbe = HandshakeTBE((
     474         ("identity", KEY_OUR_SIGN_PUB_HASH),
     475         ("signature", OctetString(signature)),
     476         ("identityMac", MAC(mac_tag)),
     477     ))
     478     tbe_raw = tbe.encode()
     479     key_handshake2_enc = kdf.expand(b"handshake2-enc")
     480     key_handshake2_mac = kdf.expand(b"handshake2-mac")
     481     ciphertext = ctr(
     482         GOST3412Kuznechik(key_handshake2_enc).encrypt,
     483         KUZNECHIK_BLOCKSIZE,
     484         tbe_raw,
     485         8 * b"x00",
     486     )
     487     mac_tag = mac(
     488         GOST3412Kuznechik(key_handshake2_mac).encrypt,
     489         KUZNECHIK_BLOCKSIZE,
     490         ciphertext,
     491     )
     492     writer.write(Msg(("handshake2", MsgHandshake2((
     493         ("ciphertext", OctetString(ciphertext)),
     494         ("ciphertextMac", MAC(mac_tag)),
     495     )))).encode())
     496     # }}}
     497     await writer.drain()
     498     logging.info("%s: session established: %s", _id, peer_name)
     

    Nuair a bhĂ­onn an seisiĂșn bunaithe, gintear eochracha iompair (eochair ar leith le haghaidh criptithe, fĂ­ordheimhnithe, do gach pĂĄirtĂ­), agus cuirtear an Grasshopper ar dtĂșs chun an MAC a dhĂ­chriptiĂș agus a sheiceĂĄil:

     499     # Run text message sender, initialize transport decoder {{{
     500     key_initiator_enc = kdf.expand(b"transport-initiator-enc")
     501     key_initiator_mac = kdf.expand(b"transport-initiator-mac")
     502     key_responder_enc = kdf.expand(b"transport-responder-enc")
     503     key_responder_mac = kdf.expand(b"transport-responder-mac")
     ...
     509     asyncio.ensure_future(msg_sender(
     510         peer_name,
     511         key_initiator_enc,
     512         key_initiator_mac,
     513         writer,
     514     ))
     515     encrypter = GOST3412Kuznechik(key_responder_enc).encrypt
     516     macer = GOST3412Kuznechik(key_responder_mac).encrypt
     517     # }}}
     519     nonce_expected = 0
    
     520     # Wait for test messages {{{
     521     while True:
     522         data = await reader.read(MaxMsgLen)
     ...
     530             msg, tail = Msg().decode(buf)
     ...
     537         try:
     538             await msg_receiver(
     539                 msg.value,
     540                 nonce_expected,
     541                 macer,
     542                 encrypter,
     543                 peer_name,
     544             )
     545         except ValueError as err:
     546             logging.warning("%s: %s", err)
     547             break
     548         nonce_expected += 1
     549     # }}}
    

    CriptĂ­onn coroutine msg_sender teachtaireachtaĂ­ anois sula seoltar ar nasc TCP iad. TĂĄ mĂ©adĂș monatonach ag gach teachtaireacht, agus is Ă© sin an veicteoir tosaigh freisin nuair a bhĂ­onn sĂ© criptithe i mĂłd cuntair. TĂĄ rĂĄthaĂ­ocht ar chuntarluach difriĂșil ag gach teachtaireacht agus bloc teachtaireachta.

    async def msg_sender(peer_name: str, key_enc: bytes, key_mac: bytes, writer) -> None:
        nonce = 0
        encrypter = GOST3412Kuznechik(key_enc).encrypt
        macer = GOST3412Kuznechik(key_mac).encrypt
        in_queue = IN_QUEUES[peer_name]
        while True:
            text = await in_queue.get()
            if text is None:
                break
            ciphertext = ctr(
                encrypter,
                KUZNECHIK_BLOCKSIZE,
                text.encode("utf-8"),
                long2bytes(nonce, 8),
            )
            payload = MsgTextPayload((
                ("nonce", Integer(nonce)),
                ("ciphertext", OctetString(ciphertext)),
            ))
            mac_tag = mac(macer, KUZNECHIK_BLOCKSIZE, payload.encode())
            writer.write(Msg(("text", MsgText((
                ("payload", payload),
                ("payloadMac", MAC(mac_tag)),
            )))).encode())
            nonce += 1
    

    DĂ©anann coroutine msg_receiver teachtaireachtaĂ­ isteach a phrĂłiseĂĄil, a lĂĄimhseĂĄlann fĂ­ordheimhniĂș agus dĂ­chriptiĂș:

    async def msg_receiver(
            msg_text: MsgText,
            nonce_expected: int,
            macer,
            encrypter,
            peer_name: str,
    ) -> None:
        payload = msg_text["payload"]
        if int(payload["nonce"]) != nonce_expected:
            raise ValueError("unexpected nonce value")
        mac_tag = mac(macer, KUZNECHIK_BLOCKSIZE, payload.encode())
        if not compare_digest(mac_tag, bytes(msg_text["payloadMac"])):
            raise ValueError("invalid MAC")
        plaintext = ctr(
            encrypter,
            KUZNECHIK_BLOCKSIZE,
            bytes(payload["ciphertext"]),
            long2bytes(nonce_expected, 8),
        )
        text = plaintext.decode("utf-8")
        await OUT_QUEUES[peer_name].put(text)
    

    ConclĂșid

    TĂĄ GOSTIM beartaithe le hĂșsĂĄid go heisiach chun crĂ­ocha oideachais (Ăłs rud Ă© nach bhfuil sĂ© clĂșdaithe ag tĂĄstĂĄlacha, ar a laghad)! Is fĂ©idir cĂłd foinse an chlĂĄir a Ă­oslĂłdĂĄil anseo (ĐĄŃ‚Ń€ĐžĐ±ĐŸĐł-256 хэш: 995bbd368c04e50a481d138c5fa2e43ec7c89bc77743ba8dbabee1fde45de120). КаĐș Đž ĐČсД ĐŒĐŸĐž ĐżŃ€ĐŸĐ”Đșты, топа GoGOST, PyDERASN, NCCP, GoVPN, tĂĄ GOSTIM go hiomlĂĄn bogearraĂ­ saor in aiscedhĂĄileadh faoi na tĂ©armaĂ­ GPLv3 +.

    Sergey Matveev, cipherpunk, ball FondĂșireacht SPO, Python/Go-forbrĂłir, prĂ­omhspeisialtĂłir FiontraĂ­ocht StĂĄit ChĂłnaidhme "STC "Atlas".

Foinse: will.com

Add a comment