GOSTIM: P2P F2F E2EE IM dina hiji sore kalayan kriptografi GOST

Janten pamekar PyGOST perpustakaan (GOST cryptographic primitif dina Python murni), Kuring mindeng narima patarosan ngeunaan kumaha carana nerapkeun olahtalatah aman pangbasajanna on dengkul teh. Loba jalma nganggap kriptografi terapan cukup basajan, sarta nelepon .encrypt () dina block cipher bakal cukup pikeun ngirim eta aman ngaliwatan saluran komunikasi. Batur yakin yรฉn kriptografi terapan mangrupikeun takdir ti sababaraha urang, sareng tiasa ditarima yรฉn perusahaan beunghar sapertos Telegram sareng olimpiade-matematikawan. teu bisa ngalaksanakeun protokol aman.

Sadaya ieu nyababkeun kuring nyerat tulisan ieu pikeun nunjukkeun yรฉn ngalaksanakeun protokol kriptografi sareng IM aman sanรฉs tugas anu sesah. Sanajan kitu, teu patut inventing autรฉntikasi sorangan jeung protokol perjangjian konci.

GOSTIM: P2P F2F E2EE IM dina hiji sore kalayan kriptografi GOST
artikel bakal nulis titik ka titik, babaturan-ka-babaturan, end-to-end รฉnkripsi utusan instan kalawan SIGMA-I autรฉntikasi sareng protokol perjanjian konci (dina dasar anu dilaksanakeun IPsec IKE), ngagunakeun algoritma kriptografi GOST รฉksklusif perpustakaan PyGOST jeung perpustakaan encoding pesen ASN.1 PyDERASN (ngeunaan anu kuring parantos nyerat sateuacan). A prerequisite: kudu jadi basajan nu bisa ditulis ti scratch dina hiji malem (atawa workday), disebutkeun eta geus euweuh program basajan. ร‰ta sigana ngagaduhan kasalahan, komplikasi anu teu dipikabutuh, kakurangan, sareng ieu mangrupikeun program munggaran kuring nganggo perpustakaan asyncio.

Desain IM

Kahiji, urang kudu ngarti kumaha IM urang bakal kasampak kawas. Pikeun kesederhanaan, hayu eta jadi jaringan peer-to-peer, tanpa kapanggihna pamilon. Kami pribadi bakal nunjukkeun alamat mana: port anu nyambungkeun pikeun komunikasi sareng interlocutor.

Kuring ngarti yรฉn, dina waktos ayeuna, anggapan yรฉn komunikasi langsung sadia antara dua komputer sawenang mangrupakeun watesan signifikan dina applicability of IM dina prakna. Tapi beuki pamekar nerapkeun sagala sorts crutches NAT-traversal, beuki lila urang bakal tetep dina Internet IPv4, kalawan kamungkinan depresi komunikasi antara komputer sawenang. Sabaraha lami anjeun tiasa tolerate kurangna IPv6 di bumi sareng di tempat kerja?

Urang bakal gaduh jaringan rรฉrรฉncangan-ka-rรฉncang: sadaya kamungkinan interlocutors kedah dipikanyaho sateuacanna. Firstly, ieu greatly simplifies sagalana: urang ngawanohkeun diri, kapanggih atawa teu manggihan ngaran / konci, dipegatkeun atawa neruskeun gawรฉ, nyaho interlocutor nu. Brรฉh, sacara umum, รฉta aman sareng ngaleungitkeun seueur serangan.

Antarbeungeut IM bakal caket kana solusi klasik proyรฉk suckless, anu kuring resep pisan pikeun minimalisme sareng filosofi Unix-way na. Program IM nyiptakeun dirรฉktori sareng tilu sockets domain Unix pikeun unggal interlocutor:

  • di-pesen anu dikirim ka interlocutor kacatet di jerona;
  • kaluar - pesen anu ditampi ti interlocutor nu dibaca ti dinya;
  • kaayaan - ku maca ti dinya, urang manggihan naha interlocutor nu ayeuna disambungkeun, alamat sambungan / port.

Sajaba ti รฉta, stop kontak conn dijieun, ku nulis port host kana nu urang initiate sambungan ka interlocutor jauh.

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

pendekatan ieu ngidinan Anjeun pikeun nyieun palaksanaan bebas angkutan IM jeung panganteur pamakรฉ, sabab euweuh sobat, anjeun moal bisa mangga dulur. Ngagunakeun tmux jeung / atawa multitail, anjeun tiasa kรฉngingkeun antarmuka multi-jandela sareng panyorot sintaksis. Sareng kalayan bantosan rlwrap anjeun tiasa kรฉngingkeun jalur input pesen anu cocog sareng GNU Readline.

Kanyataanna, proyรฉk suckless ngagunakeun file FIFO. Pribadi, kuring henteu tiasa ngartos kumaha cara damel sareng file sacara kompetitif dina asyncio tanpa latar tukang tulisan leungeun tina benang khusus (Kuring parantos ngagunakeun basa pikeun hal-hal sapertos kitu kanggo waktos anu lami. Go). Ku alatan รฉta, kuring mutuskeun pikeun ngalakukeun sareng sockets domain Unix. Hanjakal, ieu ngajadikeun eta teu mungkin mun ngalakukeun gema 2001:470:maot::babe 6666 > conn. Kuring direngsekeun masalah ieu ngagunakeun socat: gema 2001:470:maot::babe 6666 | socat - UNIX-CONNECT:conn, socat READLINE UNIX-CONNECT:alice/in.

Protokol teu aman aslina

TCP dipakรฉ salaku angkutan: eta ngajamin pangiriman jeung urutan na. UDP henteu ngajamin (anu bakal mangpaat nalika kriptografi dianggo), tapi ngadukung SCTP Python teu kaluar tina kotak.

Hanjakalna, dina TCP teu aya konsรฉp pesen, ngan ukur aliran bait. Ku alatan รฉta, perlu datang nepi ka format pikeun pesen ambรฉh maranรฉhanana bisa dibagikeun diantara sorangan dina thread ieu. Urang bisa satuju ngagunakeun karakter feed garis. Henteu kunanaon pikeun ngamimitian, tapi saatos urang ngamimitian รฉnkripsi pesen urang, karakter ieu tiasa muncul dimana waรฉ dina ciphertext. Dina jaringan, ku kituna, protokol anu ngirim heula panjang pesen dina bait anu populรฉr. Salaku conto, out of the box Python gaduh xdrlib, anu ngamungkinkeun anjeun damel sareng format anu sami XDR.

Kami moal tiasa dianggo leres sareng รฉfisiรฉn sareng bacaan TCP - kami bakal nyederhanakeun kodeu. Urang maca data tina stop kontak dina loop sajajalan dugi kami decode pesen lengkep. JSON sareng XML ogรฉ tiasa dianggo salaku format pikeun pendekatan ieu. Tapi nalika kriptografi ditambahkeun, data kudu ditandatanganan tur diotรฉntikasi - sarta ieu merlukeun representasi bait-pikeun-bait idรฉntik objรฉk, nu JSON / XML teu nyadiakeun (hasil dump bisa rupa-rupa).

XDR cocog pikeun tugas ieu, Tapi kuring milih ASN.1 kalawan DER encoding jeung PyDERASN perpustakaan, saprak urang bakal boga obyรฉk-tingkat tinggi on leungeun nu mindeng leuwih pikaresepeun tur merenah pikeun digawรฉ. Teu kawas schemaless bencode, MessagePack atawa CBOR, ASN.1 otomatis bakal pariksa data ngalawan schema hard-disandi.

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

Pesen anu ditampi bakal janten Msg: boh tรฉks MsgText (kalayan hiji widang tรฉks pikeun ayeuna) atanapi pesen sasalaman MsgHandshake (anu ngandung nami interlocutor). Ayeuna sigana langkung rumit, tapi ieu mangrupikeun pondasi pikeun masa depan.

     โ”Œโ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ” โ”‚PeerAโ”‚ โ”‚PeerBโ”‚ โ””โ”€โ”€โ”ฌโ”€โ”€โ”˜ โ”ฌโ”€โ”€โ”€โ”‚โ”€โ”€ ) โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚MsgSasalaman(IdB) โ”‚ โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚ โ”‚ MsgText() โ”‚ โ”‚โ”€โ”€โ”€โ”€ MsgText() โ”‚ โ”‚ โ”‚

IM tanpa kriptografi

Sakumaha anu kuring parantos nyarios, perpustakaan asyncio bakal dianggo pikeun sadaya operasi stop kontak. Hayu urang ngumumkeun naon anu urang ngarepkeun dina peluncuran:

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

Setel ngaran anjeun sorangan (--our-name alice). Kabรฉh interlocutors ekspektasi didaptarkeun dipisahkeun ku koma (-na-ngaran bob, eve). Pikeun unggal interlocutors, hiji dirรฉktori kalawan Unix sockets dijieun, kitu ogรฉ coroutine pikeun tiap asup, kaluar, kaayaan:

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

Pesen anu asalna ti pangguna tina stop kontak dikirim ka antrian 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"))

Pesen anu datang ti interlocutors dikirim ka OUT_QUEUES antrian, ti mana data ditulis kana stop kontak kaluar:

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

Nalika maca tina stop kontak kaayaan, program milarian alamat interlocutor dina kamus PEER_ALIVE. Upami teu acan aya sambungan ka interlocutor, teras baris kosong ditulis.

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

Nalika nulis alamat ka stop kontak, fungsi "inisiator" sambungan dijalankeun:

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

Hayu urang nganggap inisiator. Mimitina รฉcรฉs muka sambungan ka host / port anu ditunjuk sareng ngirim pesen sasalaman kalayan namina:

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

Lajeng, eta ngantosan respon ti pihak jauh. Nyobaan decode respon asup ngagunakeun skรฉma Msg ASN.1. Urang nganggap yรฉn sakabรฉh pesen bakal dikirim dina hiji bagean TCP sarta kami bakal nampa eta atom nalika nelepon .baca (). Kami pariksa yรฉn kami nampi pesen sasalaman.

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

Kami pariksa yรฉn nami anu ditampi tina interlocutor dipikanyaho ku urang. Lamun henteu, teras urang megatkeun sambungan. Urang pariksa naha urang geus ngadegkeun sambungan kalawan anjeunna (interlocutor deui masihan parรฉntah pikeun nyambung ka kami) jeung nutup eta. Antrian IN_QUEUES nahan string Python jeung tรฉks pesen, tapi boga nilai husus tina Euweuh nu sinyal msg_sender coroutine eureun gawรฉ meh poho ngeunaan panulis na pakait sareng sambungan TCP warisan.

 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 narima pesen kaluar (ngantri tina stop kontak), serializes kana pesen MsgText sarta ngirimkeunana ngaliwatan sambungan TCP. ร‰ta tiasa ngarecah iraha waรฉ - urang jelas ngahalangan ieu.

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

Dina tungtungna, inisiator asup ka loop tanpa wates of maca pesen ti stop kontak nu. Pariksa naha pesen ieu pesen tรฉks sareng nempatkeunna dina antrian OUT_QUEUES, dimana aranjeunna bakal dikirim ka stop kontak kaluar tina interlocutor anu saluyu. Naha anjeun teu bisa ngan ngalakukeun .baca () jeung decode pesen? Kusabab kamungkinan yรฉn sababaraha pesen ti pamakรฉ bakal aggregated dina panyangga sistem operasi sarta dikirim dina hiji bagean TCP. Urang tiasa nga-decode anu kahiji, teras bagian tina anu salajengna tiasa tetep aya dina panyangga. Upami aya kaayaan anu teu normal, urang nutup sambungan TCP sareng ngeureunkeun coroutine msg_sender (ku ngirim Euweuh kana antrian 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)

Hayu urang balik deui ka kode utama. Sanggeus nyieun sagala coroutines dina waktu program dimimitian, urang ngamimitian server TCP. Pikeun unggal sambungan ngadegkeun, รฉta nyiptakeun coroutine responder.

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

responder tรฉh sarupa jeung inisiator jeung kaca spion sadaya lampah sarua, tapi loop taya wates maca pesen dimimitian geuwat, pikeun kesederhanaan. Ayeuna, protokol sasalaman ngirimkeun hiji pesen ti saban gigir, tapi di hareup bakal aya dua ti inisiator sambungan, saatos pesen tรฉks tiasa langsung dikirim.

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

Protokol aman

Geus waktuna pikeun ngamankeun komunikasi urang. Naon anu kami maksud ku kaamanan sareng naon anu kami pikahoyong:

  • karusiahan pesen dikirimkeun;
  • kaaslian sareng integritas pesen anu dikirimkeun - parobahanana kedah dideteksi;
  • panyalindungan ngalawan serangan replay - kanyataan pesen leungit atawa diulang kudu dideteksi (sarta urang mutuskeun pikeun nungtungan sambungan);
  • idรฉntifikasi sareng autรฉntikasi interlocutors nganggo konci umum anu tos diasupkeun - kami parantos mutuskeun sateuacana yรฉn kami ngadamel jaringan rรฉrรฉncangan. Ngan saatos autรฉntikasi urang bakal ngartos saha anu urang komunikasi;
  • kasadiaan rasiah maju sampurna properties (PFS) - kompromi konci penandatanganan umur panjang urang henteu kedah ngakibatkeun kamampuan maca sadaya korespondensi sateuacana. Ngarekam lalulintas disadap janten gunana;
  • validitas / validitas pesen (transportasi jeung sasalaman) ngan dina hiji sรฉsi TCP. Inserting leres ditandatanganan / pesen diotรฉntikasi ti sรฉsi sรฉjรฉn (sanajan ku interlocutor sarua) teu mungkin;
  • panitรฉn pasip teu kudu ningali boh identifiers pamakรฉ, dikirimkeun lila-cicing konci publik, atawa hashes ti aranjeunna. A anonymity tangtu ti panitรฉn pasip.

Ahรฉngna, ampir sadayana hoyong gaduh minimum ieu dina protokol sasalaman, sareng sakedik pisan di luhur anu tungtungna dipendakan pikeun protokol "homegrown". Ayeuna urang moal invent nanaon anyar. Kuring pasti bakal nyarankeun ngagunakeun Kerangka noise pikeun ngawangun protokol, tapi hayu urang milih hal basajan.

Dua protokol anu pang populerna nyaรฉta:

  • TLS - protokol anu kompleks pisan sareng sajarah panjang bug, jambs, kerentanan, pamikiran anu gorรฉng, pajeulitna sareng kakurangan (tapi, ieu teu aya hubunganana sareng TLS 1.3). Tapi kami henteu nganggap รฉta kusabab รฉta rumit.
  • IPSec ั IKE โ€” teu boga masalah cryptographic serius, sanajan maranehna oge teu basajan. Upami anjeun maca ngeunaan IKEv1 sareng IKEv2, maka sumberna nyaรฉta STS, ISO/IEC IS 9798-3 jeung protokol SIGMA (SIGn-and-MAc) - cukup basajan pikeun diimplementasikeun dina hiji sore.

Naon alus ngeunaan SIGMA, salaku link panganyarna dina ngembangkeun STS / protokol ISO? Ieu meets sadayana sarat urang (kaasup "nyumput" identifiers interlocutor) jeung teu boga masalah cryptographic dipikawanoh. ร‰ta minimalis - miceun sahenteuna hiji unsur tina pesen protokol bakal ngakibatkeun kerawanan na.

Hayu urang angkat tina protokol anu pangbasajanna di bumi ka SIGMA. Operasi paling dasar urang museurkeun tรฉh perjangjian konci: Fungsi nu outputs duanana pamilon nilai sarua, nu bisa dipakรฉ salaku konci simetris. Tanpa lebet kana detil: masing-masing pihak ngahasilkeun pasangan konci ephemeral (ngan ukur dianggo dina hiji sรฉsi) (konci umum sareng swasta), tukeur konci umum, nelepon fungsi perjangjian, kana input anu aranjeunna lulus konci pribadi sareng umum. konci interlocutor.

โ”Œโ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ” โ”‚PeerAโ”‚ โ”‚PeerBโ”‚ โ””โ”€โ”€โ”ฌโ”€โ”€โ”˜ โ”€โ”€โ”€ โ”‚โ”ฌโ”€โ”€ โ”‚ โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•— โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ•‘PrvA โ•‘โ”€โ”‚ โ•‘PrvA, Pu โ• โ•โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ”‚ IdB, PubB โ”‚ โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โโ•โ•โ•โโโ•โ• โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ•‘PrvB, PubB = DHgen()โ•‘ โ”‚ โ”‚ โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โโ•โ• โ”€โ”€โ”€โ” โ•”โ•โ•โ•โ• โ•โ•โ•โ•งโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•— โ”‚ โ•‘Key = DH(PrvA, PubB)โ•‘ <โ”€โ”€โ”€โ”โโ•šโ••โ”โโ•šโ••โ”โ˜ โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ• โ”‚ โ”‚ โ”‚ โ”‚

Saha waรฉ tiasa ngaluncat di tengah sareng ngagentos konci umum sorangan - henteu aya autรฉntikasi interlocutors dina protokol ieu. Hayu urang tambahkeun tanda tangan sareng konci umur panjang.

โ”Œโ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ” โ”‚PeerAโ”‚ โ”‚PeerBโ”‚ โ””โ”€โ”€โ”ฌโ”€โ”€โ”˜ โ”ฌโ”€ โ”‚โ”ฌโ”€โ”€ SignPrvA, (PubA)) โ”‚ โ•”โ• โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ ubA = beban()โ•‘ โ”‚ โ”‚ โ•‘PrvA, PubA = DHgen() โ•‘ โ”‚ โ”‚ โ•šโ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โโ•โ•โ•โโ•โ• , tanda(SignPrvB, (PubB)) โ”‚ โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ•โ€” โ”‚โ€— โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”‚ โ•‘SignPrvB, SignPubB = beban( )โ•‘ โ”‚ โ”‚ โ•‘PrvB, PubB = DHโ•‘ โ”‚ โ”‚ โ•‘PrvB, PubB = DHโ•‘โ‘š() โ”• โ”‚ โ•โ•โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ•โ•โ• โ”€โ”€โ”€โ”€โ” โ•” โ•โ•โ•โ•โ•โโ•โ•โ•โ•โโ•โ• โ•โ•โ•โ•โ•โ•— โ”‚ โ”‚ โ•‘verifikasi( SignPubB, ...)โ•‘ โ”‚ <โ”€โ”€โ”€โ”˜ โ•‘Key = DH(Pr vA, PubB) โ•‘ โ”‚ โ”‚ โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โโ•โ•โ•โโ•โ•โ•โโ•โ•โ•โ•โโ•โ•โ• โ•โ• โ”‚ โ”‚ โ”‚

Tanda tangan sapertos kitu moal jalan, sabab henteu dihijikeun kana sรฉsi khusus. Pesen sapertos kitu ogรฉ "cocog" pikeun sesi sareng pamilon sanรฉs. Sakabรฉh kontรฉks kedah ngalanggan. Ieu maksakeun urang ogรฉ nambihan pesen anu sanรฉs ti A.

Sajaba ti รฉta, penting pikeun nambahkeun identifier sorangan handapeun signature nu, saprak disebutkeun urang bisa ngaganti IdXXX jeung ulang asup suratna ku konci interlocutor dipikawanoh sรฉjรฉn. Pikeun nyegah serangan refleksi, perlu yรฉn unsur-unsur dina tanda tangan aya di tempat-tempat anu didefinisikeun sacara jelas dumasar kana hartosna: upami tanda A (PubA, PubB), maka B kedah asup (PubB, PubA). Ieu ogรฉ nyarioskeun pentingna milih struktur sareng format data serial. Contona, susunan dina ASN.1 DER encoding diurutkeun: SET OF (PubA, PubB) bakal idรฉntik jeung SET OF (PubB, PubA).

โ”Œโ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ” โ”‚PeerAโ”‚ โ”‚PeerBโ”‚ โ””โ”€โ”€โ”ฌโ”€โ”€โ”˜ โ”€โ”€โ”€ โ”‚โ”ฌโ”€โ”€ โ”‚ โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•— โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ€”โ€”โ”€โ”€โ€”โ€”โ”€โ”€โ€” โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ•‘SignPrvA, SignPubA = beban()โ•‘ โ”‚ โ”‚ โ•‘PrvA, PubA = โ‘‚ โ‚ โ•š โ• โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ”‚IdB, PubB, tanda(SignPrvB, (IdB, PubA, PubB)) โ”‚ โ”โ•โ•โ••โ•• โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•— โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ€”โ”€โ”€โ”€โ€”โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ•‘SignPrvB, SignPubB = beban()โ•‘ โ”‚ โ”‚ โ•‘PrvB, PubB = DHgen() โ•‘ โ”‚ โ”โ• โ•šโ•โ•โ•š โ• โ•โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ”‚ tanda(SignPrvA, (IdA, PubB, PubA)) โ”‚ โ•”โ•โ•โ•โ•โ•โ•โ•โโ•โ•โ•โโ•โ•โ•โโ•โ• โ•โ•โ•โ•โ•— โ”‚โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ€”โ”€โ”€ โ”€โ”€โ”€>โ”‚ โ•‘verifikasi(SignPubB, ...) โ•‘ โ”‚ โ”‚ โ•‘key = dh (prva, PUBB) โ•‘ โ”‚ โ”‚ โ”‚

Najan kitu, urang masih teu "kabuktian" yรฉn kami geus dihasilkeun konci dibagikeun sarua keur sรฉsi ieu. Sacara prinsip, urang tiasa ngalakukeun tanpa lรฉngkah ieu - sambungan angkutan anu pangheulana henteu sah, tapi urang hoyong nalika sasalaman parantos rรฉngsรฉ, urang bakal yakin yรฉn sadayana leres-leres sapuk. Ayeuna kami gaduh protokol ISO / IEC IS 9798-3.

Urang bisa asup kana konci dihasilkeun sorangan. Ieu bahaya, sabab mungkin aya bocor dina algoritma signature dipakรฉ (sanajan bit-per-signature, tapi tetep bocor). Kasebut nyaรฉta dimungkinkeun pikeun ngadaptarkeun hash tina konci derivasi, tapi bocor malah hash tina konci turunan tiasa berharga dina serangan brute-force dina fungsi derivasi. SIGMA ngagunakeun pungsi MAC nu authenticates ID pangirim.

โ”Œโ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ” โ”‚PeerAโ”‚ โ”‚PeerBโ”‚ โ””โ”€โ”€โ”ฌโ”€โ”€โ”˜ โ”€โ”€โ”€ โ”‚โ”ฌโ”€โ”€ โ”‚ โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•— โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ€”โ€”โ”€โ”€โ€”โ€”โ”€โ”€โ€” โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ•‘SignPrvA, SignPubA = beban()โ•‘ โ”‚ โ”‚ โ•‘ โ”‚ โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ•‘SignPrvA, SignPubA = beban()โ•‘ โ”‚ โ”‚ โ•‘ โ”‚ โ”‚ โ•‘PrvA = โ•‘PrvA โ•š โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ”‚IdB, PubB, tanda(SignPrvB, (PubA, PubB) โ•โ•โ”โ•โ•โ•โ•โ•โ•โ• โ•โ•โ• โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ€”โ€”โ”€โ”€โ€”โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”‚ โ•‘SignPrvB, SignPubB = beban()โ•‘ โ”‚ โ”‚ โ•‘PrvB, PubB = DHgen() โ•‘ โ”‚ โ”‚ โ•šโ•โ•โ•โ• โ•โ•โโ•โ•โ•โ•โโ•โ••โ•โโโ••โ•โโโ••โ•โ•โโ••โ•• โ•โ•โ•โ•โ•โ•โ•โ•โ• โ•โ•โ• โ”‚ โ”‚ โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•— โ•โ•โ•โ•— โ”‚ tanda MAC(A)B, Pu(A)B,โ”‚,P (A)B,โ”‚ (P) โ•‘Konci = DH( PrvA, PubB) โ•‘ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ€‚โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ . โ•โ•โ•โ• โ•โ• โ”‚ โ”‚

Salaku optimasi, sababaraha meureun hoyong nganggo deui konci ephemeral maranรฉhanana (anu, tangtosna, musibah pikeun PFS). Contona, urang dihasilkeun pasangan konci, nyoba nyambung, tapi TCP teu sadia atawa interrupted wae di tengah protokol. Ieu รฉra mun runtah wasted รฉntropi jeung sumberdaya processor dina pasangan anyar. Ku alatan รฉta, urang bakal ngenalkeun nu disebut cookie - nilai pseudo-acak anu bakal ngajaga ngalawan kamungkinan serangan replay acak nalika makรฉ deui konci publik ephemeral. Alatan beungkeutan antara cookie jeung konci publik ephemeral, konci publik ti pihak sabalikna bisa dihapus tina signature sakumaha teu perlu.

โ”Œโ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ” โ”‚PeerAโ”‚ โ”‚PeerBโ”‚ โ””โ”€โ”€โ”ฌโ”€โ”€โ”˜ โ”ฌโ”€ โ”‚โ”ฌโ”€โ”€ A โ”‚ โ•”โ•โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•— โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ€”โ€”โ”€โ”€โ€”โ”€โ”€โ€”โ€”โ”€โ”€โ€” โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ€‚โ”€โ”€โ”€โ”€โ”€โ”€ โ”€>โ”‚ โ•‘SignPrvA, SignPubA = beban( )โ•‘ โ”‚ โ”‚ โ•‘PrvA, PubA = DHgen() โ•‘ โ”‚ โ”‚ โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โโ•โ•โ•โ•โโ•โ•โ•โโโ•โ• โ•โ•โ• โ”‚IdB, PubB, CookieB , tanda (SignPrvB, (CookieA, CookieB, PubB)), MAC(IdB) โ”‚ โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โโ•โ•โ•โโ•โ•โ•โโ•โ•โ•โโ•โ• โ•— โ”‚< โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ€‚โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ•‘SignPrvB, SignPubB = beban()โ•‘ โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ•‘SignPrvB, SignPubB = beban()โ•‘ โ”‚ โ”‚ = ,โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ•šโ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ”‚ โ”‚ โ•”โ•โ•โ•โ•โโ•โ•โ•โโ•โ• โ•โ•โ•โ•โ•โ•โ•โ•— โ”‚ tanda( SignPrvA, (CookieB, CookieA, PubA)), MAC(IdA) โ”‚ โ•‘Key = DH(PrvA, PubB) โ•‘ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ€‚โ”€ โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ€‚โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ•‘ verifikasi(Konci, IdB) โ•‘ โ”‚ โ”‚ โ•‘verifikasi(SignPubB, ...)โ•‘ โ”‚ โ”‚ โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โโ•โ•โ•โโ•โ•โ•โโ•โ• โ”‚

Tungtungna, urang hoyong kรฉngingkeun privasi mitra paguneman urang ti panitรฉn pasip. Jang ngalampahkeun ieu, SIGMA ngusulkeun pikeun tukeur heula konci ephemeral sareng ngembangkeun konci umum pikeun รฉnkripsi otentikasi sareng ngaidentipikasi pesen. SIGMA ngajelaskeun dua pilihan:

  • SIGMA-I - ngajaga inisiator tina serangan aktip, responder tina pasif: inisiator authenticates responder jeung lamun aya hiji hal teu cocog, mangka teu masihan kaluar idรฉntifikasi na. terdakwa mรฉrรฉ kaluar idรฉntifikasi na lamun hiji protokol aktif dimimitian kalawan anjeunna. Pengamat pasip teu diajar nanaon;
    SIGMA-R - ngajaga responder tina serangan aktip, inisiator tina serangan pasip. Sagalana persis sabalikna, tapi dina protokol ieu opat seratan sasalaman geus dikirimkeun.

    Urang milih SIGMA-I sabab leuwih sarupa jeung naon urang nyangka ti klien-server hal akrab: klien nu dipikawanoh ukur ku server otรฉntikasi, jeung dulur geus nyaho server. Tambih Deui, eta leuwih gampang pikeun nerapkeun alatan pangsaeutikna seratan sasalaman. Sadaya anu urang tambahkeun kana protokol nyaรฉta รฉnkripsi bagian tina pesen sareng mindahkeun identifier A ka bagian รฉnkripsi tina pesen anu terakhir:

    PubA, CookieA โ”‚ โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ€— โ•โ•โ€โ€โ•โ•โ€โ• โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ€”โ”€โ”€โ”€โ€”โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ•‘SignPrvA , SignPubA = beban()โ•‘ โ”‚ โ”‚ โ•‘PrvA, PubA = DHgen() โ‘ โ• โ•• โ•โ•โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ• โ”‚ PubB, CookieB, Enc((IdB, sign(SignPrvB, (CookieA, CookieB, PubB)), MAC(IdB) โ••) โ•”โ)โ••) . โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ•‘SignP rvB, SignPubB = beban()โ•‘ โ”‚ โ”‚ โ•‘ PrvB, PubB โ•‘ DHgen () โ•‘ โ•โ•โ•โ•โ•โ•โ•โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ”‚ โ”‚ โ•”โ•โ•โ•โ•โ•โ•โ•โ• โ•โโ•โ•โ•โโ• โ•โ•โ•— โ”‚ Enc((IdA, tanda( Tandapvva, (cookieb, cookiea, puba)), MAC (Ida))) โ”‚ โ”‚ โ”‚ey = prva, โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ€”โ”€ โ”€โ”€โ€”โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ•‘verifikasi(Konci, IdB) โ•‘ โ”‚ โ”‚ โ•‘verifikasi( SignPubB, ...)โ•‘ โ”‚ โ”‚ โ•šโ•โ•โ•โ•โ•โโ•โ••โ•โโ•โ••โ•โโ•โ•• โ•โ•โ•โ• โ•โ•โ• โ”‚ โ”‚
    
    • GOST R dipakรฉ pikeun signature 34.10-2012 algoritma jeung konci 256-bit.
    • Pikeun ngahasilkeun konci publik, 34.10/2012/XNUMX VKO dipakรฉ.
    • CMAC dipakรฉ salaku MAC. Tรฉhnisna, ieu tรฉh mode husus tina operasi block cipher, dijelaskeun dina GOST R 34.13-2015. Salaku fungsi รฉnkripsi pikeun mode ieu โˆ’ simeut (34.12-2015).
    • Hash tina konci publik na dipakรฉ salaku identifier interlocutor urang. Dipakรฉ salaku hash a Stribog-256 (34.11/2012/256 XNUMX bit).

    Saatos sasalaman, urang bakal satuju dina konci dibagikeun. Urang tiasa nganggo รฉta pikeun รฉnkripsi pesen angkutan anu diotรฉntikasi. Bagian ieu saderhana pisan sareng sesah ngadamel kasalahan: urang ningkatkeun counter pesen, รฉnkripsi pesen, ngabuktoskeun kaaslianana (MAC) counter sareng ciphertext, kirimkeun. Nalika nampi pesen, urang pariksa yรฉn konter ngagaduhan nilai anu dipiharep, ngabuktoskeun kaaslianana ciphertext sareng konter, sareng ngadekrip รฉta. Konci naon anu kuring kedah dianggo pikeun รฉnkripsi pesen sasalaman, ngangkut pesen, sareng kumaha ngabuktoskeunana? Ngagunakeun hiji konci pikeun sakabรฉh pancรฉn ieu bahaya sarta teu wijaksana. Perlu ngahasilkeun konci nganggo fungsi khusus KDF (fungsi turunan konci). Sakali deui, hayu urang henteu ngabagi rambut sareng nyiptakeun hiji hal: HKDF geus lila dipikawanoh, well researched tur teu boga masalah dipikawanoh. Hanjakal, perpustakaan Python pituin teu boga fungsi ieu, jadi kami nganggo hkdf kantong plastik. HKDF internal migunakeun HMAC, anu dina gilirannana ngagunakeun fungsi hash. Hiji conto palaksanaan di Python dina kaca Wikipedia nyokot ngan sababaraha baris kode. Saperti dina kasus 34.10/2012/256, urang bakal ngagunakeun Stribog-XNUMX salaku fungsi Hash. Kaluaran tina fungsi perjangjian konci urang bakal disebut konci sรฉsi, ti mana simetris leungit bakal dihasilkeun:

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

    Struktur / Skรฉma

    Hayu urang tingali naon struktur ASN.1 anu urang gaduh ayeuna pikeun ngirimkeun sadaya data ieu:

    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)
    

    SasalamanTBS anu bakal ditandatanganan. HandshakeTBE - naon anu bakal รฉnkripsi. Kuring narik perhatian anjeun kana widang ukm di MsgHandshake1. 34.10 VKO, pikeun randomization malah leuwih gede tina konci dihasilkeun, ngawengku UKM (bahan konci pamakรฉ) parameter - ngan รฉntropi tambahan.

    Nambahkeun Kriptografi kana Kode

    Hayu urang nganggap ukur parobahan dina kode aslina, saprak kerangka tetep sarua (kanyataanna, palaksanaan final ditulis heula, lajeng sadayana kriptografi ieu motong kaluar ti dinya).

    Kusabab autรฉntikasi sareng idรฉntifikasi interlocutors bakal dilaksanakeun nganggo konci umum, aranjeunna ayeuna kedah disimpen di tempat anu lami. Pikeun kesederhanaan, kami nganggo JSON sapertos kieu:

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

    urang - pasangan konci urang, hexadecimal konci swasta jeung publik. maranรฉhanana โ€” ngaran interlocutors jeung konci publik maranรฉhanana. Hayu urang robih argumen baris parรฉntah sareng tambahkeun post-processing data JSON:

    from pygost import gost3410
    from pygost.gost34112012256 import GOST34112012256
    
    CURVE = gost3410.GOST3410Curve(
        *gost3410.CURVE_PARAMS["GostR3410_2001_CryptoPro_A_ParamSet"]
    )
    
    parser = argparse.ArgumentParser(description="GOSTIM")
    parser.add_argument(
        "--keys-gen",
        action="store_true",
        help="Generate JSON with our new keypair",
    )
    parser.add_argument(
        "--keys",
        default="keys.json",
        required=False,
        help="JSON with our and their keys",
    )
    parser.add_argument(
        "--bind",
        default="::1",
        help="Address to listen on",
    )
    parser.add_argument(
        "--port",
        type=int,
        default=6666,
        help="Port to listen on",
    )
    args = parser.parse_args()
    
    if args.keys_gen:
        prv_raw = urandom(32)
        pub = gost3410.public_key(CURVE, gost3410.prv_unmarshal(prv_raw))
        pub_raw = gost3410.pub_marshal(pub)
        print(json.dumps({
            "our": {"prv": hexenc(prv_raw), "pub": hexenc(pub_raw)},
            "their": {},
        }))
        exit(0)
    
    # Parse and unmarshal our and their keys {{{
    with open(args.keys, "rb") as fd:
        _keys = json.loads(fd.read().decode("utf-8"))
    KEY_OUR_SIGN_PRV = gost3410.prv_unmarshal(hexdec(_keys["our"]["prv"]))
    _pub = hexdec(_keys["our"]["pub"])
    KEY_OUR_SIGN_PUB = gost3410.pub_unmarshal(_pub)
    KEY_OUR_SIGN_PUB_HASH = OctetString(GOST34112012256(_pub).digest())
    for peer_name, pub_raw in _keys["their"].items():
        _pub = hexdec(pub_raw)
        KEYS[GOST34112012256(_pub).digest()] = {
            "name": peer_name,
            "pub": gost3410.pub_unmarshal(_pub),
        }
    # }}}
    

    Konci pribadi tina algoritma 34.10 nyaรฉta nomer acak. Ukuran 256-bit pikeun kurva elliptic 256-bit. PyGOST henteu dianggo sareng sakumpulan bait, tapi kalayan angka nu gede ngarupakeun, jadi konci swasta urang (urandom(32)) kudu dirobah jadi angka makรฉ gost3410.prv_unmarshal(). Konci publik ditangtukeun deterministik tina konci swasta ngagunakeun gost3410.public_key (). Konci publik 34.10 dua angka nu gede ngarupakeun ogรฉ kudu dirobah jadi runtuyan bait pikeun betah neundeun jeung transmisi makรฉ gost3410.pub_marshal ().

    Saatos maca file JSON, konci umum kedah dirobih deui nganggo gost3410.pub_unmarshal (). Kusabab urang bakal nampi identifiers tina interlocutors dina bentuk hash tina konci publik, maranรฉhna bisa langsung diitung sateuacanna tur disimpen dina kamus pikeun pilarian gancang. Stribog-256 hash nyaeta gost34112012256.GOST34112012256 (), nu pinuh satisfies panganteur hashlib tina fungsi Hash.

    Kumaha coroutine inisiator parantos robih? Sagalana sakumaha per skรฉma sasalaman: urang ngahasilkeun cookie a (128-bit tรฉh nyatu), hiji pasangan konci ephemeral 34.10, nu bakal dipakรฉ pikeun fungsi perjangjian konci 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()
    

    • urang ngadagoan rรฉspon jeung decode pesen Msg asup;
    • pastikeun anjeun meunang sasalaman1;
    • decode konci publik ephemeral ti pihak sabalikna jeung ngitung konci sรฉsi;
    • Kami ngahasilkeun konci simetris anu dipikabutuh pikeun ngolah bagian TBE tina suratna.

     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 mangrupakeun angka 64-bit (urandom (8)), nu ogรฉ merlukeun deserialization tina ngagambarkeun bait na makรฉ gost3410_vko.ukm_unmarshal (). fungsi VKO pikeun 34.10/2012/256 3410-bit nyaeta gost34102012256_vko.kek_XNUMX () (KEK - konci enkripsi).

    Konci sรฉsi anu dihasilkeun tรฉh geus mangrupa runtuyan bait pseudo-acak 256-bit. Ku alatan รฉta, รฉta bisa langsung dipakรฉ dina fungsi HKDF. Kusabab GOST34112012256 nyugemakeun antarmuka hashlib, รฉta tiasa langsung dianggo dina kelas Hkdf. Urang teu nangtukeun uyah (argumen mimiti Hkdf), saprak konci dihasilkeun, alatan ephemerality sahiji pasangan konci milu, bakal bรฉda pikeun tiap sรฉsi tur geus ngandung cukup รฉntropi. kdf.expand () sacara standar geus ngahasilkeun kenop 256-bit diperlukeun pikeun Grasshopper engkรฉ on.

    Salajengna, bagian TBE sareng TBS tina pesen anu datang dipariksa:

    • MAC dina ciphertext anu asup diitung sareng dipariksa;
    • ciphertext didekripsi;
    • Struktur TBE didekodekeun;
    • identifier tina interlocutor dicokot ti dinya tur eta dipariksa naha anjeunna dipikawanoh ka urang pisan;
    • MAC leuwih identifier ieu diitung sarta dipariksa;
    • signature leuwih struktur TBS geus diverifikasi, nu ngawengku cookie duanana pihak jeung konci ephemeral publik ti pihak sabalikna. Tanda tangan diverifikasi ku konci tandatangan anu umurna panjang tina 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"]
    

    Salaku I wrote luhur, 34.13/2015/XNUMX ngajelaskeun rupa modeu operasi cipher blok ti 34.12/2015/3413. Diantarana aya mode pikeun ngahasilkeun sisipan imitasi sareng itungan MAC. Dina PyGOST ieu gost34.12.mac (). Modeu ieu ngabutuhkeun ngalirkeun fungsi enkripsi (narima sareng mulangkeun hiji blok data), ukuran blok enkripsi sareng, kanyataanna, data sorangan. Naha anjeun teu tiasa hardcode ukuran blok enkripsi? 2015/128/64 ngajelaskeun henteu ngan ukur cipher Grasshopper XNUMX-bit, tapi ogรฉ XNUMX-bit. Magma - a rada dirobah GOST 28147-89, dijieun deui dina KGB sarta masih boga salah sahiji thresholds kaamanan pangluhurna.

    Kuznechik ieu initialized ku panggero gost.3412.GOST3412Kuznechik (konci) sarta mulih hiji obyรฉk kalawan .encrypt () / .decrypt () mรฉtode cocog pikeun lolos ka 34.13 fungsi. MAC diitung kieu: gost3413.mac(GOST3412Kuznechik(konci).encrypt, KUZNECHIK_BLOCKSIZE, ciphertext). Pikeun ngabandingkeun MAC anu diitung sareng ditampi, anjeun moal tiasa nganggo perbandingan biasa (==) tina senar bait, sabab operasi ieu bocor waktos ngabandingkeun, anu, dina kasus umum, tiasa ngakibatkeun kerentanan fatal sapertos. TIAR serangan dina TLS. Python boga fungsi husus, hmac.compare_digest, pikeun ieu.

    Fungsi block cipher ngan bisa encrypt hiji blok data. Pikeun angka nu leuwih gede, komo teu kakalian panjangna, perlu ngagunakeun mode enkripsi. 34.13-2015 ngajelaskeun handap: ECB, CTR, OFB, KBK, CFB. Masing-masing gaduh daรฉrah aplikasi sareng ciri anu tiasa ditampi. Hanjakal, urang masih teu boga standarisasi modeu enkripsi diotรฉntikasi (sapertos CCM, OCB, GCM sareng anu sanรฉsna) - urang kapaksa sahenteuna nambihan MAC sorangan. Kuring milih modeu counter (CTR): teu merlukeun padding kana ukuran blok, bisa parallelized, ngan ngagunakeun fungsi enkripsi, bisa aman dipakรฉ pikeun encrypt angka nu gede ngarupakeun pesen (teu kawas CBC, nu tabrakan rรฉlatif gancang).

    Kawas .mac (), .ctr () nyokot input sarupa: ciphertext = gost3413.ctr (GOST3412Kuznechik (konci).encrypt, KUZNECHIK_BLOCKSIZE, plaintext, IV). Ieu diperlukeun pikeun nangtukeun hiji vรฉktor initialization nu persis satengah panjang blok enkripsi. Upami konci enkripsi kami dianggo ngan ukur pikeun รฉnkripsi hiji pesen (sanaos tina sababaraha blok), maka aman pikeun nyetรฉl vektor inisialisasi nol. Pikeun รฉnkripsi pesen sasalaman, kami nganggo konci anu misah unggal waktos.

    Verifying signature gost3410.verify() nyaeta trivial: urang lulus kurva elliptic di mana urang gawe (urang ngan saukur ngarekam dina protokol GOSTIM kami), konci publik signer (ulah poho yรฉn ieu kudu tuple dua. angka nu gede ngarupakeun, na teu string bait), 34.11/2012/XNUMX Hash jeung signature sorangan.

    Salajengna, dina inisiator urang nyiapkeun sareng ngirim pesen sasalaman ka sasalaman2, ngalaksanakeun tindakan anu sami sareng anu urang lakukeun nalika verifikasi, ngan sacara simetris: asup kana konci kami tibatan mariksa, jsb ...

     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)
     

    Nalika sรฉsi diadegkeun, konci angkutan dibangkitkeun (konci anu misah pikeun รฉnkripsi, pikeun autรฉntikasi, pikeun unggal pihak), sareng Grasshopper diinisialisasi pikeun ngadekrip sareng pariksa 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     # }}}
    

    Coroutine msg_sender ayeuna ngenkripsi pesen sateuacan dikirim dina sambungan TCP. Unggal pesen ngabogaan monotonically ngaronjatna nonce, nu oge vรฉktor initialization nalika รฉnkripsi dina modeu counter. Unggal pesen sareng blok pesen dijamin gaduh nilai kontra anu bรฉda.

    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
    

    Pesen anu asup diolah ku coroutine msg_receiver, anu ngatur autรฉntikasi sareng dekripsi:

    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)
    

    kacindekan

    GOSTIM dimaksudkeun pikeun dianggo sacara รฉksklusif pikeun tujuan pendidikan (sabab henteu katutupan ku tรฉs, sahenteuna)! Kodeu sumber program tiasa diunduh di dieu (ะกั‚ั€ะธะฑะพะณ-256 ั…ััˆ: 995bbd368c04e50a481d138c5fa2e43ec7c89bc77743ba8dbabee1fde45de120). ะšะฐะบ ะธ ะฒัะต ะผะพะธ ะฟั€ะพะตะบั‚ั‹, ั‚ะธะฟะฐ GoGOST, PyDERASN, NCCP, GoVPN, GOSTIM sagemblengna software bรฉbas, disebarkeun dina kaayaan GPLv3 +.

    Sergey Matveev, cypherpunk, anggota Yayasan SPO, Python / Go pamekar, lulugu spesialis FSUE "STC "Atlas".

sumber: www.habr.com

Tambahkeun komentar