GOSTIM: P2P F2F E2EE IM madzulo amodzi ndi GOST cryptography

Kukhala wopanga Chithunzi cha PyGOST malaibulale (GOST cryptographic primitives in pure Python), nthawi zambiri ndimalandira mafunso okhudza momwe ndingagwiritsire ntchito mauthenga otetezeka kwambiri pa bondo. Anthu ambiri amaona kuti cryptography yogwiritsidwa ntchito ndiyosavuta, ndipo kuyimba .encrypt() pa block cipher kumakhala kokwanira kutumiza mosatekeseka panjira yolumikizirana. Ena amakhulupirira kuti kugwiritsa ntchito cryptography ndiye tsogolo la ochepa, ndipo ndizovomerezeka kuti makampani olemera ngati Telegraph ndi akatswiri a masamu a olympiad. sangathe kukhazikitsa chitetezo protocol.

Zonsezi zidandipangitsa kuti ndilembe nkhaniyi kuti ndiwonetse kuti kukhazikitsa ma protocol a cryptographic ndi chitetezo cha IM si ntchito yovuta. Komabe, sikuli koyenera kuti mupange ma protocol anu otsimikizika komanso ofunikira.

GOSTIM: P2P F2F E2EE IM madzulo amodzi ndi GOST cryptography
Nkhaniyi idzalemba pachinzawo, bwenzi ndi bwenzi, zolembedwa kumapeto mpaka kumapeto mthenga wapompopompo ndi SIGMA-I kutsimikizika ndi ma protocol ofunikira (kutengera momwe amagwiritsidwira ntchito IPsec IKE), pogwiritsa ntchito laibulale ya GOST cryptographic algorithms ya PyGOST ndi laibulale ya mauthenga a ASN.1 Zotsatira PyDERASN (zomwe ndanena kale adalemba kale). Chofunikira: chiyenera kukhala chophweka kotero kuti chikhoza kulembedwa kuyambira usiku umodzi (kapena tsiku la ntchito), apo ayi si pulogalamu yosavuta. Mwina ili ndi zolakwika, zovuta zosafunikira, zoperewera, kuphatikiza iyi ndi pulogalamu yanga yoyamba kugwiritsa ntchito laibulale ya asyncio.

Kupanga kwa IM

Choyamba, tiyenera kumvetsetsa momwe IM yathu idzawonekera. Kuti zikhale zosavuta, lolani kuti ikhale maukonde a anzanu ndi anzawo, osapezeka otenga nawo mbali. Tidzawonetsa panokha kuti ndi adilesi iti: doko loti mulumikizane nalo kuti mulumikizane ndi wolumikizirana.

Ndikumvetsetsa kuti, panthawiyi, kulingalira kuti kulankhulana kwachindunji kulipo pakati pa makompyuta awiri osagwirizana ndizovuta kwambiri pakugwiritsa ntchito kwa IM. Koma otukula akamakhazikitsa ndodo zamtundu uliwonse za NAT, m'pamenenso tikhalabe pa intaneti ya IPv4, ndi mwayi wofooketsa wa kulumikizana pakati pa makompyuta osasintha. Kodi mungapirire mpaka liti kusowa kwa IPv6 kunyumba ndi kuntchito?

Tidzakhala ndi maukonde a bwenzi ndi abwenzi: onse omwe angagwirizane nawo ayenera kudziwitsidwa pasadakhale. Choyamba, izi zimathandizira kwambiri chilichonse: tidadzidziwitsa tokha, tapeza kapena sitinapeze dzina / fungulo, kulumikizidwa kapena kupitiliza kugwira ntchito, podziwa wolowera. Kachiwiri, nthawi zambiri, imakhala yotetezeka komanso imachotsa ziwopsezo zambiri.

Mawonekedwe a IM adzakhala pafupi ndi mayankho apamwamba ntchito zopanda pake, zomwe ndimakonda kwambiri za minimalism yawo ndi filosofi ya njira ya Unix. Pulogalamu ya IM imapanga chikwatu chokhala ndi sockets zitatu za Unix pa interlocutor iliyonse:

  • mu-mauthenga otumizidwa kwa interlocutor amalembedwamo;
  • kunja - mauthenga olandilidwa kuchokera kwa interlocutor amawerengedwa kuchokera pamenepo;
  • boma - powerenga kuchokera pamenepo, timapeza ngati interlocutor ikugwirizana, adilesi / doko.

Kuphatikiza apo, socket ya conn imapangidwa, polemba doko lolowera momwe timayambira kulumikizana ndi interlocutor yakutali.

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

Njirayi imakupatsani mwayi wopanga zodziyimira pawokha zoyendera za IM ndi mawonekedwe ogwiritsa ntchito, chifukwa palibe bwenzi, simungathe kusangalatsa aliyense. Kugwiritsa tmux ndi / kapena multitail, mutha kupeza mawonekedwe azenera ambiri okhala ndi mawu owunikira. Ndipo ndi chithandizo rlwrap mutha kupeza mzere wolowetsa uthenga wogwirizana ndi GNU Readline.

M'malo mwake, mapulojekiti osayamwitsa amagwiritsa ntchito mafayilo a FIFO. Inemwini, sindimamvetsetsa momwe ndingagwirire ntchito ndi mafayilo mopikisana mu asyncio popanda maziko olembedwa ndi manja kuchokera ku ulusi wodzipereka (Ndakhala ndikugwiritsa ntchito chilankhulo pazinthu zotere kwa nthawi yayitali. Go). Chifukwa chake, ndidaganiza zopanga ma socket a Unix domain. Tsoka ilo, izi zimapangitsa kuti zikhale zosatheka kuchita echo 2001:470:dead::babe 6666> conn. Ndinathetsa vutoli pogwiritsa ntchito kotero: echo 2001:470:kufa::babe 6666 | socat - UNIX-CONNECT:conn, socat WERENGANI UNIX-CONNECT:alice/in.

Protocol yoyambirira yosatetezeka

TCP imagwiritsidwa ntchito ngati mayendedwe: imatsimikizira kuperekedwa ndi dongosolo lake. UDP sichitsimikizira chilichonse (chomwe chingakhale chothandiza ngati cryptography ikugwiritsidwa ntchito), koma kuthandizira Mtengo wa SCTP Python satuluka m'bokosi.

Tsoka ilo, mu TCP mulibe lingaliro la uthenga, kokha mtsinje wa ma byte. Choncho, m'pofunika kubwera ndi mtundu wa mauthenga kuti athe kugawana pakati pawo mu ulusi uwu. Titha kuvomereza kugwiritsa ntchito mtundu wa feed wa mzere. Ndibwino kuti tiyambe, koma tikangoyamba kubisa mauthenga athu, munthu uyu akhoza kuwoneka paliponse pamutuwu. Pamanetiweki, ma protocol otchuka ndi omwe amayamba kutumiza utali wa uthenga mu ma byte. Mwachitsanzo, kuchokera m'bokosi Python ili ndi xdrlib, yomwe imakulolani kuti mugwiritse ntchito mawonekedwe ofanana XDR.

Sitidzagwira ntchito moyenera komanso moyenera ndi kuwerenga kwa TCP - tidzachepetsa kachidindo. Timawerenga zambiri kuchokera ku socket mu loop yosatha mpaka titazindikira uthenga wathunthu. JSON yokhala ndi XML itha kugwiritsidwanso ntchito ngati mawonekedwe anjira iyi. Koma cryptography ikawonjezedwa, deta iyenera kusayinidwa ndikutsimikiziridwa - ndipo izi zidzafunika mawonekedwe ofanana a zinthu, omwe JSON/XML sapereka (zotsatira zotaya zingasiyane).

XDR ndiyoyenera ntchitoyi, komabe ndimasankha ASN.1 yokhala ndi DER encoding ndi Zotsatira PyDERASN laibulale, popeza tidzakhala ndi zinthu zapamwamba kwambiri zomwe nthawi zambiri zimakhala zosangalatsa komanso zosavuta kugwira ntchito. Mosiyana ndi schemaless kodi, MessagePack kapena CBOR, ASN.1 idzayang'ana deta yokha motsutsana ndi schema yolimba.

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

Uthenga wolandiridwa udzakhala Msg: mwina mawu a MsgText (okhala ndi gawo limodzi lolemba pakadali pano) kapena meseji ya MsgHandshake (yomwe ili ndi dzina la wolankhulayo). Tsopano zikuwoneka zovuta kwambiri, koma izi ndi maziko amtsogolo.

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

IM popanda cryptography

Monga ndanenera kale, laibulale ya asyncio idzagwiritsidwa ntchito pazinthu zonse za socket. Tilengeze zomwe tikuyembekezera poyambitsa:

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

Khazikitsani dzina lanu (--dzina lathu alice). Onse omwe amayembekezeka olowerana nawo adalembedwa mosiyanitsidwa ndi koma (-mayina awo bob, eve). Kwa aliyense wa interlocutors, chikwatu chokhala ndi sockets Unix chimapangidwa, komanso coroutine ya aliyense mkati, kunja, chigawo:

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

Mauthenga ochokera kwa wogwiritsa ntchito ku socket amatumizidwa ku mzere wa 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"))

Mauthenga ochokera kwa interlocutors amatumizidwa ku mizere OUT_QUEUES, pomwe deta imalembedwa ku out 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()

Mukawerenga kuchokera ku state socket, pulogalamuyi imayang'ana adilesi ya olankhula nawo mu dikishonale ya PEER_ALIVE. Ngati palibe kugwirizana kwa interlocutor panobe, ndiye kuti mzere wopanda kanthu umalembedwa.

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

Mukalemba adilesi ku socket ya conn, ntchito yolumikizira "initiator" imayambitsidwa:

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

Tiyeni tilingalire woyambitsa. Choyamba mwachiwonekere chimatsegula cholumikizira ku doko / doko lodziwika ndikutumiza uthenga wogwirana chanza ndi dzina lake:

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

Kenako, imadikirira kuyankha kuchokera kuphwando lakutali. Amayesa kuzindikira yankho lomwe likubwera pogwiritsa ntchito pulogalamu ya Msg ASN.1. Timaganiza kuti uthenga wonse udzatumizidwa mu gawo limodzi la TCP ndipo tidzaulandira mwa atomiki tikamayimba .read(). Timayang'ana kuti talandira uthenga wakugwirana chanza.

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

Timayang'ana kuti dzina lolandilidwa la interlocutor limadziwika kwa ife. Ngati sichoncho, ndiye kuti timaphwanya mgwirizano. Timayang'ana ngati takhazikitsa kale kugwirizana ndi iye (wothandizira adaperekanso lamulo kuti agwirizane ndi ife) ndikutseka. Mzere wa IN_QUEUES umakhala ndi zingwe za Python ndi mawu a uthengawo, koma uli ndi mtengo wapadera wa Palibe womwe umawonetsa msg_sender coroutine kuti asiye kugwira ntchito kuti ayiwale za wolemba wake wokhudzana ndi kulumikizana kwa TCP cholowa.

 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 amavomereza mauthenga otuluka (omwe ali pamzere kuchokera mu socket), amawasintha kukhala meseji ya MsgText ndikuwatumiza pa intaneti ya TCP. Ikhoza kusweka nthawi iliyonse - timamvetsetsa bwino izi.

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

Pamapeto pake, woyambitsayo amalowa m'njira yosawerengeka yowerengera mauthenga kuchokera ku socket. Imawunika ngati mamesejiwa ndi mameseji ndikuwayika pamzere wa OUT_QUEUES, pomwe adzatumizidwa ku socket yakunja kwa wolumikizana nawo. Chifukwa chiyani simungangochita .read() ndikutsitsa uthengawo? Chifukwa ndizotheka kuti mauthenga angapo kuchokera kwa wogwiritsa ntchito adzaphatikizidwa mu buffer ya opareshoni ndikutumizidwa mu gawo limodzi la TCP. Titha kusankha yoyamba, ndiyeno gawo lotsatira likhoza kukhalabe mu buffer. Pakakhala zovuta zilizonse, timatseka kulumikiza kwa TCP ndikuyimitsa msg_sender coroutine (potumiza Palibe pamzere wa 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)

Tiyeni tibwerere ku code yayikulu. Pambuyo popanga ma coroutines onse panthawi yomwe pulogalamuyo ikuyamba, timayamba seva ya TCP. Pa kulumikizana kulikonse komwe kukhazikitsidwa, kumapanga njira yoyankha.

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

woyankha ndi wofanana ndi woyambitsa ndikuwonetsa zochita zonse zomwezo, koma kuchuluka kwa mauthenga kumayamba nthawi yomweyo, kuti zikhale zosavuta. Pakalipano, ndondomeko yogwirana chanza imatumiza uthenga umodzi kuchokera kumbali iliyonse, koma m'tsogolomu padzakhala awiri kuchokera kwa woyambitsa kugwirizana, pambuyo pake mauthenga amatha kutumizidwa nthawi yomweyo.

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

Chitetezo cha protocol

Yakwana nthawi yoti titeteze mauthenga athu. Tikutanthauza chiyani ndi chitetezo ndipo tikufuna chiyani:

  • chinsinsi cha mauthenga opatsirana;
  • zowona ndi kukhulupirika kwa mauthenga opatsirana - zosintha zawo ziyenera kudziwika;
  • chitetezo pakuwukiridwanso - mfundo yosowa kapena mauthenga obwerezabwereza iyenera kuzindikirika (ndipo taganiza zothetsa kulumikizana);
  • kuzindikiritsa ndi kutsimikizira kwa interlocutors pogwiritsa ntchito makiyi omwe adalowetsedwa kale - tidaganiza kale kuti tikupanga maukonde a bwenzi ndi anzathu. Pokhapokha pambuyo potsimikizika tidzamvetsetsa yemwe tikulankhula naye;
  • kupezeka wangwiro patsogolo chinsinsi katundu (PFS) - kusokoneza chinsinsi chathu chosaina chomwe chakhala nthawi yayitali sikuyenera kupangitsa kuti tizitha kuwerenga makalata onse am'mbuyomu. Kujambulitsa magalimoto oletsedwa kumakhala kopanda phindu;
  • kutsimikizika / kutsimikizika kwa mauthenga (mayendedwe ndi kugwirana chanza) mkati mwa gawo limodzi la TCP. Kuyika mauthenga osainidwa bwino / ovomerezeka kuchokera ku gawo lina (ngakhale ndi wolankhulana yemweyo) sikuyenera kutheka;
  • wongoyang'ana chabe sayenera kuwona zozindikiritsa ogwiritsa ntchito, makiyi a anthu omwe akhalapo kwanthawi yayitali, kapena ma heshi kuchokera kwa iwo. Kusadziwika kwina kochokera kwa wongoonerera chabe.

Chodabwitsa n'chakuti, pafupifupi aliyense amafuna kukhala ndi zochepa izi mu ndondomeko ya kugwirana chanza, ndipo zochepa kwambiri zomwe zili pamwambazi zimakwaniritsa ndondomeko za "homegrown". Tsopano sitipanga china chatsopano. Ine ndithudi amalangiza ntchito Phokoso chimango pomanga ma protocol, koma tiyeni tisankhe chosavuta.

Ma protocol awiri omwe amadziwika kwambiri ndi awa:

  • TLS - ndondomeko yovuta kwambiri yomwe ili ndi mbiri yakale ya nsikidzi, kugwedezeka, zofooka, malingaliro oipa, zovuta ndi zofooka (komabe, izi sizikugwirizana ndi TLS 1.3). Koma sitikuziganizira chifukwa ndizovuta kwambiri.
  • IPsec с IKE - alibe mavuto aakulu a cryptographic, ngakhale kuti nawonso si ophweka. Mukawerenga za IKEv1 ndi IKEv2, ndiye kuti gwero lawo ndi STS, ISO/IEC IS 9798-3 ndi SIGMA (SIGn-ndi-MAc) protocol - yosavuta kugwiritsa ntchito madzulo amodzi.

Ubwino wa SIGMA ndi chiyani, monga ulalo waposachedwa kwambiri pakupanga ma protocol a STS/ISO? Imakwaniritsa zofunikira zathu zonse (kuphatikiza zozindikiritsa za "kubisala") ndipo ilibe zovuta zodziwika bwino zachinsinsi. Ndi minimalistic - kuchotsa chinthu chimodzi mu uthenga wa protocol kumabweretsa kusatetezeka kwake.

Tiyeni tichoke ku protocol yosavuta yokulira kunyumba kupita ku SIGMA. Ntchito yofunika kwambiri yomwe timakondwera nayo ndi mgwirizano wofunikira: Ntchito yomwe imatulutsa onse omwe atenga nawo mbali pamtengo wofanana, womwe ungagwiritsidwe ntchito ngati kiyi yofananira. Popanda kulowa mwatsatanetsatane: aliyense wa maphwando amapanga ephemeral (yogwiritsidwa ntchito mkati mwa gawo limodzi) makiyi awiri (makiyi apagulu ndi achinsinsi), kusinthana makiyi a anthu onse, kuyitanira ntchito ya mgwirizano, kuti alowetse makiyi awo achinsinsi komanso pagulu. kiyi ya interlocutor.

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

Aliyense akhoza kudumphira pakati ndikusintha makiyi a anthu onse ndi awo - palibe kutsimikizika kwa interlocutors mu protocol iyi. Tiyeni tiwonjezere siginecha yokhala ndi makiyi omwe akhalapo nthawi yayitali.

β”Œβ”€β”€β”€β”€β”€β” β”Œβ”€- SignPrvA, (PubA)) β”‚ ╔═ │─────────── ────────── ──────────── bA = katundu()β•‘ β”‚ β”‚ β•‘PrvA, PubA = DHgen() β•‘ β”‚ β”‚ β•šβ•β•β•β•β•β•β• ═══════ ══════════════════════ , chizindikiro(SignPrvB, (PubB)) β”‚ ╔══════════════ ═══════ ═════════ ═══════ ────────── ───────────── ──│ β•‘SignPrvB, SignPubB = katundu( )β•‘ β”‚ β”‚ β•‘PrvB, Pub β‚• β‚• β‚• β‚• β‚• ═════════ ══════════════ ══╝ ────┐ β•” ═════╗ β”‚ β”‚ β•‘verify( SignPubB, ...)β•‘ β”‚ <β”€β”€β”€β”˜ β•‘Key = DH(Pr vA, PubB) β•‘ β”‚ β”‚ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• ═╝ β”‚ β”‚ β”‚

Kusaina koteroko sikungagwire ntchito, chifukwa sikumangirizidwa ku gawo linalake. Mauthenga otere nawonso ndi β€œoyenera” pamisonkhano ndi anthu ena. Nkhani yonse iyenera kulembetsa. Izi zimatikakamiza kuwonjezera uthenga wina kuchokera kwa A.

Kuphatikiza apo, ndikofunikira kuti muwonjezere chizindikiritso chanu pansi pa siginecha, popeza apo ayi titha kulowa m'malo mwa IdXXX ndikusayinanso uthengawo ndi kiyi ya wolumikizana wina wodziwika. Kupewa kuukira kusinkhasinkha, m'pofunika kuti zinthu zomwe zili pansi pa siginecha zikhale m'malo omveka bwino malinga ndi tanthauzo lake: ngati zizindikiro A (PubA, PubB), ndiye B ayenera kusaina (PubB, PubA). Izi zikukambanso za kufunikira kosankha kapangidwe kake ndi mawonekedwe a deta yosawerengeka. Mwachitsanzo, ma encoding a ASN.1 DER asinthidwa: SET OF(PubA, PubB) idzakhala yofanana ndi SET OF(PubB, PubA).

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

Komabe, "sitinatsimikizire" kuti tapanga makiyi omwewo a gawoli. M'malo mwake, titha kuchita popanda sitepe iyi - kulumikizana koyamba koyendera kudzakhala kosavomerezeka, koma tikufuna kuti kugwirana chanza kukatsirizika, tidzakhala otsimikiza kuti zonse zikugwirizana. Pakadali pano tili ndi protocol ya ISO/IEC IS 9798-3.

Titha kusaina kiyi yopangidwa yokha. Izi ndizowopsa, chifukwa ndizotheka kuti pakhoza kukhala kutayikira mu siginecha ya algorithm yomwe imagwiritsidwa ntchito (ngakhale bits-per-signature, koma ikutuluka). Ndizotheka kusaina hashi ya kiyi yotengera, koma kutayikira ngakhale hashi ya kiyi yochokera kungakhale kofunikira pakuwukira mwamphamvu pa ntchito yotengera. SIGMA imagwiritsa ntchito ntchito ya MAC yomwe imatsimikizira ID ya wotumiza.

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

Monga kukhathamiritsa, ena angafune kugwiritsanso ntchito makiyi awo a ephemeral (zomwe ziri, zatsoka kwa PFS). Mwachitsanzo, tinapanga awiri ofunikira, kuyesera kugwirizanitsa, koma TCP sinalipo kapena inasokonezedwa kwinakwake pakati pa protocol. Ndizochititsa manyazi kuwononga chuma cha entropy ndi purosesa pagulu latsopano. Chifukwa chake, tikuwonetsa zomwe zimatchedwa cookie - mtengo wabodza womwe ungatetezedwe kuzinthu zomwe zingachitike mwachisawawa mukamagwiritsanso ntchito makiyi a anthu a ephemeral. Chifukwa chomangirira pakati pa cookie ndi kiyi yapagulu ya ephemeral, kiyi yapagulu ya gulu linalo imatha kuchotsedwa pa siginecha ngati yosafunikira.

_ A β”‚ ╔════════ ══════════════════╗ │────────——──── ───────── ──────────────────────────────────────── ─>β”‚ β•‘SignPrvA, SignPubA = katundu( )β•‘ β”‚ β”‚ β•‘PrvA, PubA = DHgen() β•‘ β”‚ β”‚ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• ══╝ β”‚IdB, PubB, CookieB , chizindikiro(SignPrvB, (CookieA, CookieB, PubB)), MAC(IdB) β”‚ ╔═════════════════════════════════════════════════════ ═ β•— β”‚< ──────────────────────────────────────── ───────── ────────────────- β”‚ β•šβ•β•β•β•β•β• ═════════════════════╝ β”‚ β”‚ ╔═══════════════ ═══════╗ β”‚ chizindikiro( SignPrvA, (CookieB, CookieA, PubA)), MAC(IdA) β”‚ β•‘Key = DH(PrvA, PubB) β•‘ │────────────────── ─ ── ──────────────────────────────────────── ───────>β”‚ β•‘ verify(Key, IdB) β•‘ β”‚ β”‚ β•‘verify(SignPubB, ...)β•‘ β”‚ β”‚ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• β”‚ β”‚

Pomaliza, tikufuna kupeza zinsinsi za omwe timacheza nawo kuchokera kwa munthu wongoonerera chabe. Kuti izi zitheke, SIGMA ikufuna kusinthanitsa makiyi a ephemeral kaye ndikupanga kiyi wamba yomwe ingasungirepo mauthenga otsimikizira ndi kuzindikira. SIGMA ikufotokoza njira ziwiri:

  • SIGMA-I - imateteza woyambitsa ku kuukira kogwira ntchito, woyankha kuchokera kuzinthu zopanda pake: woyambitsa amatsimikizira woyankhayo ndipo ngati chinachake sichikugwirizana, ndiye kuti sichimapereka chizindikiritso chake. Wotsutsa amapereka chizindikiritso chake ngati protocol yogwira iyambika ndi iye. Woyang'anitsitsa saphunzira kanthu;
    SIGMA-R - imateteza woyankha kuti asawukidwe, woyambitsa kuchokera kuzinthu zopanda pake. Chilichonse chiri chosiyana ndendende, koma mu protocol iyi mauthenga anayi ogwirana chanza amafalitsidwa kale.

    Timasankha SIGMA-I chifukwa ndizofanana ndi zomwe timayembekezera kuchokera kuzinthu zodziwika bwino za kasitomala: kasitomala amadziwika ndi seva yotsimikizika, ndipo aliyense amadziwa kale seva. Kuphatikizanso ndikosavuta kukhazikitsa chifukwa cha mauthenga ocheperako akugwirana chanza. Zomwe timawonjezera pa protocol ndikubisa gawo la uthenga ndikusamutsa chizindikiritso A kupita ku gawo lobisika la uthenga womaliza:

    PubA, cookieA ───────── ───── ────────── ──────────────────────── ────────── ───── ────- ════════ ═════════ ════╝ β”‚ PubB, CookieB, Enc((IdB, sign(SignPrvB, (CookieA, CookieB, PubB)), MAC(Id════) ══════════════ ═══════╗ β”‚<───═─═ ───────── ───── ────────── β•‘SignP rvB, SignPubB = katundu()β•‘ β”‚ β”‚ β•‘ PrvB, PubB = DHgen β”• ₐ ════════ ════════════════╝ β”‚ β”‚ ╔════════ ═════════════════════════ ══╗ β”‚ Enc((IdA, sign( SignPrvA, (CookieB, CookieA, PubA)), MAC(IdA))) β”‚ β•‘Key = DH(PrvA, PubB) β•‘ │───────────────── ─ ───────────────── ────────── ───────────── ────────── ──────>β”‚ β•‘verify(Key, IdB) β•‘ β”‚ β”‚ β•‘verify( SignPubB, ...)β•‘ β”‚ β”‚ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• ═════ ══╝ β”‚ β”‚
    
    • GOST R imagwiritsidwa ntchito posayina 34.10-2012 algorithm yokhala ndi makiyi a 256-bit.
    • Kuti apange kiyi yapagulu, 34.10/2012/XNUMX VKO imagwiritsidwa ntchito.
    • CMAC imagwiritsidwa ntchito ngati MAC. Mwaukadaulo, iyi ndi njira yapadera yogwiritsira ntchito block cipher, yofotokozedwa mu GOST R 34.13-2015. Monga ntchito yobisa pamachitidwe awa - Grasshopper (34.12-2015).
    • Hashi ya kiyi yake yapagulu imagwiritsidwa ntchito ngati chizindikiritso cha interlocutor. Amagwiritsidwa ntchito ngati hash Zithunzi za Stribog-256 (34.11/2012/256 XNUMX bits).

    Pambuyo pakugwirana chanza, tidzagwirizana pa kiyi yogawana. Titha kugwiritsa ntchito kubisa kwa mauthenga otsimikizika. Gawo ili ndi losavuta komanso lovuta kulakwitsa: timawonjezera kauntala ya uthenga, kubisa uthengawo, kutsimikizira (MAC) kauntala ndi zolemba, kutumiza. Tikalandira uthenga, timayang'ana ngati kauntala ili ndi mtengo woyembekezeka, kutsimikizira mawu achinsinsi ndi kauntala, ndikuyimasulira. Ndi fungulo lanji lomwe ndiyenera kugwiritsa ntchito pobisa mauthenga ogwirana chanza, mauthenga oyendetsa, ndi momwe ndingawatsimikizire? Kugwiritsa ntchito kiyi imodzi pazochitika zonsezi ndi koopsa komanso kopanda nzeru. Ndikofunikira kupanga makiyi pogwiritsa ntchito ntchito zapadera KDF (makiyi otengera ntchito). Apanso, tisamagawane tsitsi ndikupanga china chake: HKDF wakhala akudziwika, akufufuzidwa bwino ndipo alibe mavuto odziwika. Tsoka ilo, laibulale yaku Python ilibe ntchitoyi, chifukwa chake timagwiritsa ntchito hkdf thumba la pulasitiki. HKDF imagwiritsa ntchito mkati Mtengo wa HMAC, yomwe imagwiritsanso ntchito hash. Kukhazikitsa kwachitsanzo ku Python patsamba la Wikipedia kumangotengera mizere ingapo. Monga momwe zilili ndi 34.10/2012/256, tidzagwiritsa ntchito Stribog-XNUMX ngati ntchito ya hashi. Zotsatira za ntchito yathu yofunikira zidzatchedwa kiyi ya gawo, pomwe zosowa zofananira zidzapangidwa:

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

    Kapangidwe/Njira

    Tiyeni tiwone zomwe ASN.1 ali nazo tsopano potumiza deta yonseyi:

    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 ndi yomwe idzasainidwe. HandshakeTBE - zomwe zidzasinthidwe. Ndikuwonetsani gawo la ukm mu MsgHandshake1. 34.10 VKO, pazambiri zamtundu wa makiyi opangidwa, kuphatikiza UKM (user keying material) parameter - entropy yowonjezera.

    Kuwonjezera Cryptography ku Code

    Tiyeni tingoganizira zosintha zomwe zidapangidwa ku code yoyambirira, popeza chimangocho chidakhalabe chofanana (kwenikweni, kukhazikitsidwa komaliza kudalembedwa koyamba, ndiyeno cryptography yonse idadulidwa).

    Popeza kutsimikizika ndi kuzindikiritsa ophatikizana kudzachitidwa pogwiritsa ntchito makiyi apagulu, tsopano akuyenera kusungidwa kwinakwake kwa nthawi yayitali. Kuti zikhale zosavuta, timagwiritsa ntchito JSON monga chonchi:

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

    athu - makiyi athu awiri, makiyi a hexadecimal achinsinsi komanso agulu. awo - maina a interlocutors ndi makiyi awo pagulu. Tiyeni tisinthe mikangano yamalamulo ndikuwonjezera kukonzanso kwa data ya 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),
        }
    # }}}
    

    Kiyi yachinsinsi ya 34.10 algorithm ndi nambala yachisawawa. 256-bit kukula kwa 256-bit elliptic curves. PyGOST sagwira ntchito ndi ma byte, koma ndi ziwerengero zazikulu, kotero kiyi yathu yachinsinsi (urandom(32)) iyenera kusinthidwa kukhala nambala pogwiritsa ntchito gost3410.prv_unmarshal(). Kiyi yapagulu imatsimikiziridwa motsimikiza kuchokera ku kiyi yachinsinsi pogwiritsa ntchito gost3410.public_key(). Kiyi yapagulu 34.10 ndi ziwerengero zazikulu ziwiri zomwe zimafunikiranso kusinthidwa kukhala kalozera kakang'ono kuti musungidwe mosavuta ndikutumiza pogwiritsa ntchito gost3410.pub_marshal().

    Mukawerenga fayilo ya JSON, makiyi a anthu onse ayenera kusinthidwanso pogwiritsa ntchito gost3410.pub_unmarshal(). Popeza tidzalandira zizindikiritso za interlocutors mu mawonekedwe a hashi kuchokera kuchinsinsi cha anthu, akhoza kuwerengedwera nthawi yomweyo ndikuyika mu dikishonale kuti afufuze mwamsanga. Stribog-256 hashi ndi gost34112012256.GOST34112012256(), zomwe zimakwaniritsa mawonekedwe a hashib a hashi.

    Kodi njira yoyambira yasintha bwanji? Chilichonse chili molingana ndi chiwembu chogwirana chanza: timapanga cookie (128-bit ndi yochuluka), ephemeral key 34.10, yomwe idzagwiritsidwe ntchito pa mgwirizano waukulu wa 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()
    

    • timadikirira kuyankha ndikusankha uthenga wa Msg womwe ukubwera;
    • onetsetsani kuti mwagwirana chanza1;
    • zindikirani kiyi yapagulu ya ephemeral ya gulu lina ndikuwerengera makiyi a gawolo;
    • Timapanga makiyi ofananira ofunikira pokonza gawo la TBE la uthengawo.

     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 ndi nambala ya 64-bit (urandom(8)), yomwe imafunanso kuchotsedwa kwa mawonekedwe ake pogwiritsa ntchito gost3410_vko.ukm_unmarshal(). VKO ntchito ya 34.10/2012/256 3410-bit ndi gost34102012256_vko.kek_XNUMX () (KEK - encryption key).

    Kiyi yagawo yopangidwa kale ndi 256-bit pseudo-random byte sequence. Chifukwa chake, itha kugwiritsidwa ntchito nthawi yomweyo muzochita za HKDF. Popeza GOST34112012256 imakwaniritsa mawonekedwe a hahlib, imatha kugwiritsidwa ntchito nthawi yomweyo m'gulu la Hkdf. Sititchula mchere (mkangano woyamba wa Hkdf), popeza kiyi yopangidwa, chifukwa cha ephemerality ya awiriawiri ofunikira, idzakhala yosiyana pa gawo lililonse ndipo ili kale ndi entropy yokwanira. kdf.expand() mwachisawawa imapanga kale makiyi a 256-bit omwe amafunikira Grasshopper pambuyo pake.

    Kenako, magawo a TBE ndi TBS a uthenga wobwera amawunikidwa:

    • MAC pa ciphertext yomwe ikubwera imawerengedwa ndikufufuzidwa;
    • ciphertext ndi decrypted;
    • Mapangidwe a TBE asinthidwa;
    • chizindikiritso cha interlocutor amatengedwa mmenemo ndipo amafufuzidwa ngati iye amadziwika kwa ife konse;
    • MAC pamwamba pa chizindikiritsochi imawerengedwa ndikufufuzidwa;
    • siginecha yamtundu wa TBS imatsimikiziridwa, yomwe imaphatikizapo cookie ya mbali zonse ziwiri ndi kiyi yapagulu ya chipani china. Siginecha imatsimikiziridwa ndi kiyi yosayina yanthawi yayitali ya 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"]
    

    Monga ndalemba pamwambapa, 34.13/2015/XNUMX ikufotokoza zosiyanasiyana block cipher modes kuyambira 34.12/2015/3413. Pakati pawo pali njira yopangira zoyika motsanzira ndi kuwerengera kwa MAC. Mu PyGOST izi ndi gost34.12.mac (). Njirayi imafuna kupititsa ntchito yolembera (kulandira ndi kubweza chipika chimodzi cha deta), kukula kwa chipika cha encryption ndipo, kwenikweni, deta yokha. Chifukwa chiyani simungathe kusindikiza kukula kwa block block? 2015/128/64 sikufotokoza za XNUMX-bit Grasshopper cipher, komanso XNUMX-bit Magma - GOST 28147-89 yosinthidwa pang'ono, yomwe idapangidwanso ku KGB ndipo ikadali ndi imodzi mwazinthu zotetezeka kwambiri.

    Kuznechik imayambitsidwa poyitana gost.3412.GOST3412Kuznechik(kiyi) ndikubwezeretsa chinthu ndi .encrypt()/.decrypt() njira zoyenera kudutsa ku 34.13 ntchito. MAC imawerengedwa motere: gost3413.mac(GOST3412Kuznechik(key).encrypt, KUZNECHIK_BLOCKSIZE, ciphertext). Kuti mufananize ma MAC owerengeredwa ndi olandilidwa, simungagwiritse ntchito kufananitsa kwanthawi zonse (==) kwa zingwe za byte, popeza ntchitoyi imataya nthawi yofananiza, yomwe, nthawi zambiri, imatha kubweretsa zovuta zakupha ngati. CHIYAMBI kuukira kwa TLS. Python ili ndi ntchito yapadera, hmac.compare_digest, pa izi.

    Ntchito ya block cipher imatha kubisa deta imodzi yokha. Kwa nambala yokulirapo, ndipo ngakhale osachulukitsa kutalika kwake, ndikofunikira kugwiritsa ntchito njira yobisa. 34.13-2015 ikufotokoza zotsatirazi: ECB, CTR, OFB, CBC, CFB. Iliyonse ili ndi madera ake ovomerezeka ogwiritsira ntchito ndi mawonekedwe. Tsoka ilo, tilibe okhazikika mitundu yotsimikizika ya encryption (monga CCM, OCB, GCM ndi zina zotero) - tikukakamizika kuwonjezera MAC tokha. Ndikusankha counter mode (CTR): sichifunikira padding kukula kwa chipika, ikhoza kufananizidwa, imangogwiritsa ntchito encryption, ingagwiritsidwe ntchito mosamala kubisa mauthenga ambiri (mosiyana ndi CBC, yomwe imagunda mwachangu).

    Monga .mac(), .ctr() imalowetsanso chimodzimodzi: ciphertext = gost3413.ctr(GOST3412Kuznechik(key).encrypt, KUZNECHIK_BLOCKSIZE, plaintext, iv). Ndikofunikira kutchula vekitala yoyambira yomwe ili ndendende theka la kutalika kwa chipika chobisa. Ngati kiyi yathu yobisa ikugwiritsidwa ntchito kubisa uthenga umodzi wokha (ngakhale kuchokera ku midadada ingapo), ndiye kuti ndibwino kukhazikitsa zero zoyambira. Kuti tisunge mauthenga akugwirana chanza, timagwiritsa ntchito kiyi yosiyana nthawi iliyonse.

    Kutsimikizira siginecha gost3410.verify() n'kochepa: timadutsa elliptic curve mkati momwe tikugwira ntchito (timangolemba mu protocol yathu ya GOSTIM), kiyi yapagulu ya wosayina (musaiwale kuti izi ziyenera kukhala ziwiri ziwiri. ziwerengero zazikulu, osati chingwe chocheperako), 34.11/2012/XNUMX hashi ndi siginecha yokha.

    Chotsatira, muzoyambitsa timakonzekera ndikutumiza uthenga wogwirana chanza kwa kugwirana chanza2, kuchita zomwezo monga tidachita pakutsimikizira, molingana: kusaina pa makiyi athu m'malo moyang'ana, ndi zina ...

     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)
     

    Gawoli likakhazikitsidwa, makiyi oyendera amapangidwa (kiyi yosiyana ya kubisa, kutsimikizika, pagulu lililonse), ndipo Grasshopper imayambitsidwa kuti isinthe ndikuwunika 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     # }}}
    

    Msg_sender coroutine tsopano imasunga mauthenga asanawatumize pa intaneti ya TCP. Uthenga uliwonse umakhala ndi mawu ochulukirapo ochulukirapo, omwenso ndi ma vector oyambitsira akabisidwa mumayendedwe. Uthenga uliwonse ndi chipika cha uthenga chimatsimikiziridwa kukhala ndi mtengo wotsutsa wosiyana.

    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
    

    Mauthenga obwera amakonzedwa ndi msg_receiver coroutine, yomwe imatsimikizira ndi kubisa:

    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)
    

    Pomaliza

    GOSTIM idapangidwa kuti igwiritsidwe ntchito pazolinga zamaphunziro zokha (popeza sichikuphimbidwa ndi mayeso, osachepera)! Kachidindo kochokera pulogalamu akhoza dawunilodi apa (Π‘Ρ‚Ρ€ΠΈΠ±ΠΎΠ³-256 Ρ…ΡΡˆ: 995bbd368c04e50a481d138c5fa2e43ec7c89bc77743ba8dbabee1fde45de120). Как ΠΈ всС ΠΌΠΎΠΈ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Ρ‹, Ρ‚ΠΈΠΏΠ° GoGOST, Zotsatira PyDERASN, NCCP, GoVPN, GOSTIM ndi kwathunthu pulogalamu yaulere, kugawidwa pansi pa malamulo GPLv3 +.

    SERGEY Matveev, cypherpunk, membala SPO Foundation, Wopanga Python/Go, katswiri wamkulu FSUE "STC" Atlas.

Source: www.habr.com

Kuwonjezera ndemanga