Browse Source

Security utils method refactored

master
Preyea Regmi 5 years ago
parent
commit
366888ae96
  1. 4
      app/src/main/java/com/gmeremit/online/gmeremittance_native/changepasswordV2/presenter/ChangePasswordV2Presenter.java
  2. 8
      app/src/main/java/com/gmeremit/online/gmeremittance_native/loginV2/presenter/LoginV2Presenter.java
  3. 4
      app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/presenter/TransactionPasswordPromptV2Presenter.java
  4. 4
      app/src/main/java/com/gmeremit/online/gmeremittance_native/transactionpasspromt/view/TransactionBiometricPromptDialog.java
  5. 12
      app/src/main/java/com/gmeremit/online/gmeremittance_native/utils/security/AESEncryptionHelper.java
  6. 65
      app/src/main/java/com/gmeremit/online/gmeremittance_native/utils/security/SecurityUtils.java

4
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) { private void encryptPassword(String newPassword, String pwdChangeMessage) {
SecurityUtils.generateKey() SecurityUtils.generateKey()
.flatMap(key -> Observable.zip( .flatMap(key -> Observable.zip(
SecurityUtils.encryptSymmetric(newPassword, key).subscribeOn(Schedulers.io()),
SecurityUtils.encryptUsingAES(newPassword, key).subscribeOn(Schedulers.io()),
encryptToKeyStore(key).subscribeOn(Schedulers.io()), encryptToKeyStore(key).subscribeOn(Schedulers.io()),
Observable.just(pwdChangeMessage), Observable.just(pwdChangeMessage),
FingerprintEncResult::new) FingerprintEncResult::new)
@ -166,7 +166,7 @@ public class ChangePasswordV2Presenter extends BasePresenter implements ChangePa
} }
private Observable<String> encryptToKeyStore(String data) { private Observable<String> encryptToKeyStore(String data) {
return SecurityUtils.encryptByKeyStore(view.getContext(), data)
return SecurityUtils.encryptUsingKeyStore(view.getContext(), data)
.flatMap(encKey ->Observable.just(encKey.getEncrypted())); .flatMap(encKey ->Observable.just(encKey.getEncrypted()));
} }

8
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) { private void persistUserCredentialForFingerprintAuth(String userId, String pwd,LoginModelV2 loginModelV2) {
SecurityUtils.generateKey() SecurityUtils.generateKey()
.flatMap(key -> Observable.zip(Observable.just(userId), .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()), encryptByKeyStore(key).subscribeOn(Schedulers.io()),
FingerprintEncResult::new) FingerprintEncResult::new)
).observeOn(AndroidSchedulers.mainThread()) ).observeOn(AndroidSchedulers.mainThread())
@ -64,14 +64,14 @@ public class LoginV2Presenter extends BasePresenter implements LoginV2PresenterI
} }
private Observable<String> encryptByKeyStore(String data) { private Observable<String> encryptByKeyStore(String data) {
return SecurityUtils.encryptByKeyStore(view.getContext(), data)
return SecurityUtils.encryptUsingKeyStore(view.getContext(), data)
.flatMap(encKey -> Observable.just(encKey.getEncrypted())); .flatMap(encKey -> Observable.just(encKey.getEncrypted()));
} }
private Observable<FingerprintDecResult> authenticateFingerprint() { private Observable<FingerprintDecResult> authenticateFingerprint() {
return Observable.zip(Observable.fromCallable(gateway::getPersistedUserId), return Observable.zip(Observable.fromCallable(gateway::getPersistedUserId),
Observable.fromCallable(gateway::getPersistedSecretKey) 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()), .subscribeOn(Schedulers.io()),
FingerprintDecResult::new) FingerprintDecResult::new)
.observeOn(AndroidSchedulers.mainThread()); .observeOn(AndroidSchedulers.mainThread());
@ -79,7 +79,7 @@ public class LoginV2Presenter extends BasePresenter implements LoginV2PresenterI
private Observable<String> decryptByKeyStore(String data) { private Observable<String> decryptByKeyStore(String data) {
return SecurityUtils.decryptByKeyStore(view.getContext(), data)
return SecurityUtils.decryptUsingKeyStore(view.getContext(), data)
.flatMap(authentication -> { .flatMap(authentication -> {
switch (authentication.getResult()) { switch (authentication.getResult()) {
case FAILED: case FAILED:

4
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<FingerprintDecResult> authenticateFingerprint() { private Observable<FingerprintDecResult> authenticateFingerprint() {
return Observable.zip(Observable.fromCallable(gateway::getPersistedUserId), return Observable.zip(Observable.fromCallable(gateway::getPersistedUserId),
Observable.fromCallable(gateway::getPersistedSecretKey) 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()), .subscribeOn(Schedulers.io()),
FingerprintDecResult::new) FingerprintDecResult::new)
.doOnSubscribe(subs -> { .doOnSubscribe(subs -> {
@ -130,7 +130,7 @@ public class TransactionPasswordPromptV2Presenter extends BasePresenter implemen
} }
private Observable<String> decryptFromKeyStore(String data) { private Observable<String> decryptFromKeyStore(String data) {
return SecurityUtils.decryptByKeyStore(view.getContext(), data)
return SecurityUtils.decryptUsingKeyStore(view.getContext(), data)
.flatMap(authentication -> { .flatMap(authentication -> {
switch (authentication.getResult()) { switch (authentication.getResult()) {
case FAILED: case FAILED:

4
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<FingerprintDecResult> authenticateFingerprint() { private Observable<FingerprintDecResult> authenticateFingerprint() {
return Observable.zip(Observable.fromCallable(()-> GmeApplication.getStorage().getString(PrefKeys.APP_USER_ID_SECRET_KEY,null)), 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)) 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()), .subscribeOn(Schedulers.io()),
FingerprintDecResult::new) FingerprintDecResult::new)
.doOnSubscribe(subs -> { .doOnSubscribe(subs -> {
@ -129,7 +129,7 @@ public class TransactionBiometricPromptDialog extends android.support.v4.app.Dia
} }
private Observable<String> decryptFromKeyStore(String data) { private Observable<String> decryptFromKeyStore(String data) {
return SecurityUtils.decryptByKeyStore(getActivity(), data)
return SecurityUtils.decryptUsingKeyStore(getActivity(), data)
.flatMap(authentication -> { .flatMap(authentication -> {
switch (authentication.getResult()) { switch (authentication.getResult()) {
case FAILED: case FAILED:

12
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 * @param plaintext The text that will be encrypted, which
* will be serialized with UTF-8 * 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 * @return a tuple of the IV, ciphertext, mac
* @throws GeneralSecurityException if AES is not implemented on this system * @throws GeneralSecurityException if AES is not implemented on this system
* @throws UnsupportedEncodingException if UTF-8 is not supported in 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. * a hashed MAC, which is contained in the CipherTextIvMac class.
* *
* @param plaintext The bytes that will be encrypted * @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 * @return a tuple of the IV, ciphertext, mac
* @throws GeneralSecurityException if AES is not implemented on this system * @throws GeneralSecurityException if AES is not implemented on this system
* @throws UnsupportedEncodingException if the specified encoding is invalid * @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. * a hashed MAC, which is contained in the CipherTextIvMac class.
* *
* @param plaintext The text that will be encrypted * @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 * @return a tuple of the IV, ciphertext, mac
* @throws GeneralSecurityException if AES is not implemented on this system * @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 civ The cipher text, IV, and mac
* @param secretKeys The AES and HMAC keys * @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 civ The cipher text, IV, and mac
* @param secretKeys The AES and HMAC keys * @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 civ the cipher text, iv, and mac
* @param secretKeys the AES and HMAC keys * @param secretKeys the AES and HMAC keys

65
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; 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 { public class SecurityUtils {
@ -21,30 +43,63 @@ public class SecurityUtils {
return RxFingerprint.isAvailable(context); return RxFingerprint.isAvailable(context);
} }
public static Observable<FingerprintEncryptionResult> 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<FingerprintEncryptionResult> encryptUsingKeyStore(Context context, String secret) {
return RxFingerprint.encrypt(EncryptionMethod.RSA, context, KEY_STORE_SECRET_ALIAS, secret); return RxFingerprint.encrypt(EncryptionMethod.RSA, context, KEY_STORE_SECRET_ALIAS, secret);
} }
public static Observable<FingerprintDecryptionResult> decryptFromKeyStore(Context context, String secret) {
/**
* Consider reading this helper class purpose before using this method.
* @param context
* @param secret
* @return
*/
public static Observable<FingerprintDecryptionResult> decryptUsingKeyStore(Context context, String secret) {
return RxFingerprint.decrypt(EncryptionMethod.RSA, context, KEY_STORE_SECRET_ALIAS, 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<FingerprintAuthenticationResult> authenticateFingerPrint(Context context) { public static Observable<FingerprintAuthenticationResult> authenticateFingerPrint(Context context) {
return RxFingerprint.authenticate(context); return RxFingerprint.authenticate(context);
} }
public static Observable<String> 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<String> encryptUsingAES(String plainText, String key) {
return Observable.fromCallable(() -> AESEncryptionHelper.encrypt(plainText, AESEncryptionHelper.keys(key)).toString()); return Observable.fromCallable(() -> AESEncryptionHelper.encrypt(plainText, AESEncryptionHelper.keys(key)).toString());
} }
public static Observable<String> 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<String> decryptUsingAES(String encryptedText, String key){
return Observable.fromCallable(() -> { return Observable.fromCallable(() -> {
AESEncryptionHelper.CipherTextIvMac cipherTextIvMac = new AESEncryptionHelper.CipherTextIvMac(encryptedText); 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<String> generateKey() { public static Observable<String> generateKey() {
return Observable.fromCallable(()->AESEncryptionHelper.keyString(AESEncryptionHelper.generateKey())); return Observable.fromCallable(()->AESEncryptionHelper.keyString(AESEncryptionHelper.generateKey()));
} }

Loading…
Cancel
Save