गोल्फ एंड-टू-एंड एन्क्रिप्शन


16

यह चुनौती पहले जवाब देने के लिए 200 अंकों का इनाम देती है और कम से कम 3 दिनों तक नाबाद रहती है। User3080953 द्वारा दावा किया गया ।

एंड-टू-एंड एन्क्रिप्शन के बारे में हाल ही में बहुत सी बात हुई है, और कंपनियों पर अपने उत्पादों से इसे हटाने का दबाव है। मुझे उस के अधिकारों और गलतताओं में कोई दिलचस्पी नहीं है, लेकिन मैंने सोचा: कोड कितना छोटा हो सकता है जो किसी कंपनी को इसका उपयोग न करने के लिए दबाव डाले?

यहां चुनौती दो नेटवर्क सिस्टम के बीच एक डिफी हेलमैन कुंजी विनिमय को लागू करना है , फिर उपयोगकर्ताओं को उत्पन्न सममित कुंजी का उपयोग करके आगे-पीछे संवाद करने की अनुमति देता है। इस कार्य के उद्देश्य के लिए, किसी अन्य सुरक्षा की आवश्यकता नहीं है (उदाहरण के लिए कुंजी को चक्रित करने, पहचान सत्यापित करने, DoS से सुरक्षा करना, आदि) की आवश्यकता नहीं है और आप एक खुला इंटरनेट मान सकते हैं (आपके द्वारा सुने जाने वाले सभी पोर्ट सभी के लिए उपलब्ध हैं)। बिल्डिंस के उपयोग की अनुमति और प्रोत्साहित किया जाता है!

आप दो में से एक मॉडल चुन सकते हैं:

  • एक सर्वर और एक क्लाइंट: क्लाइंट सर्वर से कनेक्ट होता है, फिर सर्वर या क्लाइंट दूसरे को संदेश भेज सकते हैं। दोनों के बीच तीसरे पक्ष के संदेश पढ़ने में असमर्थ होना चाहिए। एक उदाहरण प्रवाह हो सकता है:
    1. उपयोगकर्ता ए सर्वर लॉन्च करता है
    2. उपयोगकर्ता बी क्लाइंट लॉन्च करता है और इसे उपयोगकर्ता ए के सर्वर (जैसे आईपी / पोर्ट के माध्यम से) को निर्देशित करता है, प्रोग्राम एक कनेक्शन खोलता है
    3. उपयोगकर्ता ए के कार्यक्रम कनेक्शन को स्वीकार करता है (वैकल्पिक रूप से उपयोगकर्ता पहले सहमति के लिए पूछ रहा है)
    4. उपयोगकर्ता बी का कार्यक्रम एक डीएच सीक्रेट की पीढ़ी शुरू करता है, और आवश्यक डेटा (सार्वजनिक कुंजी, प्राइम, जनरेटर, कुछ और आपके कार्यान्वयन की आवश्यकता के लिए) उपयोगकर्ता A को भेजता है
    5. उपयोगकर्ता ए का कार्यक्रम साझा किए गए रहस्य को पूरा करने के लिए भेजे गए डेटा का उपयोग करता है और उपयोगकर्ता बी को आवश्यक डेटा (सार्वजनिक कुंजी) वापस भेजता है। इस बिंदु से, उपयोगकर्ता ए संदेश (जैसे स्टड के माध्यम से) दर्ज कर सकता है जिसे एन्क्रिप्ट किया जाएगा और उपयोगकर्ता को भेजा जाएगा बी (उदाहरण के लिए stdout)।
    6. उपयोगकर्ता बी का कार्यक्रम साझा रहस्य की पीढ़ी को पूरा करता है। इस बिंदु से, उपयोगकर्ता B उपयोगकर्ता A को संदेश भेज सकता है।
  • या: एक सर्वर जिसमें दो क्लाइंट जुड़े हैं: प्रत्येक क्लाइंट सर्वर से बात करता है, जो दूसरे क्लाइंट को अपना संदेश भेज देता है। स्वयं सर्वर (और बीच में कोई भी तृतीय-पक्ष) संदेशों को पढ़ने में असमर्थ होना चाहिए। प्रारंभिक कनेक्शन के अलावा, प्रक्रिया वही है जो पहले विकल्प में वर्णित है।

विस्तृत नियम:

  • आप एक कार्यक्रम, या कई कार्यक्रम (जैसे सर्वर और क्लाइंट) प्रदान कर सकते हैं। आपका स्कोर सभी कार्यक्रमों में कुल कोड आकार है।
  • आपका कार्यक्रम सैद्धांतिक रूप से एक नेटवर्क पर संचार करने में सक्षम होना चाहिए (लेकिन परीक्षण के लिए, लोकलहोस्ट ठीक है)। यदि आपकी पसंद की भाषा नेटवर्किंग का समर्थन नहीं करती है, तो आप इसे किसी ऐसी चीज़ के साथ जोड़ सकते हैं (जैसे शेल स्क्रिप्ट); इस स्थिति में आपका स्कोर उपयोग की जाने वाली सभी भाषाओं में कुल कोड आकार है।
  • डिफी हेलमैन प्रमुख पीढ़ी हार्ड-कोडित "पी" और "जी" मूल्यों का उपयोग कर सकती है।
  • उत्पन्न साझा कुंजी कम से कम 1024 बिट होनी चाहिए।
  • एक बार कुंजी साझा करने के बाद, सममित-कुंजी एन्क्रिप्शन का विकल्प आप पर निर्भर है, लेकिन आपको ऐसी विधि नहीं अपनानी चाहिए, जो वर्तमान में इसके खिलाफ एक व्यावहारिक हमला करने के लिए जानी जाती है (उदाहरण के लिए एक सीज़र शिफ्ट कुंजी के ज्ञान के बिना रिवर्स करने के लिए तुच्छ है )। उदाहरण के लिए अनुमत एल्गोरिदम:
    • एईएस (कोई भी महत्वपूर्ण आकार)
    • RC4 (सैद्धांतिक रूप से टूटा हुआ है, लेकिन कोई भी व्यावहारिक हमला नहीं है जिसका मैं उल्लेख कर सकता हूं, इसलिए यह यहां स्वीकार्य है)
  • उपयोगकर्ता A और B दोनों को एक-दूसरे को (दो-तरफ़ा संचार) संदेश भेजने में सक्षम होना चाहिए (जैसे स्टड से लाइनें पढ़ना, लगातार संकेत देना, या एक बटन दबाने जैसी घटनाएं)। यदि यह आसान हो जाता है, तो आप एक वैकल्पिक वार्तालाप मान सकते हैं (जैसे कि उपयोगकर्ता द्वारा संदेश भेजे जाने के बाद, उन्हें अपना अगला संदेश भेजने से पहले प्रतिक्रिया की प्रतीक्षा करनी चाहिए)
  • भाषा बिल्डरों को अनुमति दी जाती है (यदि वे पहले से ही समर्थित हैं तो अपने स्वयं के क्रिप्टोग्राफिक या नेटवर्किंग विधियों को लिखने की आवश्यकता नहीं है)।
  • अंतर्निहित संचार प्रारूप आपके ऊपर है।
  • ऊपर दिए गए संचार चरण एक उदाहरण हैं, लेकिन आपको उनका पालन करने की आवश्यकता नहीं है (जब तक आवश्यक जानकारी साझा नहीं की जाती है, और कोई भी मध्य-पुरुष साझा कुंजी या संदेशों की गणना करने में सक्षम नहीं हैं)
  • यदि आपके सर्वर से जुड़ने के लिए आवश्यक विवरण पहले से ज्ञात नहीं हैं (जैसे कि यदि यह यादृच्छिक पोर्ट पर सुनता है), तो इन विवरणों को मुद्रित किया जाना चाहिए। आप मान सकते हैं कि मशीन का आईपी पता ज्ञात है।
  • त्रुटि से निपटने (जैसे अमान्य पते, खो कनेक्शन, आदि) की आवश्यकता नहीं है।
  • चुनौती कोड गोल्फ है, इसलिए बाइट्स में सबसे छोटा कोड जीत जाता है।

क्या हार्डकोडिंग pऔर gअनुमति है?
केवल

@ ASCII- केवल मैं जो बता सकता हूं, हार्ड-कोडिंग अच्छी गुणवत्ता वाले पी एंड जी मूल्यों को ठीक माना जाता है (जब तक कि डेवलपर दुर्भावनापूर्ण रूप से विशेष हमलों के लिए कमजोर होने के लिए ज्ञात मूल्यों का उपयोग नहीं करता है)। तो इस चुनौती के लिए यह ठीक है (जब तक परिणामी रहस्य कम से कम 1024 बिट्स हो)
डेव

जवाबों:


3

Node.js ( 372 423 + 94 = 517 513 बाइट्स)

golfed

लाइनब्रीक्स को "पठनीयता" के लिए जोड़ा गया।

चैट.जेएस ( 423 419 बाइट्स)

कोई रेखा नहीं टूटती

[n,c,p]=["net","crypto","process"].map(require);r="rc4",a="create",h="DiffieHellman",z="pipe",w="write",o=128,g=p.argv;s=e=d=0,y=c[a+h](8*o),k=y.generateKeys();v=n.connect(9,g[2],_=>{g[3]&&(v[w](y.getPrime()),v[w](k));v.on("data",b=>{s||(g[3]||(y=c[a+h](b.slice(0,o)),k=y.generateKeys(),v[w](k),b=b.slice(o)),s=y.computeSecret(b),e=c[a+"Cipher"](r,s),p.stdin[z](e)[z](v),d=c[a+"Decipher"](r,s),v[z](d)[z](p.stdout))})})

कतार टूट जाती है

[n,c,p]=["net","crypto","process"].map(require);
r="rc4",a="create",h="DiffieHellman",z="pipe",w="write",o=128,g=p.argv;
s=e=d=0,y=c[a+h](8*o),k=y.generateKeys();
v=n.connect(9,g[2],_=>{g[3]&&(v[w](y.getPrime()),v[w](k));
v.on("data",b=>{s||(g[3]||(y=c[a+h](b.slice(0,o)),k=y.generateKeys(),
v[w](k),b=b.slice(o)),s=y.computeSecret(b),e=c[a+"Cipher"](r,s),p.stdin[z](e)[z](v)
,d=c[a+"Decipher"](r,s),v[z](d)[z](p.stdout))})})

echo_server.js (94 बाइट्स)

c=[],require("net").createServer(a=>{c.forEach(b=>{a.pipe(b),b.pipe(a)});c.push(a)}).listen(9);

Ungolfed

नोड में अंतर्निहित नेटवर्किंग और क्रिप्टो क्षमताएं हैं। यह नेटवर्किंग के लिए टीसीपी का उपयोग करता है (क्योंकि यह HTTP के लिए नोड के इंटरफेस की तुलना में सरल है, और यह अच्छी तरह से धाराओं के साथ खेलता है)।

मैं ब्लॉक आकारों से निपटने के लिए एईएस के बजाय एक धारा सिफर (आरसी 4) का उपयोग करता हूं। विकिपीडिया को लगता है कि यह असुरक्षित हो सकता है, इसलिए यदि किसी के पास ऐसी कोई अंतर्दृष्टि है जिसमें सिफर पसंद किए जाते हैं, तो यह बहुत अच्छा होगा।

गूंज सर्वर चलाने node echo_server.jsजो बंदरगाह 9. रन के साथ इस कार्यक्रम के दो उदाहरणों पर सुनने जाएगा node chat.js <server IP>और node chat.js <server IP> 1(अंतिम तर्क सिर्फ सेट एक एक प्रमुख भेजता है)। प्रत्येक उदाहरण इको सर्वर से जुड़ता है। पहला संदेश प्रमुख पीढ़ी को संभालता है, और बाद के संदेश धारा सिफर का उपयोग करते हैं।

इको सर्वर सिर्फ मूल को छोड़कर सभी जुड़े हुए क्लाइंट को सब कुछ वापस भेज देता है।

ग्राहक

var net = require('net');
var crypto = require('crypto');
var process = require('process');
let [serverIP, first] = process.argv.slice(2);

var keys = crypto.createDiffieHellman(1024); // DH key exchange
var prime = keys.getPrime();
var k = keys.generateKeys();
var secret;

var cipher; // symmetric cipher
var decipher;

// broadcast prime
server = net.connect(9, serverIP, () => {
    console.log('connect')
    if(first) {
        server.write(prime);
        console.log('prime length', prime.length)
        server.write(k);
    }

    server.on('data', x => {
        if(!secret) { // if we still need to get the ciphers
            if(!first) { // generate a key with the received prime
                keys = crypto.createDiffieHellman(x.slice(0,128)); // separate prime and key
                k = keys.generateKeys();
                server.write(k);
                x = x.slice(128)
            }

            // generate the secret
            console.log('length x', x.length);
            secret = keys.computeSecret(x);
            console.log('secret', secret, secret.length) // verify that secret key is the same
            cipher = crypto.createCipher('rc4', secret);
            process.stdin.pipe(cipher).pipe(server);
            decipher = crypto.createDecipher('rc4', secret);
            server.pipe(decipher).pipe(process.stdout);
        }
        else {
            console.log('sent text ', x.toString()) // verify that text is sent encrypted
        }
    });
})

इको सर्वर

var net = require('net');
clients = [];

net.createServer(socket => {
    clients.forEach(c=>{socket.pipe(c); c.pipe(socket)});
    clients.push(socket);
}).listen(9)

सभी सुझावों के लिए डेव धन्यवाद + प्रतिक्रिया!


1
गोल्फ संस्करण के लिए पठनीयता को न जोड़ें, यह वही है जो अन-गोल्ड संस्करण है। या यदि आप ऐसा करते हैं, तो लाइन टूटने से पहले अर्धविराम हटा दें, इसलिए यह समान लंबाई है।
mbomb007

@ mbomb007 "पठनीयता" ज्यादातर स्क्रॉल करने से बचने के लिए है। दुर्भाग्य से, कोड के शरीर में कोई अर्धविराम नहीं है, इसलिए यह काम नहीं करता है। मुझे लगा कि एक त्वरित खोज और जगह बहुत अधिक नहीं होगी। हालांकि भविष्य की टिप्पणियों के लिए निश्चित रूप से आपकी टिप को ध्यान में रखना होगा!
user3080953

@ सभी प्रतिक्रिया के लिए धन्यवाद! मैंने वेनिला डीएच का उपयोग करने के लिए बदलाव किए हैं, जो वास्तव में काफी लंबाई में जोड़ा गया है क्योंकि आपको प्रिम्स का आदान-प्रदान करने की आवश्यकता है क्योंकि एईएस वास्तव में ड्रॉप-इन प्रतिस्थापन के रूप में काम करता है, लेकिन एईएस के साथ समस्या यह है कि जब तक आप पूरा नहीं करते तब तक कुछ भी नहीं भेजता है। एक ब्लॉक, और पैडिंग एक दर्द होगा। यह भी rc4 aes128 से कम है
user3080953

1
मुझे यकीन नहीं था कि यह एक नेटवर्क पर काम करेगा, लेकिन यह शायद नहीं होगा, और मैंने इसे एक बस पर लिखा था, इसलिए मेरे पास जांच का कोई तरीका नहीं था। नया संस्करण इसके बजाय एक इको सर्वर का उपयोग करता है। इससे टाइमआउट की समस्या भी हल हो जाती है। मैं एक सर्वर + क्लाइंट से बचने की कोशिश कर रहा था, लेकिन यह बेहतर रूप है। अंत में, इस चुनौती के लिए धन्यवाद, मैंने एक टन सीखा कि वास्तव में हर जगह से पुस्तकालयों को हथियाने के बजाय नोड का उपयोग कैसे करें :)
user3080953

@ user3080953 अच्छा लगता है। उन अपडेट के साथ आपको इनाम के लिए दौड़ में होना चाहिए!
डेव

0

नोड.जेएस, 638 607 बाइट्स

अब जब यह अच्छी तरह से और वास्तव में (उसी भाषा में) पीटा गया है, तो यहां मेरा परीक्षण उत्तर है:

R=require,P=process,s=R('net'),y=R('crypto'),w=0,C='create',W='write',D='data',B='hex',G=_=>a.generateKeys(B),Y=(t,m,g,f)=>g((c=y[C+t+'ipher']('aes192',w,k='')).on('readable',_=>k+=(c.read()||'').toString(m)).on('end',_=>f(k)))+c.end(),F=C+'DiffieHellman',X=s=>s.on(D,x=>(x+'').split(B).map(p=>p&&(w?Y('Dec','utf8',c=>c[W](p,B),console.log):P.stdin.on(D,m=>Y('C',B,c=>c[W](m),r=>s[W](r+B)),([p,q,r]=p.split(D),r&&s[W](G(a=y[F](q,B,r,B))),w=a.computeSecret(p,B))))));(R=P.argv)[3]?X(s.Socket()).connect(R[3],R[2]):s[C+'Server'](s=>X(s,a=y[F](2<<9))[W](G()+D+a.getPrime(B)+D+a.getGenerator(B)+B)).listen(R[2])

या लपेटने के साथ:

R=require,P=process,s=R('net'),y=R('crypto'),w=0,C='create',W='write',D='data',B
='hex',G=_=>a.generateKeys(B),Y=(t,m,g,f)=>g((c=y[C+t+'ipher']('aes192',w,k=''))
.on('readable',_=>k+=(c.read()||'').toString(m)).on('end',_=>f(k)))+c.end(),F=C+
'DiffieHellman',X=s=>s.on(D,x=>(x+'').split(B).map(p=>p&&(w?Y('Dec','utf8',c=>c[
W](p,B),console.log):P.stdin.on(D,m=>Y('C',B,c=>c[W](m),r=>s[W](r+B)),([p,q,r]=p
.split(D),r&&s[W](G(a=y[F](q,B,r,B))),w=a.computeSecret(p,B))))));(R=P.argv)[3]?
X(s.Socket()).connect(R[3],R[2]):s[C+'Server'](s=>X(s,a=y[F](2<<9))[W](G()+D+a.
getPrime(B)+D+a.getGenerator(B)+B)).listen(R[2])

प्रयोग

यह एक सर्वर / क्लाइंट कार्यान्वयन है; एक तात्कालिकता सर्वर होगा, और दूसरा क्लाइंट। सर्वर को एक विशिष्ट पोर्ट के साथ लॉन्च किया जाता है, फिर क्लाइंट को सर्वर के पोर्ट को इंगित किया जाता है। यदि आपकी मशीन एन्ट्रापी पर कम है, तो डीएच को सेट-अप करने में कुछ सेकंड लग सकते हैं, इसलिए पहले संदेशों में थोड़ी देरी हो सकती है।

MACHINE 1                       MACHINE 2
$ node e2e.js <port>            :
:                               $ node e2e.js <address> <port>
$ hello                         :
:                               : hello
:                               $ hi
: hi                            :

टूट - फूट

s=require('net'),
y=require('crypto'),
w=0,                                      // Shared secret starts unknown
Y=(t,m,g,f)=>g(                           // Helper for encryption & decryption
  (c=y['create'+t+'ipher']('aes192',w,k=''))
  .on('readable',_=>k+=(c.read()||'').toString(m))
  .on('end',_=>f(k)))+c.end();
X=s=>s.on('data',x=>(x+'').split('TOKEN2').map(p=>
  p&&(w                                   // Have we completed handshake?
    ?Y('Dec','utf8',c=>c.write(p,'hex'),console.log) // Decrypt + print messages
    :                                     // Haven't completed handshake:
     process.stdin.on('data',m=>          //  Prepare to encrypt + send input
       Y('C','hex',c=>c.write(m),r=>s.write(r+'TOKEN2')),(
       [p,q,r]=p.split('TOKEN1'),         //  Split up DH data sent to us
       r&&                                //  Given DH details? (client)
          s.write(
            (a=y.createDiffieHellman(     //   Compute key pair...
              q,'hex',r,'hex')            //   ...using the received params
            ).generateKeys('hex')),       //   And send the public key
       w=a.computeSecret(p,'hex')         //  Compute shared secret
       //,console.log(w.toString('hex'))  //  Print if you want to verify no MITM
))))),
(R=process.argv)[3]                       // Are we running as a client?
  ?X(s.Socket()).connect(R[3],R[2])       // Connect & start chat
  :s.createServer(s=>                     // Start server. On connection:
    X(s,                                  //  Start chat,
      a=y.createDiffieHellman(1024))      //  Calc DiffieHellman,
    .write(                               //  Send public key & public DH details
      a.generateKeys('hex')+'TOKEN1'+
      a.getPrime('hex')+'TOKEN1'+
      a.getGenerator('hex')+'TOKEN2')
  ).listen(R[2])                          // Listen on requested port

टोकन के लिए एकमात्र आवश्यकता यह है कि उनमें कम से कम एक गैर-हेक्स वर्ण होता है, इसलिए न्यूनतम कोड में अन्य स्ट्रिंग स्थिरांक का उपयोग किया जाता है ( dataऔर hex)।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.