2012-02-02 9 views
8

साथ डेस के लिए मजबूर कर रहा क्रिप्टोग्राफी पर एक पाठ्यक्रम ले रहा हूँ और एक काम पर अटक कर रहा हूँ।ब्रूट ने कमज़ोर कुंजी

प्लेन plain6.txt 8 वर्णों (64 बिट्स की एक स्ट्रिंग जिनमें से हर 8 वीं बिट नजरअंदाज कर दिया है के रूप में दिया एक 64-बिट कुंजी का उपयोग करने के लिए encrypt6.dat डेस के साथ एन्क्रिप्टेड कर दिया गया है निर्देश इस प्रकार हैं), सभी पात्रों पत्र में किया जा रहा (लोअर केस या अपर-केस) और अंक (0 से 9 तक)।

काम को पूरा करने के लिए, मुझे फ़रवरी 12, 23.59 से पहले एन्क्रिप्शन कुंजी भेजें।

नोट: मैं एक 8 बाइट (64-बिट) कुंजी प्राप्त करने की उम्मीद है। प्रत्येक बाइट मेरी कुंजी में इसी बाइट साथ मेल खाना चाहिए, कम से कम महत्वपूर्ण बिट जो डेस में है और इस तरह इस्तेमाल नहीं किया है के लिए छोड़कर, मनमाने ढंग से हो सकता है।

import time 
from Crypto.Cipher import DES 

class BreakDES(object): 
    def __init__(self, file, passwordLength = 8, testLength = 8): 
     self.file = file 
     self.passwordLength = passwordLength 
     self.testLength = testLength 
     self.EncryptedFile = open(file + '.des') 
     self.DecryptedFile = open(file + '.txt') 
     self.encryptedChunk = self.EncryptedFile.read(self.testLength) 
     self.decryptedChunk = self.DecryptedFile.read(self.testLength) 
     self.start = time.time() 
     self.counter = 0 
     self.chars = range(48, 58) + range(65, 91) + range(97, 123) 
     self.key = False 
     self.broken = False 

     self.testPasswords(passwordLength, 0, '') 

     if not self.broken: 
      print "Password not found." 

     duration = time.time() - self.start 

     print "Brute force took %.2f" % duration 
     print "Tested %.2f per second" % (self.counter/duration) 

    def decrypt(self): 
     des = DES.new(self.key.decode('hex')) 
     if des.decrypt(self.encryptedChunk) == self.decryptedChunk: 
      self.broken = True 
      print "Password found: 0x%s" % self.key 
     self.counter += 1 

    def testPasswords(self, width, position, baseString): 
      for char in self.chars: 
       if(not self.broken): 
        if position < width: 
         self.testPasswords(width, position + 1, baseString + "%c" % char) 
         self.key = (baseString + "%c" % char).encode('hex').zfill(16) 
         self.decrypt() 

# run it for password length 4 
BreakDES("test3", 4) 

मैं 60.000 कोशिश करता/सेकंड की गति हो रही है:

यहाँ पायथन में मेरा पहला प्रयास करने के लिए कोड है। 62 अक्षरों से 8 बाइट्स का पासवर्ड 13 ट्रिलियन संभावनाएं देता है, जिसका मतलब है कि इस गति से मुझे हल करने में 130 साल लगेंगे। मुझे पता है कि यह एक कुशल कार्यान्वयन नहीं है और मैं सी या इसके स्वाद जैसे तेज भाषा में बेहतर गति प्राप्त कर सकता हूं, लेकिन मैंने कभी उन लोगों में प्रोग्राम नहीं किया है। यहां तक ​​कि यदि मुझे 10 की गति मिलती है, तो भी हम घंटों की सीमा तक पहुंचने के लिए 10,000,000,000 प्रति सेकंड से एक बड़ी छलांग लगा रहे हैं।

मुझे क्या याद आ रही है? यह एक कमजोर कुंजी माना जाता है :)। खैर, पूर्ण 256 चरित्र सेट से कमजोर। http://users.abo.fi/ipetre/crypto/assignment6.html

संपादित 2

यह एक कच्चे सी दिया गया है:

संपादित

असाइनमेंट के बारे में कुछ अस्पष्टता के कारण, यहाँ पूर्ण विवरण और अंशांकन के लिए कुछ परीक्षण फ़ाइलों है जो i7 2600K पर लगभग 2.000.000 पासवर्ड/प्रति कोर हो जाता है। आपको पासवर्ड का पहला अक्षर निर्दिष्ट करना होगा और विभिन्न कोर/कंप्यूटर पर मैन्युअल रूप से कई उदाहरण चला सकते हैं। मैं चार कंप्यूटरों पर कुछ घंटों के भीतर इस समस्या का समाधान करने में कामयाब रहा।

#include <stdio.h>  /* fprintf */ 
#include <stdlib.h>  /* malloc, free, exit */ 
#include <unistd.h> 
#include <string.h>  /* strerror */ 
#include <signal.h> 
#include <openssl/des.h> 

static long long unsigned nrkeys = 0; // performance counter 

char * 
Encrypt(char *Key, char *Msg, int size) 
{ 
     static char* Res; 
     free(Res); 
     int    n=0; 
     DES_cblock  Key2; 
     DES_key_schedule schedule; 
     Res = (char *) malloc(size); 
     /* Prepare the key for use with DES_ecb_encrypt */ 
     memcpy(Key2, Key,8); 
     DES_set_odd_parity(&Key2); 
     DES_set_key_checked(&Key2, &schedule); 
     /* Encryption occurs here */ 
     DES_ecb_encrypt((unsigned char (*) [8]) Msg, (unsigned char (*) [8]) Res, 
          &schedule, DES_ENCRYPT); 
     return (Res); 
} 

char * 
Decrypt(char *Key, char *Msg, int size) 
{ 
     static char* Res; 
     free(Res); 
     int    n=0; 
     DES_cblock  Key2; 
     DES_key_schedule schedule; 
     Res = (char *) malloc(size); 
     /* Prepare the key for use with DES_ecb_encrypt */ 
     memcpy(Key2, Key,8); 
     DES_set_odd_parity(&Key2); 
     DES_set_key_checked(&Key2, &schedule); 
     /* Decryption occurs here */ 
     DES_ecb_encrypt((unsigned char (*) [8]) Msg, (unsigned char (*) [8]) Res, 
          &schedule, DES_DECRYPT); 
     return (Res); 
} 

void ex_program(int sig); 

int main(int argc, char *argv[]) 
{ 
    (void) signal(SIGINT, ex_program); 

    if (argc != 4) /* argc should be 2 for correct execution */ 
    { 
     printf("Usage: %s ciphertext plaintext keyspace \n", argv[0]); 
     exit(1); 
    } 

    FILE *f, *g; 
    int counter, i, prime = 0, len = 8; 
    char cbuff[8], mbuff[8]; 
    char letters[] = "02468ACEGIKMOQSUWYacegikmoqsuwy"; 
    int nbletters = sizeof(letters)-1; 
    int entry[len]; 
    char *password, *decrypted, *plain; 

    if(atoi(argv[3]) > nbletters-2) { 
     printf("The range must be between 0-%d\n", nbletters-2); 
     exit(1); 
    } 
    prime = atoi(argv[1]) 

    // read first 8 bytes of the encrypted file 
    f = fopen(argv[1], "rb"); 
    if(!f) { 
     printf("Unable to open the file\n"); 
     return 1; 
    } 
    for (counter = 0; counter < 8; counter ++) cbuff[counter] = fgetc(f); 
    fclose(f); 

    // read first 8 bytes of the plaintext file 
    g = fopen(argv[2], "r"); 
    if(!f) { 
     printf("Unable to open the file\n"); 
     return 1; 
    } 
    for (counter = 0; counter < 8; counter ++) mbuff[counter] = fgetc(g); 
    fclose(g); 

    plain = malloc(8); 
    memcpy(plain, mbuff, 8); 

    // fill the keys 
    for(i=0 ; i<len ; i++) entry[i] = 0; 
    entry[len-1] = prime; 

    // loop until the length is reached 
    do { 
     password = malloc(8); 
     decrypted = malloc(8); 

     // build the pasword 
     for(i=0 ; i<len ; i++) password[i] = letters[entry[i]]; 
     nrkeys++; 

     // end of range and notices 
     if(nrkeys % 10000000 == 0) { 
      printf("Current key: %s\n", password); 
      printf("End of range "); 
      for(i=0; i<len; i++) putchar(letters[lastKey[i]]); 
      putchar('\n'); 
     } 

     // decrypt 
     memcpy(decrypted,Decrypt(password,cbuff,8), 8); 

     // compare the decrypted with the mbuff 
     // if they are equal, exit the loop, we have the password 
     if (strcmp(mbuff, decrypted) == 0) 
     { 
      printf("We've got it! The key is: %s\n", password); 
      printf("%lld keys searched\n", nrkeys); 
      exit(0); 
     } 

     free(password); 
     free(decrypted); 

     // spin up key until it overflows 
     for(i=0 ; i<len && ++entry[i] == nbletters; i++) entry[i] = 0; 
    } while(i<len); 

    return 0; 
} 

void ex_program(int sig) { 
printf("\n\nProgram terminated %lld keys searched.\n", nrkeys); 
(void) signal(SIGINT, SIG_DFL); 
exit(0); 
} 
+2

शायद डीईएस की संरचना के बारे में पढ़ें। पास के माध्यम से जानकारी कैसे प्रसारित होती है इस पर आधारित शोषण हैं। – Marcin

+2

ब्रावो रात पहले तक इंतजार नहीं कर रहा था। – roken

+1

यदि आपके पास पैसा झूठ बोल रहा है, और आप वास्तव में इसे बलपूर्वक बल देना चाहते हैं, तो इस पर विचार करें कि आप 10^16 अमेज़ॅन ec2 नौकरियां बना सकते हैं, जिनमें से प्रत्येक केवल आवंटित कुंजी के साथ दिए गए सादे पाठ को एन्क्रिप्ट करता है। – Marcin

उत्तर

5

मुझे लगता है कि वांछित समाधान वास्तव में एल्गोरिदम लागू करने के लिए है। फिर, चूंकि आप स्वयं को डिक्रिप्ट कर रहे हैं, आप जल्दी ही जमानत दे सकते हैं, जो कि सादा पाठ को ए-ज़ा-जे 0-9 भी मानते हैं, आपको एक बाइट डिक्रिप्ट करने के बाद रोकने में 98% मौका देता है, 99.97% 2 बाइट्स को डिक्रिप्ट करने के बाद रोकने और 3 बाइट्स के बाद रोकने का 99.9 99 5% मौका देने का मौका।

इसके अलावा, सी या ओकंपल या ऐसा कुछ उपयोग करें। आप शायद क्रिप्शन कर रहे हैं की तुलना में स्ट्रिंग मैनिपुलेशन करने में अधिक समय व्यतीत कर रहे हैं। या, कम से कम बहु प्रसंस्करण का उपयोग करें और अपने सभी कोर ऊपर स्पिन ...

+0

+1। सी में एक मौजूदा मुक्त कार्यान्वयन के लिए यहां देखें: http://linux.die.net/man/3/ecb_crypt बस मौजूदा सी लाइब्रेरी का उपयोग करना, शायद पाइथन क्रिप्टो की तुलना में काफी तेज नहीं है। –

+0

संभवतः, लेकिन उस कोड के बिट्स जहां वह कुंजी उत्पन्न कर रहा है, लगभग निश्चित रूप से उसे मार रहा है। –

+0

एक कुशल एल्गोरिदम पर कोई सुझाव जो ओवरहेड के बिना पूरी कुंजी स्थान की खोज करता है? – element

1

इस उत्तर अन्य अधिक विशिष्ट सुझाव के पूरक हो सकता है लेकिन पहली बात आपको क्या करना चाहिए एक प्रोफाइलर चलाया जाता है।

वहाँ वास्तव में अच्छा उदाहरण यहां हैं:

How can you profile a python script?

संपादित करें:

इस विशेष कार्य के लिए, मुझे पता है यह मदद नहीं करेगा। 10 गीगाहर्ट्ज की एक परीक्षण आवृत्ति है ... एक मशीन पर मुश्किल से कम आवृत्ति के साथ। शायद आप उल्लेख कर सकते हैं कि आपके पास कौन सा हार्डवेयर उपलब्ध है। इसके अलावा, कुछ घंटों के दौरान इसे चलाने का लक्ष्य नहीं है। जब आपको कोई ऐसी विधि मिलती है जो सप्ताह के भीतर सफलता की उचित संभावना देता है तो अपने तरीकों में सुधार करते समय इसे चलाने दें।

+1

इंटेल i7 2600K, 8 जीबी रैम, जीटीएक्स 580 मेरी मुख्य मशीन है। मैं प्रोफाइलर चला गया और वास्तव में मुख्य पीढ़ी ज्यादातर समय ले रहा है, मैं अब उस हिस्से को फिर से लिख रहा हूं। – element

1

मैं मदद नहीं कर सकता लेकिन काम के शब्दों नोटिस: आप वास्तव में एक डेस कार्यान्वयन प्रदान करने या अपने आप को पटाखा करने का अनुरोध नहीं कर रहे हैं। यदि वास्तव में यह मामला है, तो आप John the Ripper या hashcat जैसे टूल क्यों न देखें।

+0

मैंने देखा कि साथ ही, लेकिन मुझे आश्चर्य है कि असाइनमेंट का बिंदु डीईएस क्रैकिंग को लागू नहीं करना है। –

+0

कार्यान्वयन प्रदान करना आवश्यक नहीं है, केवल कुंजी, हालांकि अंतिम असाइनमेंट पूर्ण डीईएस तोड़ देगा। यह अधिकतम प्रदर्शन प्राप्त करने के लिए एक प्रतियोगिता है। आप ओपनसीएल जा सकते हैं और अमेज़ॅन जीपीयू गणना क्लॉज किराए पर ले सकते हैं, एक वितरित हमला कर सकते हैं, या कोपाकोबाना किराए पर ले सकते हैं। लेकिन वे मेरे लीग से थोड़ी दूर हैं :) – element

+1

पूर्ण डीईएस तोड़ना किसी भी प्रकार की क्रिप्टो या कोडिंग चुनौती की तुलना में "इसमें पर्याप्त धन फेंकना" जैसा लगता है। – CodesInChaos

5

एक स्पष्ट कारक 256 स्पीडअप है: एक बिट प्रति बाइट कुंजी का हिस्सा नहीं है। डीईएस में केवल 56 बिट कुंजी है, लेकिन एक 64 बिट्स में गुजरता है। यह बताएं कि यह कितना छोटा है, और समकक्ष पात्रों को फेंक दें।

2

मुझे काफी मदद मिली है और यह सी में एक समाधान है क्योंकि मैं सी शुरुआत करने वाला हूं, यह शायद बग और बुरी आदत से भरा है, लेकिन यह काम करता है।

रूप CodeInChaos पता लगा, केवल 31 वर्णों क्योंकि डेस कुंजी के हर 8 वीं बिट पर ध्यान नहीं देता है, उदाहरण के ASCII वर्ण b: *0110001*0 और c: *0110001*1 एन्क्रिप्शन/डिक्रिप्शन में समान के लिए कर रही है जब कुंजी के एक भाग के रूप में प्रयोग किया जाता है, जांच की आवश्यकता होती।

मैं डीईएस डिक्रिप्शन के लिए ओपनएसएसएल लाइब्रेरी का उपयोग कर रहा हूं। मेरी मशीन पर यह गति प्रति सेकंड ~ 1.8 मिलियन पासवर्ड प्राप्त करती है, जो कुल कुंजी को लगभग 5 दिनों तक परीक्षण करने के लिए कुल समय देती है। यह समय सीमा से कम दिन आता है। पाइथन कोड से काफी बेहतर है जो वर्षों के क्षेत्र में है।

अभी भी सुधार के लिए जगह है, शायद कोड को अनुकूलित और थ्रेड किया जा सकता है। अगर मैं अपने सभी कोर का उपयोग कर सकता हूं तो मुझे लगता है कि समय एक दिन से थोड़ा अधिक नीचे जाएगा, हालांकि मुझे अभी तक थ्रेडिंग के साथ कोई अनुभव नहीं है।

#include <stdio.h> 
#include <unistd.h> 
#include <string.h> 
#include <signal.h> 
#include <openssl/des.h> 

static long long unsigned nrkeys = 0; // performance counter 

char * 
Encrypt(char *Key, char *Msg, int size) 
{ 
     static char* Res; 
     free(Res); 
     int    n=0; 
     DES_cblock  Key2; 
     DES_key_schedule schedule; 
     Res = (char *) malloc(size); 
     /* Prepare the key for use with DES_ecb_encrypt */ 
     memcpy(Key2, Key,8); 
     DES_set_odd_parity(&Key2); 
     DES_set_key_checked(&Key2, &schedule); 
     /* Encryption occurs here */ 
     DES_ecb_encrypt((unsigned char (*) [8]) Msg, (unsigned char (*) [8]) Res, 
          &schedule, DES_ENCRYPT); 
     return (Res); 
} 

char * 
Decrypt(char *Key, char *Msg, int size) 
{ 
     static char* Res; 
     free(Res); 
     int    n=0; 
     DES_cblock  Key2; 
     DES_key_schedule schedule; 
     Res = (char *) malloc(size); 
     /* Prepare the key for use with DES_ecb_encrypt */ 
     memcpy(Key2, Key,8); 
     DES_set_odd_parity(&Key2); 
     DES_set_key_checked(&Key2, &schedule); 
     /* Decryption occurs here */ 
     DES_ecb_encrypt((unsigned char (*) [8]) Msg, (unsigned char (*) [8]) Res, 
          &schedule, DES_DECRYPT); 
     return (Res); 
} 

void ex_program(int sig); 

int main() 
{ 
    (void) signal(SIGINT, ex_program); 

    FILE *f, *g; // file handlers 
    int counter, i, len = 8; // counters and password length 
    char cbuff[8], mbuff[8]; // buffers 
    char letters[] = "02468ACEGIKMOQSUWYacegikmoqsuwy"; // reduced letter pool for password brute force 
    int nbletters = sizeof(letters)-1; 
    int entry[len]; 
    char *password, *decrypted; 

    // read first 8 bytes of the encrypted file 
    f = fopen("test2.dat", "rb"); 
    if(!f) { 
     printf("Unable to open the file\n"); 
     return 1; 
    } 
    for (counter = 0; counter < 8; counter ++) cbuff[counter] = fgetc(f); 
    fclose(f); 

    // read first 8 bytes of the plaintext file 
    g = fopen("test2.txt", "r"); 
    if(!f) { 
     printf("Unable to open the file\n"); 
     return 1; 
    } 
    for (counter = 0; counter < 8; counter ++) mbuff[counter] = fgetc(g); 
    fclose(g); 

    // fill the initial key 
    for(i=0 ; i<len ; i++) entry[i] = 0; 

    // loop until the length is reached 
    do { 
     password = malloc(8); 
     decrypted = malloc(8); 

     // build the pasword 
     for(i=0 ; i<len ; i++) password[i] = letters[entry[i]]; 
     nrkeys++; 

     if(nrkeys % 10000000 == 0) { 
      printf("Current key: %s\n", password); 
     } 

     // decrypt 
     memcpy(decrypted,Decrypt(password,cbuff,8), 8); 

     // compare the decrypted with the mbuff 
     // if they are equal, exit the loop, we have the password 
     if (strcmp(mbuff, decrypted) == 0) 
     { 
      printf("We've got it! The key is: %s\n", password); 
      printf("%lld keys searched", nrkeys); 
      exit(0); 
     } 

     free(password); 
     free(decrypted); 

     // spin up key until it overflows 
     for(i=0 ; i<len && ++entry[i] == nbletters; i++) entry[i] = 0; 
    } while(i<len); 

    return 0; 
} 

void ex_program(int sig) { 
printf("\n\nProgram terminated %lld keys searched.\n", nrkeys); 
(void) signal(SIGINT, SIG_DFL); 
exit(0); 
} 
+1

केवल कुंजी स्थान (पैरामीटर द्वारा दिए गए) के एक हिस्से पर काम करने के लिए प्रोग्राम को अनुकूलित करें, और फिर इसे समानांतर में कई बार कॉल करें, उदा। एक बार एएम से शुरू होने वाली चाबियों के लिए, एक बार एनजेड के लिए, एक बार के लिए, एक बार nz के लिए और एक बार 0-9 के लिए ... निश्चित रूप से, समान आकार के अनुभागों का उपयोग करें और बस आपके पास कोर के रूप में कई बार (या एक कम तो आप अभी भी आपके कंप्यूटर का उपयोग कर सकते हैं)। यहां फैंसी मल्टीथ्रेडिंग की कोई ज़रूरत नहीं है। –

संबंधित मुद्दे