¿Preferencias compartidas? Javax.crypto.BadPaddingException: bloque de pad corrompido sólo en algunos dispositivos
Estoy recibiendo algunos errores de google play consola donde algunos usuarios (Pixel XL, nexus 5 y Xperia Z3 +) están recibiendo
Caused by: java.lang.RuntimeException: javax.crypto.BadPaddingException: pad block corrupted at com.darwins.custom.ObscuredSharedPreferences.decrypt(ObscuredSharedPreferences.java:193) at com.darwins.custom.ObscuredSharedPreferences.getInt(ObscuredSharedPreferences.java:134)
La aplicación está funcionando bien en el resto de dispositivos (incluso en algunos nexus 5 está funcionando bien)
- Android Studio: Android Device Monitor no muestra mi dispositivo
- Cómo crear una carpeta de valores separados Sony Xperia Z1 en android
- Las cookies no se reciben en los datos móviles, pero recibió con wifi durante el registro en android (dispositivo es sony xperia)
- Linterna LED en xperia Z5
- Adb install falla con error 'INSTALL_FAILED_INSUFFICIENT_STORAGE'
El problema viene cuando la primera vez que el usuario abre la aplicación, intenta cargar el volumen de la música de las preferencias compartidas. Como nunca entraron en el menú de opciones para cambiar el valor por defecto, debería obtener el valor predeterminado:
if(sp == null) sp = new ObscuredSharedPreferences(ctx, ctx.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE)); if(musicVolume == -1) musicVolume = sp.getInt(KEY_SP_MUSIC_VOLUME,10);
Si entramos en getInt de ObsucredSharedPreferences:
@Override public int getInt(String key, int defValue) { final String v = delegate.getString(key, null); return v!=null ? Integer.parseInt(decrypt(v)) : defValue; }
Así que en lugar de obtener el valor nulo de getString
estoy recibiendo un valor como "ERKJFER89er" (nunca escribo ese valor en las preferencias, de lo contrario debería bloquearse en todos los teléfonos) por lo que cuando se trata de descifrar el valor esperado un valor int y Que lanza un javax.crypto.BadPaddingException: pad block corrupted
No sé cómo solucionar esto o cómo arreglar esto, cualquier idea será apreciate
Código de descifrado:
protected String decrypt(String value){ try { final byte[] bytes = value!=null ? Base64.decode(value,Base64.DEFAULT) : new byte[0]; SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES"); SecretKey key = keyFactory.generateSecret(new PBEKeySpec(SEKRIT)); Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES"); pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec( Secure.getString(context.getContentResolver(), Secure.ANDROID_ID).getBytes(UTF8), 20)); return new String(pbeCipher.doFinal(bytes),UTF8); } catch( Exception e) { throw new RuntimeException(e); } }
1 usuario dice que hacer un restablecimiento de fábrica no soluciona el problema, pero hacer un restablecimiento de fábrica con la caché de borrado y borrar los datos de resolverlo
Strace completo de la pila para el pixel de google
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.suduck.upgradethegame/com.darwins.cubegame.WelcomeActivity}: java.lang.RuntimeException: javax.crypto.BadPaddingException: pad block corrupted at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2665) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726) at android.app.ActivityThread.-wrap12(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6119) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) Caused by: java.lang.RuntimeException: javax.crypto.BadPaddingException: pad block corrupted at com.darwins.custom.ObscuredSharedPreferences.decrypt(ObscuredSharedPreferences.java:193) at com.darwins.custom.ObscuredSharedPreferences.getInt(ObscuredSharedPreferences.java:134) at com.darwins.clases.Logro.<init>(Logro.java:41) at com.darwins.clases.LogrosManager.iniciar(LogrosManager.java:64) at com.darwins.clases.LogrosManager.<init>(LogrosManager.java:48) at com.darwins.motor.CEngine.Inicializar(CEngine.java:141) at com.darwins.superclases.CActividad.onCreate(CActividad.java:47) at com.darwins.cubegame.WelcomeActivity.onCreate(WelcomeActivity.java:32) at android.app.Activity.performCreate(Activity.java:6679) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2618) ... 9 more Caused by: javax.crypto.BadPaddingException: pad block corrupted at com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$BufferedGenericBlockCipher.doFinal(BaseBlockCipher.java:1267) at com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(BaseBlockCipher.java:1100) at javax.crypto.Cipher.doFinal(Cipher.java:2056) at com.darwins.custom.ObscuredSharedPreferences.decrypt(ObscuredSharedPreferences.java:190)
- ADB no detecta Sony Xperia Z3 Compact (android 5.0.2)
- He utilizado el comando adb "pm bloque com.sonymobile.advancedwidget.entrance" ¿cómo desbloqueo esta aplicación?
- No se puede detectar Sony Xperia en Eclipse
- AndroidHttpClient Nullpointerexception llamando a android.net.http.AndroidHttpClient.isMmsRequest
- MediaScannerConnection # scanFile convierte directorios en archivos al acceder a ellos con USB-MTP en Android 5 Lollipop
- Cómo conectar mi dispositivo Android a eclipse
- La depuración en Sony Xperia (E2003) dejó de funcionar de repente
- Juego estrellado en Sony Xperia
No puedo decir que esto es mucho más que una suposición, pero voy a darle una oportunidad.
He visto a otros usar un valor predeterminado de null para SharedPreferences, pero me gusta usar el valor predeterminado real como una cadena. Basado en eso, tendría algo más como esto (suponiendo que hay un método de encryt()
para ir con decrypt()
).
@Override public int getInt(String key, int defValue) { final String v = delegate.getString(key, encrypt(String.valueOf(defValue)); return Integer.parseInt(decrypt(v)); }
Si eso no soluciona el problema, ha intentado usar algo distinto de null como valor predeterminado. ¿Qué tal una cuerda vacía? Algunos caracteres unicode (s) que usted está seguro no puede ser un valor almacenado cifrado real? EDIT: Esto es improbable que el problema. Después de examinar la documentación, el parámetro defValue
para getString()
es Nullable, lo que significa que el método está diseñado para manejar un parámetro nulo con gracia.
Espero que esto ayude y buena suerte.
EDIT: He intentado duplicar su problema, pero no pudo. Intenté un dispositivo emulado Nexus 5 y un dispositivo Nexus 5 real, ambos utilizando API 23. getString()
siempre devuelve null. Utilicé código basado en esto . Me imagino que es más o menos lo mismo de su código se basa.
Dejando fuera los métodos no utilizados …
public class ObscuredSharedPreferences implements SharedPreferences { private static final String TAG = "ObscuredSp"; protected static final String UTF8 = "utf-8"; private static final char[] SEKRIT = "abc".toCharArray() ; // INSERT A RANDOM PASSWORD HERE. protected SharedPreferences delegate; protected Context context; public ObscuredSharedPreferences(Context context, SharedPreferences delegate) { this.delegate = delegate; this.context = context; } @Override public int getInt(String key, int defValue) { final String v = delegate.getString(key, null); Log.d(TAG, "got int " + v); return v!=null ? Integer.parseInt(decrypt(v)) : defValue; } protected String decrypt(String value){ try { final byte[] bytes = value!=null ? Base64.decode(value, Base64.DEFAULT) : new byte[0]; SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES"); SecretKey key = keyFactory.generateSecret(new PBEKeySpec(SEKRIT)); Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES"); pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID).getBytes(UTF8), 20)); return new String(pbeCipher.doFinal(bytes),UTF8); } catch( Exception e) { throw new RuntimeException(e); } } }
En onCreate()
…
private static final String MY_PREFS_FILE_NAME = "MyFile"; private static final String KEY_SP_MUSIC_VOLUME = "KeySpMusicVol"; final SharedPreferences prefs = new ObscuredSharedPreferences( this, this.getSharedPreferences(MY_PREFS_FILE_NAME, Context.MODE_PRIVATE)); int musicVolume; musicVolume = prefs.getInt(KEY_SP_MUSIC_VOLUME, 10); Log.d(TAG, "volume = " + musicVolume);
Usted podría intentar simplificar su código a algo como esto. Si esto funciona y el tuyo no, es sólo cuestión de agregar y quitar código hasta que determine qué causa el problema. (Sé que no es necesariamente tan fácil como eso hace que suene).
Otra pregunta, cosas para pensar. ¿Han probado tanto la configuración de compilación de depuración como de liberación? ¿Desinstala la aplicación cada vez para asegurarse de que es la primera vez que se ejecuta la aplicación? ¿Es el volumen la única preferencia con la que esto sucede?
He vuelto a leer tu pregunta y ahora me doy cuenta de que escribes los problemas que informa Google Play. Esto hace que la gran pregunta, ¿puede duplicar esto usted mismo tal que usted puede probar cosas diferentes para determinar la causa raíz?
¿Cuál es el resultado de devolución de decrypt(null)
? Parece que su aplicación lee algunos datos incorrectos que se escribieron incorrectamente antes.
También me di cuenta de que algunos dispositivos tienen un comportamiento diferente en la ruta de la carpeta de datos y probablemente causó este problema.
Una solución posible para su problema es registrar el contexto de falla de detalle incluyendo los datos que causaron error de descifrado. Puede probar algún servicio de registro en línea como Fabric o Logentries. O puede implementar su ExceptionHandler global, guardar los datos y enviar los datos a usted cuando ocurrió un accidente.
IMO, prefiero guardar todos los datos en String y analizarlos en tiempo de ejecución en caso de cambio de formato de datos.
FYI. Aquí está mi aplicación de preferencia. Soporta la preferencia cifrada / codificada / cifrada guardada en SharedPreference. También es muy fácil de extender para apoyar las preferencias en línea.
https://github.com/passos/SimplePreferences/blob/master/library/src/main/java/com/ioenv/preferences/