2015-01-23 8 views
7

मैं बेतरतीब ढंग से इस अपवाद को एनक्रिप्ट/Xamarin.Android साथ तार decrypting लेकिन दुर्भाग्य से मैं इसे पुन: पेश नहीं कर सकता से संबंधित रिपोर्ट उत्पादन उपयोगकर्ताओं का एक छोटा सा प्रतिशत देख रहा हूँ।CryptographicException: खराब PKCS7 गद्दी

इस कारण बन सकता है क्या और/या कैसे मैं अपवाद पुन: पेश सकता है, ताकि मैं एक फिक्स/वैकल्पिक हल पता लगा सकते हैं?

[CryptographicException: Bad PKCS7 padding. Invalid length 147.] 
    Mono.Security.Cryptography.SymmetricTransform.ThrowBadPaddingException(PaddingMode padding, Int32 length, Int32 position):0 
    Mono.Security.Cryptography.SymmetricTransform.FinalDecrypt(System.Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount):0 
    Mono.Security.Cryptography.SymmetricTransform.TransformFinalBlock(System.Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount):0 
    System.Security.Cryptography.CryptoStream.FlushFinalBlock():0 
    com.abc.mobile.shared.Security+PasswordEncoder.DecryptWithByteArray(System.String strText, System.String strEncrypt):0 

संपादित करें: यहाँ कोड मैं एन्क्रिप्ट करने के लिए उपयोग कर रहा हूँ है/डिक्रिप्ट

private string EncryptWithByteArray(string inPassword, string inByteArray) 
    { 

     byte[] tmpKey = new byte[20]; 
     tmpKey = System.Text.Encoding.UTF8.GetBytes(inByteArray.Substring(0, 8)); 
     DESCryptoServiceProvider des = new DESCryptoServiceProvider(); 
     byte[] inputArray = System.Text.Encoding.UTF8.GetBytes(inPassword); 
     MemoryStream ms = new MemoryStream(); 
     CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(tmpKey, mInitializationVector), CryptoStreamMode.Write); 
     cs.Write(inputArray, 0, inputArray.Length); 
     cs.FlushFinalBlock(); 
     return Convert.ToBase64String(ms.ToArray()); 

    } 

     private string DecryptWithByteArray (string strText, string strEncrypt) 
     { 

      try 
      { 
       byte[] tmpKey = new byte[20]; 
       tmpKey = System.Text.Encoding.UTF8.GetBytes (strEncrypt.Substring (0, 8)); 
       DESCryptoServiceProvider des = new DESCryptoServiceProvider(); 
       Byte[] inputByteArray = Convert.FromBase64String (strText); 
       MemoryStream ms = new MemoryStream(); 
       CryptoStream cs = new CryptoStream (ms, des.CreateDecryptor (tmpKey, mInitializationVector), CryptoStreamMode.Write); 
       cs.Write (inputByteArray, 0, inputByteArray.Length); 
      try { 
       cs.FlushFinalBlock(); 
      } catch (Exception ex) { 
       throw(ex); 
      } 
      System.Text.Encoding encoding = System.Text.Encoding.UTF8; 
      return encoding.GetString(ms.ToArray()); 
      } 
      catch (Exception ex) 
      { 
       throw ex; 
      } 
     } 

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

एन्क्रिप्शन कुंजी हमेशा स्थानीय डिवाइस आईडी है। यहाँ मैं यह कैसे हो रही है है:

 TelephonyManager telephonyMgr = Application.Context.GetSystemService(Context.TelephonyService) as TelephonyManager; 
     string deviceId = telephonyMgr.DeviceId == null ? "UNAVAILABLE" : telephonyMgr.DeviceId; 

यह इस प्रकार से कहा जाता है की एक उदाहरण है:

string mByteArray = GetDeviceId(); 
string mEncryptedString = EncryptWithByteArray(stringToEncrypt, mByteArray); 
string mDecryptedString = DecryptWithByteArray(mEncryptedString, mByteArray); 
+0

क्या ब्लॉक सिफर और ऑपरेशन मोड? क्या आप उस संदेश की एक प्रति प्रदान कर सकते हैं जो डिक्रिप्ट करने में विफल रहा? 147 एक अजीब लंबाई की तरह लगता है। यह * आमतौर पर * ब्लॉक सिफर की ब्लॉक लंबाई (अक्सर 16) का एक बहु होना चाहिए। हालांकि, सीटीएस और सीटीआर जैसे मोड में यह आवश्यकता नहीं है। सीबीसी जैसे मोड को मानते हुए, यह लगभग एक अधूरा संदेश संसाधित होने जैसा लगता है। – jww

+0

मैंने अपने मूल सत्यापन में कोड जोड़ा =) –

+0

आपके संपादन के आधार पर और डीईएस का उपयोग कर कोड, 147 *** *** गलत है। डीईएस का ब्लॉक आकार 8 बाइट्स है, इसलिए संदेश 8 बाइट्स का एक बहु होना चाहिए। गायब 3 बाइट्स खोजें (यह 152 बाइट होना चाहिए), और आपकी समस्या हल हो गई है। साथ ही, आपको एन्क्रिप्टेड डेटा के लिए 'बाइट []', 'स्ट्रिंग' नहीं, का उपयोग करना चाहिए। एन्क्रिप्टेड डेटा में 0x00 बाइट शामिल हो सकता है, जो समस्याएं पैदा कर सकता है। या बेस 64 डेटा ताकि यह नल बाइट्स को संभाल सके। – jww

उत्तर

3

आप अपने उपयोग के मामले के बारे में अधिक से अधिक जानकारी प्रदान नहीं की है, लेकिन मैं कहूंगा कि क्योंकि आप नहीं कर रहे हैं यह हो रहा है एन्क्रिप्शन और डिक्रिप्शन ऑपरेशंस के दौरान एक ही सिफर सेटिंग्स का उपयोग करना। सममित सिफर के लिए आपको डेटा एन्क्रिप्शन और डिक्रिप्शन के दौरान बिल्कुल वही सेटिंग्स/पैरामीटर का उपयोग करने की आवश्यकता होती है। उदाहरण के लिए एईएस सीबीसी के लिए आपको दोनों डिवाइसों पर बिल्कुल उसी कुंजी, चतुर्थ, सिफर मोड और पैडिंग का उपयोग करना होगा। यह इन कोड में स्पष्ट रूप से स्थापित करने के लिए सेट करने के लिए सबसे अच्छा है:

System.Security.Cryptography.RijndaelManaged aes = new System.Security.Cryptography.RijndaelManaged(); 
aes.Key = new byte[] { ... }; 
aes.IV = new byte[] { ... }; 
aes.Mode = CipherMode.CBC; 
aes.Padding = PaddingMode.PKCS7; 

क्या आप वाकई एक ही सेटिंग्स का उपयोग कर रहे है तो आप भी परिदृश्य है कि कुछ डेटा दूषित या नेटवर्क स्थानान्तरण के दौरान बदल पाने पर विचार करना चाहिए रहे हैं।

संपादित करने के बाद कुछ कोड के टुकड़े प्रदान किया गया है:

डिक्रिप्शन विधि आपके द्वारा दी गई सभी में तो मैं एक साथ अपने सभी नमूने डाल दिया है मेरे लिए काम नहीं करता है और उन्हें कोड है जो एक ही बात करता है में बदल गया आपके रूप में लेकिन आईएमओ का उपयोग थोड़ा साफ करने वाला दृष्टिकोण है। उदाहरण के लिए इस कोड को और अधिक मजबूत "कुंजी व्युत्पत्ति" का उपयोग करता है (मुझे माफ कर दीजिए cryptoguys) और यह भी बुनियादी कोड विश्लेषण बीत चुका है।

आप आसानी से आप क्या जरूरत है ऐसा करने के लिए सार्वजनिक तरीकों का उपयोग करने के लिए सक्षम होना चाहिए:

string plainData = "This information should be encrypted"; 
string encryptedData = EncryptStringified(plainData); 
string decryptedData = DecryptStringified(encryptedData); 
if (plainData != decryptedData) 
    throw new Exception("Decryption failed"); 

कार्यान्वयन और निजी तरीके इस प्रकार:

/// <summary> 
/// Encrypts string with the key derived from device ID 
/// </summary> 
/// <returns>Base64 encoded encrypted data</returns> 
/// <param name="stringToEncrypt">String to encrypt</param> 
public string EncryptStringified(string stringToEncrypt) 
{ 
    if (stringToEncrypt == null) 
     throw new ArgumentNullException("stringToEncrypt"); 

    byte[] key = DeviceIdToDesKey(); 
    byte[] plainData = Encoding.UTF8.GetBytes(stringToEncrypt); 
    byte[] encryptedData = Encrypt(key, plainData); 
    return Convert.ToBase64String(encryptedData); 
} 

/// <summary> 
/// Decrypts Base64 encoded data with the key derived from device ID 
/// </summary> 
/// <returns>Decrypted string</returns> 
/// <param name="b64DataToDecrypt">Base64 encoded data to decrypt</param> 
public string DecryptStringified(string b64DataToDecrypt) 
{ 
    if (b64DataToDecrypt == null) 
     throw new ArgumentNullException("b64DataToDecrypt"); 

    byte[] key = DeviceIdToDesKey(); 
    byte[] encryptedData = Convert.FromBase64String(b64DataToDecrypt); 
    byte[] decryptedData = Decrypt(key, encryptedData); 
    return Encoding.UTF8.GetString(decryptedData); 
} 

private byte[] DeviceIdToDesKey() 
{ 
    TelephonyManager telephonyMgr = Application.Context.GetSystemService(Context.TelephonyService) as TelephonyManager; 
    string deviceId = telephonyMgr.DeviceId ?? "UNAVAILABLE"; 

    // Compute hash of device ID so we are sure enough bytes have been gathered for the key 
    byte[] bytes = null; 
    using (SHA1 sha1 = SHA1.Create()) 
     bytes = sha1.ComputeHash(Encoding.UTF8.GetBytes(deviceId)); 

    // Get last 8 bytes from device ID hash as a key 
    byte[] desKey = new byte[8]; 
    Array.Copy(bytes, bytes.Length - desKey.Length, desKey, 0, desKey.Length); 
    return desKey; 
} 

private byte[] Encrypt(byte[] key, byte[] plainData) 
{ 
    if (key == null) 
     throw new ArgumentNullException("key"); 

    if (plainData == null) 
     throw new ArgumentNullException("plainData"); 

    using (DESCryptoServiceProvider desProvider = new DESCryptoServiceProvider()) 
    { 
     if (!desProvider.ValidKeySize(key.Length * 8)) 
      throw new CryptographicException("Key with invalid size has been specified"); 
     desProvider.Key = key; 
     // desProvider.IV should be automatically filled with random bytes when DESCryptoServiceProvider instance is created 
     desProvider.Mode = CipherMode.CBC; 
     desProvider.Padding = PaddingMode.PKCS7; 

     using (MemoryStream encryptedStream = new MemoryStream()) 
     { 
      // Write IV at the beginning of memory stream 
      encryptedStream.Write(desProvider.IV, 0, desProvider.IV.Length); 

      // Perform encryption and append encrypted data to the memory stream 
      using (ICryptoTransform encryptor = desProvider.CreateEncryptor()) 
      { 
       byte[] encryptedData = encryptor.TransformFinalBlock(plainData, 0, plainData.Length); 
       encryptedStream.Write(encryptedData, 0, encryptedData.Length); 
      } 

      return encryptedStream.ToArray(); 
     } 
    } 
} 

private byte[] Decrypt(byte[] key, byte[] encryptedData) 
{ 
    if (key == null) 
     throw new ArgumentNullException("key"); 

    if (encryptedData == null) 
     throw new ArgumentNullException("encryptedData"); 

    using (DESCryptoServiceProvider desProvider = new DESCryptoServiceProvider()) 
    { 
     if (!desProvider.ValidKeySize(key.Length * 8)) 
      throw new CryptographicException("Key with invalid size has been specified"); 
     desProvider.Key = key; 
     if (encryptedData.Length <= desProvider.IV.Length) 
      throw new CryptographicException("Too short encrypted data has been specified"); 
     // Read IV from the beginning of encrypted data 
     // Note: New byte array needs to be created because data written to desprovider.IV are ignored 
     byte[] iv = new byte[desProvider.IV.Length]; 
     Array.Copy(encryptedData, 0, iv, 0, iv.Length); 
     desProvider.IV = iv; 
     desProvider.Mode = CipherMode.CBC; 
     desProvider.Padding = PaddingMode.PKCS7; 

     // Remove IV from the beginning of encrypted data and perform decryption 
     using (ICryptoTransform decryptor = desProvider.CreateDecryptor()) 
      return decryptor.TransformFinalBlock(encryptedData, desProvider.IV.Length, encryptedData.Length - desProvider.IV.Length); 
    } 
} 

यह बताने के लिए वास्तव में क्या साथ समस्या थी वास्तव में कठिन है अपने कोड क्योंकि आपके डिक्रिप्शन विधि बिल्कुल मेरे लिए काम नहीं किया - सबसे अधिक संभावना है, क्योंकि यह जो मेरे लिए थोड़ा अजीब लगता है डिक्रिप्शन के लिए राइट मोड में CryptoStream उपयोग कर रहा है।

तो कोड के लिए बहुत

। अब चलिए एन्क्रिप्शन प्राप्त करें जो वास्तव में वास्तव में कमजोर है। यह अधिक सिर्फ एक कहानियो कि गलती से सादे पाठ के रूप में प्रदर्शित किया जा रहा से डेटा की सुरक्षा करना चाहिए (कुछ लोगों को एक ही बात के लिए Base64 एन्कोडिंग का उपयोग) है। इसका मुख्य कारण अपेक्षाकृत पुराना एन्क्रिप्शन एल्गोरिदम और आसानी से अनुमानित एन्क्रिप्शन कुंजी है। AFAIK एक ही डिवाइस पर चल रहे प्रत्येक एप्लिकेशन को बिना किसी विशेषाधिकार के डिवाइस आईडी पढ़ सकते हैं। इसका मतलब है कि कोई भी एप्लिकेशन आपके डेटा को डिक्रिप्ट कर सकता है। बेशक आपका SQLite डेटाबेस शायद आपके एप्लिकेशन पर पहुंच योग्य है लेकिन यदि आप एसडी कार्ड हटाते हैं या अपने फोन को रूट करते हैं तो यह अब सत्य नहीं हो सकता है।इसे थोड़ा बेहतर बनाने के लिए आप उदाहरण के लिए उपयोगकर्ता को पासवर्ड प्रदान करने के लिए कह सकते हैं और फिर अद्वितीय एन्क्रिप्शन कुंजी प्राप्त करने के लिए इसका उपयोग कर सकते हैं लेकिन यह पूरी तरह से अलग समस्या है। वैसे भी मुझे सच में यकीन नहीं है कि आप इस एन्क्रिप्शन के साथ क्या हासिल करने की कोशिश कर रहे हैं - यह आपकी आवश्यकताओं के लिए पूरी तरह से पर्याप्त हो सकता है भले ही इसे कमजोर माना जा सके।

उम्मीद है कि इससे मदद मिलती है।

+0

कृपया आरई के ऊपर मेरे संपादन देखें जो मैं एन्क्रिप्ट/डिक्रिप्ट करने के लिए उपयोग कर रहा हूं। दुर्भाग्यवश मुझे त्रुटि को डुप्लिकेट करने का कोई तरीका नहीं मिला है- हमारी त्रुटि रिपोर्टिंग कार्यान्वयन द्वारा रिपोर्ट की जा रही है। मैंने जानबूझकर पैडिंग और एन्क्रिप्शन स्ट्रिंग्स के साथ गड़बड़ करने की कोशिश की लेकिन यह एक अलग त्रुटि फेंकता है- क्योंकि एन्क्रिप्शन के साथ ज्ञान की मेरी कमी भी इसके टोल ले सकती है। –

+0

@ उन विधियों के ली-रॉय कार्यान्वयन मेरे लिए थोड़ा अजीब लगता है लेकिन यह एक लापता संदर्भ के कारण हो सकता है। क्या आप इनपुट पैरामीटर का वर्णन कर सकते हैं क्योंकि मुझे यकीन नहीं है कि मैं समझता हूं कि आप एन्क्रिप्ट करने की कोशिश कर रहे हैं और एन्क्रिप्शन कुंजी और प्रारंभिक वेक्टर कहां से आ रहा है। इससे आपकी मदद भी होगी यदि आप अपने कोड को उस हिस्से के साथ बढ़ा सकते हैं जो वास्तव में इन दो विधियों को कॉल करता है। – jariq

+0

धन्यवाद जारीक। मैं एपीआई कुंजी एन्क्रिप्ट कर रहा हूं और फिर डिवाइस पर SQLite डेटाबेस में संग्रहीत कर रहा हूं। एन्क्रिप्शन कुंजी डिवाइस आईडी है और मुझे यकीन नहीं है कि प्रारंभिक वेक्टर द्वारा आपका क्या मतलब है! (अभी एक त्वरित Google के अलावा)। मैंने शुरू में इस कोड को नेट पर कहीं और पाया जो मुझे मिला (मुझे पता है!)। मैं अपने ओपी को कुछ अतिरिक्त कोड के साथ संपादित कर दूंगा। –

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