From 8f9c864b81cccc81d5260eaddf7a495a3ef532c7 Mon Sep 17 00:00:00 2001 From: Preyea Regmi Date: Mon, 29 Apr 2019 16:54:39 +0545 Subject: [PATCH] AES encryption added --- .../gmeremittance_native/base/PrefKeys.java | 1 + .../base/PrivilegedGateway.java | 28 +++- .../base/PrivilegedGatewayInterface.java | 3 + .../presenter/ChangePasswordV2Presenter.java | 2 +- .../loginV2/presenter/LoginV2Presenter.java | 153 +++++++++--------- .../settings/view/SettingsView.java | 8 +- .../TransactionPasswordPromptV2Presenter.java | 2 +- .../utils/security/SecurityUtils.java | 11 +- 8 files changed, 112 insertions(+), 96 deletions(-) diff --git a/app/src/main/java/com/gmeremit/online/gmeremittance_native/base/PrefKeys.java b/app/src/main/java/com/gmeremit/online/gmeremittance_native/base/PrefKeys.java index 74213cfd..fa85fac8 100644 --- a/app/src/main/java/com/gmeremit/online/gmeremittance_native/base/PrefKeys.java +++ b/app/src/main/java/com/gmeremit/online/gmeremittance_native/base/PrefKeys.java @@ -51,4 +51,5 @@ public class PrefKeys { public static String APP_FINGER_PRINT_ENABLED ="APP_FINGER_PRINT_ENABLED"; public static String APP_USER_SECRET_KEY ="APP_USER_SECRET_KEY"; public static String APP_USER_ID_SECRET_KEY ="APP_USER_ID_KEY"; + public static String APP_SECRET_KEY ="APP_SECRET_KEY"; } diff --git a/app/src/main/java/com/gmeremit/online/gmeremittance_native/base/PrivilegedGateway.java b/app/src/main/java/com/gmeremit/online/gmeremittance_native/base/PrivilegedGateway.java index 7c5a9649..960ec31f 100644 --- a/app/src/main/java/com/gmeremit/online/gmeremittance_native/base/PrivilegedGateway.java +++ b/app/src/main/java/com/gmeremit/online/gmeremittance_native/base/PrivilegedGateway.java @@ -6,6 +6,7 @@ import android.util.Log; import com.gmeremit.online.gmeremittance_native.GmeApplication; import com.gmeremit.online.gmeremittance_native.homeV2.model.UserInfoModelV2; +import com.gmeremit.online.gmeremittance_native.utils.security.SecurityUtils; import static com.gmeremit.online.gmeremittance_native.base.PrefKeys.USER_PREFERRED_LOCALE; @@ -13,6 +14,7 @@ import static com.gmeremit.online.gmeremittance_native.base.PrefKeys.USER_PREFER @SuppressWarnings("HardCodedStringLiteral") public abstract class PrivilegedGateway implements PrivilegedGatewayInterface { + private static PrivilegedGatewayDataObserverManager privilegedGatewayDataObserverManager = null; public interface PrivilegedGatewayDataObserver { @@ -135,15 +137,17 @@ public abstract class PrivilegedGateway implements PrivilegedGatewayInterface { @SuppressLint("ApplySharedPref") @Override public void clearAllUserData() { - String persistedPwd=GmeApplication.getStorage().getString(PrefKeys.APP_USER_SECRET_KEY,null); - String persistedUserId=GmeApplication.getStorage().getString(PrefKeys.APP_USER_ID_SECRET_KEY,null); - boolean persistedFingerAuthEnabled=GmeApplication.getStorage().getBoolean(PrefKeys.APP_FINGER_PRINT_ENABLED,false); + String persistedPwd=getPersistedUserPwd(); + String persistedUserId=getPersistedUserId(); + String persistedSecretKey=getPersistedSecretKey(); + boolean persistedFingerAuthEnabled=isFingerPrintAuthEnabled(); GmeApplication.getStorage().edit().clear().commit(); - GmeApplication.getStorage().edit().putString(PrefKeys.APP_USER_ID_SECRET_KEY,persistedUserId).apply(); - GmeApplication.getStorage().edit().putString(PrefKeys.APP_USER_SECRET_KEY,persistedPwd).apply(); - GmeApplication.getStorage().edit().putBoolean(PrefKeys.APP_FINGER_PRINT_ENABLED,persistedFingerAuthEnabled).apply(); + persistUserId(persistedUserId); + persistUserPwd(persistedPwd); + persistSecretKey(persistedSecretKey); + turnOffFingerprintAuth(!persistedFingerAuthEnabled); } /** @@ -179,6 +183,12 @@ public abstract class PrivilegedGateway implements PrivilegedGatewayInterface { } + @Override + public void persistSecretKey(String encrypted) { + Log.d(SecurityUtils.TAG,"To be Stored Key :"+encrypted); + GmeApplication.getStorage().edit().putString(PrefKeys.APP_SECRET_KEY,encrypted).apply(); + } + @Override public boolean isFingerPrintAuthEnabled() { return GmeApplication.getStorage().getBoolean(PrefKeys.APP_FINGER_PRINT_ENABLED,false); @@ -196,6 +206,12 @@ public abstract class PrivilegedGateway implements PrivilegedGatewayInterface { return GmeApplication.getStorage().getString(PrefKeys.APP_USER_SECRET_KEY,null); } + @Override + public String getPersistedSecretKey() { + Log.d(SecurityUtils.TAG,"Stored Key :"+GmeApplication.getStorage().getString(PrefKeys.APP_SECRET_KEY,null)); + return GmeApplication.getStorage().getString(PrefKeys.APP_SECRET_KEY,null); + } + @Override public void turnOffFingerprintAuth(boolean action) { GmeApplication.getStorage().edit().putBoolean(PrefKeys.APP_FINGER_PRINT_ENABLED,!action).apply(); diff --git a/app/src/main/java/com/gmeremit/online/gmeremittance_native/base/PrivilegedGatewayInterface.java b/app/src/main/java/com/gmeremit/online/gmeremittance_native/base/PrivilegedGatewayInterface.java index dece59e9..3d3a77b7 100644 --- a/app/src/main/java/com/gmeremit/online/gmeremittance_native/base/PrivilegedGatewayInterface.java +++ b/app/src/main/java/com/gmeremit/online/gmeremittance_native/base/PrivilegedGatewayInterface.java @@ -65,6 +65,7 @@ public interface PrivilegedGatewayInterface extends BaseGatewayInterface { */ void persistUserId(String encrypted); void persistUserPwd(String encrypted); + void persistSecretKey(String encrypted); boolean isFingerPrintAuthEnabled(); @@ -72,6 +73,8 @@ public interface PrivilegedGatewayInterface extends BaseGatewayInterface { String getPersistedUserPwd(); + String getPersistedSecretKey(); + void turnOffFingerprintAuth(boolean action); void flushBiometricData(); diff --git a/app/src/main/java/com/gmeremit/online/gmeremittance_native/changepasswordV2/presenter/ChangePasswordV2Presenter.java b/app/src/main/java/com/gmeremit/online/gmeremittance_native/changepasswordV2/presenter/ChangePasswordV2Presenter.java index b44d1391..74e12f43 100644 --- a/app/src/main/java/com/gmeremit/online/gmeremittance_native/changepasswordV2/presenter/ChangePasswordV2Presenter.java +++ b/app/src/main/java/com/gmeremit/online/gmeremittance_native/changepasswordV2/presenter/ChangePasswordV2Presenter.java @@ -174,7 +174,7 @@ public class ChangePasswordV2Presenter extends BasePresenter implements ChangePa @Override protected void onSuccess(ChangePasswordActivityV2APIResponse changePasswordActivityV2APIResponse) { if (changePasswordActivityV2APIResponse.getErrorCode().equalsIgnoreCase(Constants.SUCCESS_CODE_V2)) { - if (SecurityUtils.doesAppHasBiometricFeature(view.getContext())) { + if (SecurityUtils.checkFingerPrintUsablity(view.getContext())) { encryptPassword(newPassword, changePasswordActivityV2APIResponse.getMsg()); } else { view.showPopUpMessage(changePasswordActivityV2APIResponse.getMsg(), CustomAlertDialog.AlertType.SUCCESS, alertType -> view.exitView()); diff --git a/app/src/main/java/com/gmeremit/online/gmeremittance_native/loginV2/presenter/LoginV2Presenter.java b/app/src/main/java/com/gmeremit/online/gmeremittance_native/loginV2/presenter/LoginV2Presenter.java index ccd5ad1f..40527937 100644 --- a/app/src/main/java/com/gmeremit/online/gmeremittance_native/loginV2/presenter/LoginV2Presenter.java +++ b/app/src/main/java/com/gmeremit/online/gmeremittance_native/loginV2/presenter/LoginV2Presenter.java @@ -1,7 +1,5 @@ package com.gmeremit.online.gmeremittance_native.loginV2.presenter; -import android.os.Build; -import android.security.keystore.KeyPermanentlyInvalidatedException; import android.util.Log; import com.gmeremit.online.gmeremittance_native.GmeApplication; @@ -14,11 +12,7 @@ import com.gmeremit.online.gmeremittance_native.utils.Constants; import com.gmeremit.online.gmeremittance_native.utils.Utils; import com.gmeremit.online.gmeremittance_native.utils.https.GenericApiObserverResponse; import com.gmeremit.online.gmeremittance_native.utils.security.SecurityUtils; -import com.mtramin.rxfingerprint.data.FingerprintAuthenticationException; import com.mtramin.rxfingerprint.data.FingerprintDecryptionResult; -import com.mtramin.rxfingerprint.data.FingerprintEncryptionResult; - -import java.util.concurrent.TimeUnit; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; @@ -53,21 +47,33 @@ public class LoginV2Presenter extends BasePresenter implements LoginV2PresenterI } } - private void persistUserCredentialForBiometricAuth(String userId, String pwd) { - Observable.zip(Observable.just(userId), encryptData(pwd), BiometricEncParams::new) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new BiometricEncrypterObserver()); + private void persistUserCredentialForFingerprintAuth(String userId, String pwd) { + SecurityUtils.generateKey() + .flatMap(key -> Observable.zip(Observable.just(userId), + SecurityUtils.encryptSymmetric(pwd, key).subscribeOn(Schedulers.io()), + encryptToKeyStore(key).subscribeOn(Schedulers.io()), + FingerprintEncResult::new) + ).observeOn(AndroidSchedulers.mainThread()) + .subscribe(new FingerprintEncResultObserver()); } - private Observable encryptData(String data) { + private Observable encryptToKeyStore(String data) { return SecurityUtils.encryptToKeyStore(view.getContext(), data) - .subscribeOn(Schedulers.io()); + .flatMap(encKey -> Observable.just(encKey.getEncrypted())); + } + + private Observable authenticateFingerprint() { + return Observable.zip(Observable.fromCallable(gateway::getPersistedUserId), + Observable.fromCallable(gateway::getPersistedSecretKey) + .flatMap(storedKey -> decryptFromKeyStore(storedKey).flatMap(decAesKey -> SecurityUtils.decryptSymmetric(gateway.getPersistedUserPwd(), decAesKey))) + .subscribeOn(Schedulers.io()), + FingerprintDecResult::new) + .observeOn(AndroidSchedulers.mainThread()); } - private Observable decryptData(String data) { + private Observable decryptFromKeyStore(String data) { return SecurityUtils.decryptFromKeyStore(view.getContext(), data) - .subscribeOn(Schedulers.io()) .flatMap(authentication -> { switch (authentication.getResult()) { case FAILED: @@ -80,7 +86,8 @@ public class LoginV2Presenter extends BasePresenter implements LoginV2PresenterI return io.reactivex.Observable.error(new Throwable(authentication.getMessage())); } - }); + }) + .map(FingerprintDecryptionResult::getDecrypted); } @@ -102,7 +109,7 @@ public class LoginV2Presenter extends BasePresenter implements LoginV2PresenterI @Override public boolean checkIfBiometricIsAvailable() { - return SecurityUtils.doesAppHasBiometricFeature(view.getContext()) && gateway.isFingerPrintAuthEnabled() && gateway.getPersistedUserId() != null && gateway.getPersistedUserPwd() != null; + return SecurityUtils.checkFingerPrintUsablity(view.getContext()) && gateway.isFingerPrintAuthEnabled() && gateway.getPersistedUserId() != null && gateway.getPersistedUserPwd() != null; } @Override @@ -115,29 +122,12 @@ public class LoginV2Presenter extends BasePresenter implements LoginV2PresenterI } else { if (fingerPrintScanningSubscription == null || fingerPrintScanningSubscription.isDisposed()) view.showFingerPrintScanner(true); - fingerPrintScanningSubscription = Observable.zip(Observable.fromCallable(gateway::getPersistedUserId), decryptData(gateway.getPersistedUserPwd()), BiometricDecParams::new) - .observeOn(AndroidSchedulers.mainThread()) - .retryWhen(errors -> errors.flatMap( - error -> { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && error instanceof KeyPermanentlyInvalidatedException) { - view.showFingerPrintScanner(false); - gateway.flushBiometricData(); - } - else if(error instanceof FingerprintAuthenticationException) - { - view.showFingerPrintScanner(false); - } - else if (error instanceof SecurityUtils.FailedFingerPrintException || error instanceof SecurityUtils.SensorNotReadyException) { - view.showToastMessage(error.getMessage()); - return Observable.timer(100, TimeUnit.MILLISECONDS); - } - return Observable.error(error); - } - )) - .subscribeWith(new BiometricDecrypterObserver()); + fingerPrintScanningSubscription = authenticateFingerprint() + .subscribeWith(new FingerprintDecResultObserver()); } } + @Override public void loginUser(String userId, String userPwd) { String auth = "Basic " + Utils.toBase64("172017F9EC11222E8107142733:QRK2UM0Q:" + GmeApplication.getAppRelatedMetaData().getDeviceId()); @@ -182,8 +172,8 @@ public class LoginV2Presenter extends BasePresenter implements LoginV2PresenterI @Override protected void onSuccess(Boolean aBoolean) { - if (SecurityUtils.doesAppHasBiometricFeature(view.getContext())) - persistUserCredentialForBiometricAuth(userId, encUserPassword); + if (SecurityUtils.checkFingerPrintUsablity(view.getContext())) + persistUserCredentialForFingerprintAuth(userId, encUserPassword); else { view.showInvalidPassword(null); view.showInvalidUserId(null); @@ -209,74 +199,85 @@ public class LoginV2Presenter extends BasePresenter implements LoginV2PresenterI } } - public class BiometricEncParams { - private String userId; - private FingerprintEncryptionResult pwd; - BiometricEncParams(String userId, FingerprintEncryptionResult pwd) { + public class FingerprintEncResult { + String userId; + String encPwd; + String encKey; + + public FingerprintEncResult(String userId, String encPwd, String encKey) { this.userId = userId; - this.pwd = pwd; + this.encPwd = encPwd; + this.encKey = encKey; } public String getUserId() { return userId; } - public void setUserId(String userId) { - this.userId = userId; + public String getEncPwd() { + return encPwd; } - public FingerprintEncryptionResult getPwd() { - return pwd; + public String getEncKey() { + return encKey; } - public void setPwd(FingerprintEncryptionResult pwd) { - this.pwd = pwd; + @Override + public String toString() { + return "FingerprintEncResult{" + + "userId='" + userId + '\'' + + ", encPwd='" + encPwd + '\'' + + ", encKey='" + encKey + '\'' + + '}'; } } - public class BiometricDecParams { - private String userId; - private FingerprintDecryptionResult pwd; + public class FingerprintDecResult { + String userId; + String userPwd; - BiometricDecParams(String userId, FingerprintDecryptionResult pwd) { + public FingerprintDecResult(String userId, String userPwd) { this.userId = userId; - this.pwd = pwd; + this.userPwd = userPwd; } public String getUserId() { return userId; } - public void setUserId(String userId) { - this.userId = userId; - } - - public FingerprintDecryptionResult getPwd() { - return pwd; + public String getUserPwd() { + return userPwd; } - public void setPwd(FingerprintDecryptionResult pwd) { - this.pwd = pwd; + @Override + public String toString() { + return "FingerprintDecResult{" + + "userId='" + userId + '\'' + + ", userPwd='" + userPwd + '\'' + + '}'; } } - public class BiometricEncrypterObserver extends DisposableObserver { + + public class FingerprintEncResultObserver extends DisposableObserver { @Override - public void onNext(BiometricEncParams biometricParams) { - gateway.persistUserId(biometricParams.getUserId()); - gateway.persistUserPwd(biometricParams.getPwd().getEncrypted()); + public void onNext(FingerprintEncResult fingerprintEncResult) { + Log.d(SecurityUtils.TAG, "Success : " + fingerprintEncResult.toString()); + gateway.persistSecretKey(fingerprintEncResult.getEncKey()); + gateway.persistUserPwd(fingerprintEncResult.getEncPwd()); + gateway.persistUserId(fingerprintEncResult.getUserId()); view.showInvalidPassword(null); view.showInvalidUserId(null); view.redirectToDashboard(); encUserPassword = null; - } @Override public void onError(Throwable e) { - Log.d(SecurityUtils.TAG,e.getMessage()); + Log.d(SecurityUtils.TAG, "Failed : " + e.getMessage()); + } @Override @@ -285,19 +286,21 @@ public class LoginV2Presenter extends BasePresenter implements LoginV2PresenterI } } - public class BiometricDecrypterObserver extends DisposableObserver { + public class FingerprintDecResultObserver extends DisposableObserver { @Override - public void onNext(BiometricDecParams biometricParams) { - encUserPassword = biometricParams.getPwd().getDecrypted(); - view.onLoginPerformTask(() -> loginUser(biometricParams.getUserId(), "")); + public void onNext(FingerprintDecResult fingerprintDecResult) { + Log.d(SecurityUtils.TAG, "Success : " + fingerprintDecResult.toString()); + + encUserPassword = fingerprintDecResult.getUserPwd(); + view.onLoginPerformTask(() -> loginUser(fingerprintDecResult.getUserId(), "")); + } @Override public void onError(Throwable e) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && e instanceof KeyPermanentlyInvalidatedException) - return; - view.showToastMessage(e.getMessage()); + Log.d(SecurityUtils.TAG, "Failed : " + e.getMessage()); + } @Override diff --git a/app/src/main/java/com/gmeremit/online/gmeremittance_native/settings/view/SettingsView.java b/app/src/main/java/com/gmeremit/online/gmeremittance_native/settings/view/SettingsView.java index edf8a2f0..c7deed8a 100644 --- a/app/src/main/java/com/gmeremit/online/gmeremittance_native/settings/view/SettingsView.java +++ b/app/src/main/java/com/gmeremit/online/gmeremittance_native/settings/view/SettingsView.java @@ -18,8 +18,6 @@ import com.gmeremit.online.gmeremittance_native.customwidgets.CustomAlertDialog; import com.gmeremit.online.gmeremittance_native.settings.adapter.LanguageSelectionDialogRVAdapter; import com.gmeremit.online.gmeremittance_native.splash_screen.model.LanguageModel; import com.gmeremit.online.gmeremittance_native.utils.security.SecurityUtils; -import com.mtramin.rxfingerprint.data.FingerprintAuthenticationResult; -import com.mtramin.rxfingerprint.data.FingerprintEncryptionResult; import java.util.ArrayList; import java.util.List; @@ -27,11 +25,7 @@ import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; -import io.reactivex.Observable; -import io.reactivex.Observer; -import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; -import io.reactivex.schedulers.Schedulers; import static com.gmeremit.online.gmeremittance_native.base.PrefKeys.USER_PREFERRED_COUNTRY_CODE; import static com.gmeremit.online.gmeremittance_native.base.PrefKeys.USER_PREFERRED_LANGUAGE; @@ -59,7 +53,7 @@ public class SettingsView extends BaseActivity implements CompoundButton.OnCheck private void init() { ButterKnife.bind(this); - if (!SecurityUtils.doesAppHasBiometricFeature(this)) { + if (!SecurityUtils.checkFingerPrintUsablity(this)) { view_fingerprint.setVisibility(View.GONE); view_fingerprint_divider.setVisibility(View.GONE); } else { diff --git a/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/presenter/TransactionPasswordPromptV2Presenter.java b/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/presenter/TransactionPasswordPromptV2Presenter.java index 4f010ec5..dc3212ce 100644 --- a/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/presenter/TransactionPasswordPromptV2Presenter.java +++ b/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/presenter/TransactionPasswordPromptV2Presenter.java @@ -95,7 +95,7 @@ public class TransactionPasswordPromptV2Presenter extends BasePresenter implemen @Override public boolean checkIfUserHasEnabledBiometricAuth() { - return SecurityUtils.doesAppHasBiometricFeature(view.getContext()) && gateway.isFingerPrintAuthEnabled() && gateway.getPersistedUserId() != null && gateway.getPersistedUserPwd() != null; + return SecurityUtils.checkFingerPrintUsablity(view.getContext()) && gateway.isFingerPrintAuthEnabled() && gateway.getPersistedUserId() != null && gateway.getPersistedUserPwd() != null; } diff --git a/app/src/main/java/com/gmeremit/online/gmeremittance_native/utils/security/SecurityUtils.java b/app/src/main/java/com/gmeremit/online/gmeremittance_native/utils/security/SecurityUtils.java index b89f707e..417c7bab 100644 --- a/app/src/main/java/com/gmeremit/online/gmeremittance_native/utils/security/SecurityUtils.java +++ b/app/src/main/java/com/gmeremit/online/gmeremittance_native/utils/security/SecurityUtils.java @@ -17,7 +17,7 @@ public class SecurityUtils { private static final String KEY_STORE_SECRET_ALIAS = "gmeSecret321"; private static String algorithm = "AES"; - public static boolean doesAppHasBiometricFeature(Context context) { + public static boolean checkFingerPrintUsablity(Context context) { return RxFingerprint.isAvailable(context); } @@ -33,21 +33,20 @@ public class SecurityUtils { return RxFingerprint.authenticate(context); } - public static Observable encryptSymmetric(String plainText, String key) throws Exception { + public static Observable encryptSymmetric(String plainText, String key) { return Observable.fromCallable(() -> AESEncryptionHelper.encrypt(plainText, AESEncryptionHelper.keys(key)).toString()); } - public static Observable decryptSymmetric(String encryptedText, String keys) throws Exception { + public static Observable decryptSymmetric(String encryptedText, String keys){ return Observable.fromCallable(() -> { AESEncryptionHelper.CipherTextIvMac cipherTextIvMac = new AESEncryptionHelper.CipherTextIvMac(encryptedText); return AESEncryptionHelper.decryptString(cipherTextIvMac, AESEncryptionHelper.keys(keys)); }); } - //generateKey() is used to generate a secret key for AES algorithm - private static String generateKey() throws Exception { - return AESEncryptionHelper.keyString(AESEncryptionHelper.generateKey()); + public static Observable generateKey() { + return Observable.fromCallable(()->AESEncryptionHelper.keyString(AESEncryptionHelper.generateKey())); }