GOSTIM: P2P F2F E2EE IM manheru mamwe neGOST cryptography

Kuva mugadziri PyGOST maraibhurari (GOST cryptographic primitives in pure Python), ini ndinowanzo gamuchira mibvunzo nezve maitiro ekuita iyo yakapfava yakachengeteka meseji pamabvi. Vanhu vazhinji vanofunga kuti application cryptography iri nyore, uye kufona .encrypt() pablock cipher kunokwana kuti utumire zvakachengeteka pamusoro penzira yekutaurirana. Vamwe vanotenda kuti application cryptography ndiyo magumo evashoma, uye zvinotenderwa kuti makambani akapfuma akaita seTeregiramu ane olympiad-masvomhu. haikwanise kuita yakachengeteka protocol.

Zvese izvi zvakandikurudzira kunyora chinyorwa ichi kuratidza kuti kuita cryptographic protocol uye kuchengetedza IM harisi basa rakaoma kudaro. Nekudaro, hazvina kukodzera kugadzira yako yechokwadi uye yakakosha chibvumirano mapuroteni.

GOSTIM: P2P F2F E2EE IM manheru mamwe neGOST cryptography
Nyaya ichanyora nditarisise-to-vezera, shamwari-ku-shamwari, end-to-end encrypted mutumwa pakarepo ne SIGMA-I authentication uye kiyi chibvumirano cheprotocol (pachikonzero chairi kuitwa IPsec IKE), uchishandisa chete GOST cryptographic algorithms PyGOST raibhurari uye ASN.1 meseji encoding raibhurari PyDERASN (zvandatove nazvo akanyora kare) Chinodiwa: inofanira kunge iri nyore zvekuti inogona kunyorwa kubva pakutanga manheru mamwe (kana zuva rekushanda), kana zvisina kudaro haisisiri chirongwa chiri nyore. Inogona kunge ine zvikanganiso, zvisingakodzeri matambudziko, zvikanganiso, uye ichi ndicho chirongwa changu chekutanga kushandisa asyncio raibhurari.

IM design

Kutanga, isu tinofanirwa kunzwisisa kuti IM yedu ichataridzika sei. Kuti zvive nyore, ngaive network yevaenzani-kune-vezera, pasina kuwanikwa kwevatori vechikamu. Isu pachedu ticharatidza kuti ndeipi kero: chiteshi chekubatanidza kune kutaurirana neanopindirana.

Ini ndinonzwisisa kuti, panguva ino, fungidziro yekuti kutaurirana kwakananga kunowanikwa pakati pemakomputa maviri asina tsananguro chinhu chakakosha pakupikiswa kwekushandiswa kweIM mukuita. Asi vagadziri vanowedzera kushandisa marudzi ese emadondoro eNAT-anotenderera, ticharamba tiri paIPv4 Internet, paine mukana unoodza mwoyo wekutaurirana pakati pemakombuta asina tsarukano. Inguva yakareba sei iwe unogona kushivirira kushomeka kweIPv6 kumba uye kubasa?

Isu tichava neshamwari-kune-shamwari network: ese anogona interlocutors anofanira kuzivikanwa pachine nguva. Chekutanga, izvi zvinorerutsa zvakanyanya zvese: isu takazvisuma isu, takawana kana kusawana zita / kiyi, yakabviswa kana kuenderera mberi nekushanda, tichiziva mutauri. Chechipiri, kazhinji, yakachengeteka uye inobvisa kurwiswa kwakawanda.

Iyo IM interface ichave iri padyo neklass mhinduro mapurojekiti asina kunaka, izvo zvandinoda chaizvo kune yavo minimalism uye Unix-nzira uzivi. Iyo IM chirongwa inogadzira dhairekitori ine matatu Unix domain sockets kune yega interlocutor:

  • mu-mashoko anotumirwa kune interlocutor akanyorwa mairi;
  • kunze - mameseji akagamuchirwa kubva kune interlocutor anoverengwa kubva kwairi;
  • nyika - nekuverenga kubva pairi, tinoona kana iyo interlocutor parizvino yakabatana, kero yekubatanidza / chiteshi.

Mukuwedzera, conn socket inogadzirwa, nekunyora chiteshi chengarava umo isu tinotanga kubatana kune kure interlocutor.

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

Iyi nzira inobvumidza iwe kuita yakazvimirira mashandisirwo eIM yekufambisa uye mushandisi interface, nekuti hapana shamwari, haugone kufadza munhu wese. Kushandisa tmux uye / kana multitail, unogona kuwana akawanda-mahwindo interface ine syntax inoratidzira. Uye nerubatsiro rlwrap unogona kuwana GNU Readline-inoenderana meseji mutsara wekuisa.

Muchokwadi, mapurojekiti anoyamwa anoshandisa mafaira eFIFO. Ini pachangu, ini handina kunzwisisa maitiro ekushanda nemafaira nemakwikwi muasyncio pasina chinyorwa chakanyorwa nemaoko kubva kune tambo dzakatsaurirwa (ndanga ndichishandisa mutauro wezvinhu zvakadaro kwenguva yakareba. Go) Naizvozvo, ndakafunga kuita neUnix domain sockets. Nehurombo, izvi zvinoita kuti zvisaite echo 2001:470:dead::babe 6666 > conn. Ndakagadzirisa dambudziko iri ndichishandisa socat: echo 2001:470:dead::babe 6666 | socat - UNIX-CONNECT:conn, socat READLINE UNIX-CONNECT:alice/in.

Iyo yekutanga isina kuchengeteka protocol

TCP inoshandiswa sekutakura: inovimbisa kutumira uye kurongeka kwayo. UDP haivimbisi (izvo zvingabatsira kana cryptography ikashandiswa), asi rutsigiro SCTP Python haibude mubhokisi.

Nehurombo, muTCP hapana pfungwa yemeseji, chete rwizi rwemabheti. Naizvozvo, zvinofanirwa kuuya nefomati yemameseji kuitira kuti vagovane pakati pavo mune ino tambo. Tinogona kubvumirana kushandisa mutsara wekudyisa hunhu. Zvakanaka kune vanotanga, asi kana tangotanga kuvharidzira mameseji edu, uyu hunhu anogona kuoneka chero papi. Mune network, saka, maprotocol akakurumbira ndeaya anotanga kutumira hurefu hwemeseji mumabhayiti. Semuenzaniso, kunze kwebhokisi Python ine xdrlib, iyo inokutendera kuti ushande nefomati yakafanana XDR.

Hatizoshande nemazvo uye nemazvo nekuverenga TCP - isu tichaita kuti kodhi ive nyore. Isu tinoverenga data kubva pane socket mune isingaperi loop kusvika isu tasarudza iyo yakazara meseji. JSON ine XML inogona zvakare kushandiswa sefomati yeiyi nzira. Asi kana cryptography yawedzerwa, iyo data ichafanirwa kusainwa uye kutenderwa - uye izvi zvinoda byte-for-byte yakafanana inomiririra yezvinhu, izvo zvisingapiwe neJSON/XML (kurasa mhedzisiro inogona kusiyana).

XDR inokodzera basa iri, zvisinei ini ndinosarudza ASN.1 neDER encoding uye PyDERASN raibhurari, sezvo tichava nezvinhu zvepamusoro-soro paruoko izvo zvinowanzonyanya kunakidza uye zviri nyore kushanda. Kusiyana schemaless bencode, MessagePack kana CBOR, ASN.1 ichaongorora otomatiki iyo data inopesana neiyo yakaoma-coded schema.

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

Meseji yakagamuchirwa ichave Msg: ingave mameseji MsgText (ine ndima imwe chete yemavara parizvino) kana meseji yeMsgHandshake yekubata ruoko (ine zita remutauri). Iye zvino zvinoratidzika zvakanyanya kuoma, asi iyi ndiyo nheyo yeramangwana.

     β”Œβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β” β”‚PeerAβ”‚ β”‚PeerBβ”‚ β””β”€β”€β”¬β”€β”€β”˜ └─ke─ └─ke─s A) β”‚ │──────── ────────>β”‚ β”‚ β”‚ β”‚MsgHandshake(IdB) β”‚ β”‚<───────────────── β”‚ β”‚ MsgText() β”‚ │──── MsgText() β”‚ β”‚ β”‚

IM pasina cryptography

Sezvandambotaura, iyo asyncio raibhurari ichashandiswa kune ese socket mashandiro. Ngatizivise zvatinotarisira pakuvhurwa:

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

Isa zita rako pachako (--yedu-zita alice). Vese vanotarisirwa interlocutors vakanyorwa vakapatsanurwa nemakoma (-mazita avo bob,eve). Kune yega yega interlocutors, dhairekitori ine Unix sockets inogadzirwa, pamwe neiyo coroutine kune yega yega mukati, kunze, nyika:

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

Mameseji anobva kumushandisi kubva mu socket anotumirwa ku IN_QUEUES mutsara:

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

Mameseji anobva kuvanopindirana anotumirwa kuOUT_QUEUES mitsetse, kubva painonyorwa data kune kunze socket:

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

Kana uchiverenga kubva pachisoketi chehurumende, chirongwa chinotarisa kero yeanopindira muduramazwi rePEER_ALIVE. Kana pasina kubatana kune interlocutor zvakadaro, ipapo mutsara usina chinhu unonyorwa.

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

Paunenge uchinyora kero kune conn socket, yekubatanidza "initiator" basa rinotangwa:

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

Ngatifungei nezvekutanga. Kutanga zviri pachena inovhura chinongedzo kune yakatsanangurwa host / chiteshi uye inotumira meseji yekubata ruoko ine zita rayo:

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

Zvadaro, inomirira mhinduro kubva kubati iri kure. Inoedza kutsanangura mhinduro inouya uchishandisa Msg ASN.1 chirongwa. Isu tinofungidzira kuti meseji yese ichatumirwa muchikamu chimwe cheTCP uye isu tichaigamuchira paatomu kana tichifona .read(). Takatarisa kuti tatambira here meseji yekubata maoko.

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

Tinotarisa kuti zita rakagamuchirwa re interlocutor rinozivikanwa kwatiri. Kana zvisina kudaro, saka tinoputsa kubatana. Isu tinotarisa kana isu takatogadzira hukama naye (mupindiri zvakare akapa murairo wekubatanidza kwatiri) uye kuvhara. The IN_QUEUES queue inobata Python tambo dzine chinyorwa chemeseji, asi ine yakakosha kukosha kweNone inosaina msg_sender coroutine kumira kushanda kuitira kuti ikanganwe nezve munyori wayo ane chekuita nenhaka TCP yekubatanidza.

 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 inogamuchira mameseji anobuda (akaiswa mumutsara kubva mune socket), anoaisa mu meseji yeMsgText uye anoatumira kuburikidza neTCP yekubatanidza. Inogona kutyora chero nguva - isu tinonyatso gamuchira izvi.

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

Pakupedzisira, mutangi anopinda musingaverengeki loop yekuverenga mameseji kubva pane socket. Inotarisa kana mameseji aya ari mameseji uye oaisa mu OUT_QUEUES mutsara, kubva paachazotumirwa kune kunze socket yeanopindirana. Sei usingakwanisi kungoita .read() uye decode meseji? Nekuti zvinogoneka kuti mameseji akati wandei kubva kumushandisi achaunganidzwa musystem yekushandisa buffer uye kutumirwa mune imwe TCP chikamu. Isu tinokwanisa decode yekutanga, uyezve chikamu cheinotevera chinogona kuramba chiri mubuffer. Mune chero mamiriro ezvinhu asina kujairika, tinovhara kubatana kweTCP uye kumisa msg_sender coroutine (nekutumira Hapana kune OUT_QUEUES mutsara).

 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)

Ngatidzokei kune kodhi huru. Mushure mekugadzira ese coroutines panguva iyo chirongwa chinotanga, tinotanga iyo TCP server. Kune yega yega yakagadzwa yekubatanidza, inogadzira anopindura coroutine.

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

anopindura akafanana neanotanga uye magirazi zviito zvese zvakafanana, asi iyo isingaperi loop yekuverenga mameseji inotanga pakarepo, kuitira nyore. Parizvino, iyo handshake protocol inotumira meseji kubva kune rumwe rutivi, asi mune ramangwana pachava maviri kubva kune yekubatanidza yekutanga, mushure meiyo mameseji anogona kutumirwa nekukurumidza.

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

Secure protocol

Yasvika nguva yekuchengetedza kutaurirana kwedu. Tinorevei nekuchengeteka uye chii chatinoda:

  • kuvanzika kwemameseji anofambiswa;
  • chokwadi uye kuvimbika kwemameseji anofambiswa - shanduko dzavo dzinofanira kuonekwa;
  • dziviriro kubva pakurwiswa kwekudzokorora - chokwadi chekushaikwa kana kudzokororwa meseji inofanira kuonekwa (uye isu tinosarudza kumisa kubatana);
  • kuzivikanwa uye kutendeseka kwevanopindirana vachishandisa pre-yakapinda veruzhinji makiyi - isu takatosarudza kare kuti taigadzira shamwari-ku-shamwari network. Chete mushure mehuchokwadi ndipo patinozonzwisisa watiri kutaurirana naye;
  • kuwanikwa zvakakwana mberi zvakavanzika zvivakwa (PFS) - kukanganisa kiyi yedu yekusaina yekugara kwenguva refu haifanire kutungamira mukukwanisa kuverenga zvese zvakapfuura tsamba. Kurekodha yakabatwa traffic inova isina basa;
  • chokwadi / kutendeseka kwemameseji (kutakura uye kubata maoko) chete mukati mechikamu chimwe cheTCP. Kupinza meseji dzakasainwa nemazvo kubva kune imwe chikamu (kunyangwe nemutauriri mumwe chete) hazvifanirwe kuitika;
  • munhu anongotarisa haafanire kuona chero zviziviso zvevashandisi, zvinotapurirwa makiyi eruzhinji anogara kwenguva refu, kana hashi kubva mazviri. Kumwe kusazivikanwa kubva kune anoona zvake.

Sezvineiwo, anenge munhu wese anoda kuve neichi chishoma mune chero ruoko protocol, uye zvishoma zviri pamusoro zvinozosangana zve "pamba" mapuroteni. Iye zvino hatisi kuzogadzira chero chinhu chitsva. Ndinonyatso kurudzira kushandisa Noise framework yekuvaka maprotocol, asi ngatisarudze chimwe chinhu chakareruka.

Iwo maviri anonyanya kufarirwa maprotocol ndeaya:

  • TLS - protocol yakaoma kwazvo ine nhoroondo refu yezvipembenene, jambs, kushaya simba, kufunga kwakashata, kuomarara uye kukanganisa (zvisinei, izvi zvine zvishoma zvekuita neTLS 1.3). Asi isu hatizvifungire nekuti yakanyanya kuoma.
  • IPsec с Ike - usave nematambudziko akakomba e-cryptographic, kunyangwe asiriwo ari nyore. Kana iwe ukaverenga nezve IKEv1 uye IKEv2, saka sosi yavo ndeye STS, ISO/IEC IS 9798-3 uye SIGMA (SIGn-uye-MAc) mapuroteni - ari nyore kuita manheru mamwe chete.

Chii chakanaka nezveSIGMA, seyazvino chinongedzo mukuvandudzwa kweSTS/ISO protocol? Iyo inosangana nezvose zvatinoda (kusanganisira "kuvanza" interlocutor identifiers) uye haina inozivikanwa cryptographic matambudziko. Iyo minimalistic - kubvisa chimwe chinhu kubva kune protocol meseji kunotungamira mukusachengeteka kwayo.

Ngatibvei kubva kune yakapusa-yakakura-protocol toenda kuSIGMA. Kuvhiya kwakanyanya kwatinofarira ndekwe chibvumirano chikuru: Basa rinoburitsa vese vatori vechikamu kukosha kwakafanana, iyo inogona kushandiswa sekiyi inoenzanirana. Pasina kupinda mune zvakadzama: bato rega rega rinogadzira ephemeral (inoshandiswa chete mukati mechikamu chimwe chete) kiyi mbiri (yeruzhinji uye yakavanzika makiyi), inotsinhanisa makiyi eruzhinji, inodaidza basa rechibvumirano, kune iyo yekupinza yavanopfuudza yavo yakavanzika kiyi uye yeruzhinji kiyi ye. mutauriri.

β”Œβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β” β”‚PeerAβ”‚ β”‚PeerBβ”‚ β””β”€β”€β”¬β”€β”€β”˜ └── Ipua, β”‚ ╔══════════ ══════════╗ │───────────────>β”‚ β•‘PrvA β”• β”‚ β•‘PrvA,Pub. ═ ════════ ═══════════╝ β”‚ IdB, PubB β”‚<──────── ──────│ β•‘PrvB, PubB = DHgen()β•‘ β”‚ β”‚ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• ───┐ ╔════ ═══╧════════════╗ β”‚ β•‘Key = DH(PrvA, PubB)β•‘ <β”€β”€β”€β”˜β•β•β•β•β•β•β•β•β•β•β•β•β• ═══════ ════╝ β”‚ β”‚ β”‚ β”‚

Chero ani zvake anogona kusvetukira pakati uye kutsiva makiyi eruzhinji neavo - hapana humbowo hwevanopindirana mune iyi protocol. Ngatiwedzere siginicha ine makiyi enguva refu.

β”Œβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β” β”‚PeerAβ”‚ β”‚PeerBβ”‚ β””β”€β”€β”¬β”€β”€β”˜ └── └── └── SignPrvA, (PubA)) β”‚ ╔═ │─────────── ────────── ────────────Saina bA = mutoro()β•‘ β”‚ β”‚ β•‘PrvA, PubA = DHgen() β•‘ β”‚ β”‚ β•šβ•β•β•β•β•β•β• ═══════ ═════════════════════ , sign(SignPrvB, (PubB)) β”‚ ╔══════════════ ═══════ ═════════ ═══════ ────────── ───────────── ──│ β•‘SignPrvB, SignPubB = mutoro( )β•‘ β”‚ β”‚ β•‘PrvB, Pub β”• β‚• β‚• β‚• β‚• ═════════ ══════════════ ══╝ ────┐ β•” ═════╗ β”‚ β”‚ β•‘verify( SignPub. ═╝ β”‚ β”‚ β”‚

Siginecha yakadaro haishande, nekuti haina kusungirirwa kune imwe nguva. Mameseji akadai "akakodzera" kumisangano nevamwe vatori vechikamu. Chimiro chese chinofanira kunyoresa. Izvi zvinotimanikidza kuwedzera imwe meseji kubva kuA.

Pamusoro pezvo, zvakakosha kuti uwedzere chiziviso chako pasi pe siginicha, sezvo tikasadaro tinogona kutsiva IdXXX uye kusainazve meseji nekiyi yemumwe anozivikanwa interlocutor. Kudzivirira reflection attack, zvinodikanwa kuti zvinhu zviri pasi pesiginicha zvive munzvimbo dzakanyatsotsanangurwa zvinoenderana nezvazvinoreva: kana A zviratidzo (PubA, PubB), ipapo B anofanira kusaina (PubB, PubA). Izvi zvinotaurawo nezvekukosha kwekusarudza chimiro uye fomati yeserialized data. Semuenzaniso, seti muASN.1 DER encoding yakarongedzwa: SET OF(PubA, PubB) ichafanana neSET OF(PubB, PubA).

β”Œβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β” β”‚PeerAβ”‚ β”‚PeerBβ”‚ β””β”€β”€β”¬β”€β”€β”˜ └── Ipua, β”‚ ╔══════════ ═══════════════╗ │───────────———─ ───────── ────────────>β”‚ β•‘SignPrvA, SignPubA = mutoro()β•‘ β”‚ β”‚ β•‘PrvA, PubA = DHgen() β•• β•• β•‘ ═ ═══════ ═══════════════╝ β”‚IdB, PubB, sign(SignPrvB, (IdB, PubA, PubB)) ═════ ═══════════╗ β”‚<────────────────—─ ───────── ─────────│ β•‘SignPrvB, SignPubB = mutoro()β•‘ β”‚ β”‚ β•‘PrvB, PubB = DHgen() β•‘ β”‚ β”‚ β”‚ ═══════│ ════════ ══════════╝ β”‚ sign(SignPrvA, (IdA, PubB, PubA)) β”‚ ╔══════════════════════ ════╗ │─ ──────────────────────────────────── ───>β”‚ β•‘verify(SignPubB, ...) β•‘ β”‚ β”‚ β•‘kiyi = dh (prva, PUBB) β•‘ β”‚ β”‚ β”‚

Nekudaro, isu hatisati "takaratidza" kuti takagadzira imwechete yakagovaniswa kiyi yechikamu chino. Muchidimbu, tinogona kuita pasina danho iri - iyo yekutanga yekufambisa yekubatanidza ichave isingashande, asi isu tinoda kuti kana kubatwa kwemaoko kwapera, isu tinoita chokwadi chekuti zvese zvinonyatso kubvumirana. Parizvino isu tine ISO/IEC IS 9798-3 protocol paruoko.

Tinogona kusaina kiyi yakagadzirwa pachayo. Izvi zvine njodzi, sezvo zvichikwanisika kuti panogona kuve nekuvuza mune siginecha algorithm inoshandiswa (kunyangwe bits-per-siginicha, asi ichiri kuvuza). Zvinogoneka kusaina hashi yekiyi yekubvisa, asi kudonhedza kunyange hashi yekiyi yakatorwa kunogona kuve kwakakosha mukurwisa kwechisimba-simba pane basa rekubvisa. SIGMA inoshandisa MAC basa rinosimbisa iyo yekutumira ID.

β”Œβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β” β”‚PeerAβ”‚ β”‚PeerBβ”‚ β””β”€β”€β”¬β”€β”€β”˜ └── Ipua, β”‚ ╔══════════ ═══════════════╗ │───────────———─ ───────── ────────────- β•š ═══════ ════════════════════╝ β”‚IdB, PubB, sign(SignPrvB, (PubA, PubIB)β••), MAC │═╝ ═══ β”‚<───────────────── ────────── ──—─—─ ───────── ─│ β•‘SignPrvB, SignPubB = load()β•‘ β”‚ β”‚ β•‘PrvB, PubB = DHgen() β•‘ β”‚ β”‚ β•šβ•β•β•β• ══════════════════════ ═════════ ══╝ β”‚ β”‚ ╔════════════ ═════════╗ │══╗ β”‚ sign),(Pubb)(Pub) β”‚ β•‘Kiyi = DH( PrvA, PubB) β•‘ │───────────────────── ── ────────── ───────── ─────>β”‚ β•‘verify(Key, IdB) β•‘ β”‚ β”‚ β•‘verify(SignPubB, ...)β•‘ β”‚ β”‚ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• ═════ ═╝ β”‚ β”‚

Sekugonesa, vamwe vangangoda kushandisazve makiyi avo ephemeral (zvinova, zvechokwadi, zvinosiririsa kuPFS). Semuenzaniso, takagadzira peya kiyi, takaedza kubatanidza, asi TCP yakanga isipo kana kuti yakakanganiswa pane imwe nzvimbo pakati peprotocol. Zvinonyadzisa kuparadza entropy uye processor zviwanikwa pane imwe nyowani. Naizvozvo, isu tichasuma iyo inonzi cookie - pseudo-random kukosha iyo inodzivirira kubva pane zvingangoita zvemango replay kurwiswa kana uchishandisa zvakare ephemeral makiyi eruzhinji. Nekuda kwekusungirirwa pakati pekuki nekiyi yeruzhinji ephemeral, kiyi yeruzhinji yerimwe bato inogona kubviswa kubva mukusaina sekusina basa.

β”Œβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β” β”‚PeerAβ”‚ β”‚PeerBβ”‚ β””β”€β”€β”¬β”€β”€β”˜ └──────Id A β”‚ ╔════════ ═════════════════╗ │────────———─ ───────── ──────────────────────────────────── ─> β”‚ ​​║SignPrvA, SignPubA = mutoro( )β•‘ β”‚ β”‚ β•‘PrvA, PubA = DHgen() β•‘ β”‚ β”‚ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• ══╝ β”‚IdB, PubB, CookieB , saina(SignPrvB, (CookieA, CookieB, PubB)), MAC(IdB) β”‚ ╔═════════════════╕═══════════════════════ ═ β•— β”‚< ──────────────────────────────────── ───────── ───────────────────│ β•‘SignPrvB, SignPubB = load()β•‘ β”‚ β”‚ β”‚B) β”‚ β•šβ•β•β•β•β•β• ═════════════════════╝ β”‚ β”‚ ╔═════╕══════╝ ═══════╗ β”‚ sign( SignPrvA, (CookieB, CookieA, PubA)), MAC(IdA) β”‚ β•‘Kiyi = DH(PrvA, PubB) β•‘ │────────────── ─ ── ─────────────────────────────────── ───────>β”‚ β•‘ simbisa(Kiyi, IdB) β•‘ β”‚ β”‚ β•‘ simbisa(SignPubB, ...)β•‘ β”‚ β”‚ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• β”‚ β”‚

Chekupedzisira, tinoda kuwana kuvanzika kwevatinobata navo hurukuro kubva kune anoona zvake. Kuti uite izvi, SIGMA inokurudzira kutanga kuchinjana ephemeral makiyi uye kugadzira kiyi yakajairwa iyo yekuvharira echokwadi uye yekuzivisa mameseji. SIGMA inotsanangura sarudzo mbiri:

  • SIGMA-I - inodzivirira muvambi kubva pakurwiswa kwakasimba, anopindura kubva kune anozvimiririra: muvambi anosimbisa anopindura uye kana chimwe chinhu chisingaenderane, saka hachipi chitupa chayo. Mupomerwi anopa chiziviso chake kana protocol inoshanda yatangwa naye. Mucherechedzi asina chaanodzidzira;
    SIGMA-R - inodzivirira anopindura kubva pakurwiswa kunoshanda, mutangi kubva kune anongoita. Zvese zvakapesana, asi muprotocol mana mameseji ekubata maoko atofambiswa.

    Isu tinosarudza SIGMA-Ini sezvo yakanyanya kufanana nezvatinotarisira kubva kune mutengi-server zvinhu zvinozivikanwa: mutengi anozivikanwa chete neiyo yakavimbiswa sevha, uye munhu wese anotoziva sevha. Uyezve zviri nyore kuita nekuda kwemameseji mashoma ekubata maoko. Zvese zvatinowedzera kuprotocol ndeye encrypt chikamu chemeseji uye kuendesa identifier A kune yakavharidzirwa chikamu chekupedzisira meseji:

    PubA, cookiesA ───────── ───── ────────── ────────────────── ────────── ───── ──────>β”‚ β•‘SignPrvA , SignPubA = load()β•‘ β”‚ β”‚ β•‘PrvA, PubA = DHgen() ═══ β•‘ ════════ ═════════ ════╝ β”‚ PubB, CookieB, Enc((IdB, sign(SignPrvB, (CookieA, CookieB, PubB)), MAC(Id═══) ══════════════ ═══════╗ β”‚<─────═———— ───────── ───── ────────── β•‘SignP rvB, SignPubB = load()β•‘ β”‚ β”‚ β•‘ PrvB, PubB = DHgen β”• ₐ β”• ════════ ════════════════╝ β”‚ β”‚ ╔═══════════════════════ ══╗ β”‚ Enc((IdA, sign( SignPrvA, (CookieB, CookieA, PubA)), MAC(IdA))) β”‚ β•‘Kiyi = DH(PrvA, PubB) β•‘ │───────────── ─ ───────────────── ────────── ───────── ────────── ──────>β”‚ β•‘verify(Kiyi, IdB) β•‘ β”‚ β”‚ β•‘verify( SignPubB, ...)β•‘ β”‚ β”‚ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• ═════ ══╝ β”‚ β”‚
    
    • GOST R inoshandiswa pakusaina 34.10-2012 algorithm ine 256-bit kiyi.
    • Kugadzira kiyi yeruzhinji, 34.10-2012 VKO inoshandiswa.
    • CMAC inoshandiswa seMAC. Nehunyanzvi, iyi ndiyo nzira yakakosha yekushanda kwe block cipher, inotsanangurwa muGOST R 34.13-2015. Sebasa rekunyorera reiyi modhi - Grasshopper (34.12-2015).
    • Iyo hashi yekiyi yake yeruzhinji inoshandiswa semutauri weinterlocutor. Inoshandiswa sehashi Stribog-256 (34.11/2012/256 XNUMX bits).

    Mushure mekubata maoko, tichabvumirana pane kiyi yakagovaniswa. Tinogona kuishandisa kune yakatendeseka encryption yemameseji ekufambisa. Ichi chikamu chiri nyore uye chakaoma kuita chikanganiso: isu tinowedzera iyo meseji counter, encrypt meseji, simbisa (MAC) iyo counter uye ciphertext, tumira. Kana tichitambira meseji, tinoongorora kuti counter ine hukoshi hunotarisirwa, simbisa ciphertext nekaunda, toibvisa. Ndeipi kiyi yandinofanira kushandisa kunyora mameseji ekubata maoko, mameseji ekufambisa, uye maitiro ekuasimbisa? Kushandisa kiyi imwe pamabasa ese aya kune ngozi uye kusachenjera. Izvo zvinodikanwa kugadzira makiyi uchishandisa yakasarudzika mabasa KDF (key derivation function). Zvakare, ngatirege kuparadzanisa bvudzi uye kugadzira chimwe chinhu: HKDF yave ichizivikanwa kwenguva refu, yakatsvakurudzwa zvakanaka uye haina matambudziko anozivikanwa. Nehurombo, raibhurari yePython yekuzvarwa haina basa iri, saka tinoshandisa hkdf plastic bag. HKDF mukati inoshandisa HMAC, iyo inoshandisawo hashi basa. Muenzaniso kushandiswa muPython pane peji reWikipedia inotora mitsetse mishoma yekodhi. Sezvakaitika muna 34.10/2012/256, tichashandisa Stribog-XNUMX sebasa rehashi. Kubuda kwebasa redu rechibvumirano chakakosha kuchadaidzwa kuti kiyi yesesheni, kubva kwairi kusiko symmetric inogadzirwa:

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

    Zvirongwa/Zvirongwa

    Ngatitarisei kuti ndezvipi ASN.1 zvimiro zvatave nazvo zvekufambisa data rese:

    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)
    

    HandshakeTBS ndiyo ichasainwa. HandshakeTBE - chii chichave chakanyorwa. Ini ndinokwevera kutarisa kwako kumunda weukm muMsgHandshake1. 34.10 VKO, kune yakatokura randomisation yemakiyi akagadzirwa, inosanganisira iyo UKM (mushandisi keying material) parameter - kungowedzera entropy.

    Kuwedzera Cryptography kune Code

    Ngatitarisei chete shanduko dzakaitwa kune yekutanga kodhi, sezvo dhizaini yakaramba yakafanana (chaizvoizvo, kuitisa kwekupedzisira kwakanyorwa kutanga, uyezve cryptography yese yakatemwa kubva mairi).

    Sezvo kuvimbiswa uye kuzivikanwa kwevanopindirana kuchaitwa uchishandisa makiyi eruzhinji, ivo zvino vanofanirwa kuchengetwa kumwe kwenguva yakareba. Kuti zvive nyore, tinoshandisa JSON seizvi:

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

    yedu - yedu kiyi mbiri, hexadecimal yakavanzika uye yeruzhinji makiyi. avo - mazita evanopindirana uye makiyi avo eruzhinji. Ngatichinjei mutsara wemirairo nharo uye tiwedzere post-kugadzirisa yeJSON 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),
        }
    # }}}
    

    Iyo yakavanzika kiyi ye34.10 algorithm inhamba isina kurongeka. 256-bit size ye 256-bit elliptic curves. PyGOST haishande neseti yemabheti, asi ne nhamba huru, saka kiyi yedu yakavanzika (urandom(32)) inoda kushandurwa kuita nhamba uchishandisa gost3410.prv_unmarshal(). Kiyi yeruzhinji inotemerwa zvine mutsindo kubva kukiyi yakavanzika uchishandisa gost3410.public_key(). Kiyi yeruzhinji 34.10 inhamba huru mbiri dzinodawo kushandurwa kuita byte sequence kuitira kurerutsira kuchengetedza uye kutapurirana uchishandisa gost3410.pub_marshal().

    Mushure mekuverenga faira reJSON, makiyi eruzhinji anofanirwa kudzoserwa kumashure uchishandisa gost3410.pub_unmarshal(). Sezvo isu tichizogamuchira zviziviso zvevanopindirana muchimiro chehashi kubva kukiyi yeruzhinji, vanogona kuverengerwa nekukurumidza uye kuiswa muduramazwi nekukurumidza kutsvaga. Stribog-256 hash is gost34112012256.GOST34112012256(), iyo inogutsa zvizere iyo hashib interface yehashi mabasa.

    Ko coroutine yekutanga yakachinja sei? Zvese zvinoenderana nechirongwa chekubata maoko: isu tinogadzira cookie (128-bit yakawanda), ephemeral kiyi pair 34.10, iyo ichashandiswa kune iyo VKO yakakosha chibvumirano basa.

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

    • isu tinomirira mhinduro uye tinosarudza iyo inouya Msg meseji;
    • ita shuwa kuti wabata ruoko1;
    • decode ephemeral public kiyi yerimwe bato uye verenga kiyi yesesheni;
    • Isu tinogadzira symmetric kiyi inodiwa kugadzirisa iyo TBE chikamu chemeseji.

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

    UKM inhamba ye64-bit (urandom(8)), inodawo deserialization kubva pakumiririra kwayo byte uchishandisa gost3410_vko.ukm_unmarshal(). VKO basa re34.10/2012/256 3410-bit is gost34102012256_vko.kek_XNUMX() (KEK - encryption key).

    Iyo yakagadzirwa chikamu kiyi yatove 256-bit pseudo-random byte sequence. Naizvozvo, inogona kushandiswa nekukurumidza muHKDF mabasa. Sezvo GOST34112012256 ichigutsa hahlib interface, inogona kushandiswa nekukurumidza mukirasi yeHkdf. Isu hatitsanangure munyu (nharo yekutanga yeHkdf), sezvo kiyi yakagadzirwa, nekuda kweiyo ephemerality yevatori vechikamu makiyi maviri, ichave yakasiyana pachikamu chega chega uye yatove neyakakwana entropy. kdf.expand() by default inotogadzira 256-bit kiyi inodiwa kuGrasshopper gare gare.

    Tevere, zvikamu zveTBE neTBS zvemeseji iri kuuya zvinotariswa:

    • iyo MAC pamusoro peiyo inouya ciphertext inoverengerwa nekutariswa;
    • the ciphertext is decrypted;
    • TBE chimiro chakatemwa;
    • iyo identifier ye interlocutor inotorwa kubva mairi uye inotariswa kana iye anozivikanwa kwatiri zvachose;
    • MAC pamusoro peichi chiziviso inoverengerwa nekutariswa;
    • siginicha pamusoro peiyo TBS chimiro inosimbiswa, iyo inosanganisira cookie yemapato ese uye yeruzhinji ephemeral kiyi yerimwe bato. Siginicha inosimbiswa nekiyi yekugara kwenguva refu siginecha ye interlocutor.

     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"]
    

    Sezvandakanyora pamusoro, 34.13/2015/XNUMX inotsanangura zvakasiyana-siyana block cipher inoshanda modes kubva 34.12/2015/3413. Pakati pavo pane modhi yekugadzira yekutevedzera inoisa uye MAC kuverenga. MuPyGOST iyi ndiyo gost34.12.mac(). Iyi modhi inoda kupfuudza iyo encryption basa (kugamuchira uye kudzorera imwe block yedata), saizi yevhavhavhavhavha uye, iko iko, iyo data pachayo. Sei usingakwanise hardcode saizi yeiyo encryption block? 2015/128/64 inotsanangura kwete chete XNUMX-bit Grasshopper cipher, asiwo iyo XNUMX-bit. Magma - yakagadziridzwa zvishoma GOST 28147-89, yakagadzirwa kumashure muKGB uye ichine imwe yepamusoro-soro chengetedzo zvikumbaridzo.

    Kuznechik inotangwa nekudaidza gost.3412.GOST3412Kuznechik(kiyi) uye inodzosera chinhu chine .encrypt()/.decrypt() nzira dzakakodzera kupfuudza ku34.13 mabasa. MAC inoverengwa sezvizvi: gost3413.mac(GOST3412Kuznechik(key).encrypt, KUZNECHIK_BLOCKSIZE, ciphertext). Kuenzanisa iyo yakaverengerwa uye yakagashirwa MAC, haugone kushandisa yakajairwa kuenzanisa (==) yebyte tambo, sezvo kuvhiya uku kuchiburitsa nguva yekuenzanisa, iyo, mune yakajairika, inogona kutungamirira kune ngozi inouraya senge. CHIKARA kurwisa TLS. Python ine basa rinokosha, hmac.compare_digest, nokuda kweizvi.

    Iyo block cipher basa inogona kungovhara imwe block yedata. Kune nhamba yakakura, uye kunyange isiri yakawanda yehurefu, zvinodikanwa kushandisa encryption mode. 34.13-2015 inotsanangura zvinotevera: ECB, CTR, OFB, CBC, CFB. Imwe neimwe ine nzvimbo dzayo dzinogamuchirwa dzekushandisa uye maitiro. Nehurombo, isu hatisati tave nestandard authenticated encryption modes (zvakadai seCCM, OCB, GCM nezvimwe zvakadaro) - tinomanikidzwa kuwedzera MAC isu pachedu. Ndinosarudza counter mode (CTR): haidi padding kune saizi yebhuroka, inogona kufananidzwa, inoshandisa chete encryption basa, inogona kushandiswa zvakachengeteka kuvharidzira nhamba huru dzemeseji (kusiyana neCBC, ine kudhumhana nekukurumidza).

    Senge .mac(), .ctr() inotora mashoko akafanana: ciphertext = gost3413.ctr(GOST3412Kuznechik(key).encrypt, KUZNECHIK_BLOCKSIZE, plaintext, iv). Izvo zvinodikanwa kutsanangura yekutanga vector iyo inonyatso hafu yehurefu hweiyo encryption block. Kana kiyi yedu yekuvharidzira ichishandiswa chete kuvharidzira meseji imwe chete (kunyangwe kubva kune akati wandei), saka zvakachengeteka kuseta zero yekutanga vector. Kuti tivhare mameseji ekubata maoko, tinoshandisa kiyi yakaparadzana nguva yega yega.

    Kuongorora siginecha gost3410.verify() hazvina basa: tinopfuura elliptic curve mukati matiri kushanda (tinongoinyora muGOSTIM protocol yedu), kiyi yeruzhinji yeanosaina (usakanganwa kuti iyi inofanira kunge iri tuple yezviviri. nhamba huru, uye kwete tambo yebyte), 34.11/2012/XNUMX hashi uye siginicha pachayo.

    Tevere, mune yekutanga isu tinogadzirira uye nekutumira meseji yekubata ruoko kunobata maoko2, tichiita zvimwechetezvo sezvatakaita panguva yekusimbisa, chete symmetrically: kusaina pamakiyi edu pachinzvimbo chekutarisa, nezvimwe ...

     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)
     

    Kana iyo sesheni yatangwa, makiyi ekufambisa anogadzirwa (kiyi yakaparadzana yekuvharidzira, yekusimbisa, kune yega yega mapato), uye Grasshopper inotangwa kudhipta uye kutarisa MAC:

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

    Iyo msg_sender coroutine ikozvino encrypts mameseji isati yaatumira paTCP yekubatanidza. Imwe neimwe meseji ine monotonically inowedzera nonce, inova zvakare yekutanga vector kana yakavharidzirwa mune counter mode. Imwe neimwe meseji uye meseji block inovimbiswa kuve neyakasiyana counter value.

    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
    

    Mameseji anouya anogadziriswa ne msg_receiver coroutine, inobata chokwadi uye decryption:

    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)
    

    mhedziso

    GOSTIM inotarisirwa kushandiswa chete nekuda kwezvinangwa zvekudzidzisa (sezvo isina kuvharwa nemiedzo, kanenge)! Iyo kodhi yekodhi yepurogiramu inogona kutorwa pano (Π‘Ρ‚Ρ€ΠΈΠ±ΠΎΠ³-256 Ρ…ΡΡˆ: 995bbd368c04e50a481d138c5fa2e43ec7c89bc77743ba8dbabee1fde45de120). Как ΠΈ всС ΠΌΠΎΠΈ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Ρ‹, Ρ‚ΠΈΠΏΠ° GoGOST, PyDERASN, NCCP, GoVPN, GOSTIM zvachose software yemahara, yakagoverwa pasi pemitemo GPLv3 +.

    Sergey Matveev, cypherpunk, nhengo SPO Foundation, Python/Go mugadziri, nyanzvi huru FSUE "STC "Atlas".

Source: www.habr.com

Voeg