Implemented Crypto

for better (not the best) password saving
This commit is contained in:
Przemek Grondek 2014-07-29 12:30:23 +02:00
parent e2421ae720
commit 974ffcdd7b
3 changed files with 109 additions and 26 deletions

View file

@ -1,11 +1,22 @@
package info.nerull7.mysqlbrowser;
import android.content.Context;
import android.util.Base64;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
@ -13,57 +24,83 @@ import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.PBEKeySpec;
/**
* Created by nerull7 on 28.07.14.
*/
public class Crypto {
private static final String KEY_FILE = "null_file"; // to trick h4x0r5
// private static final String ENCRYPTION_ALGORITHM = "AES/CBC/PKCS5Padding"; // doesn't work TODO: Maybe fix?
private static final String ENCRYPTION_ALGORITHM = "AES";
private static final String KEY_ALGORITHM = "AES";
private static final int OUTPUT_KEY_LENGTH = 256;
private static SecretKey secretKey;
private SecretKey secretKey;
private Context context;
private static SecretKey generateKey() throws NoSuchAlgorithmException {
public Crypto(Context context){
this.context = context;
try {
getSecretKey();
} catch (Exception e) {
e.printStackTrace();
}
}
private SecretKey generateKey() throws NoSuchAlgorithmException {
SecureRandom secureRandom = new SecureRandom();
KeyGenerator keyGenerator = KeyGenerator.getInstance(ENCRYPTION_ALGORITHM);
KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
keyGenerator.init(OUTPUT_KEY_LENGTH, secureRandom);
SecretKey secretKey = keyGenerator.generateKey();
return secretKey;
}
private static SecretKey getSecretKey() throws NoSuchAlgorithmException {
if(secretKey==null)
secretKey = generateKey();
private void getSecretKey() throws NoSuchAlgorithmException, IOException, ClassNotFoundException {
String key;
Log.d("SecureKEY", "Hash:" + secretKey.hashCode());
return secretKey;
// First try to open file
File keyFile = new File(context.getFilesDir(), KEY_FILE);
if(!keyFile.exists()) { // new key
secretKey = generateKey();
FileOutputStream fileOutputStream = new FileOutputStream(keyFile);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(secretKey);
objectOutputStream.close();
fileOutputStream.close();
} else { // read existing key from file
FileInputStream fileInputStream = new FileInputStream(keyFile);
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
secretKey = (SecretKey) objectInputStream.readObject();
objectInputStream.close();
fileInputStream.close();
}
}
public static byte[] encrypt(String input) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
public byte[] encrypt(String input) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
byte[] output;
Cipher cipher = Cipher.getInstance(ENCRYPTION_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey());
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
output = cipher.doFinal(input.getBytes(Charset.defaultCharset()));
return output;
}
public static String decrypt(byte[] input) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
public String decrypt(byte[] input) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
String output;
byte [] tmp; // TODO: REMOVE
Cipher cipher = Cipher.getInstance(ENCRYPTION_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, getSecretKey());
// output = String.valueOf(cipher.doFinal(input));
tmp = cipher.doFinal(input);
// output = tmp.toString();
output = new String(input, Charset.defaultCharset());
cipher.init(Cipher.DECRYPT_MODE, secretKey);
output = new String(cipher.doFinal(input), Charset.defaultCharset());
return output;
}
public String decryptBase64(String encodedString) throws IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
byte [] encryptedString = Base64.decode(encodedString, Base64.DEFAULT);
String decrypted = decrypt(encryptedString);
return decrypted;
}
}

View file

@ -63,8 +63,14 @@ public class LoginFragment extends Fragment implements View.OnClickListener, Asy
if(sharedPreferences.getBoolean(SettingsFragment.SAVE_SERVER_CREDENTIALS, false)){
urlTextbox.setText(sharedPreferences.getString(SettingsFragment.URL_CREDENTIALS, null));
loginTextbox.setText(sharedPreferences.getString(SettingsFragment.LOGIN_CREDENTIALS, null));
passwordTextbox.setText(sharedPreferences.getString(SettingsFragment.PASSWORD_CREDENTIALS, null));
test(urlTextbox.getText().toString());
Crypto crypto = new Crypto(getActivity());
String password = sharedPreferences.getString(SettingsFragment.PASSWORD_CREDENTIALS, null);
if(password!=null) {
try {
passwordTextbox.setText(crypto.decryptBase64(password));
} catch (Exception e) { e.printStackTrace(); }
}
// test(urlTextbox.getText().toString());
}
}
@ -72,10 +78,9 @@ public class LoginFragment extends Fragment implements View.OnClickListener, Asy
String tmp;
byte [] tmp_byte;
try {
tmp_byte = Crypto.encrypt(text);
Log.d("Crypto", "encrypted: " + tmp_byte);
tmp = Crypto.decrypt(tmp_byte);
Log.d("Crypto", "decrypted: " + tmp);
Crypto crypto = new Crypto(getActivity());
tmp_byte = crypto.encrypt(text);
crypto.decrypt(tmp_byte);
} catch (Exception e) { e.printStackTrace(); }
}

View file

@ -7,11 +7,19 @@ import android.preference.EditTextPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.preference.PreferenceScreen;
import android.util.Base64;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
/**
* Created by nerull7 on 18.07.14.
*/
public class SettingsFragment extends PreferenceFragment implements NumberPickerDialog.OnNumberSetListener, Preference.OnPreferenceClickListener {
public class SettingsFragment extends PreferenceFragment implements NumberPickerDialog.OnNumberSetListener, Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
public static final String ENTRIES_PAGE_LIMIT = "entries_limit";
public static final String SAVE_SERVER_CREDENTIALS = "save_credentials_enabled";
public static final String URL_CREDENTIALS = "url";
@ -29,10 +37,13 @@ public class SettingsFragment extends PreferenceFragment implements NumberPicker
private EditTextPreference loginCredentials;
private EditTextPreference passwordCredentials;
private Crypto crypto;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
preferences = getPreferenceManager().getDefaultSharedPreferences(getActivity());
crypto = new Crypto(getActivity());
loadPrefs();
}
@ -49,9 +60,11 @@ public class SettingsFragment extends PreferenceFragment implements NumberPicker
// Settings fields
setEntriesPageLimitSummary();
setPasswordCredentials();
// Settings Listener
saveCredentials.setOnPreferenceClickListener(this);
passwordCredentials.setOnPreferenceChangeListener(this);
}
private void setSaveServerCredentials(boolean isEnabled){
@ -85,6 +98,26 @@ public class SettingsFragment extends PreferenceFragment implements NumberPicker
mEntriesLimit.setSummary(getString(R.string.entries_summary, getEntriesPageLimit()));
}
private void setPasswordCredentials(){
String password;
password = preferences.getString(PASSWORD_CREDENTIALS, null);
if(password != null)
try {
passwordCredentials.setText(crypto.decryptBase64(password));
} catch (Exception e) { e.printStackTrace(); } // TODO: Something useful
}
private void savePassword(String password){
try {
SharedPreferences.Editor editor = preferences.edit();
byte [] encryptedPassword;
encryptedPassword = crypto.encrypt(password);
String passwordBase64 = Base64.encodeToString(encryptedPassword, Base64.DEFAULT);
editor.putString(PASSWORD_CREDENTIALS, passwordBase64);
editor.apply();
} catch (Exception e) { e.printStackTrace(); } // TODO: Something useful
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
if(preference == mEntriesLimit){
@ -112,4 +145,12 @@ public class SettingsFragment extends PreferenceFragment implements NumberPicker
return true;
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if(preference == passwordCredentials){
savePassword((String) newValue);
}
return false;
}
}