2014-10-20 6 views
6

मैं वर्तमान में सी # में एईएस कार्यान्वयन पर काम कर रहा हूं। एन्क्रिप्शन विधि में दो पैरामीटर हैं: एक स्ट्रिंग और पासवर्ड। मैं आपूर्ति की गई स्ट्रिंग ले रहा हूं और इसे बाइट्स की एक सरणी में परिवर्तित कर रहा हूं, इसलिए मैं इसे बाद में BinaryWriter के साथ डेटा लिखने के लिए उपयोग कर सकता हूं।एईएस एन्क्रिप्शन के लिए स्ट्रिंग से बाइट्स को सही तरीके से और लगातार कैसे प्राप्त करें?

समस्या यह है कि जब मैं Convert.FromBase64String(string) का उपयोग मैं FormatException: Invalid length. हो और जब मैं का उपयोग Encoding.UTF8.GetBytes(string) मेरी डिक्रिप्शन विधि फेंकता है और अवैध PKCS7.Padding अपवाद नहीं है।

मैं पिछले कुछ दिनों से इस समस्या को हल करने का प्रयास कर रहा हूं। मैंने stackoverflow.com और अन्य वेबसाइटों में अनंत प्रश्नों के करीब पढ़ा है, लेकिन मुझे अभी भी पता नहीं है कि इस समस्या को हल करने का सबसे विश्वसनीय तरीका क्या है।

इस प्रोग्राम में उपयोग किए जाने वाले स्ट्रिंग्स वाक्यों तक सीमित हैं (उदा। "कुछ एन्क्रिप्ट करने के लिए।") और संख्याएं (उदा। "12345")।

अग्रिम धन्यवाद, यहाँ समय में कोड इस बिंदु पर मेरे पास है:

public class AESProvider { 

    public byte[] EncryptStringToBytes_Aes(string plainText, string Key) 
    { 
     // Check arguments. 
     if (plainText == null || plainText.Length <= 0) 
      throw new ArgumentNullException("plainText"); 
     if (Key == null || Key.Length <= 0) 
      throw new ArgumentNullException("Key"); 
     byte[] plainTextInBytes = Convert.FromBase64String(plainText); 
     byte[] encrypted; 

     //Create an Aes object 
     //with the specified key and IV. 

     using (Aes aesAlg = Aes.Create()) 
     { 
      aesAlg.GenerateIV(); 
      byte[] IV = aesAlg.IV; 
      //The Salt will be the first 8 bytes of the IV. 
      byte[] theSalt = new byte[8]; 
      Array.Copy(IV,theSalt,8); 
      //A key for AES is generated by expanding the password using the following method. 
      Rfc2898DeriveBytes keyGen = new Rfc2898DeriveBytes(Key,theSalt); 
      byte[] aesKey = keyGen.GetBytes(16); 
      aesAlg.Key = aesKey; 

      // Create a decrytor to perform the stream transform. 
      ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, IV); 

      // Create the streams used for encryption. 
      using (MemoryStream msEncrypt = new MemoryStream()) 
      { 
       using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) 
       { 
        using (BinaryWriter swEncrypt = new BinaryWriter(csEncrypt)) 
        { 

         //Write all data to the stream. 
         swEncrypt.Write(plainTextInBytes); 
        } 
        encrypted = msEncrypt.ToArray(); 
       } 
      } 
      // Prepend the IV to the ciphertext so it can be used in the decryption process. 
      using (MemoryStream ivPlusCipher = new MemoryStream()) 
      { 
       using (BinaryWriter tBinaryWriter = new BinaryWriter(ivPlusCipher)) 
       { 
        tBinaryWriter.Write(IV); 
        tBinaryWriter.Write(encrypted); 
        tBinaryWriter.Flush(); 
       } 
       return ivPlusCipher.ToArray(); 
      } 
     } 
    } 

    public byte[] DecryptStringFromBytes_Aes(byte[] cipherText, string Key) 
    { 
     // Check arguments. 
     if (cipherText == null || cipherText.Length <= 0) 
      throw new ArgumentNullException("cipherText"); 
     if (Key == null || Key.Length <= 0) 
      throw new ArgumentNullException("Key"); 
     // Declare the string used to hold 
     // the decrypted text. 
     byte[] decrypted; 

     // Create an Aes object 
     // with the specified key and IV. 

     // Create the streams used for decryption. 

     using (Aes aesAlg = Aes.Create()) 
     { 
      aesAlg.Mode = CipherMode.CBC; 
      aesAlg.Padding = PaddingMode.PKCS7; 
      //Grab IV from ciphertext 
      byte[] IV = new byte[16]; 
      Array.Copy(cipherText,0,IV,0,16); 
      //Use the IV for the Salt 
      byte[] theSalt = new byte[8]; 
      Array.Copy(IV,theSalt,8); 
      Rfc2898DeriveBytes keyGen = new Rfc2898DeriveBytes(Key,theSalt); 
      byte[] aesKey = keyGen.GetBytes(16); 
      aesAlg.Key = aesKey; 

      // Create a decrytor to perform the stream transform. 
      ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, IV); 

      using (MemoryStream msDecrypt = new MemoryStream()) 
      { 
       using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write)) 
       { 
        using (BinaryWriter srDecrypt = new BinaryWriter(csDecrypt)) 
        { 
         //Decrypt the ciphertext 
         srDecrypt.Write(cipherText, IV.Length, (cipherText.Length - IV.Length)); 
        } 
        decrypted = msDecrypt.ToArray(); 
        return decrypted; 
       } 
      } 
     } 
    } 
} 
+0

आपकी 'डिक्रिप्टस्ट्रिंगफ्रॉमबाइट्स' एक स्ट्रिंग नहीं लौटाती है, क्यों? –

+1

सबसे महत्वपूर्ण सवाल यह है और रहेगा: इनपुट स्ट्रिंग में क्या रखा जाता है जिसे आप डिक्रिप्ट करना चाहते हैं। मेरा मतलब है, अगर यह हेक्साडेसिमल है तो कोई जवाब सही नहीं होगा। कृपया एक उदाहरण प्रदान करें! –

+0

इनपुट के लिए धन्यवाद। स्ट्रिंग के उदाहरण जहां पहले से ही प्रश्न में जोड़ा गया है! – Mandos

उत्तर

6

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

जब आप एन्क्रिप्ट करना एक मनमानी स्ट्रिंग के साथ शुरू करते हैं। Encoding.UTF8.GetBytes() का उपयोग करके इसे बाइट [] में कनवर्ट करें। इसे एन्क्रिप्ट करें। परिणामी बाइट [] अब Convert.ToBase64String() का उपयोग कर स्ट्रिंग में परिवर्तित किया जा सकता है।

जब आपको डिक्रिप्ट करना अब बेस 64 एन्कोडेड स्ट्रिंग के साथ शुरू होता है। Convert.FromBase64String() का उपयोग करके इसे बाइट [] पर डीकोड करें। इसे डिक्रिप्ट करें। अब आपके पास अपनी मूल स्ट्रिंग का यूटीएफ -8 एन्कोडिंग है, जिसे आप Encoding.UTF8.GetString() का उपयोग करके डीकोड कर सकते हैं।

याद रखें:

  • Encoding.UTF8 बाइट-सरणियों को मनमाने ढंग से तार कन्वर्ट करने के लिए काम करता है (लेकिन यह केवल बाइट-सरणियों कि वास्तविक UTF8-एनकोडिंग वापस शामिल परिवर्तित कर सकते हैं)।
  • कनवर्ट करें। [से/से] बेस 64 स्ट्रिंग स्ट्रिंग्स के लिए मनमानी बाइट-एरे को परिवर्तित करने के लिए काम करता है (लेकिन यह केवल उन स्ट्रिंग्स को परिवर्तित कर सकता है जिनमें वास्तविक बेस 64-एन्कोडिंग वापस आती हैं)।
+1

"हर बुरी तरह से पुनर्निर्मित करने के लिए, स्टैक ओवरफ़्लो में बहुत लंबा प्रश्न पोस्ट किया जाता है बहुत सरल जवाब जो आपको बहुत बेवकूफ महसूस करता है। " अल्बर्ट आइंस्टीन। उत्तर के लिए धन्यवाद, यह खूबसूरती से काम किया। – Mandos

2

Convert.FromBase64String(string); एक स्ट्रिंग Convert.ToBase64String(byte[]); एक मनमाना स्ट्रिंग काम नहीं करेगा में गुजर द्वारा उत्पन्न मिलने की उम्मीद है।

सबसे आसान समाधान BinaryWriter और BinaryReader को StreamWriter और StreamReader के साथ प्रतिस्थापित करता है और कोई भी रूपांतरण नहीं करता है।

public byte[] EncryptStringToBytes_Aes(string plainText, string Key) 
{ 
    // Check arguments. 
    if (plainText == null || plainText.Length <= 0) 
     throw new ArgumentNullException("plainText"); 
    if (Key == null || Key.Length <= 0) 
     throw new ArgumentNullException("Key"); 


    //Create an Aes object 
    //with the specified key and IV. 

    using (Aes aesAlg = Aes.Create()) 
    { 
     aesAlg.GenerateIV(); 
     byte[] IV = aesAlg.IV; 
     //The Salt will be the first 8 bytes of the IV. 
     byte[] theSalt = new byte[8]; 
     Array.Copy(IV,theSalt,8); 
     //A key for AES is generated by expanding the password using the following method. 
     Rfc2898DeriveBytes keyGen = new Rfc2898DeriveBytes(Key,theSalt); 
     byte[] aesKey = keyGen.GetBytes(16); 
     aesAlg.Key = aesKey; 

     // Create a decrytor to perform the stream transform. 
     ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, IV); 

     // Create the streams used for encryption. 
     using (MemoryStream msEncrypt = new MemoryStream()) 
     { 
      //You can write the IV here and not need to do it later. 
      msEncrypt.Write(IV, 0, IV.Length); 

      using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) 
      { 
       using (StreamWriter swEncrypt = new StreamWriter (csEncrypt)) 
       {  
        //Write all data to the stream. 
        swEncrypt.Write(plainText); 
       } 
      } 

      //Move this outside of the using statement for CryptoStream so it is flushed and dipsoed. 
      return msEncrypt.ToArray(); 
     } 
    } 
} 

इसके अलावा, अपने डिक्रिप्शन समारोह वास्तव में पाठ एक 2 बार एन्क्रिप्ट करने के लिए कोशिश कर रहा है, तो आप msDecrypt के निर्माता के लिए बाइट सरणी गुजरती हैं और डिक्रिप्शन मोड में डाल करने के लिए की जरूरत है।

public string DecryptStringFromBytes_Aes(byte[] cipherText, string Key) 
{ 
    // Check arguments. 
    if (cipherText == null || cipherText.Length <= 0) 
     throw new ArgumentNullException("cipherText"); 
    if (Key == null || Key.Length <= 0) 
     throw new ArgumentNullException("Key"); 

    // Create an Aes object 
    // with the specified key and IV. 

    // Create the streams used for decryption. 

    using (Aes aesAlg = Aes.Create()) 
    { 
     aesAlg.Mode = CipherMode.CBC; 
     aesAlg.Padding = PaddingMode.PKCS7; 
     //Grab IV from ciphertext 
     byte[] IV = new byte[16]; 
     Array.Copy(cipherText,0,IV,0,16); 
     //Use the IV for the Salt 
     byte[] theSalt = new byte[8]; 
     Array.Copy(IV,theSalt,8); 
     Rfc2898DeriveBytes keyGen = new Rfc2898DeriveBytes(Key,theSalt); 
     byte[] aesKey = keyGen.GetBytes(16); 
     aesAlg.Key = aesKey; 

     // Create a decrytor to perform the stream transform. 
     ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, IV); 

     //You can chain using statements like this to make the code easier to read. 
     using (MemoryStream msDecrypt = new MemoryStream(cipherText)) 
     using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) //Notice this is Read mode not Write mode. 
     using (StreamReader srDecrypt = new StreamReader(csDecrypt)) 
     { 
      //Decrypt the ciphertext 
      return srDecrypt.ReadToEnd(); 
     } 
    } 
} 

आपके कोड के साथ अन्य त्रुटियां हो सकती हैं, लेकिन कम से कम यह आपको सही रास्ते पर ले जाती है।

+0

उत्तर के लिए धन्यवाद। लेकिन मुझे लगता है कि इस दृष्टिकोण में कोई समस्या है (अगर मैं गलत हूं तो मुझे सही करें क्योंकि मुझे सी # में धाराओं के बारे में बहुत कुछ पता नहीं है) ... एन्क्रिप्शन प्रक्रिया में आप IV के साथ संदेश को एन्क्रिप्ट करते हैं, इसलिए ड्रेरीशन प्रक्रिया जब ऐरे। चॉपी विधि को चतुर्थ कहा जाता है, वह मूल नहीं होगा, लेकिन यह सिफरटेक्स्ट के पहले 16 बाइट्स होगा। तो यह एक समस्या होगी। इसके अलावा जब सिफरटेक्स्ट को डिक्रिप्ट करना आपके कोड को संदेश के साथ चतुर्थ को डिक्रिप्ट करेगा (हल करने में आसान है लेकिन फिर भी मुझे नहीं पता कि कोई बेहतर तरीका है या नहीं)। – Mandos

+0

क्या कोई तरीका है जिसमें मैं StreamReader/Writer का उपयोग कर सकता हूं और फिर भी वही कार्यक्षमता प्रदान करता हूं जो मेरा मूल कोड IV के बारे में था? – Mandos

+0

हां, मैंने अभी आपके कोड को समेकित किया है, स्ट्रीम रीडर और लेखक का आईवी भाग पर कोई प्रभाव नहीं पड़ता है। यदि आप चाहें तो अपने चतुर्थ भाग के लिए बस एक बाइनरी राइटर का उपयोग करें (मुझे लगता है कि यह ऐसा करने का अक्षम तरीका है क्योंकि आप अनावश्यक विज्ञान के पीछे स्मृति में अतिरिक्त बाइट [] बना रहे हैं।)। बस 'msEncrypt.Write (IV, 0, IV.Length) हटाएं; और फिर अपने पुराने ब्लॉक में वापस डालें जहां आपने IV को कॉपी किया था। –

2

अपने लाइनों को देखते हुए

public byte[] EncryptStringToBytes_Aes(string plainText, string Key) 
byte[] plainTextInBytes = Convert.FromBase64String(plainText); 

मनमानी सादा पाठ एक आधार 64 इनकोडिंग स्ट्रिंग नहीं होगा। यहां तक ​​कि अगर यह 64 एन्कोडेड पाठ आधार माना जाता है, अपने त्रुटि संदेश बताता है कि लंबाई रों की लंबाई, सफेद-अंतरिक्ष पात्रों अनदेखी 4

FormatException
से विभाज्य नहीं है, नहीं है शून्य या 4. -or- का एक बहुमत अमान्य है। एस में गैर-बेस -64 वर्ण, दो से अधिक पैडिंग वर्ण, या पैडिंग वर्णों के बीच एक गैर-सफेद अंतरिक्ष-वर्ण शामिल है।

http://msdn.microsoft.com/en-us/library/system.convert.frombase64string(v=vs.110).aspx

यदि यह एक आधार 64 इनकोडिंग स्ट्रिंग है, तो आप पैड की जरूरत है यह accorgingly

http://en.wikipedia.org/wiki/Base64

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