patrickfav / armadillo

A shared preference implementation for confidential data in Android. Per default uses AES-GCM, BCrypt and HKDF as cryptographic primitives. Uses the concept of device fingerprinting combined with optional user provided passwords and strong password hashes.
https://favr.dev/opensource/armadillo
Apache License 2.0
280 stars 52 forks source link

Library crashing in devices running KitKat #6

Closed davidmigloz closed 6 years ago

davidmigloz commented 6 years ago

According to the Readme:

Minimum SDK 19 (Android 4.4): A way to increase security is to cap older implementation. SDK 19 seems to be a good compromise where most of the older security hack fixes are not necessary anymore, but still targeting most devices.

But if you look into the build.gradle file, it declares:

minSdkVersion = 21

Are the docs not up to date? Or it is still safe to use the library with minSdkVersion = 19?

Thanks.

patrickfav commented 6 years ago

Hi David,

It should be safe SDK 19+, I will check in the next couple of days and release a new version with the correct version.

davidmigloz commented 6 years ago

Ah perfect! Thank you.

HonzaR commented 6 years ago

Hi Patrik,

can you please public release of this great lib with fixed min sdk? It causes problems in my app. Thanks in advance.

Honza

davidmigloz commented 6 years ago

Meanwhile, you can force it in your manifest to avoid the merge errors:

<uses-sdk android:minSdkVersion="19" tools:overrideLibrary="at.favre.lib:armadillo"/>
HonzaR commented 6 years ago

Yep, thanks.

I can only build my app with: <uses-sdk tools:overrideLibrary="at.favre.lib.armadillo"/>

But still app crashes on SDK 19 on start with: java.lang.IllegalStateException: at.favre.lib.armadillo.EncryptionProtocolException: at.favre.lib.armadillo.AuthenticatedEncryptionException: could not encrypt

davidmigloz commented 6 years ago

GCMParameterSpec is supposed to be available in devices running KitKat, but apparently, it's not implemented in all devices. IvParameterSpec can be used instead. Also, associated data is not available in Android KitKat. I've made a pull request with the fixes.

HonzaR commented 6 years ago

Hey guys,

thanks for new version 0.5.0, but crash still occurs with the same error on Kitkat as before, see:

07-12 10:28:52.235 3485-3485/cz.dpp.praguepublictransport E/AndroidRuntime: FATAL EXCEPTION: main Process: cz.dpp.praguepublictransport, PID: 3485 java.lang.RuntimeException: Unable to create application cz.dpp.praguepublictransport.utils.CustomApplication: java.lang.IllegalStateException: at.favre.lib.armadillo.EncryptionProtocolException: at.favre.lib.armadillo.AuthenticatedEncryptionException: could not encrypt at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4476) at android.app.ActivityThread.access$1500(ActivityThread.java:144) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1265) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:136) at android.app.ActivityThread.main(ActivityThread.java:5146) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:732) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:566) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.IllegalStateException: at.favre.lib.armadillo.EncryptionProtocolException: at.favre.lib.armadillo.AuthenticatedEncryptionException: could not encrypt at at.favre.lib.armadillo.SecureSharedPreferences.encryptToBase64(SecureSharedPreferences.java:338) at at.favre.lib.armadillo.SecureSharedPreferences.access$300(SecureSharedPreferences.java:31) at at.favre.lib.armadillo.SecureSharedPreferences$Editor.putLong(SecureSharedPreferences.java:280)

patrickfav commented 6 years ago

0.5.0 did only change the minSDK, the fallback implementation for the GCM block mode is in progress (needed a fast release yesterday)

patrickfav commented 6 years ago

fyi: This is going to be the next issue I'll tackle in the next couple of days.

HonzaR commented 6 years ago

Hi Patric, do you have any idea, when the lib will be fixed? My project is close to deadline :( Thanks. Honza

patrickfav commented 6 years ago

@HonzaR sorry, since I do my open source projects in my spare time I cannot give you any ETA. You could fix it yourself however with only moderate effort.

Just check out how @davidmigloz modified the AuthenticatedEncryption in his PR #10 (see AesGcmEncryption.java). Just copy AesGcmEncryption.java, name it e.g. KitKatPatchedAesGcmEncryptionand add the patch from david and set it as default encryption with:

SharedPreferences preferences = Armadillo.create(context, "myCustomPreferences")
    .symmetricEncryption(new KitKatPatchedAesGcmEncryption())
    ...
    .build();
HonzaR commented 6 years ago

@patrickfav Thanks, but even with custom implementation of AesGsmEncryption I am getting same error, see:

07-17 09:09:41.082 4951-4951/cz.dpp.praguepublictransport E/AndroidRuntime: FATAL EXCEPTION: main
    Process: cz.dpp.praguepublictransport, PID: 4951
    java.lang.RuntimeException: Unable to create application cz.dpp.praguepublictransport.utils.CustomApplication: java.lang.IllegalStateException: at.favre.lib.armadillo.EncryptionProtocolException: at.favre.lib.armadillo.AuthenticatedEncryptionException: could not encrypt
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4347)
        at android.app.ActivityThread.access$1500(ActivityThread.java:135)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:136)
        at android.app.ActivityThread.main(ActivityThread.java:5017)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
        at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.IllegalStateException: at.favre.lib.armadillo.EncryptionProtocolException: at.favre.lib.armadillo.AuthenticatedEncryptionException: could not encrypt
        at at.favre.lib.armadillo.SecureSharedPreferences.encryptToBase64(SecureSharedPreferences.java:338)
        at at.favre.lib.armadillo.SecureSharedPreferences.access$300(SecureSharedPreferences.java:31)
        at at.favre.lib.armadillo.SecureSharedPreferences$Editor.putLong(SecureSharedPreferences.java:280)
        at cz.dpp.praguepublictransport.utils.SharedPreferencesManager.setBootTime(SharedPreferencesManager.java:458)
        at cz.dpp.praguepublictransport.utils.TrueTimeUtils.checkDeviceBootTime(TrueTimeUtils.java:83)
        at cz.dpp.praguepublictransport.utils.TrueTimeUtils.initImmediately(TrueTimeUtils.java:45)
        at cz.dpp.praguepublictransport.utils.CustomApplication.onCreate(CustomApplication.java:51)
        at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1007)
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4344)
        at android.app.ActivityThread.access$1500(ActivityThread.java:135) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:136) 
        at android.app.ActivityThread.main(ActivityThread.java:5017) 
        at java.lang.reflect.Method.invokeNative(Native Method) 
        at java.lang.reflect.Method.invoke(Method.java:515) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595) 
        at dalvik.system.NativeStart.main(Native Method) 
     Caused by: at.favre.lib.armadillo.EncryptionProtocolException: at.favre.lib.armadillo.AuthenticatedEncryptionException: could not encrypt
        at at.favre.lib.armadillo.DefaultEncryptionProtocol.encrypt(DefaultEncryptionProtocol.java:98)
        at at.favre.lib.armadillo.SecureSharedPreferences.encryptToBase64(SecureSharedPreferences.java:336)
        at at.favre.lib.armadillo.SecureSharedPreferences.access$300(SecureSharedPreferences.java:31) 
        at at.favre.lib.armadillo.SecureSharedPreferences$Editor.putLong(SecureSharedPreferences.java:280) 
        at cz.dpp.praguepublictransport.utils.SharedPreferencesManager.setBootTime(SharedPreferencesManager.java:458) 
        at cz.dpp.praguepublictransport.utils.TrueTimeUtils.checkDeviceBootTime(TrueTimeUtils.java:83) 
        at cz.dpp.praguepublictransport.utils.TrueTimeUtils.initImmediately(TrueTimeUtils.java:45) 
        at cz.dpp.praguepublictransport.utils.CustomApplication.onCreate(CustomApplication.java:51) 
        at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1007) 
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4344) 
        at android.app.ActivityThread.access$1500(ActivityThread.java:135) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:136) 
        at android.app.ActivityThread.main(ActivityThread.java:5017) 
        at java.lang.reflect.Method.invokeNative(Native Method) 
        at java.lang.reflect.Method.invoke(Method.java:515) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595) 
        at dalvik.system.NativeStart.main(Native Method) 
     Caused by: at.favre.lib.armadillo.AuthenticatedEncryptionException: could not encrypt
        at cz.dpp.praguepublictransport.utils.KitKatPatchedAesGcmEncryption.encrypt(KitKatPatchedAesGcmEncryption.java:91)
        at at.favre.lib.armadillo.DefaultEncryptionProtocol.encrypt(DefaultEncryptionProtocol.java:87)
        at at.favre.lib.armadillo.SecureSharedPreferences.encryptToBase64(SecureSharedPreferences.java:336) 
        at at.favre.lib.armadillo.SecureSharedPreferences.access$300(SecureSharedPreferences.java:31) 
        at at.favre.lib.armadillo.SecureSharedPreferences$Editor.putLong(SecureSharedPreferences.java:280) 
        at cz.dpp.praguepublictransport.utils.SharedPreferencesManager.setBootTime(SharedPreferencesManager.java:458) 
        at cz.dpp.praguepublictransport.utils.TrueTimeUtils.checkDeviceBootTime(TrueTimeUtils.java:83) 
        at cz.dpp.praguepublictransport.utils.TrueTimeUtils.initImmediately(TrueTimeUtils.java:45) 
        at cz.dpp.praguepublictransport.utils.CustomApplication.onCreate(CustomApplication.java:51) 
        at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1007) 
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4344) 
        at android.app.ActivityThread.access$1500(ActivityThread.java:135) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:136) 
        at android.app.ActivityThread.main(ActivityThread.java:5017) 
        at java.lang.reflect.Method.invokeNative(Native Method) 
        at java.lang.reflect.Method.invoke(Method.java:515) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595) 
        at dalvik.system.NativeStart.main(Native Method) 
     Caused by: java.lang.UnsupportedOperationException: This cipher does not support Authenticated Encryption with Additional Data
        at javax.crypto.CipherSpi.engineUpdateAAD(CipherSpi.java:393)
        at javax.crypto.Cipher.updateAAD(Cipher.java:1056)
        at cz.dpp.praguepublictransport.utils.KitKatPatchedAesGcmEncryption.encrypt(KitKatPatchedAesGcmEncryption.java:80)
        at at.favre.lib.armadillo.DefaultEncryptionProtocol.encrypt(DefaultEncryptionProtocol.java:87) 
        at at.favre.lib.armadillo.SecureSharedPreferences.encryptToBase64(SecureSharedPreferences.java:336) 
        at at.favre.lib.armadillo.SecureSharedPreferences.access$300(SecureSharedPreferences.java:31) 
        at at.favre.lib.armadillo.SecureSharedPreferences$Editor.putLong(SecureSharedPreferences.java:280) 
        at cz.dpp.praguepublictransport.utils.SharedPreferencesManager.setBootTime(SharedPreferencesManager.java:458) 
        at cz.dpp.praguepublictransport.utils.TrueTimeUtils.checkDeviceBootTime(TrueTimeUtils.java:83) 
        at cz.dpp.praguepublictransport.utils.TrueTimeUtils.initImmediately(TrueTimeUtils.java:45) 
        at cz.dpp.praguepublictransport.utils.CustomApplication.onCreate(CustomApplication.java:51) 
        at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1007) 
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4344) 
        at android.app.ActivityThread.access$1500(ActivityThread.java:135) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:136) 
        at android.app.ActivityThread.main(ActivityThread.java:5017) 
        at java.lang.reflect.Method.invokeNative(Native Method) 
        at java.lang.reflect.Method.invoke(Method.java:515) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595) 
        at dalvik.system.NativeStart.main(Native Method) 

I have implemented as @davidmigloz suggested and initialize as preferences = Armadillo.create(mContext, PREFS_NAME) .symmetricEncryption(new KitKatPatchedAesGcmEncryption()) .encryptionFingerprint(mContext) .build();

Do you have any idea? Thank you, Honza

patrickfav commented 6 years ago

@HonzaR You will need to disable the associated Data on KitKat. That means adding to this code (for encrypt and decrypt)

if (associatedData != null) {
    cipherDec.updateAAD(associatedData);
}

the KitKat check

if (!isKitKat() && associatedData != null) {
    cipherDec.updateAAD(associatedData);
}

Note however that this will break the encrypted data if users upgrade from KitKat to anything newer. That is the reason the fix is not included as of yet, as Im not sure how to handle this special case. A workaround would be to force these users to use the kitkat version forever even after upgrade.

davidmigloz commented 6 years ago

Do you have any idea how to proceed with this?

patrickfav commented 6 years ago

Hey, sorry for the radio silence, I was really swampt. Will tackle this in the next few days if nothing comes in between.

patrickfav commented 6 years ago

PR is ready #31

patrickfav commented 6 years ago

Fixed with 0.6.0