Various Fixes (#279)

* load password only if it's passed

* cancel fingerprint if password entered

* rework fingerprint code

* cleanup unused params

* new version code
This commit is contained in:
m2049r 2018-05-10 13:48:11 +02:00 committed by GitHub
parent a8f08fb9b9
commit cb12d64e5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 125 additions and 100 deletions

View File

@ -7,8 +7,8 @@ android {
applicationId "com.m2049r.xmrwallet" applicationId "com.m2049r.xmrwallet"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 25 targetSdkVersion 25
versionCode 92 versionCode 93
versionName "1.5.2 'CrAzY Nacho'" versionName "1.5.3 'CrAzY Nacho'"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild { externalNativeBuild {
cmake { cmake {

View File

@ -53,7 +53,6 @@ import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
import com.m2049r.xmrwallet.widget.Toolbar; import com.m2049r.xmrwallet.widget.Toolbar;
import java.io.File; import java.io.File;
import java.security.KeyStoreException;
import timber.log.Timber; import timber.log.Timber;
@ -392,19 +391,19 @@ public class GenerateReviewFragment extends Fragment {
@Override @Override
protected Boolean doInBackground(String... params) { protected Boolean doInBackground(String... params) {
if (params.length != 4) return false; if (params.length != 2) return false;
File walletFile = Helper.getWalletFile(getActivity(), params[0]); final String userPassword = params[0];
String oldPassword = params[1]; final boolean fingerPassValid = Boolean.valueOf(params[1]);
String userPassword = params[2];
boolean fingerprintAuthAllowed = Boolean.valueOf(params[3]);
newPassword = KeyStoreHelper.getCrazyPass(getActivity(), userPassword); newPassword = KeyStoreHelper.getCrazyPass(getActivity(), userPassword);
boolean success = changeWalletPassword(newPassword); final boolean success = changeWalletPassword(newPassword);
if (success) { if (success) {
if (fingerprintAuthAllowed) { Context ctx = getActivity();
KeyStoreHelper.saveWalletUserPass(getActivity(), walletName, userPassword); if (ctx != null)
} else { if (fingerPassValid) {
KeyStoreHelper.removeWalletUserPass(getActivity(), walletName); KeyStoreHelper.saveWalletUserPass(ctx, walletName, userPassword);
} } else {
KeyStoreHelper.removeWalletUserPass(ctx, walletName);
}
} }
return success; return success;
} }
@ -412,7 +411,7 @@ public class GenerateReviewFragment extends Fragment {
@Override @Override
protected void onPostExecute(Boolean result) { protected void onPostExecute(Boolean result) {
super.onPostExecute(result); super.onPostExecute(result);
if (getActivity().isDestroyed()) { if ((getActivity() == null) || getActivity().isDestroyed()) {
return; return;
} }
if (progressCallback != null) if (progressCallback != null)
@ -467,11 +466,7 @@ public class GenerateReviewFragment extends Fragment {
} }
}); });
try { swFingerprintAllowed.setChecked(FingerprintHelper.isFingerPassValid(getActivity(), walletName));
swFingerprintAllowed.setChecked(FingerprintHelper.isFingerprintAuthAllowed(walletName));
} catch (KeyStoreException ex) {
ex.printStackTrace();
}
} }
etPasswordA.getEditText().addTextChangedListener(new TextWatcher() { etPasswordA.getEditText().addTextChangedListener(new TextWatcher() {
@ -547,7 +542,7 @@ public class GenerateReviewFragment extends Fragment {
} else if (!newPasswordA.equals(newPasswordB)) { } else if (!newPasswordA.equals(newPasswordB)) {
etPasswordB.setError(getString(R.string.generate_bad_passwordB)); etPasswordB.setError(getString(R.string.generate_bad_passwordB));
} else if (newPasswordA.equals(newPasswordB)) { } else if (newPasswordA.equals(newPasswordB)) {
new AsyncChangePassword().execute(walletName, getPassword(), newPasswordA, Boolean.toString(swFingerprintAllowed.isChecked())); new AsyncChangePassword().execute(newPasswordA, Boolean.toString(swFingerprintAllowed.isChecked()));
Helper.hideKeyboardAlways(getActivity()); Helper.hideKeyboardAlways(getActivity());
openDialog.dismiss(); openDialog.dismiss();
openDialog = null; openDialog = null;
@ -569,7 +564,7 @@ public class GenerateReviewFragment extends Fragment {
} else if (!newPasswordA.equals(newPasswordB)) { } else if (!newPasswordA.equals(newPasswordB)) {
etPasswordB.setError(getString(R.string.generate_bad_passwordB)); etPasswordB.setError(getString(R.string.generate_bad_passwordB));
} else if (newPasswordA.equals(newPasswordB)) { } else if (newPasswordA.equals(newPasswordB)) {
new AsyncChangePassword().execute(walletName, getPassword(), newPasswordA, Boolean.toString(swFingerprintAllowed.isChecked())); new AsyncChangePassword().execute(newPasswordA, Boolean.toString(swFingerprintAllowed.isChecked()));
Helper.hideKeyboardAlways(getActivity()); Helper.hideKeyboardAlways(getActivity());
openDialog.dismiss(); openDialog.dismiss();
openDialog = null; openDialog = null;

View File

@ -50,7 +50,6 @@ import com.m2049r.xmrwallet.model.NetworkType;
import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.model.WalletManager; import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.service.WalletService; import com.m2049r.xmrwallet.service.WalletService;
import com.m2049r.xmrwallet.util.FingerprintHelper;
import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.KeyStoreHelper; import com.m2049r.xmrwallet.util.KeyStoreHelper;
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor; import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
@ -63,7 +62,6 @@ import java.io.IOException;
import java.net.Socket; import java.net.Socket;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
import java.security.KeyStoreException;
import java.util.Date; import java.util.Date;
import timber.log.Timber; import timber.log.Timber;
@ -229,17 +227,20 @@ public class LoginActivity extends SecureActivity
@Override @Override
protected Boolean doInBackground(String... params) { protected Boolean doInBackground(String... params) {
if (params.length != 2) return false; if (params.length != 2) return false;
File walletFile = Helper.getWalletFile(LoginActivity.this, params[0]); String oldName = params[0];
String newName = params[1]; String newName = params[1];
File walletFile = Helper.getWalletFile(LoginActivity.this, oldName);
boolean success = renameWallet(walletFile, newName); boolean success = renameWallet(walletFile, newName);
try { try {
if (success && FingerprintHelper.isFingerprintAuthAllowed(params[0])) { if (success) {
String savedPass = KeyStoreHelper.loadWalletUserPass(LoginActivity.this, params[0]); String savedPass = KeyStoreHelper.loadWalletUserPass(LoginActivity.this, oldName);
KeyStoreHelper.saveWalletUserPass(LoginActivity.this, newName, savedPass); KeyStoreHelper.saveWalletUserPass(LoginActivity.this, newName, savedPass);
KeyStoreHelper.removeWalletUserPass(LoginActivity.this, params[0]);
} }
} catch (KeyStoreException ex) { } catch (KeyStoreHelper.BrokenPasswordStoreException ex) {
ex.printStackTrace(); Timber.w(ex);
} finally {
// we have either set a new password or it is broken - kill the old one either way
KeyStoreHelper.removeWalletUserPass(LoginActivity.this, oldName);
} }
return success; return success;
} }

View File

@ -133,6 +133,7 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
acquireWakeLock(); acquireWakeLock();
String walletId = extras.getString(REQUEST_ID); String walletId = extras.getString(REQUEST_ID);
needVerifyIdentity = extras.getBoolean(REQUEST_FINGERPRINT_USED); needVerifyIdentity = extras.getBoolean(REQUEST_FINGERPRINT_USED);
password = extras.getString(REQUEST_PW);
connectWalletService(walletId, password); connectWalletService(walletId, password);
} else { } else {
finish(); finish();
@ -259,8 +260,6 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
.add(R.id.fragment_container, walletFragment, WalletFragment.class.getName()).commit(); .add(R.id.fragment_container, walletFragment, WalletFragment.class.getName()).commit();
Timber.d("fragment added"); Timber.d("fragment added");
password = getIntent().getExtras().getString(REQUEST_PW);
startWalletService(); startWalletService();
Timber.d("onCreate() done."); Timber.d("onCreate() done.");
} }

View File

@ -5,8 +5,7 @@ import android.content.Context;
import android.support.v4.hardware.fingerprint.FingerprintManagerCompat; import android.support.v4.hardware.fingerprint.FingerprintManagerCompat;
import android.support.v4.os.CancellationSignal; import android.support.v4.os.CancellationSignal;
import java.security.KeyStore; import timber.log.Timber;
import java.security.KeyStoreException;
public class FingerprintHelper { public class FingerprintHelper {
@ -20,15 +19,14 @@ public class FingerprintHelper {
fingerprintManager.hasEnrolledFingerprints(); fingerprintManager.hasEnrolledFingerprints();
} }
public static boolean isFingerprintAuthAllowed(String wallet) throws KeyStoreException { public static boolean isFingerPassValid(Context context, String wallet) {
KeyStore keyStore = KeyStore.getInstance(KeyStoreHelper.SecurityConstants.KEYSTORE_PROVIDER_ANDROID_KEYSTORE);
try { try {
keyStore.load(null); KeyStoreHelper.loadWalletUserPass(context, wallet);
} catch (Exception ex) { return true;
throw new IllegalStateException("Could not load KeyStore", ex); } catch (KeyStoreHelper.BrokenPasswordStoreException ex) {
Timber.w(ex);
return false;
} }
return keyStore.containsAlias(KeyStoreHelper.SecurityConstants.WALLET_PASS_KEY_PREFIX + wallet);
} }
public static void authenticate(Context context, CancellationSignal cancelSignal, public static void authenticate(Context context, CancellationSignal cancelSignal,
@ -36,5 +34,4 @@ public class FingerprintHelper {
FingerprintManagerCompat manager = FingerprintManagerCompat.from(context); FingerprintManagerCompat manager = FingerprintManagerCompat.from(context);
manager.authenticate(null, 0, cancelSignal, callback, null); manager.authenticate(null, 0, cancelSignal, callback, null);
} }
} }

View File

@ -64,7 +64,6 @@ import java.math.BigInteger;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.net.URL; import java.net.URL;
import java.security.KeyStoreException;
import java.util.Locale; import java.util.Locale;
import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.HttpsURLConnection;
@ -368,12 +367,7 @@ public class Helper {
final TextInputLayout etPassword = (TextInputLayout) promptsView.findViewById(R.id.etPassword); final TextInputLayout etPassword = (TextInputLayout) promptsView.findViewById(R.id.etPassword);
etPassword.setHint(context.getString(R.string.prompt_password, wallet)); etPassword.setHint(context.getString(R.string.prompt_password, wallet));
boolean fingerprintAuthCheck; final boolean fingerprintAuthCheck = FingerprintHelper.isFingerPassValid(context, wallet);
try {
fingerprintAuthCheck = FingerprintHelper.isFingerprintAuthAllowed(wallet);
} catch (KeyStoreException ex) {
fingerprintAuthCheck = false;
}
final boolean fingerprintAuthAllowed = !fingerprintDisabled && fingerprintAuthCheck; final boolean fingerprintAuthAllowed = !fingerprintDisabled && fingerprintAuthCheck;
final CancellationSignal cancelSignal = new CancellationSignal(); final CancellationSignal cancelSignal = new CancellationSignal();
@ -425,13 +419,18 @@ public class Helper {
@Override @Override
public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) { public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
String userPass = KeyStoreHelper.loadWalletUserPass(context, wallet); try {
if (Helper.processPasswordEntry(context, wallet, userPass, true, action)) { String userPass = KeyStoreHelper.loadWalletUserPass(context, wallet);
Helper.hideKeyboardAlways((Activity) context); if (Helper.processPasswordEntry(context, wallet, userPass, true, action)) {
openDialog.dismiss(); Helper.hideKeyboardAlways((Activity) context);
openDialog = null; openDialog.dismiss();
} else { openDialog = null;
} else {
etPassword.setError(context.getString(R.string.bad_password));
}
} catch (KeyStoreHelper.BrokenPasswordStoreException ex) {
etPassword.setError(context.getString(R.string.bad_password)); etPassword.setError(context.getString(R.string.bad_password));
// TODO: better errror message here - what would it be?
} }
} }
@ -455,6 +454,7 @@ public class Helper {
String pass = etPassword.getEditText().getText().toString(); String pass = etPassword.getEditText().getText().toString();
if (processPasswordEntry(context, wallet, pass, false, action)) { if (processPasswordEntry(context, wallet, pass, false, action)) {
Helper.hideKeyboardAlways((Activity) context); Helper.hideKeyboardAlways((Activity) context);
cancelSignal.cancel();
openDialog.dismiss(); openDialog.dismiss();
openDialog = null; openDialog = null;
} else { } else {
@ -472,6 +472,7 @@ public class Helper {
String pass = etPassword.getEditText().getText().toString(); String pass = etPassword.getEditText().getText().toString();
if (processPasswordEntry(context, wallet, pass, false, action)) { if (processPasswordEntry(context, wallet, pass, false, action)) {
Helper.hideKeyboardAlways((Activity) context); Helper.hideKeyboardAlways((Activity) context);
cancelSignal.cancel();
openDialog.dismiss(); openDialog.dismiss();
openDialog = null; openDialog = null;
} else { } else {

View File

@ -23,8 +23,10 @@ import android.os.Build;
import android.security.KeyPairGeneratorSpec; import android.security.KeyPairGeneratorSpec;
import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties; import android.security.keystore.KeyProperties;
import android.support.annotation.NonNull;
import android.util.Base64; import android.util.Base64;
import java.io.IOException;
import java.math.BigInteger; import java.math.BigInteger;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException; import java.security.InvalidAlgorithmParameterException;
@ -39,10 +41,15 @@ import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.Signature; import java.security.Signature;
import java.security.SignatureException; import java.security.SignatureException;
import java.security.UnrecoverableEntryException;
import java.security.cert.CertificateException;
import java.util.Calendar; import java.util.Calendar;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.security.auth.x500.X500Principal; import javax.security.auth.x500.X500Principal;
import timber.log.Timber; import timber.log.Timber;
@ -58,43 +65,54 @@ public class KeyStoreHelper {
static final private String RSA_ALIAS = "MonerujoRSA"; static final private String RSA_ALIAS = "MonerujoRSA";
public static String getCrazyPass(Context context, String password) { public static String getCrazyPass(Context context, String password) {
// TODO we should check Locale.getDefault().getLanguage() here but for now we default to English
return getCrazyPass(context, password, "English");
}
public static String getCrazyPass(Context context, String password, String language) {
byte[] data = password.getBytes(StandardCharsets.UTF_8); byte[] data = password.getBytes(StandardCharsets.UTF_8);
byte[] sig = null; byte[] sig = null;
try { try {
KeyStoreHelper.createKeys(context, RSA_ALIAS); KeyStoreHelper.createKeys(context, RSA_ALIAS);
sig = KeyStoreHelper.signData(RSA_ALIAS, data); sig = KeyStoreHelper.signData(RSA_ALIAS, data);
} catch (Exception ex) { } catch (NoSuchProviderException | NoSuchAlgorithmException |
InvalidAlgorithmParameterException | KeyStoreException |
InvalidKeyException | SignatureException ex) {
throw new IllegalStateException(ex); throw new IllegalStateException(ex);
} }
return CrazyPassEncoder.encode(cnSlowHash(sig)); return CrazyPassEncoder.encode(cnSlowHash(sig));
} }
public static void saveWalletUserPass(Context context, String wallet, String password) { public static boolean saveWalletUserPass(@NonNull Context context, String wallet, String password) {
String walletKeyAlias = SecurityConstants.WALLET_PASS_KEY_PREFIX + wallet; String walletKeyAlias = SecurityConstants.WALLET_PASS_KEY_PREFIX + wallet;
byte[] data = password.getBytes(StandardCharsets.UTF_8); byte[] data = password.getBytes(StandardCharsets.UTF_8);
try { try {
KeyStoreHelper.createKeys(context, walletKeyAlias); KeyStoreHelper.createKeys(context, walletKeyAlias);
byte[] encrypted = KeyStoreHelper.encrypt(walletKeyAlias, data); byte[] encrypted = KeyStoreHelper.encrypt(walletKeyAlias, data);
if (encrypted == null) return false;
context.getSharedPreferences(SecurityConstants.WALLET_PASS_PREFS_NAME, Context.MODE_PRIVATE).edit() context.getSharedPreferences(SecurityConstants.WALLET_PASS_PREFS_NAME, Context.MODE_PRIVATE).edit()
.putString(wallet, Base64.encodeToString(encrypted, Base64.DEFAULT)) .putString(wallet, Base64.encodeToString(encrypted, Base64.DEFAULT))
.apply(); .apply();
} catch (Exception ex) { return true;
throw new IllegalStateException(ex); } catch (NoSuchProviderException | NoSuchAlgorithmException |
InvalidAlgorithmParameterException | KeyStoreException ex) {
Timber.w(ex);
return false;
} }
} }
public static String loadWalletUserPass(Context context, String wallet) { static public class BrokenPasswordStoreException extends Exception {
BrokenPasswordStoreException() {
super();
}
BrokenPasswordStoreException(Throwable cause) {
super(cause);
}
}
public static String loadWalletUserPass(@NonNull Context context, String wallet) throws BrokenPasswordStoreException {
String walletKeyAlias = SecurityConstants.WALLET_PASS_KEY_PREFIX + wallet; String walletKeyAlias = SecurityConstants.WALLET_PASS_KEY_PREFIX + wallet;
String encoded = context.getSharedPreferences(SecurityConstants.WALLET_PASS_PREFS_NAME, Context.MODE_PRIVATE) String encoded = context.getSharedPreferences(SecurityConstants.WALLET_PASS_PREFS_NAME, Context.MODE_PRIVATE)
.getString(wallet, ""); .getString(wallet, "");
byte[] data = Base64.decode(encoded, Base64.DEFAULT); byte[] data = Base64.decode(encoded, Base64.DEFAULT);
byte[] decrypted = KeyStoreHelper.decrypt(walletKeyAlias, data); byte[] decrypted = KeyStoreHelper.decrypt(walletKeyAlias, data);
if (decrypted == null) throw new BrokenPasswordStoreException();
return new String(decrypted, StandardCharsets.UTF_8); return new String(decrypted, StandardCharsets.UTF_8);
} }
@ -102,23 +120,23 @@ public class KeyStoreHelper {
String walletKeyAlias = SecurityConstants.WALLET_PASS_KEY_PREFIX + wallet; String walletKeyAlias = SecurityConstants.WALLET_PASS_KEY_PREFIX + wallet;
try { try {
KeyStoreHelper.deleteKeys(walletKeyAlias); KeyStoreHelper.deleteKeys(walletKeyAlias);
context.getSharedPreferences(SecurityConstants.WALLET_PASS_PREFS_NAME, Context.MODE_PRIVATE).edit() } catch (KeyStoreException ex) {
.remove(wallet).apply(); Timber.w(ex);
} catch (Exception ex) {
throw new IllegalStateException(ex);
} }
context.getSharedPreferences(SecurityConstants.WALLET_PASS_PREFS_NAME, Context.MODE_PRIVATE).edit()
.remove(wallet).apply();
} }
/** /**
* Creates a public and private key and stores it using the Android Key * Creates a public and private key and stores it using the Android Key
* Store, so that only this application will be able to access the keys. * Store, so that only this application will be able to access the keys.
*/ */
public static void createKeys(Context context, String alias) throws NoSuchProviderException, private static void createKeys(Context context, String alias) throws NoSuchProviderException,
NoSuchAlgorithmException, InvalidAlgorithmParameterException, KeyStoreException { NoSuchAlgorithmException, InvalidAlgorithmParameterException, KeyStoreException {
KeyStore keyStore = KeyStore.getInstance(SecurityConstants.KEYSTORE_PROVIDER_ANDROID_KEYSTORE); KeyStore keyStore = KeyStore.getInstance(SecurityConstants.KEYSTORE_PROVIDER_ANDROID_KEYSTORE);
try { try {
keyStore.load(null); keyStore.load(null);
} catch (Exception ex) { // don't care why it failed } catch (IOException | CertificateException ex) {
throw new IllegalStateException("Could not load KeySotre", ex); throw new IllegalStateException("Could not load KeySotre", ex);
} }
if (!keyStore.containsAlias(alias)) { if (!keyStore.containsAlias(alias)) {
@ -130,13 +148,25 @@ public class KeyStoreHelper {
} }
} }
public static void deleteKeys(String alias) throws KeyStoreException { private static boolean deleteKeys(String alias) throws KeyStoreException {
KeyStore keyStore = KeyStore.getInstance(SecurityConstants.KEYSTORE_PROVIDER_ANDROID_KEYSTORE); KeyStore keyStore = KeyStore.getInstance(SecurityConstants.KEYSTORE_PROVIDER_ANDROID_KEYSTORE);
try { try {
keyStore.load(null); keyStore.load(null);
keyStore.deleteEntry(alias); keyStore.deleteEntry(alias);
} catch (Exception ex) { // don't care why it failed return true;
throw new IllegalStateException("Could not load KeySotre", ex); } catch (IOException | NoSuchAlgorithmException | CertificateException ex) {
Timber.w(ex);
return false;
}
}
public static boolean keyExists(String wallet) throws BrokenPasswordStoreException {
try {
KeyStore keyStore = KeyStore.getInstance(KeyStoreHelper.SecurityConstants.KEYSTORE_PROVIDER_ANDROID_KEYSTORE);
keyStore.load(null);
return keyStore.containsAlias(KeyStoreHelper.SecurityConstants.WALLET_PASS_KEY_PREFIX + wallet);
} catch (IOException | NoSuchAlgorithmException | CertificateException | KeyStoreException ex) {
throw new BrokenPasswordStoreException(ex);
} }
} }
@ -164,22 +194,19 @@ public class KeyStoreHelper {
} }
@TargetApi(Build.VERSION_CODES.M) @TargetApi(Build.VERSION_CODES.M)
private static void createKeysM(String alias) { private static void createKeysM(String alias) throws NoSuchProviderException,
try { NoSuchAlgorithmException, InvalidAlgorithmParameterException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_RSA, SecurityConstants.KEYSTORE_PROVIDER_ANDROID_KEYSTORE); KeyProperties.KEY_ALGORITHM_RSA, SecurityConstants.KEYSTORE_PROVIDER_ANDROID_KEYSTORE);
keyPairGenerator.initialize( keyPairGenerator.initialize(
new KeyGenParameterSpec.Builder( new KeyGenParameterSpec.Builder(
alias, KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) alias, KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setDigests(KeyProperties.DIGEST_SHA256) .setDigests(KeyProperties.DIGEST_SHA256)
.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1) .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
.build()); .build());
KeyPair keyPair = keyPairGenerator.generateKeyPair(); KeyPair keyPair = keyPairGenerator.generateKeyPair();
Timber.d("M Keys created"); Timber.d("M Keys created");
} catch (NoSuchProviderException | NoSuchAlgorithmException | InvalidAlgorithmParameterException e) {
throw new RuntimeException(e);
}
} }
private static KeyStore.PrivateKeyEntry getPrivateKeyEntry(String alias) { private static KeyStore.PrivateKeyEntry getPrivateKeyEntry(String alias) {
@ -199,33 +226,38 @@ public class KeyStoreHelper {
return null; return null;
} }
return (KeyStore.PrivateKeyEntry) entry; return (KeyStore.PrivateKeyEntry) entry;
} catch (Exception ex) { } catch (IOException | NoSuchAlgorithmException | CertificateException
| UnrecoverableEntryException | KeyStoreException ex) {
Timber.e(ex); Timber.e(ex);
return null; return null;
} }
} }
public static byte[] encrypt(String alias, byte[] data) { private static byte[] encrypt(String alias, byte[] data) {
try { try {
PublicKey publicKey = getPrivateKeyEntry(alias).getCertificate().getPublicKey(); PublicKey publicKey = getPrivateKeyEntry(alias).getCertificate().getPublicKey();
Cipher cipher = Cipher.getInstance(SecurityConstants.CIPHER_RSA_ECB_PKCS1); Cipher cipher = Cipher.getInstance(SecurityConstants.CIPHER_RSA_ECB_PKCS1);
cipher.init(Cipher.ENCRYPT_MODE, publicKey); cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(data); return cipher.doFinal(data);
} catch (Exception ex) { } catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException
throw new IllegalStateException("Could not initialize RSA cipher", ex); | NoSuchAlgorithmException | NoSuchPaddingException ex) {
Timber.e(ex);
return null;
} }
} }
public static byte[] decrypt(String alias, byte[] data) { private static byte[] decrypt(String alias, byte[] data) {
try { try {
PrivateKey privateKey = getPrivateKeyEntry(alias).getPrivateKey(); PrivateKey privateKey = getPrivateKeyEntry(alias).getPrivateKey();
Cipher cipher = Cipher.getInstance(SecurityConstants.CIPHER_RSA_ECB_PKCS1); Cipher cipher = Cipher.getInstance(SecurityConstants.CIPHER_RSA_ECB_PKCS1);
cipher.init(Cipher.DECRYPT_MODE, privateKey); cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(data); return cipher.doFinal(data);
} catch (Exception ex) { } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException |
throw new IllegalStateException("Could not initialize RSA cipher", ex); IllegalBlockSizeException | BadPaddingException ex) {
Timber.e(ex);
return null;
} }
} }
@ -236,7 +268,7 @@ public class KeyStoreHelper {
* *
* @return The data signature generated * @return The data signature generated
*/ */
public static byte[] signData(String alias, byte[] data) throws NoSuchAlgorithmException, private static byte[] signData(String alias, byte[] data) throws NoSuchAlgorithmException,
InvalidKeyException, SignatureException { InvalidKeyException, SignatureException {
PrivateKey privateKey = getPrivateKeyEntry(alias).getPrivateKey(); PrivateKey privateKey = getPrivateKeyEntry(alias).getPrivateKey();
@ -256,7 +288,7 @@ public class KeyStoreHelper {
* @return A boolean value telling you whether the signature is valid or * @return A boolean value telling you whether the signature is valid or
* not. * not.
*/ */
public static boolean verifyData(String alias, byte[] data, byte[] signature) private static boolean verifyData(String alias, byte[] data, byte[] signature)
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
// Make sure the signature string exists // Make sure the signature string exists