ê°ë°ìê° ëë€ ëŒìŽëžë¬ëЬ(ìì Pythonì GOST ìíží Ʞ볞 ìì)륌 ì¬ì©í멎ì 묎ëŠì ê°ì¥ ê°ëší 볎ì ë©ìì§ì 구ííë ë°©ë²ì ëí ì§ë¬žì ì죌 ë°ìµëë€. ë§ì ì¬ëë€ì ì ì©ë ìížíê° ë§€ì° ê°ëšíë€ê³ ìê°íë©°, ëžë¡ ìížìì .encrypt()륌 ížì¶íë ê²ë§ìŒë¡ë íµì ì±ëì íµíŽ ìì íê² ì ì¡í ì ììµëë€. ë€ë¥ž ì¬ëë€ì ìì© ìížíê° ììì ìŽëª ìŽëŒê³ 믿ìŒë©°, ì¬ëŠŒíŒìë ìíìë€ìŽ ìë Telegram곌 ê°ì ë¶ì í íì¬ë íì©ë©ëë€. 볎ì íë¡í ìœ.
ìŽ ëªšë ê²ìŽ ìíží íë¡í ìœê³Œ 볎ì IMì 구ííë ê²ìŽ ê·žë ê² ìŽë €ìŽ ìì ìŽ ìëëŒë ê²ì 볎ì¬ì£Œêž° ìíŽ ìŽ êž°ì¬ë¥Œ ìì±íê² ë§ë€ììµëë€. ê·žë¬ë ì첎 ìžìŠ ë° í€ ê³ìœ íë¡í ìœì ê°ë°íë ê²ì ê°ì¹ê° ììµëë€.

êž°ì¬ê° ì°ê² ë€ , , ìžì€íŽíž ë©ì ì ìžìŠ ë° í€ ê³ìœ íë¡í ìœ(ìŽë¥Œ êž°ë°ìŒë¡ 구íëš) ), GOST ìíží ìê³ ëŠ¬ìŠ PyGOST ëŒìŽëžë¬ëЬ ë° ASN.1 ë©ìì§ ìžìœë© ëŒìŽëžë¬ëŠ¬ë§ ì¬ì© (ëë ìŽë¯ž ìŽì ëíŽ ). ì ì 조걎: í룚 ì ë
(ëë 귌묎ìŒ)ì ì²ìë¶í° ìì±í ì ìì ì ëë¡ ë§€ì° ëšìíŽìŒ í©ëë€. ê·žë ì§ ììŒë©Ž ë ìŽì ê°ëší íë¡ê·žëšìŽ ìëëë€. ìë§ë ì€ë¥, ë¶íìí ë³µì¡íš, ëšì ìŽ ìì ê²ì
ëë€. ê²ë€ê° ìŽê²ì asyncio ëŒìŽëžë¬ëŠ¬ë¥Œ ì¬ì©íë 첫 ë²ì§ž íë¡ê·žëšì
ëë€.
ë©ì ì ëììž
뚌ì IMìŽ ìŽë€ 몚ìµìŒì§ ìŽíŽíŽìŒ í©ëë€. ëšìí륌 ìíŽ ì°žê°ì륌 ê²ìíì§ ìê³ PXNUMXP ë€ížìí¬ë¡ ë§ëëë€. ëëŽìì íµì íêž° ìíŽ ì°ê²°í í¬íž 죌ì륌 ê°ìžì ìŒë¡ íìí©ëë€.
íì¬ë¡ìë ììì ë 컎íší° ê°ì ì§ì íµì ìŽ ê°ë¥íë€ë ê°ì ìŽ IMì ì€ì ì ì© ê°ë¥ì±ì ì¬ê°í ì íìŽ ëë€ë ì ì ìŽíŽí©ëë€. ê·žë¬ë ë ë§ì ê°ë°ìê° ëªšë ì¢ ë¥ì NAT íµê³Œ 목ë°ì 구íí ìë¡ ì°ëЬë IPv4 ìží°ë·ì ë ì€ë ëšžë¬Œê² ë ê²ìŽë©° ììì 컎íší° ê°ì íµì ê°ë¥ì±ì ë®ìì§ ê²ì ëë€. ì§ê³Œ ì§ì¥ìì IPv6ì ë¶ì¡±ì ìžì ê¹ì§ 견ë ì ììµëê¹?
ì°ëЬë ì¹êµ¬ ë ì¹êµ¬ ë€ížìí¬ë¥Œ ê°ê² ë ê²ì ëë€. ê°ë¥í 몚ë ëí ìë륌 믞늬 ìììŒ í©ëë€. 첫짞, ìŽê²ì 몚ë ê²ì í¬ê² ëšìíí©ëë€. ì°ëЬë ìì ì ìê°íê³ , ìŽëŠ/í€ë¥Œ ì°Ÿê±°ë ì°Ÿì§ ëª»íê³ , ì°ê²°ì ëê±°ë ê³ì ìì íê³ , ëëŽì륌 ìê³ ììµëë€. ëì§ž, ìŒë°ì ìŒë¡ ìì íë©° ë§ì 공격ì ì ê±°í©ëë€.
IM ìží°íìŽì€ë Ʞ졎 ì룚ì ì ê°ê¹ìµëë€. , ì ë ê·žë€ì 믞ëë©ëЬìŠê³Œ Unix-way ì² íì ì ë§ ì¢ìí©ëë€. IM íë¡ê·žëšì ê° ëíìì ëíŽ ìž ê°ì Unix ëë©ìž ììŒìŽ ìë ëë í°ëŠ¬ë¥Œ ë§ëëë€.
- in - ëëŽììê² ë³Žëž ë©ìì§ê° êž°ë¡ë©ëë€.
- out - ëëŽìë¡ë¶í° ë°ì ë©ìì§ë¥Œ ìœìµëë€.
- ìí - ìŽë¥Œ ìœìŽì ëí ìëê° íì¬ ì°ê²°ëìŽ ìëì§ ì¬ë¶, ì°ê²° 죌ì/í¬ížë¥Œ ììë ëë€.
ëí ì격 ëëŽìì ëí ì°ê²°ì ììíë ížì€íž í¬ížë¥Œ ìì±íì¬ conn ììŒìŽ ìì±ë©ëë€.
|-- alice
| |-- in
| |-- out
| `-- state
|-- bob
| |-- in
| |-- out
| `-- state
`- conn
ìŽ ì ê·Œ ë°©ìì ì¬ì©í멎 IM ì ì¡ ë° ì¬ì©ì ìží°íìŽì€ë¥Œ ë 늜ì ìŒë¡ 구íí ì ììµëë€. ì¹êµ¬ê° ìê³ ëªšë ì¬ëì ë§ì¡±ìí¬ ìë ìêž° ë묞ì ëë€. ì¬ì© ë° / ëë , 구묞 ê°ì¡° êž°ë¥ìŽ ìë ë€ì€ ì°œ ìží°íìŽì€ë¥Œ ì»ì ì ììµëë€. ê·žëŠ¬ê³ ëììŒë¡ GNU Readline íží ë©ìì§ ì ë ¥ ëŒìžì ì»ì ì ììµëë€.
ì€ì ë¡ íížìë íë¡ì ížë FIFO íìŒì ì¬ì©í©ëë€. ê°ìžì ìŒë¡ ì ì© ì€ë ëìì ììŒë¡ ì§ì ìì±í 배겜 ììŽ asyncioìì 겜ìì ìŒë¡ íìŒ ìì ì ìííë ë°©ë²ì ìŽíŽí ì ìììµëë€(ì ë ì€ë«ëì ê·žë° ìŒì ìíŽ ìžìŽë¥Œ ì¬ì©íŽ ììµëë€) ). ë°ëŒì ëë Unix ëë©ìž ììŒì ì¬ì©íêž°ë¡ ê²°ì íìµëë€. ë¶ííë ìŽë¡ ìžíŽ echo 2001:470:dead::babe 6666 > connì ìíí ì ììµëë€. ëë ë€ìì ì¬ì©íì¬ ìŽ ë¬žì 륌 íŽê²°íìµëë€. : ììœ 2001:470:죜ì::ë² ìŽë¹ 6666 | socat - UNIX-CONNECT:conn, socat READLINE UNIX-CONNECT:alice/in.
ìëì ìì íì§ ìì íë¡í ìœ
TCPë ì ì¡ìŒë¡ ì¬ì©ë©ëë€. ìŽë ë°°ë¬ê³Œ ìì륌 볎ì¥í©ëë€. UDPë ë ë€ ë³Žì¥íì§ ìì§ë§(ìíží륌 ì¬ì©í ë ì ì©íš) ë€ìì ì§ìí©ëë€. íìŽì¬ì Ʞ볞ì ìŒë¡ ëì€ì§ ììµëë€.
ë¶ííê²ë TCPìë ë©ìì§ëŒë ê°ë ìŽ ìê³ ëšì§ ë°ìŽíž ì€ížëŠŒë§ ììµëë€. ë°ëŒì ìŽ ì€ë ëìì ë©ìì§ë¥Œ ìë¡ ê³µì í ì ìëë¡ ë©ìì§ íìì ê³ ìíë ê²ìŽ íìí©ëë€. ì€ ë°ê¿ 묞ì륌 ì¬ì©íë ë° ëìí ì ììµëë€. ì²ììë êŽì°®ì§ë§ ìŒëš ë©ìì§ ìíží륌 ììí멎 ìŽ ë¬žìê° ìížë¬žì ìŽë ê³³ìë ëíë ì ììµëë€. ë°ëŒì ë€ížìí¬ìì ë늬 ì¬ì©ëë íë¡í ìœì 뚌ì ë©ìì§ êžžìŽë¥Œ ë°ìŽíž ëšìë¡ ë³ŽëŽë íë¡í ìœì ëë€. ì륌 ë€ìŽ, Ʞ볞ì ìŒë¡ Pythonìë ë¹ì·í íììŒë¡ ìì í ì ìë xdrlibê° ììµëë€. .
ì°ëЬë TCP ìœêž°ë¥Œ ì ííê³ íšìšì ìŒë¡ ìííì§ ìì ê²ì ëë€. ìœë륌 ëšìíí ê²ì ëë€. ìì í ë©ìì§ë¥Œ ëìœë©í ëê¹ì§ 묎í 룚í륌 íµíŽ ììŒìì ë°ìŽí°ë¥Œ ìœìµëë€. XMLìŽ í¬íšë JSONë ìŽ ì ê·Œ ë°©ìì íììŒë¡ ì¬ì©í ì ììµëë€. ê·žë¬ë ìížíê° ì¶ê°ë멎 ë°ìŽí°ì ìëª íê³ ìžìŠíŽìŒ í©ëë€. ìŽë¥Œ ìíŽìë JSON/XMLìŽ ì ê³µíì§ ìë ë°ìŽíž ëšìì ëìŒí ê°ì²Ž ííìŽ íìí©ëë€(ë€í 결곌ë ë€ë¥Œ ì ìì).
XDRì ìŽ ìì ì ì í©íì§ë§ ì ë DER ìžìœë©ìŽ í¬íšë ASN.1ì ì ííê³ ëìêŽì ìì íêž°ê° ë ìŠê²ê³ ížëЬí ëì ìì€ì ê°ì²Žë¥Œ 볎ì íê² ë ê²ìŽêž° ë묞ì ëë€. ì€í€ë§ ìë ê²ê³Œ ë¬ëЬ , ëë , ASN.1ì íë ìœë©ë ì€í€ë§ì ë¹êµíì¬ ë°ìŽí°ë¥Œ ìëìŒë¡ íìží©ëë€.
# Msg ::= CHOICE {
# text MsgText,
# handshake [0] EXPLICIT MsgHandshake }
class Msg(Choice):
schema = ((
("text", MsgText()),
("handshake", MsgHandshake(expl=tag_ctxc(0))),
))
# MsgText ::= SEQUENCE {
# text UTF8String (SIZE(1..MaxTextLen))}
class MsgText(Sequence):
schema = ((
("text", UTF8String(bounds=(1, MaxTextLen))),
))
# MsgHandshake ::= SEQUENCE {
# peerName UTF8String (SIZE(1..256)) }
class MsgHandshake(Sequence):
schema = ((
("peerName", UTF8String(bounds=(1, 256))),
))
ìì ë ë©ìì§ë Msgì ëë€. í ì€íž MsgText(íì¬ë íëì í ì€íž íë í¬íš) ëë MsgHandshake ížëì °ìŽí¬ ë©ìì§(ëíìì ìŽëŠ í¬íš)ì ëë€. ì§êžì ë묎 ë³µì¡íŽ ë³ŽìŽì§ë§ ìŽë 믞ë륌 ìí êž°ë°ì ëë€.
âââââââ âââââââ âPeerAâ âPeerBâ ââââ¬âââ ââââ¬âââ âMsgHandshake( IdA) â ââââââââââ ââââââââ>â â â âMsgHandshake(IdB) â â<ââââââââââââââââââ â â â MsgText() â âââââ MsgText() â â â
ìíží ìë IM
ìŽë¯ž ë§íë¯ìŽ asyncio ëŒìŽëžë¬ëЬë 몚ë ììŒ ìì ì ì¬ì©ë©ëë€. ì¶ì ì êž°ëëë ì¬íì ë°ííŽ ë³Žê² ìµëë€.
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(","))
ìì ì ìŽëŠì ì€ì íìžì(--our-name alice). ììëë 몚ë ëëŽìë ìŒíë¡ êµ¬ë¶ëìŽ ëìŽë©ëë€(âê·žë€ì ìŽëŠ bob,eve). ê° ëëŽìì ëíŽ Unix ììŒìŽ ìë ëë í°ëЬì ê° in, out, ìíì ëí ìœë£šíŽìŽ ìì±ë©ëë€.
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"))
in ììŒìì ì¬ì©ìë¡ë¶í° ì€ë ë©ìì§ë 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"))
ëëŽìë¡ë¶í° ì€ë ë©ìì§ë OUT_QUEUES ëêž°ìŽë¡ ì ì¡ëë©°, ì¬êž°ìì ë°ìŽí°ê° ì¶ë ¥ ììŒì êž°ë¡ë©ëë€.
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()
ìí ììŒìì ìœì ë íë¡ê·žëšì PEER_ALIVE ì¬ì ìì ëëŽìì 죌ì륌 ì°Ÿìµëë€. ëëŽ ìì ìì§ ì°ê²°ìŽ ììŒë©Ž ë¹ ì€ìŽ êž°ë¡ë©ëë€.
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()
conn ììŒì 죌ì륌 ìž ë ì°ê²° "ìŽêž°ì" êž°ë¥ìŽ ììë©ëë€.
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))
ê°ìì륌 ê³ ë €íŽ ëŽ ìë€. 뚌ì ì§ì ë ížì€íž/í¬ížì ëí ì°ê²°ì ìŽê³ íŽë¹ ìŽëŠê³Œ íšê» ížëì °ìŽí¬ ë©ìì§ë¥Œ 볎ë ëë€.
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()
ê·žë° ë€ì ì격 ìëë°©ì ìëµì êž°ë€ëŠœëë€. Msg ASN.1 구ì±í륌 ì¬ì©íì¬ ë€ìŽì€ë ìëµì ëìœë©ì ìëí©ëë€. ì°ëЬë ì 첎 ë©ìì§ê° íëì TCP ìžê·žëšŒížë¡ ì ì¡ëê³ .read()륌 ížì¶í ë ììì ìŒë¡ ìì íë€ê³ ê°ì í©ëë€. Handshake ë©ìì§ë¥Œ ë°ìëì§ íìží©ëë€.
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 # }}}
ì°ëЬë ëëŽ ìì ìì ìŽëŠìŽ ì°ëЬìê² ìë €ì ž ìëì§ íìží©ëë€. ê·žë ì§ ìë€ë©Ž ì°ê²°ì ëìµëë€. ì°ëЬë ìŽë¯ž ê·žìì ì°ê²°ì ì€ì íëì§ íìžíê³ (ëëŽìê° ë€ì ì°ëЬìê² ì°ê²°íëŒë ëª ë ¹ì ëŽëŠŒ) ë«ìµëë€. IN_QUEUES ëêž°ìŽì ë©ìì§ í ì€ížê° í¬íšë Python 묞ììŽì 볎ì íì§ë§ msg_sender ìœë£šíŽì ìì ì ì€ì§íì¬ ë ê±°ì TCP ì°ê²°ê³Œ êŽë šë ìì±ì륌 ììŽë²ëЬëë¡ ì ížë¥Œ 볎ëŽë í¹ë³í ê° NoneìŽ ììµëë€.
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ë ëê°ë ë©ìì§(ììŒ ëŽ ëêž°ìŽì ìì)륌 ìëœíê³ ìŽë¥Œ MsgText ë©ìì§ë¡ ì§ë ¬íí ë€ì TCP ì°ê²°ì íµíŽ ë³Žë ëë€. ìžì ë ì§ ê¹šì§ ì ììµëë€. ì°ëЬë ìŽê²ì ëª ííê² ì°šëší©ëë€.
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))
ê²°êµ ê°ììë ììŒìì ë©ìì§ë¥Œ ìœë 묎í 룚íì ë€ìŽê°ëë€. ìŽë¬í ë©ìì§ê° í ì€íž ë©ìì§ìžì§ íìžíê³ OUT_QUEUES ëêž°ìŽì ë°°ì¹í멎 íŽë¹ ëí ìëì ì¶ë ¥ ììŒìŒë¡ ì ì¡ë©ëë€. ì .read()륌 ìííê³ ë©ìì§ë¥Œ ëìœë©í ì ìëì? ì¬ì©ìì ì¬ë¬ ë©ìì§ê° ìŽì 첎ì ë²íŒì ì§ê³ëìŽ íëì TCP ìžê·žëšŒížë¡ ì ì¡ë ì ìêž° ë묞ì ëë€. 첫 ë²ì§ž ê²ì ëìœë©í멎 ë€ì ë¶ë¶ì ìŒë¶ê° ë²íŒì ëšì ì ììµëë€. ë¹ì ìì ìž ìí©ìŽ ë°ìíë ê²œì° TCP ì°ê²°ì ë«ê³ msg_sender ìœë£šíŽì ì€ì§í©ëë€(OUT_QUEUES ëêž°ìŽì Noneì ì ì¡íì¬).
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)
ë©ìž ìœëë¡ ëìê°ì. íë¡ê·žëš ìì ì 몚ë ìœë£šíŽì ìì±í í TCP ìë²ë¥Œ ììí©ëë€. ì€ì ë ê° ì°ê²°ì ëíŽ ìëµì ìœë£šíŽì ìì±í©ëë€.
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()
ìëµìë ê°ììì ì ì¬íë©° ëìŒí ìì ì 몚ë 믞ë¬ë§íì§ë§ ëšìí륌 ìíŽ ë©ìì§ ìœêž°ì 묎í 룚íê° ìŠì ììë©ëë€. íì¬ ížëì °ìŽí¬ íë¡í ìœì ê° ìž¡ìì íëì ë©ìì§ë¥Œ 볎ëŽì§ë§ ììŒë¡ë ì°ê²° ê°ììë¡ë¶í° ë ê°ì ë©ìì§ê° ì ì¡ë ìì ìŽë©° ê·ž íìë 묞ì ë©ìì§ë¥Œ ìŠì ë³ŽëŒ ì ììµëë€.
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()
볎ì íë¡í ìœ
ìŽì ì°ëЬì íµì ì 볎ížíŽìŒ í ëì ëë€. 볎ììŽë 묎ìì ì믞íë©° ì°ëŠ¬ê° ìíë ê²ì 묎ìì ëê¹?
- ì ì¡ë ë©ìì§ì êž°ë°ì±;
- ì ì¡ë ë©ìì§ì ì ë¢°ì± ë° ë¬Žê²°ì± - ë³ê²œ ì¬íì ê°ì§íŽìŒ í©ëë€.
- ì¬ì 공격ìŒë¡ë¶í° ë³Žíž - ë©ìì§ê° ëëœëê±°ë ë°ë³µëë€ë ì¬ì€ì ê°ì§íŽìŒ í©ëë€(ê·žëŠ¬ê³ ì°ê²°ì ì¢ ë£íêž°ë¡ ê²°ì í©ëë€).
- 믞늬 ì ë ¥ë ê³µê° í€ë¥Œ ì¬ì©íì¬ ëí ìë륌 ìë³íê³ ìžìŠí©ëë€. ì°ëЬë ìŽë¯ž ì¹êµ¬ ê° ë€ížìí¬ë¥Œ ë§ë€êž°ë¡ ê²°ì íìµëë€. ìžìŠ íììŒ ì°ëЬë ë구ì íµì íê³ ìëì§ ìŽíŽí ì ììµëë€.
- ê°ì©ì± ìì±(PFS) - ìëª ìŽ êžŽ ìëª í€ê° ììëëëŒë ìŽì ì 몚ë ìì ì ìœì ì ìë ë¥ë ¥ìŽ ììŽì žìë ì ë©ëë€. ê°ë¡ì±ë ížëíœì êž°ë¡í멎 ìžëªšê° ìê² ë©ëë€.
- íëì TCP ìžì ëŽììë§ ë©ìì§(ì ì¡ ë° ížëì °ìŽí¬)ì ì íšì±/ì íšì±. ë€ë¥ž ìžì ìì ì¬ë°ë¥Žê² ìëª /ìžìŠë ë©ìì§ë¥Œ ìœì íë ê²ì (ëìŒí ëí ìëëŒë) ë¶ê°ë¥íŽìŒ í©ëë€.
- ìëì êŽì°°ìë ì¬ì©ì ìë³ì, ì ì¡ë ìëª ìŽ êžŽ ê³µê° í€ ëë íŽì륌 볌 ì ììµëë€. ìëì ìž êŽì°°ìì í¹ì ìµëª ì±.
ëëê²ë ê±°ì 몚ë ì¬ëìŽ ëªšë ížëì °ìŽí¬ íë¡í ìœìì ìŽ ìµìê°ì ê°êž°ë¥Œ ìíë©° "ì첎 ê°ë°" íë¡í ìœììë ìì í목 ì€ ê·¹í ìŒë¶ë§ 충족ë©ëë€. ìŽì ì°ëЬë ìë¡ìŽ ê²ì ë°ëª íì§ ìì ê²ì ëë€. ëë íì€í ì¬ì©íë ê²ìŽ ì¢ìµëë€ íë¡í ìœì 구ì¶íêž° ìí ê²ìŽì§ë§ ë ê°ëší ê²ì ì ííê² ìµëë€.
ê°ì¥ ë늬 ì¬ì©ëë ë ê°ì§ íë¡í ìœì ë€ì곌 ê°ìµëë€.
- - ë²ê·ž, ìŒ, ì·šìœì±, ì못ë ìê°, ë³µì¡ì± ë° ëšì ì ì€ë ìì¬ë¥Œ ì§ë ë§€ì° ë³µì¡í íë¡í ìœì ëë€(ê·žë¬ë ìŽë TLS 1.3곌ë ê±°ì êŽë šìŽ ììµëë€). íì§ë§ ë묎 ë³µì¡íêž° ë묞ì ê³ ë €íì§ ììµëë€.
- Ñ â ê°ëšíì§ë ìì§ë§ ì¬ê°í ìíží 묞ì ê° ììµëë€. IKEv1 ë° IKEv2ì ëíŽ ìœìŒë©Ž íŽë¹ ìì€ë ë€ì곌 ê°ìµëë€. , ISO/IEC IS 9798-3 ë° SIGMA(SIGn-and-MAc) íë¡í ìœ - í룚 ì ë ì 구íí ì ìì ë§íŒ ê°ëší©ëë€.
STS/ISO íë¡í ìœ ê°ë°ì ìµì ë§í¬ë¡ì SIGMAì ì¥ì ì 묎ìì ëê¹? ìŽë ì°ëЬì 몚ë ì구 ì¬í(ëëŽì ìë³ì "ìšêž°êž°" í¬íš)ì 충족íë©° ìë €ì§ ìíží 묞ì ê° ììµëë€. ìŽë ìµìíì ëë€. íë¡í ìœ ë©ìì§ìì ìµìí íëì ìì륌 ì ê±°í멎 볎ììŽ ë¶ìì íŽì§ëë€.
ê°ì¥ ê°ëší ì첎 ê°ë° íë¡í ìœìì SIGMAë¡ ìŽëíŽ ë³Žê² ìµëë€. ì°ëŠ¬ê° êŽì¬ì ê°ë ê°ì¥ Ʞ볞ì ìž ìì ì ë€ì곌 ê°ìµëë€. : ë ì°žì¬ì 몚ëìê² ëìŒí ê°ì ì¶ë ¥íë êž°ë¥ìŒë¡, ëì¹í€ë¡ íì© ê°ë¥í©ëë€. ììží ì€ëª íì§ ìê³ ê° ë¹ì¬ìë ìì(í ìžì ëŽììë§ ì¬ì©ëš) í€ ì(ê³µê° ë° ê°ìž í€)ì ìì±íê³ , ê³µê° í€ë¥Œ êµííê³ , ê³ìœ êž°ë¥ì ížì¶íì¬ ì ë ¥ì ê°ìž í€ì ê³µê° í€ë¥Œ ì ë¬í©ëë€. ëëŽìì ìŽì .
âââââââ âââââââ âPeerAâ âPeerBâ ââââ¬âââ ââââ¬âââ â IdA, PubA â âxxxxxx ==========â ââââââââââââââââ>â âPrvA, PubA = DHgen()â â â â= ========â ============â â IdB, PubB â â===================â â<âââââââââ âââââââ âPrvB, PubB = DHgen()â â â â===================â â ââââ â==== ===â§============â â âKey = DH(PrvA, PubB)â <ââââ â=======â€= ======= ====â â â â â
ë구ë ì§ ì€ê°ì ë°ìŽë€ìŽ ê³µê° í€ë¥Œ ìì ì ê²ìŒë¡ êµì²Ží ì ììµëë€. ìŽ íë¡í ìœìë ëí ìëì ëí ìžìŠìŽ ììµëë€. ìëª ìŽ êžŽ í€ë¡ ìëª ì ì¶ê°íŽ ë³Žê² ìµëë€.
âââââââ âââââââ âPeerAâ âPeerBâ ââââ¬âââ ââââ¬âââ âIdA, PubA, sign(SignPrvA, (PubA)) â â= âââââââââââââ ââââââââââ âââââââââââ>â âSignPrvA, SignPubA = load()â â â âPrvA, PubA = DHgen() â â â â======= =" | âââââââââââââ âââ âSignPrvB, SignPubB = ë¡ë( )â â â âPrvB, PubB = DHgen() â â â â========== ============== ==â âââââ â ====================â â â âíìž( SignPubB, ...)â â <ââââ âKey = DH(Pr vA, PubB) â â â â==================â â â â
ìŽë¬í ìëª ì í¹ì ìžì ì ì°ê²°ëìŽ ìì§ ìêž° ë묞ì ìëíì§ ììµëë€. ìŽë¬í ë©ìì§ë ë€ë¥ž ì°žê°ììì ìžì ìë "ì í©"í©ëë€. ì 첎 컚í ì€ížê° 구ë íŽìŒ í©ëë€. ìŽë¡ ìžíŽ Aì ë ë€ë¥ž ë©ìì§ë ì¶ê°íŽìŒ í©ëë€.
ëí ìëª ìëì ìì ì ìë³ì륌 ì¶ê°íë ê²ìŽ ì€ìí©ëë€. ê·žë ì§ ììŒë©Ž IdXXX륌 ë첎íê³ ìë €ì§ ë€ë¥ž ëëŽìì í€ë¡ ë©ìì§ì ë€ì ìëª í ì ìêž° ë묞ì ëë€. ë°©ì§íêž° ìíŽ , ìëª ìëì ììë íŽë¹ ì믞ì ë°ëŒ ëª ííê² ì ìë ìì¹ì ììŽìŒ í©ëë€. Aê° (PubA, PubB)ì ìëª í멎 Bë (PubB, PubA)ì ìëª íŽìŒ í©ëë€. ìŽë ëí ì§ë ¬íë ë°ìŽí°ì 구조ì íìì ì ííë ê²ì ì€ìì±ì ë§íŽì€ëë€. ì륌 ë€ìŽ, ASN.1 DER ìžìœë©ì ìžížë ì ë ¬ë©ëë€. SET OF(PubA, PubB)ë SET OF(PubB, PubA)ì ëìŒí©ëë€.
âââââââ âââââââ âPeerAâ âPeerBâ ââââ¬âââ ââââ¬âââ â IdA, PubA â âxxxxxx =================â âââââââââââââââââââââ ââââââââââ âââââââââââââ>â âSignPrvA, SignPubA = load()â â â âPrvA, PubA = DHgen() â â â â===== =" ===============â âIdB, PubB, sign(SignPrvB, (IdB, PubA, PubB)) â â=============== =============â â<ââââââââââââââââââââââââ ââââââââââ ââââââââââ âSignPrvB, SignPubB = load()â â â âPrvB, PubB = DHgen() â â â â================= ==========â â êž°íž(SignPrvA, (IdA, PubB, PubA)) â â================ ====â ââ âââââââââââââââââââââââââââââââââââââââ âââ>â âverify(SignPubB, ...) â â â âkey = dh (prva, PUBB) â â â â
ê·žë¬ë ì°ëЬë ìŽ ìžì ì ëíŽ ëìŒí ê³µì í€ë¥Œ ìì±íë€ë ê²ì ìì§ "ìŠëª "íì§ ëª»íìµëë€. ìì¹ì ìŒë¡ ìŽ ëšê³ ììŽë ìíí ì ììµëë€. 첫 ë²ì§ž ì ì¡ ì°ê²°ì ì íšíì§ ìì§ë§ ížëì °ìŽí¬ê° ìë£ë멎 몚ë ê²ìŽ ì€ì ë¡ í©ìëìëì§ íìžíꞰ륌 ìí©ëë€. íì¬ ì°ëЬë ISO/IEC IS 9798-3 íë¡í ìœì 볎ì íê³ ììµëë€.
ìì±ë í€ ì첎ì ìëª í ì ììµëë€. ìŽë ì¬ì©ë ìëª ìê³ ëŠ¬ìŠì ëì¶ìŽ ìì ì ìêž° ë묞ì ìíí©ëë€(ìëª ë¹ ë¹íž ìë ìì§ë§ ì¬ì í ëì¶ëš). íì í€ì íŽìì ìëª íë ê²ìŽ ê°ë¥íì§ë§ íì í€ì íŽì륌 ì ì¶íë ê²ë íì êž°ë¥ì ëí ë¬Žì°šë³ ëì 공격ìì ì ì©í ì ììµëë€. SIGMAë ë°ì ì ID륌 ìžìŠíë MAC êž°ë¥ì ì¬ì©í©ëë€.
âââââââ âââââââ âPeerAâ âPeerBâ ââââ¬âââ ââââ¬âââ â IdA, PubA â âxxxxxxxxxxxxxxxxxx =================â âââââââââââââââââââââ âââââââââââ ââââââââââââââââââ>â âSignPrvA, SignPubA = load()â â â âPrvA, PubA = DHgen() â â â â ======= ===================â âIdB, PubB, sign(SignPrvB, (PubA, PubB)), MAC(IdB) â â==== === â<âââââââââââââââââ ââââââââââ ââââââââââââââââââââ ââ âSignPrvB, SignPubB = ë¡ë()â â â âPrvB, PubB = DHgen() â â â â==== ================= ==â â â â===========â â sign(SignPrvA, (PubB, PubA)), MAC(IdA) â âKey = DH( PrvA, PubB) â ââââââââââââââââââââââ ââ ââââââââââââââââââââ âââââ>â âverify(Key, IdB) â â â âverify(SignPubB, ...)â â â â===xxx =â â â
ìµì í륌 ìíŽ ìŒë¶ë ìì í€ë¥Œ ì¬ì¬ì©íꞰ륌 ìí ìë ììµëë€(ë¬Œë¡ PFSìê²ë ë¶íí ìŒì ëë€). ì륌 ë€ìŽ í€ ìì ìì±íê³ ì°ê²°ì ìëíì§ë§ TCP륌 ì¬ì©í ì ìê±°ë íë¡í ìœ ì€ê°ìì ì€ëšëììµëë€. ìë¡ìŽ ìì ëë¹ëë ìížë¡íŒì íë¡ìžì 늬ìì€ë¥Œ ëë¹íë ê²ì ë¶ëë¬ìŽ ìŒì ëë€. ë°ëŒì ìì ê³µê° í€ë¥Œ ì¬ì¬ì©í ë ë°ìí ì ìë ìì ì¬ì 공격ìŒë¡ë¶í° 볎ížíë ìì¬ ëì ê°ìž ìì ì¿ í€ë¥Œ ìê°í©ëë€. ì¿ í€ì ìì ê³µê°í€ì ê²°í©ìŒë¡ ìžíŽ ìëë°©ì ê³µê°í€ê° ë¶íìíê² ìëª ìì ì ê±°ë ì ììµëë€.
âââââââ âââââââ âPeerAâ âPeerBâ ââââ¬âââ ââââ¬âââ â IdA, PubA, CookieA â âxxxxxxxxxxxxxxx ="="" âââââââââââââââââââââââââââââââââââââââ â>â âSignPrvA, SignPubA = ë¡ë( )â â â âPrvA, PubA = DHgen() â â â â======================== ==â âIdB, PubB, CookieB , ë¶íž(SignPrvB, (CookieA, CookieB, PubB)), MAC(IdB) â â========================= â â< âââââââââââââââââââââââââââââââââââââââ âââââââââââ âââââââââââââââââââââ âSignPrvB, SignPubB = load()â â â âPrvB, PubB = DHgen() â â â â====== ====================â â â â=======Problem SignPrvA, (CookieB, CookieA, PubA)), MAC(IdA) â âKey = DH(PrvA, PubB) â ââââââââââââââââââââ ââ âââââââââââââââââââââââââââââââââââââââ âââââââ>â â verify(í€, IdB) â â â âverify(SignPubB, ...)â â â â===================â â â â
ë§ì§ë§ìŒë¡, ì°ëЬë ìëì ìž êŽì°°ìë¡ë¶í° ëí ìëì íëŒìŽë²ì륌 ì»ê³ ì¶ìµëë€. ìŽë¥Œ ìíŽ SIGMAë 뚌ì ìì í€ë¥Œ êµííê³ ìžìŠ ë° ìë³ ë©ìì§ë¥Œ ìížíí ê³µíµ í€ë¥Œ ê°ë°í ê²ì ì ìí©ëë€. SIGMAë ë ê°ì§ ìµì ì ì€ëª í©ëë€:
- SIGMA-I - íì± ê³µê²©ìŒë¡ë¶í° ê°ìì륌 볎ížíê³ ìëì 공격ìŒë¡ë¶í° ìëµì륌 볎íží©ëë€. ê°ììë ìëµì륌 ìžìŠíê³ ìŒì¹íì§ ìë íëª©ìŽ ììŒë©Ž ìë³ ì 볎륌 ì ê³µíì§ ììµëë€. íŒê³ ìžê³Œ íšê» íì± íë¡í ìœìŽ ììë멎 íŒê³ ìžì ìì ì ì ë¶ìŠì ì ê³µí©ëë€. ìëì ìž êŽì°°ìë ì묎ê²ë ë°°ì°ì§ 못í©ëë€.
SIGMA-R - ë¥ëì 공격ìŒë¡ë¶í° ìëµì륌 볎ížíê³ , ìëì 공격ìŒë¡ë¶í° ê°ìì륌 볎íží©ëë€. 몚ë ê²ìŽ ì ë°ëìŽì§ë§ ìŽ íë¡í ìœììë XNUMXê°ì ížëì °ìŽí¬ ë©ìì§ê° ìŽë¯ž ì ì¡ëììµëë€.ì°ëЬë íŽëŒìŽìžíž-ìë² ì¹ìí ê²ìì êž°ëíë ê²ê³Œ ë ì ì¬íêž° ë묞ì SIGMA-I륌 ì íí©ëë€. íŽëŒìŽìžížë ìžìŠë ìë²ì ìíŽìë§ ìžìëê³ ëªšë ì¬ëìŽ ìŽë¯ž ìë²ë¥Œ ìê³ ììµëë€. ëí ížëì °ìŽí¬ ë©ìì§ê° ì êž° ë묞ì 구ííêž°ê° ë ìœìµëë€. íë¡í ìœì ì¶ê°íë ê²ì ë©ìì§ì ìŒë¶ë¥Œ ìížííê³ ìë³ì A륌 ë§ì§ë§ ë©ìì§ì ìížíë ë¶ë¶ìŒë¡ ì ì¡íë ê²ë¿ì ëë€.
PubA, CookieA â â============================â âââââââââââââââââ âââââ ââââââââââ ââââââââââââââââââââââââââââââââââ âââââ ââââââ>â âSignPrvA , SignPubA = load()â â â âPrvA, PubA = DHgen() â â â â============= ========= ====â â PubB, CookieB, Enc((IdB, sign(SignPrvB, (CookieA, CookieB, PubB)), MAC(IdB))) â â====== =======================â â<ââââââââââââââââââââââââ âââââ ââââââââââ âSignP rvB, SignPubB = load()â â â â PrvB, PubB = DHgen() â â â â=========== ===============â â â â======== =============â â Enc((IdA, sign( SignPrvA, (CookieB, CookieA, PubA)), MAC(IdA))) â âKey = DH(PrvA, PubB) â âââââââââââââââââââââ ââââââââââââââââââ ââââââââââ ââââââââââââââââââââââ ââââââ>â âverify(Key, IdB) â â â âverify(SignPubB, ...)â â â â================= ==â â â
- ìëª ìë GOST RìŽ ì¬ì©ë©ëë€. 256ë¹íž í€ë¥Œ ì¬ì©íë ìê³ ëŠ¬ìŠì ëë€.
- ê³µê° í€ë¥Œ ìì±íë €ë©Ž 34.10ë 2012ì XNUMXìŒ VKOê° ì¬ì©ë©ëë€.
- MACìŒë¡ë CMACê° ì¬ì©ëë€. êž°ì ì ìŒë¡ ìŽë GOST R 34.13-2015ì ì€ëª ë ëžë¡ ìížì í¹ì ìë 몚ëì ëë€. ìŽ ëªšëì ìíží êž°ë¥ìŒë¡ â (34.12-2015).
- ê³µê° í€ì íŽìë ëëŽìì ìë³ìë¡ ì¬ì©ë©ëë€. íŽìë¡ ì¬ì©ëš (34.11ë 2012ì 256ìŒ XNUMXë¹íž).
ì ì íì ì°ëЬë ê³µì í€ì ëìíê² ë©ëë€. ì ì¡ ë©ìì§ì ìžìŠë ìížíì ìŽë¥Œ ì¬ì©í ì ììµëë€. ìŽ ë¶ë¶ì ë§€ì° ê°ëšíê³ ì€ìíêž° ìŽë µìµëë€. ë©ìì§ ì¹ŽìŽí°ë¥Œ ëëŠ¬ê³ , ë©ìì§ë¥Œ ìížííê³ , 칎ìŽí°ì ìížë¬žì ìžìŠ(MAC)íê³ , 볎ë ëë€. ë©ìì§ë¥Œ ë°ìŒë©Ž 칎ìŽí°ì ììë ê°ìŽ ìëì§ íìžíê³ ì¹ŽìŽí°ë¡ ìížë¬žì ìžìŠí í ë³µížíí©ëë€. ížëì °ìŽí¬ ë©ìì§, ì ì¡ ë©ìì§ë¥Œ ìížííê³ ìŽë¥Œ ìžìŠíë ë°©ë²ìë ìŽë€ í€ë¥Œ ì¬ì©íŽìŒ í©ëê¹? ìŽë¬í 몚ë ìì ì íëì í€ë¥Œ ì¬ì©íë ê²ì ìííê³ íëª íì§ ììµëë€. í¹íë êž°ë¥ì ì¬ì©íì¬ í€ë¥Œ ìì±íŽìŒ í©ëë€. (í€ íì íšì). ë€ì ë§íì§ë§, 뚞늬칎ëœì 쪌ê°ì ëê°ë¥Œ ë°ëª íì§ ë§ìë€. ì€ë«ëì ìë €ì ž ììŒë©° ì ì°êµ¬ëììŒë©° ìë €ì§ ë¬žì ê° ììµëë€. ìíê¹ê²ë Ʞ볞 Python ëŒìŽëžë¬ëЬìë ìŽ êž°ë¥ìŽ ììŒë¯ë¡ ë€ìì ì¬ì©í©ëë€. ë¹ë ëŽí¬. HKDFë ëŽë¶ì ìŒë¡ , ìŽë ì°šë¡ë¡ íŽì íšì륌 ì¬ì©í©ëë€. Wikipedia íìŽì§ì ìë Pythonì ìì 구íìë ëš ëª ì€ì ìœëê° íìí©ëë€. 34.10ë 2012ì 256ìŒì 겜ì°ì ë§ì°¬ê°ì§ë¡ Stribog-XNUMXì íŽìíšìë¡ ì¬ì©íê² ìµëë€. í€ ê³ìœ êž°ë¥ì ì¶ë ¥ì ìžì í€ëŒê³ íë©°, ì¬êž°ìì ëëœë ëì¹ í€ê° ìì±ë©ëë€.
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")구조/구ì±í
ìŽ ëªšë ë°ìŽí°ë¥Œ ì ì¡íêž° ìíŽ íì¬ ê°ì§ê³ ìë ASN.1 구조륌 ìŽíŽë³Žê² ìµëë€.
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ê° ìëª ëë ê²ì ëë€. HandshakeTBE - ìížíë í목ì ëë€. MsgHandshake1ì ukm íëì 죌목íê² ìµëë€. 34.10 VKOë ìì±ë í€ì 묎ììí륌 ëì± ëìŽêž° ìíŽ UKM(ì¬ì©ì í€ ìë£) ë§€ê°ë³ì륌 í¬íší©ëë€. ìŠ, ìížë¡íŒë§ ì¶ê°ë©ëë€.
ìœëì ìíží ì¶ê°
íë ììí¬ë ëìŒíê² ì ì§ëììŒë¯ë¡ ìë ìœëì ì ì©ë ë³ê²œ ì¬íë§ ê³ ë €íŽ ë³Žê² ìµëë€(ì¬ì€ ìµì¢ 구íìŽ ëšŒì ìì±ë ë€ì 몚ë ìížíê° ì ê±°ëììµëë€).
ëëŽìì ìžìŠ ë° ìë³ì ê³µê° í€ë¥Œ ì¬ì©íì¬ ìíëë¯ë¡ ìŽì ì€ë«ëì ìŽëê°ì ì ì¥íŽìŒ í©ëë€. ëšìí륌 ìíŽ ë€ì곌 ê°ìŽ JSONì ì¬ì©í©ëë€.
{ "our": { "prv": "21254cf66c15e0226ef2669ceee46c87b575f37f9000272f408d0c9283355f98", "pub": "938c87da5c55b27b7f332d91b202dbef2540979d6ceaa4c35f1b5bfca6df47df0bdae0d3d82beac83cec3e353939489d9981b7eb7a3c58b71df2212d556312a1" }, "their": { "alice": "d361a59c25d2ca5a05d21f31168609deeec100570ac98f540416778c93b2c7402fd92640731a707ec67b5410a0feae5b78aeec93c4a455a17570a84f2bc21fce", "bob": "aade1207dd85ecd283272e7b69c078d5fae75b6e141f7649ad21962042d643512c28a2dbdc12c7ba40eb704af920919511180c18f4d17e07d7f5acd49787224a" } }our - í€ ì, XNUMXì§ì ê°ìž í€ ë° ê³µê° í€ì ëë€. ê·žë€ì â ëëŽìì ìŽëŠê³Œ ê³µê° í€. ëª ë ¹ì€ ìžì륌 ë³ê²œíê³ 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), } # }}}34.10 ìê³ ëŠ¬ìŠì ê°ìž í€ë ììì ì«ìì ëë€. 256ë¹íž íì 곡ì ì ê²œì° 256ë¹íž í¬êž°ì ëë€. PyGOSTë ë°ìŽíž ìžížììë ìëíì§ ìì§ë§ , ë°ëŒì ê°ìž í€(urandom(32))ë gost3410.prv_unmarshal()ì ì¬ì©íì¬ ì«ìë¡ ë³íëìŽìŒ í©ëë€. ê³µê° í€ë gost3410.public_key()륌 ì¬ì©íì¬ ê°ìž í€ìì ê²°ì ì ìŒë¡ ê²°ì ë©ëë€. ê³µê° í€ 34.10ì gost3410.pub_marshal()ì ì¬ì©íì¬ ì ì¥ ë° ì ì¡ì ìœê² íêž° ìíŽ ë°ìŽíž ìíì€ë¡ ë³ííŽìŒ íë ë ê°ì í° ì«ìì ëë€.
JSON íìŒì ìœì íìë gost3410.pub_unmarshal()ì ì¬ì©íì¬ ê³µê° í€ë¥Œ ë€ì ë³ííŽìŒ í©ëë€. ê³µê° í€ìì íŽì íììŒë¡ ëëŽìì ìë³ì륌 ìì íë¯ë¡ ì¬ì ì ìŠì ê³ì°íì¬ ë¹ ë¥ž ê²ìì ìíŽ ì¬ì ì ë°°ì¹í ì ììµëë€. Stribog-256 íŽìë gost34112012256.GOST34112012256()ìŽë©°, ìŽë íŽì íšìì hashlib ìží°íìŽì€ë¥Œ ìì í ë§ì¡±í©ëë€.
ê°ìì ìœë£šíŽì ìŽë»ê² ë³ê²œëìëì? 몚ë ê²ì ížëì °ìŽí¬ 첎ê³ì ë°ëŠ ëë€. ì°ëЬë VKO í€ ê³ìœ êž°ë¥ì ì¬ì©ë ìì í€ ì 128ìž ì¿ í€(34.10ë¹ížë©Ž ì¶©ë¶)륌 ìì±í©ëë€.
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()- ìëµì êž°ë€ëŠ¬ê³ ë€ìŽì€ë Msg ë©ìì§ë¥Œ ëìœë©í©ëë€.
- handshake1ì ë°ìëì§ íìžíìžì.
- ìëë°©ì ìì ê³µê° í€ë¥Œ ëìœë©íê³ ìžì í€ë¥Œ ê³ì°í©ëë€.
- ë©ìì§ì TBE ë¶ë¶ì ì²ëЬíë ë° íìí ëì¹ í€ë¥Œ ìì±í©ëë€.
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ì 64ë¹íž ì«ì(urandom(8))ìŽë©° gost3410_vko.ukm_unmarshal()ì ì¬ì©íì¬ ë°ìŽíž ííìì ìì§ë ¬íë íìí©ëë€. 34.10ë 2012ì 256ìŒ 3410ë¹ížì© VKO êž°ë¥ì gost34102012256_vko.kek_XNUMX()(KEK - ìíží í€)ì ëë€.
ìì±ë ìžì í€ë ìŽë¯ž 256ë¹íž ìì¬ ë¬Žìì ë°ìŽíž ìíì€ì ëë€. ë°ëŒì HKDF íšììì ìŠì ì¬ì©í ì ììµëë€. GOST34112012256ì hashlib ìží°íìŽì€ë¥Œ ë§ì¡±íë¯ë¡ Hkdf íŽëì€ìì ë°ë¡ ì¬ì©í ì ììµëë€. ì°žì¬íë í€ ìì ììì±ìŒë¡ ìžíŽ ìì±ë í€ê° ê° ìžì ë§ë€ ë€ë¥Žê³ ìŽë¯ž ì¶©ë¶í ìížë¡íŒë¥Œ í¬íšíê³ ìêž° ë묞ì ìíž(Hkdfì 첫 ë²ì§ž ìžì)륌 ì§ì íì§ ììµëë€. kdf.expand()ë Ʞ볞ì ìŒë¡ ëì€ì Grasshopperì íìí 256ë¹íž í€ë¥Œ ìŽë¯ž ìì±í©ëë€.
ë€ììŒë¡ ìì ë©ìì§ì TBE ë° TBS ë¶ë¶ì íìží©ëë€.
- ë€ìŽì€ë ìížë¬žì ëí MACê° ê³ì°ëê³ íìžë©ëë€.
- ìížë¬žìŽ íŽë ë©ëë€.
- TBE êµ¬ì¡°ê° ëìœë©ë©ëë€.
- ëëŽ ìì ìë³ì륌 ê°ì ž ìì ê·žê° ì°ëЬìê² ì í ìë €ì ž ìëì§ íìží©ëë€.
- ìŽ ìë³ìì ëí MACê° ê³ì°ëê³ íìžë©ëë€.
- ì ë¹ì¬ìì ì¿ í€ì ìëë°©ì ê³µê° ìì í€ë¥Œ í¬íšíë TBS 구조ì ëí ìëª ìŽ íìžë©ëë€. ìëª ì ëëŽìì ìëª ìŽ êžŽ ìëª í€ë¡ íìžë©ëë€.
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"]ììì ìŽ ê²ì²ëŒ 34.13ë 2015ì XNUMXìŒìë ë€ìí ì€ëª ìŽ ëì ììµëë€. 34.12ë 2015ì 3413ìŒë¶í°. ê·žì€ìë 몚방 ìœì ë° MAC ê³ì°ì ìì±íë 몚ëê° ììµëë€. PyGOSTììë gost34.12.mac()ì ëë€. ìŽ ëªšëììë ìíží êž°ë¥(íëì ë°ìŽí° ëžë¡ ìì ë° ë°í), ìíží ëžë¡ì í¬êž° ë° ì€ì ë¡ ë°ìŽí° ì첎륌 ì ë¬íŽìŒ í©ëë€. ìíží ëžë¡ì í¬êž°ë¥Œ íëìœë©í ì ìë ìŽì ë 묎ìì ëê¹? 2015ë 128ì 64ìŒìë XNUMXë¹íž Grasshopper ìížë¿ë§ ìëëŒ XNUMXë¹íž ìížë ì€ëª ëìŽ ììµëë€. - ìœê° ìì ë GOST 28147-89ë KGBìì ë€ì ìì±ëììŒë©° ì¬ì í ê°ì¥ ëì ìì ìê³ê° ì€ íë륌 ê°ì§ê³ ììµëë€.
Kuznechikì gost.3412.GOST3412Kuznechik(key)륌 ížì¶íì¬ ìŽêž°íëê³ 34.13 íšìì ì ë¬íë ë° ì í©í .encrypt()/.decrypt() ë©ìëê° ìë ê°ì²Žë¥Œ ë°íí©ëë€. MACë ë€ì곌 ê°ìŽ ê³ì°ë©ëë€: gost3413.mac(GOST3412Kuznechik(key).encrypt, KUZNECHIK_BLOCKSIZE, ciphertext). ê³ì°ë MAC곌 ìì ë MAC륌 ë¹êµíë €ë©Ž ë°ìŽíž 묞ììŽì ìŒë°ì ìž ë¹êµ(==)륌 ì¬ì©í ì ììµëë€. ìŽ ìì ì ë¹êµ ìê°ì ëì¶íì¬ ìŒë°ì ìŒë¡ ë€ì곌 ê°ì ì¹ëª ì ìž ì·šìœì ì ìŽëí ì ìêž° ë묞ì ëë€. TLSì ëí 공격. Pythonìë ìŽë¥Œ ìí í¹ë³í íšììž hmac.compare_digestê° ììµëë€.
ëžë¡ ìíží êž°ë¥ì íëì ë°ìŽí° ëžë¡ë§ ìížíí ì ììµëë€. ì«ìê° ë í¬ê±°ë êžžìŽì ë°°ìê° ìëëëŒë ìíží 몚ë륌 ì¬ì©íŽìŒ í©ëë€. 34.13-2015ìë ECB, CTR, OFB, CBC, CFBê° ì€ëª ëìŽ ììµëë€. ê°ê°ìë íì©ëë ì ì© ìì곌 í¹ì±ìŽ ììµëë€. ììœê²ë ìì§ íì€íê° ëìŽ ìì§ ììµëë€. (ì: CCM, OCB, GCM ë±) - ìµìí MAC륌 ì§ì ì¶ê°íŽìŒ í©ëë€. ëë ì ííë€ (CTR): ëžë¡ í¬êž°ì ëí íšë©ìŽ íìíì§ ìê³ , ë³ë ¬íë ì ììŒë©°, ìíží êž°ë¥ë§ ì¬ì©íê³ , ë§ì ìì ë©ìì§ë¥Œ ìížííë ë° ìì íê² ì¬ì©í ì ììµëë€(ë¹êµì ë¹ ë¥Žê² ì¶©ëíë CBCìë ë¬ëЬ).
.mac()곌 ë§ì°¬ê°ì§ë¡ .ctr()ë ë¹ì·í ì ë ¥ì ë°ìµëë€: ciphertext = gost3413.ctr(GOST3412Kuznechik(key).encrypt, KUZNECHIK_BLOCKSIZE, plaintext, iv). ìíží ëžë¡ êžžìŽì ì íí ì ë°ìž ìŽêž°í 벡í°ë¥Œ ì§ì íŽìŒ í©ëë€. ìíží í€ê° íëì ë©ìì§(ì¬ë¬ ëžë¡ì ë©ìì§ììë ë¶êµ¬íê³ )륌 ìížííë ë°ë§ ì¬ì©ëë ê²œì° ìŽêž°í 벡í°ë¥Œ XNUMXìŒë¡ ì€ì íë ê²ìŽ ìì í©ëë€. ížëì °ìŽí¬ ë©ìì§ë¥Œ ìížííêž° ìíŽ ë§€ë² ë³ëì í€ë¥Œ ì¬ì©í©ëë€.
gost3410.verify() ìëª ì íìžíë ê²ì ê°ëší©ëë€. ìì ì€ìž íì 곡ì (GOSTIM íë¡í ìœì ê°ëší êž°ë¡íš), ìëª ìì ê³µê° í€(34.11ê°ì ííìŽìŽìŒ íšì ìì§ ë§ìžì)륌 ì ë¬í©ëë€. í° ì«ì, ë°ìŽíž 묞ììŽ ìë), 2012ë XNUMXì XNUMXìŒ íŽì ë° ìëª ì첎.
ë€ììŒë¡, ê°ìììì ì°ëЬë ížëì °ìŽí¬ ë©ìì§ë¥Œ ì€ë¹íê³ handshake2ì 볎ëŽë©°, íìž ì€ì íë ê²ê³Œ ëìŒí ìì ì ëì¹ì ìŒë¡ë§ ìíí©ëë€. ìŠ íìžíë ëì í€ì ìëª íë ë±ì ëë€.
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)ìžì ìŽ ì€ì ë멎 ì ì¡ í€ê° ìì±ëê³ (ê° ë¹ì¬ìì ëíŽ ìíží, ìžìŠì ìí ë³ëì í€), Grasshopperê° ìŽêž°íëìŽ 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 ìœë£šíŽì ìŽì ë©ìì§ë¥Œ TCP ì°ê²°ë¡ 볎ëŽêž° ì ì ìížíí©ëë€. ê° ë©ìì§ìë ëšì¡°ë¡ê² ìŠê°íë nonceê° ììŒë©° ìŽë 칎ìŽí° 몚ëìì ìížíë ë ìŽêž°í 벡í°ìŽêž°ë í©ëë€. ê° ë©ìì§ì ë©ìì§ ëžë¡ì ìë¡ ë€ë¥ž 칎ìŽí° ê°ì ê°ìµëë€.
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ìì ë©ìì§ë ìžìŠ ë° ìíž íŽë ì ì²ëЬíë msg_receiver ìœë£šíŽì ìíŽ ì²ëЬë©ëë€.
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)ê²°ë¡
GOSTIMì êµì¡ 목ì ìŒë¡ë§ ì¬ì©íëë¡ ê³ ìëììµëë€(ì ìŽë í ì€ížììë ë€ë£šì§ ìêž° ë묞ì ëë€)! íë¡ê·žëšì ìì€ìœë륌 ë€ìŽë¡ë ë°ì ì ììµëë€. (СÑÑОбПг-256 Ñ ÑÑ: 995bbd368c04e50a481d138c5fa2e43ec7c89bc77743ba8dbabee1fde45de120). Ðак О вÑе ЌПО пÑПекÑÑ, ÑОпа , , , , GOSTIMì ìì í , ìœêŽì ë°ëŒ ë°°í¬ëš .
, íì , Python/Go ê°ë°ì, ìì ì ë¬žê° .
ì¶ì² : habr.com
