پرو هوسٽر > بلاگ > انتظاميه > GOSTIM: P2P F2F E2EE IM هڪ شام ۾ GOST cryptography سان
GOSTIM: P2P F2F E2EE IM هڪ شام ۾ GOST cryptography سان
ڊولپر ٿيڻ PyGOST لائبريريون (GOST cryptographic primitives in pure Python)، مون کي اڪثر سوال ملندا آهن ته ڪھڙيءَ طرح آسان ترين محفوظ ميسيجنگ تي عمل ڪجي. گھڻا ماڻھو اپلائيڊ ڪرپٽوگرافي کي بلڪل سادو سمجھن ٿا، ۽ .encrypt() کي بلاڪ سيفر تي ڪال ڪرڻ ڪافي ھوندو ته ان کي محفوظ طريقي سان ڪميونيڪيشن چينل تي موڪلڻ لاءِ. ٻيا مڃيندا آھن ته لاڳو ڪيل ڪرپٽوگرافي ڪجھھ ماڻھن جي قسمت آھي، ۽ اھو قابل قبول آھي ته امير ڪمپنيون ٽيليگرام وانگر اولمپياڊ-رياضيدانن سان. لاڳو نٿو ڪري سگهي محفوظ پروٽوڪول.
اهو سڀ ڪجهه مون کي هن مضمون لکڻ لاءِ حوصلا افزائي ڪرڻ لاءِ ڏيکاريو ته cryptographic پروٽوڪول ۽ محفوظ IM تي عمل ڪرڻ اهڙو ڏکيو ڪم ناهي. بهرحال، اهو توهان جي پنهنجي تصديق ۽ اهم معاهدي پروٽوڪول کي ايجاد ڪرڻ جي قابل ناهي.
مضمون لکندو پير صاحب کي پير صاحب, دوست کان دوست, آخر کان آخر تائين انڪرپٽ ٿيل انسٽنٽ ميسينجر سان SIGMA-I تصديق ۽ اهم معاهدو پروٽوڪول (جنهن جي بنياد تي اهو لاڳو ٿئي ٿو IPsec IKE)، خاص طور تي استعمال ڪندي GOST cryptographic algorithms PyGOST لائبريري ۽ ASN.1 پيغام انڪوڊنگ لائبريري پيڊراسن (جنهن بابت آئون اڳ ۾ ئي اڳ لکيو). هڪ شرط: اهو ايترو سادو هجڻ گهرجي ته اهو شروع کان هڪ شام (يا ڪم جي ڏينهن) ۾ لکي سگهجي ٿو، ٻي صورت ۾ اهو هاڻي هڪ سادي پروگرام ناهي. ان ۾ شايد غلطيون، غير ضروري پيچيدگيون، خاميون آهن، ان سان گڏ هي منهنجو پهريون پروگرام آهي جيڪو استعمال ڪري رهيو آهيان asyncio لائبريري.
آئي ايم ڊيزائن
پهرين، اسان کي سمجهڻ جي ضرورت آهي ته اسان جي IM وانگر نظر ايندي. سادگي لاءِ، اچو ته ان کي هڪ پيئر-ٽو-پيئر نيٽ ورڪ، شرڪت ڪندڙن جي ڪنهن به دريافت کان سواءِ. اسان ذاتي طور تي ظاهر ڪنداسين ته ڪهڙي پتي: بندرگاهه سان ڳنڍڻ لاء رابطو ڪندڙ سان رابطو ڪرڻ لاء.
مان سمجهان ٿو ته، هن وقت، اهو مفروضو ته سڌو ڪميونيڪيشن ٻن بااختيار ڪمپيوٽرن جي وچ ۾ موجود آهي، عملي طور تي IM جي قابل اطلاق تي هڪ اهم حد آهي. پر جيترا وڌيڪ ڊولپر NAT-traversal cruchs جي سڀني قسمن تي عمل ڪندا، اوترو ئي وڌيڪ اسان IPv4 انٽرنيٽ تي رهنداسين، وچ ۾ رابطي جي هڪ مايوس ڪندڙ امڪان سان، پاڻمرادو ڪمپيوٽرن جي وچ ۾. توهان ڪيتري وقت تائين گهر ۽ ڪم تي IPv6 جي کوٽ کي برداشت ڪري سگهو ٿا؟
اسان وٽ هڪ دوست کان دوست نيٽ ورڪ هوندو: سڀني ممڪن ڳالهين کي اڳ ۾ ڄاڻڻ گهرجي. سڀ کان پهريان، اهو سڀ ڪجهه آسان بڻائي ٿو: اسان پنهنجو تعارف ڪرايو، نالو/ڪجهه لڌو يا نه مليو، منقطع يا ڪم جاري رکو، گفتگو ڪندڙ کي ڄاڻو. ٻيو، عام طور تي، اهو محفوظ آهي ۽ ڪيترن ئي حملن کي ختم ڪري ٿو.
IM انٽرفيس کلاسک حل جي ويجهو هوندو بيڪار منصوبا، جيڪو مان واقعي پسند ڪريان ٿو انهن جي minimalism ۽ يونڪس واٽ فلسفي لاءِ. IM پروگرام هڪ ڊاريڪٽري ٺاهي ٿو ٽن يونڪس ڊومين ساکٽ سان هر هڪ ڳالهائيندڙ لاءِ:
ان ۾ - ڳالهائيندڙ ڏانهن موڪليا ويا پيغام ان ۾ رڪارڊ ٿيل آهن؛
رياست - ان مان پڙهڻ سان، اسان اهو معلوم ڪيو ته ڇا ڳالهائيندڙ هن وقت ڳنڍيل آهي، ڪنيڪشن ايڊريس/پورٽ.
ان کان علاوه، هڪ ڪني ساکٽ ٺاهي وئي آهي، ميزبان پورٽ لکڻ سان جنهن ۾ اسان ريموٽ انٽرلوڪٽر سان ڪنيڪشن شروع ڪريون ٿا.
|-- alice
| |-- in
| |-- out
| `-- state
|-- bob
| |-- in
| |-- out
| `-- state
`- conn
اهو طريقو توهان کي اجازت ڏئي ٿو IM ٽرانسپورٽ ۽ يوزر انٽرفيس جي آزاد لاڳو ڪرڻ، ڇو ته ڪو دوست ناهي، توهان سڀني کي خوش نه ٿا ڪري سگهو. استعمال ڪندي ٽمڪس ۽ / يا گھڻائي وارو، توهان حاصل ڪري سگهو ٿا هڪ گھڻ-ونڊو انٽرفيس نحو نمايان ڪرڻ سان. ۽ مدد سان آر ايل رِپ توهان حاصل ڪري سگهو ٿا هڪ GNU Readline-مطابقت رکندڙ پيغام ان پٽ لائن.
حقيقت ۾، بيڪار پروجيڪٽ استعمال ڪندا آهن FIFO فائلون. ذاتي طور تي، مان سمجهي نه سگهيو آهيان ته ڪيئن فائلن سان مقابلي ۾ ڪم ڪرڻ لاءِ asyncio ۾ وقف ٿيل موضوعن جي هٿ سان لکيل پس منظر کان سواءِ (مان ڪافي وقت کان اهڙين شين لاءِ ٻولي استعمال ڪري رهيو آهيان. Go). تنهن ڪري، مون يونڪس ڊومين ساکٽ سان ڪرڻ جو فيصلو ڪيو. بدقسمتي سان، اهو ڪرڻ ناممڪن بڻائي ٿو گونج 2001:470:dead::babe 6666 > conn. مون هن مسئلي کي استعمال ڪندي حل ڪيو ساڪٽ: گونج 2001: 470: مئل:: بيبي 6666 | socat - UNIX-Connect:conn، socat READLINE UNIX-Connect:alice/in.
اصل غير محفوظ پروٽوڪول
TCP ٽرانسپورٽ طور استعمال ڪيو ويندو آهي: اهو ترسيل ۽ ان جي آرڊر جي ضمانت ڏئي ٿو. UDP ضمانت ڏئي ٿو نه (جيڪو ڪارائتو هوندو جڏهن ڪرپٽوگرافي استعمال ڪيو ويندو)، پر سپورٽ ايس ٽي پي پٿون دٻي مان ٻاهر نٿو اچي.
بدقسمتي سان، TCP ۾ پيغام جو ڪو تصور ناهي، صرف بائيٽ جو هڪ وهڪرو. تنهن ڪري، ضروري آهي ته پيغامن لاءِ هڪ فارميٽ تيار ڪيو وڃي ته جيئن اهي هن سلسلي ۾ پاڻ ۾ شيئر ڪري سگهجن. اسان لائن فيڊ ڪردار کي استعمال ڪرڻ تي متفق ٿي سگھون ٿا. اهو شروع ڪرڻ وارن لاءِ ٺيڪ آهي، پر هڪ دفعو اسان پنهنجي پيغامن کي انڪرپٽ ڪرڻ شروع ڪريون ٿا، اهو ڪردار ڪٿي به ciphertext ۾ ظاهر ٿي سگهي ٿو. نيٽ ورڪن ۾، تنهن ڪري، مشهور پروٽوڪول اهي آهن جيڪي پهريان پيغام جي ڊيگهه بائيٽ ۾ موڪليندا آهن. مثال طور، باڪس کان ٻاهر Python وٽ xdrlib آهي، جيڪا توهان کي ساڳي فارميٽ سان ڪم ڪرڻ جي اجازت ڏئي ٿي XDR.
اسان TCP پڙهڻ سان صحيح ۽ موثر طريقي سان ڪم نه ڪنداسين - اسان ڪوڊ کي آسان ڪنداسين. اسان ساکٽ مان ڊيٽا کي اڻ لامحدود لوپ ۾ پڙهون ٿا جيستائين اسان مڪمل پيغام کي ڊيڪوڊ نه ڪريون. JSON سان XML پڻ استعمال ڪري سگھجي ٿو فارميٽ طور ھن طريقي جي لاءِ. پر جڏهن ڪرپٽوگرافي شامل ڪئي ويندي، ڊيٽا کي سائن ان ۽ تصديق ڪرڻي پوندي - ۽ ان لاءِ بائيٽ جي بائيٽ جي ضرورت پوندي شين جي هڪجهڙائي واري نمائندگي، جيڪا JSON/XML مهيا نه ڪندي آهي (ڊمپ جا نتيجا مختلف ٿي سگهن ٿا).
XDR هن ڪم لاءِ موزون آهي، تنهن هوندي به مان ASN.1 چونڊيو DER انڪوڊنگ ۽ پيڊراسن لائبريري، ڇو ته اسان وٽ هٿ تي اعلي سطحي شيون هونديون جن سان اهو اڪثر ڪري وڌيڪ خوشگوار ۽ ڪم ڪرڻ آسان آهي. اسڪيم کان سواءِ بين ڪوڊ, ميسيج پيڪ يا CBOR، ASN.1 خودڪار طريقي سان ڊيٽا کي سخت ڪوڊ ٿيل اسڪيما جي خلاف چيڪ ڪندو.
اسان چيڪ ڪريون ٿا ته انٽرويو ڪندڙ جو نالو اسان کي معلوم آهي. جيڪڏهن نه، ته پوء اسان ڪنيڪشن ٽوڙيو. اسان چيڪ ڪريون ٿا ته ڇا اسان اڳ ۾ ئي هن سان رابطو قائم ڪيو آهي (ڳالهائيندڙ ٻيهر اسان سان ڳنڍڻ جو حڪم ڏنو) ۽ ان کي بند ڪريو. IN_QUEUES قطار پيغام جي متن سان گڏ Python strings رکي ٿي، پر None جي ھڪڙي خاص قدر آھي جيڪا msg_sender coroutine کي ڪم ڪرڻ بند ڪرڻ لاءِ اشارو ڪري ٿي ته جيئن اھو پنھنجي ليکڪ جي باري ۾ وساري وڃي جيڪا ورثي واري TCP ڪنيڪشن سان لاڳاپيل آھي.
159 msg_handshake = msg.value
160 peer_name = str(msg_handshake["peerName"])
161 if peer_name not in THEIR_NAMES:
162 logging.warning("unknown peer name: %s", peer_name)
163 writer.close()
164 return
165 logging.info("%s: session established: %s", _id, peer_name)
166 # Run text message sender, initialize transport decoder {{{
167 peer_alive = PEER_ALIVES.pop(peer_name, None)
168 if peer_alive is not None:
169 peer_alive.close()
170 await IN_QUEUES[peer_name].put(None)
171 PEER_ALIVES[peer_name] = writer
172 asyncio.ensure_future(msg_sender(peer_name, writer))
173 # }}}
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 coroutine (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()
جواب ڏيڻ وارو initiator سان ملندڙ جلندڙ آهي ۽ سڀني ساڳين عملن کي آئيني ڪري ٿو، پر پيغام پڙهڻ جو لامحدود لوپ فوري طور تي شروع ٿئي ٿو، سادگي لاءِ. في الحال، هينڊ شيڪ پروٽوڪول هر پاسي کان هڪ پيغام موڪلي ٿو، پر مستقبل ۾ ڪنيڪشن جي شروعات ڪندڙ کان ٻه هوندا، جنهن کان پوء ٽيڪسٽ پيغام فوري طور تي موڪليا ويندا.
اهو اسان جي مواصلات کي محفوظ ڪرڻ جو وقت آهي. سيڪيورٽي مان اسان جو مطلب ڇا آهي ۽ اسان ڇا ٿا چاهيون:
منتقل ٿيل پيغامن جي رازداري؛
منتقل ٿيل پيغامن جي صداقت ۽ سالميت - انهن جي تبديلين کي ڳولڻ گهرجي؛
ريپلي حملن جي خلاف تحفظ - غائب يا بار بار پيغامن جي حقيقت کي ضرور معلوم ڪيو وڃي (۽ اسان ڪنيڪشن کي ختم ڪرڻ جو فيصلو ڪيو)؛
اڳ ۾ داخل ٿيل عوامي چابيون استعمال ڪندي ڳالهائيندڙن جي سڃاڻپ ۽ تصديق - اسان اڳ ۾ ئي فيصلو ڪيو آهي ته اسان هڪ دوست کان دوست نيٽ ورڪ ٺاهي رهيا آهيون. صرف تصديق کان پوءِ اسان سمجھنداسين ته اسان ڪنھن سان ڳالھائي رھيا آھيون؛
دستياب مڪمل اڳڀرائي رازداري پراپرٽيز (PFS) - اسان جي ڊگھي عرصي واري سائننگ ڪيچ کي سمجھوتو ڪرڻ سان اڳئين خط و ڪتابت کي پڙھڻ جي صلاحيت نه ھجڻ گھرجي. رڪارڊنگ روڪيل ٽرئفڪ بيڪار ٿي وڃي ٿي؛
صرف هڪ TCP سيشن جي اندر پيغامن جي صحيحيت (ٽرانسپورٽ ۽ هٿ ملائڻ) جي صحيحيت. ٻئي سيشن مان صحيح طور تي دستخط ٿيل / تصديق ٿيل پيغام داخل ڪرڻ (جيتوڻيڪ ساڳي گفتگو ڪندڙ سان) ممڪن نه هجڻ گهرجي؛
هڪ غير فعال مبصر کي نه ڏسڻ گهرجي صارف جي سڃاڻپ ڪندڙ، منتقل ٿيل ڊگهي-رهندڙ عوامي چابيون، يا انهن مان هيش. غير فعال مبصر کان هڪ خاص گمنام.
حيرت انگيز طور تي، تقريبن هرڪو چاهي ٿو ته هي گهٽ ۾ گهٽ ڪنهن به هٿ ملائڻ واري پروٽوڪول ۾، ۽ مٿين مان تمام ٿورڙو آخرڪار "گهر جي" پروٽوڪول لاء ملي ٿو. هاڻي اسان ڪا نئين شيءِ ايجاد نه ڪنداسين. مان ضرور استعمال ڪرڻ جي سفارش ڪندس شور فريم ورڪ پروٽوڪول ٺاهڻ لاءِ، پر اچو ته ڪجھ سادو چونڊيو.
ٻه مشهور پروٽوڪول آهن:
TLS - هڪ تمام پيچيده پروٽوڪول جنهن جي ڊگهي تاريخ جي بگن، جهيڙن، ڪمزورين، خراب سوچ، پيچيدگي ۽ خاميون آهن (جڏهن ته، هن جو TLS 1.3 سان ٿورو تعلق آهي). پر اسان ان تي غور نه ڪندا آهيون ڇاڪاڻ ته اهو وڌيڪ پيچيده آهي.
IPsec с آئي - سنگين cryptographic مسئلا نه آهن، جيتوڻيڪ اهي پڻ سادي نه آهن. جيڪڏهن توهان IKEv1 ۽ IKEv2 بابت پڙهو ٿا، پوء انهن جو ذريعو آهي ايس ايس, ISO/IEC IS 9798-3 ۽ SIGMA (SIGn-and-MAc) پروٽوڪول - هڪ شام ۾ لاڳو ڪرڻ لاءِ ڪافي سادو.
SIGMA بابت ڇا سٺو آهي، جيئن STS/ISO پروٽوڪول جي ترقي ۾ جديد ڪڙي؟ اهو اسان جي سڀني ضرورتن کي پورو ڪري ٿو (بشمول "لڪائڻ وارو" مداخلت ڪندڙ سڃاڻپ ڪندڙ) ۽ ڪو به ڄاڻ نه آهي cryptographic مسئلا. اهو گهٽ ۾ گهٽ آهي - پروٽوڪول پيغام مان گهٽ ۾ گهٽ هڪ عنصر کي هٽائڻ ان جي عدم تحفظ جو سبب بڻجندو.
اچو ته سڀ کان آسان گھر جي ترقي يافته پروٽوڪول کان SIGMA ڏانهن وڃو. سڀ کان وڌيڪ بنيادي آپريشن جنهن ۾ اسان کي دلچسپي آهي اهم معاهدو: هڪ فنڪشن جيڪو ٻنهي شرڪت ڪندڙن کي هڪجهڙائي ڏي ٿو، جنهن کي استعمال ڪري سگهجي ٿو سميٽري ڪيئي طور. تفصيل ۾ وڃڻ کان سواءِ: هر هڪ پارٽي هڪ عارضي (صرف هڪ سيشن ۾ استعمال ٿيل) اهم جوڙو (عوامي ۽ خانگي چاٻيون) ٺاهي ٿي، عوامي چابيون مٽائي، معاهدي جي فنڪشن کي سڏين، جنهن جي ان پٽ تي اهي پنهنجي نجي ڪي ۽ عوام کي پاس ڪن. ڳالهائيندڙ جي ڪنجي.
اهڙو دستخط ڪم نه ڪندو، ڇاڪاڻ ته اهو ڪنهن مخصوص سيشن سان ڳنڍيل ناهي. اهڙا پيغام ٻين شرڪت ڪندڙن سان گڏ سيشن لاء پڻ "مناسب" آهن. سڄو احوال سبسڪرائب ڪرڻ گهرجي. هي اسان کي مجبور ڪري ٿو ته A کان ٻيو پيغام پڻ شامل ڪريو.
اضافي طور تي، اهو ضروري آهي ته توهان جي پنهنجي سڃاڻپ ڪندڙ کي دستخط جي تحت شامل ڪيو وڃي، ڇاڪاڻ ته ٻي صورت ۾ اسان IdXXX کي تبديل ڪري سگهون ٿا ۽ پيغام کي ٻيهر سائن ان ڪري سگھون ٿا ڪنهن ٻئي ڄاڻايل ڳالهائيندڙ جي ڪنجي سان. کي روڪڻ لاءِ عڪس حملا, اهو ضروري آهي ته دستخط هيٺ عناصر واضح طور تي بيان ڪيل جڳهن ۾ انهن جي معني مطابق آهن: جيڪڏهن A نشانيون (PubA، PubB)، پوء B کي لازمي آهي (PubB، PubA). هي پڻ سيريل ٿيل ڊيٽا جي جوڙجڪ ۽ فارميٽ کي چونڊڻ جي اهميت کي ٻڌائي ٿو. مثال طور، ASN.1 DER انڪوڊنگ ۾ سيٽون ترتيب ڏنل آھن: SET OF(PubA, PubB) SET OF(PubB, PubA) سان هڪجهڙائي رکن ٿا.
هڪ اصلاح جي طور تي، ڪجهه شايد انهن جي عارضي ڪنجين کي ٻيهر استعمال ڪرڻ چاهيندا (جيڪو، يقينا، PFS لاء بدقسمتي آهي). مثال طور، اسان هڪ اهم جوڙو ٺاهيو، ڳنڍڻ جي ڪوشش ڪئي، پر TCP موجود نه هو يا پروٽوڪول جي وچ ۾ ڪٿي مداخلت ڪئي وئي. اهو هڪ نئين جوڙي تي ضايع ٿيل اينٽروپي ۽ پروسيسر وسيلن کي برباد ڪرڻ لاء شرم آهي. تنهن ڪري، اسين نام نهاد ڪوڪي متعارف ڪرائينداسين - هڪ pseudo-random value جيڪا امڪاني بي ترتيب ريپلي حملن جي خلاف حفاظت ڪندي جڏهن عارضي پبلڪ ڪيز کي ٻيهر استعمال ڪندي. ڪوڪيز ۽ ephemeral عوامي ڪيئي جي وچ ۾ پابند ٿيڻ جي ڪري، مخالف ڌر جي عوامي ڪنجي کي دستخط مان خارج ڪري سگھجي ٿو غير ضروري طور.
آخرڪار، اسان هڪ غير فعال مبصر کان اسان جي گفتگو جي ڀائيوارن جي رازداري حاصل ڪرڻ چاهيون ٿا. ائين ڪرڻ لاءِ، SIGMA تجويز ڪري ٿو ته پھرين عارضي ڪنجين جي تبادلي ۽ ھڪڙي عام ڪنجي کي ٺاھيو جنھن تي پيغامن جي تصديق ۽ سڃاڻپ ڪرڻ لاءِ انڪرپٽ ڪجي. SIGMA ٻن اختيارن کي بيان ڪري ٿو:
SIGMA-I - شروعات ڪندڙ کي فعال حملن کان بچائيندو آهي، جوابدار کي غير فعال حملن کان: شروعات ڪندڙ جوابدار کي تصديق ڪندو آهي ۽ جيڪڏهن ڪا شيءِ نه ملندي آهي، ته پوءِ ان جي سڃاڻپ نه ڪندو آهي. مدعا پنهنجي سڃاڻپ ڏئي ٿو جيڪڏهن هڪ فعال پروٽوڪول هن سان شروع ڪيو ويو آهي. غير فعال مبصر ڪجهه به نه سکندو آهي؛
SIGMA-R - جوابدار کي فعال حملن کان بچائيندو آهي، شروعات ڪندڙ کي غير فعال حملن کان. هر شيء بلڪل سامهون آهي، پر هن پروٽوڪول ۾ چار هٿ ملائڻ وارا پيغام اڳ ۾ ئي منتقل ڪيا ويا آهن.
اسان چونڊون ٿا SIGMA-I جيئن ته اهو وڌيڪ ساڳيو آهي جيڪو اسان ڪلائنٽ-سرور کان واقف شين مان توقع ڪندا آهيون: ڪلائنٽ کي صرف تصديق ٿيل سرور جي سڃاڻپ آهي، ۽ هرڪو اڳ ۾ ئي سرور کي ڄاڻي ٿو. ان سان گڏ ان کي لاڳو ڪرڻ آسان آهي گهٽ هٿ ملائڻ واري پيغامن جي ڪري. پروٽوڪول ۾ جيڪو اسان شامل ڪيو آهي اهو پيغام جي حصي کي انڪرپٽ ڪرڻ ۽ سڃاڻپ ڪندڙ A کي آخري پيغام جي انڪريپٽ ٿيل حصي ڏانهن منتقل ڪرڻ آهي:
CMAC کي MAC طور استعمال ڪيو ويندو آھي. تخنيقي طور تي، هي هڪ بلاڪ سيفر جي آپريشن جو هڪ خاص طريقو آهي، جيڪو GOST R 34.13-2015 ۾ بيان ڪيو ويو آهي. هن موڊ لاءِ هڪ انڪرپشن فنڪشن جي طور تي - گراهپر (34.12-2015).
هن جي عوامي ڪنجي جو هيش استعمال ڪيو ويندو آهي interlocutor جي سڃاڻپ ڪندڙ. هڪ hash طور استعمال ڪيو اسٽريبوگ-256 (34.11/2012/256 XNUMX بٽ).
هٿ ملائڻ کان پوءِ، اسان هڪ گڏيل چاٻي تي اتفاق ڪنداسين. اسان ان کي استعمال ڪري سگھون ٿا ٽرانسپورٽ پيغامن جي تصديق ٿيل انڪرپشن لاءِ. هي حصو تمام سادو آهي ۽ غلطي ڪرڻ ڏکيو آهي: اسان پيغام جي ڪائونٽر کي وڌايو، پيغام کي انڪرپٽ ڪريو، تصديق ڪريو (MAC) انسداد ۽ ciphertext، موڪليو. جڏهن هڪ پيغام ملي رهيو آهي، اسان چيڪ ڪريون ٿا ته ڪائونٽر وٽ متوقع قدر آهي، ڪاؤنٽر سان ciphertext جي تصديق ڪريو، ۽ ان کي رد ڪري ڇڏيو. هينڊ شيڪ پيغامن، ٽرانسپورٽ جا پيغام، ۽ انهن کي ڪيئن تصديق ڪرڻ لاءِ مون کي ڪهڙي ڪنجي استعمال ڪرڻ گهرجي؟ انهن سڀني ڪمن لاءِ هڪ ڪنجي استعمال ڪرڻ خطرناڪ ۽ بي عقل آهي. اهو ضروري آهي ته خاص فنڪشن استعمال ڪندي ڪنجيون ٺاهي ڪي ڊي ايف (اهم نڪتل فنڪشن). ٻيهر، اچو ته وار نه ورهايون ۽ ڪجهه ايجاد ڪيون: HKDF ڊگھي ڄاڻ ڏني وئي آھي، چڱي طرح تحقيق ڪئي وئي آھي ۽ ڪو به معلوم مسئلو نه آھي. بدقسمتي سان، اصلي Python لائبريري ۾ هي فنڪشن ناهي، تنهنڪري اسان استعمال ڪريون ٿا hkdf پلاسٽڪ جي ٿيلھي. HKDF اندروني طور استعمال ڪري ٿو ايڇ ايم اي سي، جيڪو موڙ ۾ هڪ hash فنڪشن استعمال ڪري ٿو. وڪيپيڊيا پيج تي پٿون ۾ مثال لاڳو ڪرڻ لاءِ صرف چند لائينون ڪوڊ لڳن ٿيون. جيئن ته 34.10/2012/256 جي صورت ۾، اسان استعمال ڪنداسين Stribog-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-bit سائيز 256-bit elliptic curves لاءِ. PyGOST بائيٽ جي سيٽ سان ڪم نٿو ڪري، پر ان سان وڏو انگ، تنهنڪري اسان جي خانگي ڪي (urandom(32)) کي gost3410.prv_unmarshal() استعمال ڪندي نمبر ۾ تبديل ڪرڻ جي ضرورت آهي. عوامي ڪيچي مقرر ڪئي وئي آهي ذاتي ڪيئي مان gost3410.public_key() استعمال ڪندي. عوامي ڪي 34.10 ٻه وڏا انگ آهن جن کي بائيٽ جي ترتيب ۾ تبديل ڪرڻ جي ضرورت آهي اسٽوريج ۽ ٽرانسميشن جي آسانيءَ لاءِ gost3410.pub_marshal().
JSON فائل پڙهڻ کان پوء، عوامي چابيون مطابق مطابق واپس تبديل ٿيڻ جي ضرورت آهي gost3410.pub_unmarshal(). جيئن ته اسان کي عوامي ڪيئي مان هڪ هيش جي صورت ۾ ڳالهائيندڙن جي سڃاڻپ ڪندڙ وصول ڪنداسين، انهن کي فوري طور تي اڳ ۾ حساب ڪري سگهجي ٿو ۽ جلدي ڳولا لاء لغت ۾ رکيل آهي. Stribog-256 hash is gost34112012256.GOST34112012256()، جيڪو مڪمل طور تي هيش افعال جي hashlib انٽرفيس کي پورو ڪري ٿو.
شروعاتي ڪورين ڪيئن تبديل ٿي وئي آهي؟ هينڊ شيڪ اسڪيم جي مطابق سڀ ڪجهه آهي: اسان هڪ ڪوڪي ٺاهيندا آهيون (128-bit ڪافي آهي)، هڪ ephemeral key pair 34.10، جيڪو VKO اهم معاهدي جي فنڪشن لاءِ استعمال ڪيو ويندو.
TBS جي ڍانچي تي دستخط جي تصديق ڪئي وئي آهي، جنهن ۾ ٻنهي ڌرين جي ڪوڪيز ۽ مخالف ڌر جي عوامي عارضي ڪنجي شامل آهي. دستخط جي تصديق ڪئي وئي آهي ڊگهي-رهندڙ دستخط جي ڪنجي ذريعي.
جيئن مون مٿي لکيو، 34.13/2015/XNUMX مختلف بيان ڪري ٿو بلاڪ سيفر آپريٽنگ موڊس کان وٺي 34.12/2015/3413. انھن مان ھڪڙو موڊ آھي تقليد داخل ڪرڻ ۽ ميڪ حساب ڪرڻ لاء. PyGOST ۾ هي gost34.12.mac(). ھن موڊ کي انڪرپشن فنڪشن پاس ڪرڻ جي ضرورت آھي (ڊيٽا جي ھڪڙي بلاڪ کي وصول ڪرڻ ۽ واپس ڪرڻ)، انڪريپشن بلاڪ جي سائيز ۽ حقيقت ۾، ڊيٽا پاڻ کي. توهان ڇو نٿا ڪري سگهو انڪرپشن بلاڪ جي سائيز کي هارڊ ڪوڊ؟ 2015/128/64 بيان ڪري ٿو نه رڳو XNUMX-bit Grasshopper cipher، پر XNUMX-bit پڻ ميگما - ھڪڙو ٿورڙو تبديل ٿيل GOST 28147-89، جيڪو واپس KGB ۾ ٺاھيو ويو آھي ۽ اڃا تائين اعليٰ ترين حفاظتي حدن مان ھڪڙو آھي.
Kuznechik جي شروعات gost.3412.GOST3412Kuznechik(key) کي ڪال ڪندي ڪئي وئي آهي ۽ .encrypt()/.decrypt() طريقن سان هڪ شئي واپس ڪري ٿي جيڪا 34.13 افعال ڏانهن منتقل ڪرڻ لاءِ مناسب آهي. MAC جو حساب ھيٺ ڏنل آھي: gost3413.mac(GOST3412Kuznechik(key).encrypt, KUZNECHIK_BLOCKSIZE, ciphertext). ڳڻپيوڪر ۽ وصول ڪيل MAC جو مقابلو ڪرڻ لاءِ، توهان بائيٽ اسٽرنگ جي معمولي مقابلي (==) کي استعمال نٿا ڪري سگهو، ڇو ته هي آپريشن موازن جو وقت لڪي ٿو، جيڪو عام صورت ۾، موتمار نقصانن جو سبب بڻجي سگهي ٿو جهڙوڪ حيوان TLS تي حملا. پٿون وٽ ھڪڙو خاص فنڪشن آھي، hmac.compare_digest، ھن لاء.
بلاڪ سيفر فنڪشن صرف ڊيٽا جي هڪ بلاڪ کي انڪرپٽ ڪري سگهي ٿو. وڏي تعداد لاءِ، ۽ ان کان به گھڻا ڊگھا نه، ان کي استعمال ڪرڻ ضروري آھي انڪريشن موڊ. 34.13-2015 ھيٺ ڏنل بيان ڪري ٿو: ECB، CTR، OFB، CBC، CFB. هر هڪ کي پنهنجي قابل قبول علائقن جي درخواست ۽ خاصيتون آهن. بدقسمتي سان، اسان اڃا تائين معياري نه ڪيو آهي تصديق ٿيل انڪرپشن موڊس (جهڙوڪ CCM، OCB، GCM ۽ جهڙوڪ) - اسان کي مجبور ڪيو وڃي ٿو ته گهٽ ۾ گهٽ MAC پاڻ کي شامل ڪريو. مان چونڊيو جوابي موڊ (CTR): ان کي بلاڪ جي سائيز ۾ پيڊنگ جي ضرورت ناهي، متوازي ٿي سگهي ٿو، صرف انڪرپشن فنڪشن استعمال ڪري ٿو، محفوظ طور تي وڏي تعداد ۾ پيغامن کي انڪرپٽ ڪرڻ لاءِ استعمال ڪري سگهجي ٿو (سي بي سي جي برعڪس، جنهن ۾ نسبتا جلدي ٽڪراءُ آهي).
جهڙوڪ .mac()، .ctr() ساڳيو انپٽ وٺندو آهي: ciphertext = gost3413.ctr(GOST3412Kuznechik(key).encrypt، KUZNECHIK_BLOCKSIZE، plaintext، iv). اهو ضروري آهي ته هڪ شروعاتي ویکٹر جي وضاحت ڪئي وڃي جيڪا انڪريشن بلاڪ جي اڌ ڊگھائي آهي. جيڪڏهن اسان جي انڪرپشن ڪيئي استعمال ٿئي ٿي صرف هڪ پيغام کي انڪرپٽ ڪرڻ لاءِ (جيتوڻيڪ ڪيترن ئي بلاڪن کان)، پوءِ صفر شروعاتي ویکٹر مقرر ڪرڻ محفوظ آهي. هٿ ملائڻ واري پيغامن کي انڪرپٽ ڪرڻ لاءِ، اسين هر دفعي هڪ الڳ چيڪ استعمال ڪندا آهيون.
دستخط جي تصديق ڪرڻ gost3410.verify() معمولي ڳالهه آهي: اسان بيضوي وکر کي پاس ڪريون ٿا جنهن جي اندر اسين ڪم ڪري رهيا آهيون (اسان صرف ان کي پنهنجي GOSTIM پروٽوڪول ۾ رڪارڊ ڪريون ٿا)، دستخط ڪندڙ جي عوامي ڪنجي (نه وساريو ته اهو ٻن جو ٽڪر هجڻ گهرجي. وڏا انگ، ۽ نه بائيٽ اسٽرنگ)، 34.11/2012/XNUMX هيش ۽ دستخط پاڻ.
اڳيون، شروعات ڪندڙ ۾ اسان تيار ڪريون ٿا ۽ هٿ ملائڻ جو پيغام موڪليو handshake2 تي، ساڳيو عمل انجام ڏيو جيئن اسان تصديق جي دوران ڪيو، صرف سميٽري طور: چيڪ ڪرڻ بدران اسان جي چاٻين تي دستخط ڪرڻ، وغيره.
GOSTIM خاص طور تي تعليمي مقصدن لاءِ استعمال ڪرڻ جو ارادو ڪيو ويو آهي (جيئن ته اهو ٽيسٽن ۾ شامل نه آهي، گهٽ ۾ گهٽ)! پروگرام جو سورس ڪوڊ ڊائون لوڊ ڪري سگھجي ٿو هتي (Стрибог-256 хэш: 995bbd368c04e50a481d138c5fa2e43ec7c89bc77743ba8dbabee1fde45de120). Как и все мои проекты, типа GoGOST, پيڊراسن, اين اين پي سي, GoVPN، GOSTIM مڪمل طور تي آهي مفت سافٽ ويئر، ورهايل شرطن ۾ جي پي ايل 3 +.