2009-06-02 18 views
11

मैं एन्क्रिप्ट और एक सॉकेट RijndaelManaged का उपयोग करने पर एक फ़ाइल धारा डिक्रिप्ट करने के लिए कोशिश कर रहा हूँ, लेकिन मैं अपवादलंबाई अमान्य है

CryptographicException: Length of the data to decrypt is invalid. 
    at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount) 
    at System.Security.Cryptography.CryptoStream.FlushFinalBlock() 
    at System.Security.Cryptography.CryptoStream.Dispose(Boolean disposing) 

अपवाद के अंत में फेंक दिया जाता है में जोड़ने से रखना प्राप्त फ़ाइल में फ़ाइल का उपयोग करें, जब पूरी फ़ाइल स्थानांतरित कर दी गई हो।

मैंने वेब पर खोज करने की कोशिश की लेकिन केवल एक स्ट्रिंग को एन्क्रिप्ट करने और डिक्रिप्ट करते समय एन्कोडिंग का उपयोग करते समय उत्पन्न होने वाली समस्याओं का जवाब मिला। मैं एक फ़ाइलस्ट्रीम का उपयोग करता हूं, इसलिए मैं उपयोग करने के लिए कोई एन्कोडिंग निर्दिष्ट नहीं करता, इसलिए यह समस्या नहीं होनी चाहिए। ये मेरी विधियां हैं:

private void transferFile(FileInfo file, long position, long readBytes) 
{ 
    // transfer on socket stream 
    Stream stream = new FileStream(file.FullName, FileMode.Open); 
    if (position > 0) 
    { 
     stream.Seek(position, SeekOrigin.Begin); 
    } 
    // if this should be encrypted, wrap the encryptor stream 
    if (UseCipher) 
    { 
     stream = new CryptoStream(stream, streamEncryptor, CryptoStreamMode.Read); 
    } 
    using (stream) 
    { 
     int read; 
     byte[] array = new byte[8096]; 
     while ((read = stream.Read(array, 0, array.Length)) > 0) 
     { 
      streamSocket.Send(array, 0, read, SocketFlags.None); 
      position += read; 
     } 
    } 
} 

private void receiveFile(FileInfo transferFile) 
{ 
    byte[] array = new byte[8096]; 
    // receive file 
    Stream stream = new FileStream(transferFile.FullName, FileMode.Append); 
    if (UseCipher) 
    { 
     stream = new CryptoStream(stream, streamDecryptor, CryptoStreamMode.Write); 
    } 
    using (stream) 
    { 
     long position = new FileInfo(transferFile.Path).Length; 
     while (position < transferFile.Length) 
     { 
      int maxRead = Math.Min(array.Length, (int)(transferFile.Length - position)); 
      int read = position < array.Length 
         ? streamSocket.Receive(array, maxRead, SocketFlags.None) 
         : streamSocket.Receive(array, SocketFlags.None); 
      stream.Write(array, 0, read); 
      position += read; 
     } 
    } 
} 

यह विधि है जिसे मैं सिफर स्थापित करने के लिए उपयोग करता हूं। बाइट [] init एक जेनरेट बाइट सरणी है।

private void setupStreamCipher(byte[] init) 
{ 
    RijndaelManaged cipher = new RijndaelManaged(); 
    cipher.KeySize = cipher.BlockSize = 256; // bit size 
    cipher.Mode = CipherMode.ECB; 
    cipher.Padding = PaddingMode.ISO10126; 
    byte[] keyBytes = new byte[32]; 
    byte[] ivBytes = new byte[32]; 

    Array.Copy(init, keyBytes, 32); 
    Array.Copy(init, 32, ivBytes, 0, 32); 

    streamEncryptor = cipher.CreateEncryptor(keyBytes, ivBytes); 
    streamDecryptor = cipher.CreateDecryptor(keyBytes, ivBytes); 
} 

किसी को भी यह पता है कि मैं क्या गलत कर रहा हूं?

उत्तर

6

ऐसा लगता है कि आप अंतिम ब्लॉक को सही तरीके से नहीं भेज रहे हैं। अंतिम ब्लॉक (जो प्राप्त करने वाली धारा की तलाश है) को यह सुनिश्चित करने के लिए आपको कम से कम FlushFinalBlock() भेजना CryptoStream भेजना होगा।

वैसे, CipherMode.ECB is more than likely an epic fail जो आप कर रहे हैं उसके लिए सुरक्षा के मामले में। कम से कम CipherMode.CBC (सिफर-ब्लॉक चेनिंग) का उपयोग करें जो वास्तव में IV का उपयोग करता है और प्रत्येक ब्लॉक को पिछले एक पर निर्भर करता है।

संपादित करें: व्हाउप्स, समेकित स्ट्रीम पढ़ने मोड में है। उस स्थिति में आपको यह सुनिश्चित करने की ज़रूरत है कि आप ईओएफ को पढ़ लें ताकि क्रिप्टोस्ट्रीम readBytes के बाद रोकने के बजाय अंतिम ब्लॉक से निपट सके। यदि आप लिखने के तरीके में समेकित स्ट्रीम चलाते हैं तो यह नियंत्रित करना शायद आसान है।

एक और नोट: आप यह नहीं मान सकते कि बाइट बराबर बराबर है। ब्लॉक सिफर के पास एक निश्चित ब्लॉक आकार होता है, और जब तक कि आप एक सिफर मोड का उपयोग नहीं कर रहे हैं जो ब्लॉक सिफर को स्ट्रीम सिफर में परिवर्तित करता है, वहां पैडिंग होगी जो सिफरटेक्स्ट को सादे टेक्स्ट से अधिक लंबा बनाता है।

+1

FlushFinalBlock() विधि कथन का उपयोग

using(stream) { // } // calls Close() -> FlushFinalBlock()
मैं CipherMode बदल जाएगा की "बंद करने खंड" में कहा जाता है, मैं सिर्फ यह एक उदाहरण के रूप में प्रवेश किया तो तुम्हें पता है कि मैं किसी भी में मेरी सिफर को प्रारंभ नहीं है "अजीब" रास्ता। Sendfile में readBytes() अभी तक नहीं किया जाता है, मैं इसे दूर करने के लिए भूल गया था। मैंने फ़ाइल के अंत तक पढ़ा है, इसलिए यह मुद्दा यहां नहीं होना चाहिए। मैंने सोचा था कि
cipher.Padding = PaddingMode.ISO10126;
गद्दी की देखभाल करने गया था? इसे काम करने के लिए मैं क्या बदल सकता हूं? – Patrick

+0

यदि समेकित स्ट्रीम रीड मोड में है, तो यदि आप इसका निपटान करते हैं तो अंतिम ब्लॉक खो जाएगा; अंतिम ब्लॉक का उत्पादन करने के लिए इसे वास्तव में अपनी अंतर्निहित स्रोत धारा से फ़ाइल का अंत पढ़ना होगा। –

+0

जेफरी के जवाब में: यदि मैं stream.FlushFinalBlock फोन करने की कोशिश() यह कहता है NonSupportedException: FlushFinalBlock दो बार एक ही धारा पर नहीं कहा जा सकता। इसका मतलब यह नहीं है कि फ़ाइल का अंत पढ़ा गया है (और भेजा गया है)? – Patrick

0
cipher.Mode = CipherMode.ECB; 

अरग! अपना खुद का सुरक्षा कोड रोल करना लगभग हमेशा एक बुरा विचार है।

+1

????? है ना? वह रिजेंडेल का उपयोग कर रहा है? यह "अपना खुद का रोल" नहीं है। हालांकि, एक अच्छा मुद्दा बनना है, डेवलपर्स को एन्क्रिप्शन का उपयोग करने के बारे में सावधान रहने की आवश्यकता है। – Cheeso

+0

ईसीबी यहां विफल रहता है क्योंकि प्रत्येक ब्लॉक स्वतंत्र रूप से एन्क्रिप्ट किया जाता है। करने के लिए आप अपनी खुद की क्रिप्टो एल्गोरिथ्म (या यहां तक ​​कि कार्यान्वयन) को बनाने होना जरूरी नहीं है: –

+0

यह कोई फर्क नहीं पड़ता जो CipherMode मैं उपयोग करते हैं, मैं अभी भी "डेटा की लंबाई ..." अपवाद मिलता है ... – Patrick

1

जेफरी Hantin द्वारा बनाई गई टिप्पणी के बाद, मैं कभी तो तरह गद्दी है कि मैं नहीं था की वजह से

using (stream) { 
    FileInfo finfo = new FileInfo(transferFile.Path); 
    long position = finfo.Length; 
    while (position < transferFile.Length) { 
     int maxRead = Math.Min(array.Length, (int)(transferFile.Length - position)); 
     int read = position < array.Length 
        ? streamSocket.Receive(array, maxRead, SocketFlags.None) 
        : streamSocket.Receive(array, SocketFlags.None); 
     stream.Write(array, 0, read); 
     position += read; 
    } 
} 

->

using (stream) { 
    int read = array.Length; 
    while ((read = streamSocket.Receive(array, read, SocketFlags.None)) > 0) { 
     stream.Write(array, 0, read); 
     if ((read = streamSocket.Available) == 0) { 
      break; 
     } 
    } 
} 

को receiveFile में कुछ लाइनें बदल और देखा, वह काम करता है (पहले के बारे में परेशान करने की परवाह नहीं है)। मुझे यकीन नहीं है कि क्या होता है यदि उपलब्ध रिटर्न 0 है, भले ही सभी डेटा स्थानांतरित नहीं किए गए हैं, लेकिन मैं उस मामले में बाद में उसमें शामिल हूं। जेफरी आपकी मदद के लिए धन्यवाद!

सम्मान।

0

मेरा मैं सिर्फ गद्दी से हटाया और यह

काम करता है टिप्पणी की इस बाहर - cipher.Padding = PaddingMode।ISO10126;

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