CryptographicException: Mala PKCS7 de relleno

Estoy viendo un pequeño porcentaje de los usuarios de producción al azar informar esta excepción relacionada con el cifrado / descifrar cadenas con Xamarin.Android, pero por desgracia no puedo reproducirlo.

¿Qué podría causar esto y / o cómo podría reproducir la excepción para que pueda encontrar una solución / solución?

[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 

EDIT: Aquí está el código que estoy usando para cifrar / descifrar

  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; } } 

EDIT 2:

La clave de cifrado es siempre el ID de dispositivo local. Así es como obtengo esto:

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

He aquí un ejemplo de cómo se llama:

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

No ha proporcionado muchos detalles acerca de su caso de uso, pero yo diría que esto está sucediendo porque no está utilizando la misma configuración de cifrado durante las operaciones de cifrado y descifrado. Las cifras simétricas requieren que utilice exactamente los mismos parámetros / parámetros durante el cifrado de datos y también el descifrado. Por ejemplo, para AES CBC necesitaría usar exactamente la misma clave, IV, modo de cifrado y relleno en ambos dispositivos. Lo mejor es establecer estos ajustes explícitamente en el código:

 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; 

Si está seguro de que está utilizando la misma configuración, también debe considerar el escenario de que algunos datos se dañen o alteren durante la transferencia de red.

Editar después de algunos fragmentos de código se han proporcionado:

Método de descifrado que ha proporcionado no funciona para mí en absoluto, así que he reunido todas sus muestras y los convirtió en el código que hace lo mismo que el suyo, pero utiliza IMO un enfoque un poco más limpio. Por ejemplo, este código utiliza una "derivación de clave" más robusta (por favor perdóname criptoguys) y también ha pasado el análisis de código básico.

Debe poder utilizar fácilmente métodos públicos para hacer lo que necesita:

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

La implementación y los métodos privados son los siguientes:

 /// <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); } } 

Es realmente difícil de saber qué fue exactamente el problema con su código porque su método de descifrado no funcionó para mí en absoluto – lo más probable es que está utilizando CryptoStream en modo de escritura para el descifrado que parece un poco extraño para mí.

Tanto para el código. Ahora vamos a llegar a la encriptación que es realmente muy débil. Es más sólo una ofuscación que debe proteger los datos de ser accidentalmente se muestra en forma de texto sin formato (algunas personas utilizan codificación BASE64 para la misma cosa). La principal causa de esto es el algoritmo de cifrado relativamente viejo y la clave de cifrado fácilmente predecible. AFAIK cada aplicación que se ejecuta en el mismo dispositivo puede leer ID de dispositivo sin privilegios. Eso significa que cualquier aplicación puede descifrar sus datos. Por supuesto, su base de datos SQLite es probablemente accesible sólo a su aplicación, pero que ya no puede ser cierto si se quita la tarjeta SD o la raíz de su teléfono. Para hacer esto un poco mejor podría por ejemplo pedir al usuario que proporcione una contraseña y luego usarla para obtener una clave de cifrado única, pero eso es un problema completamente diferente. De todos modos no estoy realmente seguro de lo que está tratando de lograr con este cifrado – puede ser totalmente suficiente para sus necesidades, incluso si se puede considerar que es débil.

Espero que esto ayude.

  • Xamarin.forms mezclando ContentPage y la actividad de Android
  • MvvmCross Navegar a ViewModel en la notificación de Android haga clic
  • ¿El oyente Scrollview no está trabajando en Xamarin para Android?
  • Xamarin aplicaciones son grandes por qué y pueden ser más pequeños
  • SSLHandshakeException en Android 4.4 y menor
  • Reciclaje Bitmap no libera memoria
  • ¿Cómo tratar con "$ {applicationid}" en Xamarin?
  • MvvmCross Checkbox se enlaza al comando android xml
  • Java.lang.NoClassDefFoundError: android.support.v7.app.AppCompatDelegateImplV14 en Xamarin Android
  • Enlace adecuado de una biblioteca nativa en Xamarin
  • Analog SetOnTouchListener o cómo se utiliza en xamarin, qué argumento debe ser
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.