2016-10-25 50 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