2016-10-25 51 views
7

我收到来自谷歌的一些错误发挥控制台,一些用户(像素XL,Nexus 5和的Xperia Z3 +)越来越共享偏好? javax.crypto.BadPaddingException:垫块在一些设备仅损坏

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) 

的应用程序工作罚款在其他设备(即使在一些联系5工作正常)

问题出现时,用户第一次打开应用程序,它尝试从共享偏好加载音乐音量。由于他们从来没有在选项菜单中输入更改默认值时,它应该得到的默认值:

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

如果我们getInt从ObsucredSharedPreferences输入:

@Override 
public int getInt(String key, int defValue) { 
    final String v = delegate.getString(key, null); 
    return v!=null ? Integer.parseInt(decrypt(v)) : defValue; 
} 

所以不是得到空值从getString我得到像“ERKJFER89er”的值(我从来没有在首选项中写入该值,否则它应该会在每个手机上崩溃),所以当它尝试解密该值时,它会期望一个int值,并且会抛出一个javax.crypto.BadPaddingException: pad block corrupted我不'吨知道如何解决这个问题或如何解决这个问题,任何想法将是一个梦想

代码解密的:

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用户说恢复出厂设置并没有解决这个问题,但恢复出厂设置有擦拭缓存和擦拭数据解决它

全栈strace的谷歌像素

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) 
+1

我之前遇到过同样的问题。改变加密模式解决了这个问题。 –

+0

我也有同样的问题,除改变加密模式之外,还有其他的选择吗? –

+0

我的同事之一也有同样的问题 – M14

回答

1

什么的decrypt(null)返回结果?看起来你的应用程序读取了一些错误的数据,这些数据以前写得不正确。

另外我注意到某些设备在数据文件夹路径上有不同的行为并可能导致此问题。

您的问题的一个可能的解决方案是记录详细的崩溃上下文,包括导致解密错误的数据。您可以尝试一些在线日志服务,如Fabric或Logentries。或者你可以实现你的全局ExceptionHandler,保存数据并在发生崩溃时将数据发送给你。

IMO,我宁愿将所有数据保存在字符串中,并在运行时解析它们以防数据格式发生变化。

仅供参考。这是我的偏好实施。它支持保存在SharedPreference中的简单/编码/加密首选项。它也很容易被扩展以支持在线偏好。

https://github.com/passos/SimplePreferences/blob/master/library/src/main/java/com/ioenv/preferences/

+0

是的,数据是不正确的,但问题是应用程序没有写入数据之前,这个问题发生在一些设备的第一次,应用程序尝试读取首选项,而不是给出默认值,它给一个随机的字符串,但那个字符串从来没有写过 – D4rWiNS

+0

我有详细的崩溃日志,我附上 – D4rWiNS

+0

你也可以尝试检测它是否是第一次执行,然后写入默认首选项。这不是最好的选择,但它应该工作。 – juanlugm

2

我不能说这是多有猜测得多,但我会试试看。

我见过其他人使用SharedPreferences的默认值为空,但我喜欢使用实际的默认值作为字符串。基于此,我会更喜欢这样的东西(假设有encryt()方法去与decrypt())。

@Override 
public int getInt(String key, int defValue) { 
    final String v = delegate.getString(key, encrypt(String.valueOf(defValue)); 
    return Integer.parseInt(decrypt(v)); 
} 

如果这样不能解决问题,是否尝试过使用非空值作为默认值。空串怎么样?您确定的一些Unicode字符不能是真正的加密存储值?编辑:这是不太可能的问题。查看文档后,getString()的参数defValue为Nullable,表示该方法旨在优雅地处理空参数。

希望这会有所帮助,祝你好运。

编辑:我试图复制你的问题,但不能。我尝试使用API​​ 23的Nexus 5仿真设备和Nexus 5真实设备。getString()总是返回null。我使用基于this的代码。我想它基本上与你的代码基于相同。

留出未使用的方法...

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

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

你可以尝试简化您的代码是这样的。如果这种方法有效,而你的方法不适用,则只需要添加&删除代码,直到确定问题的原因。 (我知道它不一定那么容易,因为它使声音)。

其他问题,需要考虑的事情。 你有没有尝试调试和发布构建配置? 是否每次卸载应用程序以确保它是第一次运行该应用程序? 音量是否与此相关的唯一偏好?

我已经回去重读你的问题&我现在注意到你写的问题是由Google Play报道的。这是一个很大的问题,你是否可以自己复制它,以便你可以尝试不同的事情来确定根本原因?

+0

我会尝试更改为不同的默认值,但问题是,而不是返回null值,它返回一个随机字符串 – D4rWiNS

+0

大多数错误来自Google Play报告或Firebase崩溃报告,但是,六个月前,我的Nexus 5出现同样的错误,我尝试了很多事情,但只使用了擦除缓存格式窍门 – D4rWiNS

+0

如果您想告诉我应用程序的名称,我会尝试下载它以查看它是否适用于我的Nexus 5.您有哪些API? – Gary99