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 df0cf0e2..43a8c9f4 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 @@ -156,7 +156,7 @@ public class ChangePasswordV2Presenter extends BasePresenter implements ChangePa private void encryptPassword(String newPassword, String pwdChangeMessage) { SecurityUtils.generateKey() .flatMap(key -> Observable.zip( - SecurityUtils.encryptSymmetric(newPassword, key).subscribeOn(Schedulers.io()), + SecurityUtils.encryptUsingAES(newPassword, key).subscribeOn(Schedulers.io()), encryptToKeyStore(key).subscribeOn(Schedulers.io()), Observable.just(pwdChangeMessage), FingerprintEncResult::new) @@ -166,7 +166,7 @@ public class ChangePasswordV2Presenter extends BasePresenter implements ChangePa } private Observable encryptToKeyStore(String data) { - return SecurityUtils.encryptByKeyStore(view.getContext(), data) + return SecurityUtils.encryptUsingKeyStore(view.getContext(), data) .flatMap(encKey ->Observable.just(encKey.getEncrypted())); } 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 8c479b4d..2b9eace9 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 @@ -56,7 +56,7 @@ public class LoginV2Presenter extends BasePresenter implements LoginV2PresenterI private void persistUserCredentialForFingerprintAuth(String userId, String pwd,LoginModelV2 loginModelV2) { SecurityUtils.generateKey() .flatMap(key -> Observable.zip(Observable.just(userId), - SecurityUtils.encryptSymmetric(pwd, key).subscribeOn(Schedulers.io()), + SecurityUtils.encryptUsingAES(pwd, key).subscribeOn(Schedulers.io()), encryptByKeyStore(key).subscribeOn(Schedulers.io()), FingerprintEncResult::new) ).observeOn(AndroidSchedulers.mainThread()) @@ -64,14 +64,14 @@ public class LoginV2Presenter extends BasePresenter implements LoginV2PresenterI } private Observable encryptByKeyStore(String data) { - return SecurityUtils.encryptByKeyStore(view.getContext(), data) + return SecurityUtils.encryptUsingKeyStore(view.getContext(), data) .flatMap(encKey -> Observable.just(encKey.getEncrypted())); } private Observable authenticateFingerprint() { return Observable.zip(Observable.fromCallable(gateway::getPersistedUserId), Observable.fromCallable(gateway::getPersistedSecretKey) - .flatMap(storedKey -> decryptByKeyStore(storedKey).flatMap(decAesKey -> SecurityUtils.decryptSymmetric(gateway.getPersistedUserPwd(), decAesKey))) + .flatMap(storedKey -> decryptByKeyStore(storedKey).flatMap(decAesKey -> SecurityUtils.decryptUsingAES(gateway.getPersistedUserPwd(), decAesKey))) .subscribeOn(Schedulers.io()), FingerprintDecResult::new) .observeOn(AndroidSchedulers.mainThread()); @@ -79,7 +79,7 @@ public class LoginV2Presenter extends BasePresenter implements LoginV2PresenterI private Observable decryptByKeyStore(String data) { - return SecurityUtils.decryptByKeyStore(view.getContext(), data) + return SecurityUtils.decryptUsingKeyStore(view.getContext(), data) .flatMap(authentication -> { switch (authentication.getResult()) { case FAILED: 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 d1371e7d..de486e9b 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 @@ -120,7 +120,7 @@ public class TransactionPasswordPromptV2Presenter extends BasePresenter implemen 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))) + .flatMap(storedKey -> decryptFromKeyStore(storedKey).flatMap(decAesKey -> SecurityUtils.decryptUsingAES(gateway.getPersistedUserPwd(), decAesKey))) .subscribeOn(Schedulers.io()), FingerprintDecResult::new) .doOnSubscribe(subs -> { @@ -130,7 +130,7 @@ public class TransactionPasswordPromptV2Presenter extends BasePresenter implemen } private Observable decryptFromKeyStore(String data) { - return SecurityUtils.decryptByKeyStore(view.getContext(), data) + return SecurityUtils.decryptUsingKeyStore(view.getContext(), data) .flatMap(authentication -> { switch (authentication.getResult()) { case FAILED: diff --git a/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/view/TransactionBiometricPromptDialog.java b/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/view/TransactionBiometricPromptDialog.java index 4ad7243e..8e3c0691 100644 --- a/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/view/TransactionBiometricPromptDialog.java +++ b/app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/view/TransactionBiometricPromptDialog.java @@ -119,7 +119,7 @@ public class TransactionBiometricPromptDialog extends android.support.v4.app.Dia private Observable authenticateFingerprint() { return Observable.zip(Observable.fromCallable(()-> GmeApplication.getStorage().getString(PrefKeys.APP_USER_ID_SECRET_KEY,null)), Observable.fromCallable(()->GmeApplication.getStorage().getString(PrefKeys.APP_SECRET_KEY,null)) - .flatMap(storedKey -> decryptFromKeyStore(storedKey).flatMap(decAesKey -> SecurityUtils.decryptSymmetric(GmeApplication.getStorage().getString(PrefKeys.APP_USER_SECRET_KEY,null), decAesKey))) + .flatMap(storedKey -> decryptFromKeyStore(storedKey).flatMap(decAesKey -> SecurityUtils.decryptUsingAES(GmeApplication.getStorage().getString(PrefKeys.APP_USER_SECRET_KEY,null), decAesKey))) .subscribeOn(Schedulers.io()), FingerprintDecResult::new) .doOnSubscribe(subs -> { @@ -129,7 +129,7 @@ public class TransactionBiometricPromptDialog extends android.support.v4.app.Dia } private Observable decryptFromKeyStore(String data) { - return SecurityUtils.decryptByKeyStore(getActivity(), data) + return SecurityUtils.decryptUsingKeyStore(getActivity(), data) .flatMap(authentication -> { switch (authentication.getResult()) { case FAILED: diff --git a/app/src/main/java/com/gmeremit/online/gmeremittance_native/utils/security/AESEncryptionHelper.java b/app/src/main/java/com/gmeremit/online/gmeremittance_native/utils/security/AESEncryptionHelper.java index d09b053e..77402aa4 100644 --- a/app/src/main/java/com/gmeremit/online/gmeremittance_native/utils/security/AESEncryptionHelper.java +++ b/app/src/main/java/com/gmeremit/online/gmeremittance_native/utils/security/AESEncryptionHelper.java @@ -214,7 +214,7 @@ public class AESEncryptionHelper { * * @param plaintext The text that will be encrypted, which * will be serialized with UTF-8 - * @param secretKeys The AES and HMAC keys with which to encryptSymmetric + * @param secretKeys The AES and HMAC keys with which to encryptUsingAES * @return a tuple of the IV, ciphertext, mac * @throws GeneralSecurityException if AES is not implemented on this system * @throws UnsupportedEncodingException if UTF-8 is not supported in this system @@ -229,7 +229,7 @@ public class AESEncryptionHelper { * a hashed MAC, which is contained in the CipherTextIvMac class. * * @param plaintext The bytes that will be encrypted - * @param secretKeys The AES and HMAC keys with which to encryptSymmetric + * @param secretKeys The AES and HMAC keys with which to encryptUsingAES * @return a tuple of the IV, ciphertext, mac * @throws GeneralSecurityException if AES is not implemented on this system * @throws UnsupportedEncodingException if the specified encoding is invalid @@ -244,7 +244,7 @@ public class AESEncryptionHelper { * a hashed MAC, which is contained in the CipherTextIvMac class. * * @param plaintext The text that will be encrypted - * @param secretKeys The combined AES and HMAC keys with which to encryptSymmetric + * @param secretKeys The combined AES and HMAC keys with which to encryptUsingAES * @return a tuple of the IV, ciphertext, mac * @throws GeneralSecurityException if AES is not implemented on this system */ @@ -288,7 +288,7 @@ public class AESEncryptionHelper { */ /** - * AES CBC decryptSymmetric. + * AES CBC decryptUsingAES. * * @param civ The cipher text, IV, and mac * @param secretKeys The AES and HMAC keys @@ -303,7 +303,7 @@ public class AESEncryptionHelper { } /** - * AES CBC decryptSymmetric. + * AES CBC decryptUsingAES. * * @param civ The cipher text, IV, and mac * @param secretKeys The AES and HMAC keys @@ -318,7 +318,7 @@ public class AESEncryptionHelper { } /** - * AES CBC decryptSymmetric. + * AES CBC decryptUsingAES. * * @param civ the cipher text, iv, and mac * @param secretKeys the AES and HMAC keys 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 417c7bab..c31aa672 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 @@ -10,6 +10,28 @@ import com.mtramin.rxfingerprint.data.FingerprintEncryptionResult; import io.reactivex.Observable; +/** + * Since we are using security keypad with Symmetric Key Encryption, we can only obtain encrypted text as password but not plain text. + * So the length of the encrypted text exceeds 256 bit and we cannot use Public/Private Encryption Algorithm i.e. RSA encryption offfered by Android's KeyStore. + * Therefore inorder to persist password and encryption key in same storage using Android's Keystore mechanism, we follow the following steps + * 1) We generate AES key seperately using "AESEncryptionHelper" class if not already generated intially. + * 2) Encrypt the confidential content with the AES Algorithm using the generated AES key and persist it. + * 3) That AES key is then encrypted using RSA key provided by Keystore and persist it to prevent from being exploited. + * + * So we can store the encryption key and encrypted data in same persistence storage without any risk. + * + * Flow Illustration for Encryption is shown below, Decryption is done in same flow but in reverse order. + * + * Generated_AES_Key= GENERATE_NEW_AES_KEY(); + * Encrypted_Password = AES_ENCRYPTION_USING_GENERATED_KEY(Generated_AES_Key, Long_Password_String); + * SAVE_TO_DISK(Encrypted_Password); + * + * Encrypted_AES_KEY = RSA_ENCRYPTION_USING_KEYSTORE(Generated_AES_Key) + * SAVE_TO_DISK(Encrypted_AES_KEY); + * + * Hence, we can persist both the key and encrypted data in same place with help of Android Key Store. + * + */ public class SecurityUtils { @@ -21,30 +43,63 @@ public class SecurityUtils { return RxFingerprint.isAvailable(context); } - public static Observable encryptToKeyStore(Context context, String secret) { + /** + * Consider reading this helper class purpose before using this method. + * @param context + * @param secret String to be encrypted. + * @return + */ + public static Observable encryptUsingKeyStore(Context context, String secret) { return RxFingerprint.encrypt(EncryptionMethod.RSA, context, KEY_STORE_SECRET_ALIAS, secret); } - public static Observable decryptFromKeyStore(Context context, String secret) { + /** + * Consider reading this helper class purpose before using this method. + * @param context + * @param secret + * @return + */ + public static Observable decryptUsingKeyStore(Context context, String secret) { return RxFingerprint.decrypt(EncryptionMethod.RSA, context, KEY_STORE_SECRET_ALIAS, secret); } + /** + * Consider reading this helper class purpose before using this method. + * @param context + * @return + */ public static Observable authenticateFingerPrint(Context context) { return RxFingerprint.authenticate(context); } - public static Observable encryptSymmetric(String plainText, String key) { + /** + * Consider reading this helper class purpose before using this method. + * @param plainText String to be encrypted + * @param key AES symmetric key + * @return + */ + public static Observable encryptUsingAES(String plainText, String key) { return Observable.fromCallable(() -> AESEncryptionHelper.encrypt(plainText, AESEncryptionHelper.keys(key)).toString()); } - public static Observable decryptSymmetric(String encryptedText, String keys){ + /** + * Consider reading this helper class purpose before using this method. + * @param encryptedText Encrypted data to be decrypted + * @param key AES symmetric key + * @return + */ + public static Observable decryptUsingAES(String encryptedText, String key){ return Observable.fromCallable(() -> { AESEncryptionHelper.CipherTextIvMac cipherTextIvMac = new AESEncryptionHelper.CipherTextIvMac(encryptedText); - return AESEncryptionHelper.decryptString(cipherTextIvMac, AESEncryptionHelper.keys(keys)); + return AESEncryptionHelper.decryptString(cipherTextIvMac, AESEncryptionHelper.keys(key)); }); } + /** + * Generate AES Symmetric Key + * @return + */ public static Observable generateKey() { return Observable.fromCallable(()->AESEncryptionHelper.keyString(AESEncryptionHelper.generateKey())); }