Merge pull request #35 from syng-io/profile-encryption-changes
Profile encryption changes
This commit is contained in:
commit
082cd9068e
|
@ -230,28 +230,30 @@ public abstract class BaseActivity extends AppCompatActivity implements
|
|||
}
|
||||
|
||||
private void requestChangeProfile(final Profile profile) {
|
||||
Dialog dialog = new MaterialDialog.Builder(BaseActivity.this)
|
||||
.title(R.string.request_profile_password)
|
||||
.customView(R.layout.profile_password, true)
|
||||
.positiveText(R.string.ok)
|
||||
.negativeText(R.string.cancel)
|
||||
.callback(new MaterialDialog.ButtonCallback() {
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Override
|
||||
public void onPositive(MaterialDialog dialog) {
|
||||
View view = dialog.getCustomView();
|
||||
EditText password = (EditText) view.findViewById(R.id.et_pass);
|
||||
if (profile.checkPassword(password.getText().toString())) {
|
||||
ProfileManager.setCurrentProfile(profile);
|
||||
flipDrawer();
|
||||
} else {
|
||||
Toast.makeText(BaseActivity.this, "Password is not correct", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
})
|
||||
.show();
|
||||
EditText name = (EditText) dialog.findViewById(R.id.et_pass);
|
||||
GeneralUtil.showKeyBoard(name, this);
|
||||
|
||||
GeneralUtil.showProfilePasswordRequestDialog(BaseActivity.this, profile.getName(), new MaterialDialog.ButtonCallback() {
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Override
|
||||
public void onPositive(MaterialDialog dialog) {
|
||||
View view = dialog.getCustomView();
|
||||
EditText passwordText = (EditText) view.findViewById(R.id.et_pass);
|
||||
String password = passwordText.getText().toString();
|
||||
if (profile.checkPassword(password)) {
|
||||
ProfileManager.setCurrentProfile(profile, password);
|
||||
flipDrawer();
|
||||
dialog.dismiss();
|
||||
} else {
|
||||
Toast.makeText(BaseActivity.this, "Password is not correct", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNegative(MaterialDialog dialog) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private void updateCurrentProfileName() {
|
||||
|
@ -404,30 +406,27 @@ public abstract class BaseActivity extends AppCompatActivity implements
|
|||
ProfileDialogFragment dialogFragment = ProfileDialogFragment.newInstance(profile);
|
||||
dialogFragment.show(getSupportFragmentManager(), "profile_dialog");
|
||||
} else {
|
||||
Dialog dialog = new MaterialDialog.Builder(BaseActivity.this)
|
||||
.title(R.string.request_profile_password)
|
||||
.customView(R.layout.profile_password, true)
|
||||
.positiveText(R.string.ok)
|
||||
.negativeText(R.string.cancel)
|
||||
.callback(new MaterialDialog.ButtonCallback() {
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Override
|
||||
public void onPositive(MaterialDialog dialog) {
|
||||
View view = dialog.getCustomView();
|
||||
EditText password = (EditText) view.findViewById(R.id.et_pass);
|
||||
if (profile.checkPassword(password.getText().toString())) {
|
||||
ProfileDialogFragment dialogFragment = ProfileDialogFragment.newInstance(profile);
|
||||
dialogFragment.show(getSupportFragmentManager(), "profile_dialog");
|
||||
} else {
|
||||
Toast.makeText(BaseActivity.this, "Password is not correct", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
})
|
||||
.show();
|
||||
EditText name = (EditText) dialog.findViewById(R.id.et_pass);
|
||||
GeneralUtil.showKeyBoard(name, this);
|
||||
}
|
||||
GeneralUtil.showProfilePasswordRequestDialog(BaseActivity.this, profile.getName(), new MaterialDialog.ButtonCallback() {
|
||||
|
||||
@Override
|
||||
public void onPositive(MaterialDialog dialog) {
|
||||
View view = dialog.getCustomView();
|
||||
EditText password = (EditText) view.findViewById(R.id.et_pass);
|
||||
if (profile.checkPassword(password.getText().toString())) {
|
||||
dialog.dismiss();
|
||||
ProfileDialogFragment dialogFragment = ProfileDialogFragment.newInstance(profile);
|
||||
dialogFragment.show(getSupportFragmentManager(), "profile_dialog");
|
||||
} else {
|
||||
Toast.makeText(BaseActivity.this, "Password is not correct", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNegative(MaterialDialog dialog) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -12,6 +12,7 @@ import android.content.Intent;
|
|||
import android.os.Bundle;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Toast;
|
||||
|
@ -44,9 +45,8 @@ public class LoginActivity extends AppCompatActivity {
|
|||
if (PrefsUtil.isFirstLaunch()) {
|
||||
createAndSetProfile();
|
||||
} else {
|
||||
startNextActivity();
|
||||
loginWallet();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void startNextActivity() {
|
||||
|
@ -76,7 +76,31 @@ public class LoginActivity extends AppCompatActivity {
|
|||
LoginActivity.this.finish();
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loginWallet() {
|
||||
final Profile profile = ProfileManager.getCurrentProfile();
|
||||
GeneralUtil.showProfilePasswordRequestDialog(LoginActivity.this, profile.getName(), new MaterialDialog.ButtonCallback() {
|
||||
@Override
|
||||
public void onPositive(MaterialDialog dialog) {
|
||||
View view = dialog.getCustomView();
|
||||
EditText passwordText = (EditText) view.findViewById(R.id.et_pass);
|
||||
String password = passwordText.getText().toString();
|
||||
if (profile.checkPassword(password)) {
|
||||
dialog.dismiss();
|
||||
ProfileManager.setCurrentProfile(profile, password);
|
||||
startNextActivity();
|
||||
} else {
|
||||
Toast.makeText(LoginActivity.this, "Password is not correct", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNegative(MaterialDialog dialog) {
|
||||
LoginActivity.this.finish();
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.ethereum.net.p2p.HelloMessage;
|
|||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.EnumSet;
|
||||
import java.util.UUID;
|
||||
|
@ -57,6 +58,8 @@ public class SyngApplication extends MultiDexApplication implements ConnectorHan
|
|||
|
||||
private boolean isRpcConnection = true;
|
||||
|
||||
public boolean isEthereumConnected = false;
|
||||
|
||||
private String mHandlerIdentifier = UUID.randomUUID().toString();
|
||||
|
||||
@Override
|
||||
|
@ -92,8 +95,9 @@ public class SyngApplication extends MultiDexApplication implements ConnectorHan
|
|||
@Override
|
||||
public void onConnectorConnected() {
|
||||
System.out.println("Connector connected");
|
||||
isEthereumConnected = true;
|
||||
SyngApplication.sEthereumConnector.addListener(mHandlerIdentifier, EnumSet.allOf(EventFlag.class));
|
||||
sEthereumConnector.init(ProfileManager.getCurrentProfile().getPrivateKeys());
|
||||
sEthereumConnector.init(new ArrayList<String>());
|
||||
sEthereumConnector.startJsonRpc();
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
String rpcServer = sharedPref.getString(getString(R.string.pref_json_rpc_server_key), "http://rpc0.syng.io:8545/");
|
||||
|
@ -103,6 +107,7 @@ public class SyngApplication extends MultiDexApplication implements ConnectorHan
|
|||
@Override
|
||||
public void onConnectorDisconnected() {
|
||||
System.out.println("Connector Disconnected");
|
||||
isEthereumConnected = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,22 +8,24 @@
|
|||
|
||||
package io.syng.entity;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.ethereum.crypto.ECKey;
|
||||
import org.ethereum.crypto.HashUtil;
|
||||
import org.ethereum.wallet.EtherSaleWallet;
|
||||
import org.ethereum.wallet.EtherSaleWalletDecoder;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.syng.util.Encryption;
|
||||
|
||||
public class Profile implements Serializable {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger("Profile");
|
||||
private static final String TAG = "Profile";
|
||||
|
||||
protected String name;
|
||||
|
||||
|
@ -31,6 +33,8 @@ public class Profile implements Serializable {
|
|||
|
||||
protected List<String> privateKeys = new ArrayList<>();
|
||||
|
||||
protected List<String> publicKeys = new ArrayList<>();
|
||||
|
||||
/* "password protect profile" (encrypt the private keys) */
|
||||
protected boolean passwordProtectedProfile;
|
||||
|
||||
|
@ -42,18 +46,21 @@ public class Profile implements Serializable {
|
|||
|
||||
protected transient boolean isEncrypted;
|
||||
|
||||
|
||||
public Profile() {
|
||||
this.privateKeys.add(createPrivateKey());
|
||||
addPrivateKey(createPrivateKey(), null);
|
||||
addDefaultApps();
|
||||
}
|
||||
|
||||
public Profile(String privateKey) {
|
||||
this.privateKeys.add(privateKey);
|
||||
addPrivateKey(privateKey, null);
|
||||
addDefaultApps();
|
||||
}
|
||||
|
||||
public Profile(List<String> privateKeys) {
|
||||
this.privateKeys = privateKeys;
|
||||
for (String privateKey: privateKeys) {
|
||||
addPrivateKey(privateKey, null);
|
||||
}
|
||||
addDefaultApps();
|
||||
}
|
||||
|
||||
|
@ -79,30 +86,53 @@ public class Profile implements Serializable {
|
|||
return Hex.toHexString(privateKey);
|
||||
}
|
||||
|
||||
public List<String> getPrivateKeys() {
|
||||
return privateKeys;
|
||||
public List<String> getPrivateKeys(String password) {
|
||||
List<String> keys = new ArrayList<>();
|
||||
|
||||
for (String privateKey: privateKeys) {
|
||||
String key = passwordProtectedProfile ? decryptPrivateKey(privateKey, password) : privateKey;
|
||||
keys.add(key);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
public List<String> getAddresses() {
|
||||
return publicKeys;
|
||||
}
|
||||
|
||||
List<String> addresses = new ArrayList<>();
|
||||
for (String privateKey : privateKeys) {
|
||||
ECKey key = ECKey.fromPrivate(Hex.decode(privateKey));
|
||||
addresses.add(Hex.toHexString(key.getAddress()));
|
||||
public void addPrivateKeys(List<String> privateKeys, String password) {
|
||||
for (String privateKey: privateKeys) {
|
||||
addPrivateKey(privateKey, password);
|
||||
}
|
||||
return addresses;
|
||||
}
|
||||
|
||||
public void setPrivateKeys(List<String> privateKeys) {
|
||||
this.privateKeys = privateKeys;
|
||||
protected String getPublicKey(String privateKey) {
|
||||
ECKey ecKey = ECKey.fromPrivate(Hex.decode(privateKey));
|
||||
return Hex.toHexString(ecKey.getAddress());
|
||||
}
|
||||
|
||||
public void addPrivateKey(String privateKey) {
|
||||
this.privateKeys.add(privateKey);
|
||||
public boolean addPrivateKey(String privateKey, String password) {
|
||||
|
||||
if (password != null && passwordProtectedProfile) {
|
||||
if (!checkPassword(password)) {
|
||||
return false;
|
||||
}
|
||||
this.privateKeys.add(encryptPrivateKey(privateKey, password));
|
||||
} else {
|
||||
this.privateKeys.add(privateKey);
|
||||
}
|
||||
this.publicKeys.add(getPublicKey(privateKey));
|
||||
return true;
|
||||
}
|
||||
|
||||
private String hash(String text) {
|
||||
return Hex.toHexString(HashUtil.sha3(text.getBytes()));
|
||||
}
|
||||
|
||||
public void removePrivateKey(String privateKey) {
|
||||
|
||||
this.privateKeys.remove(privateKey);
|
||||
this.publicKeys.remove(getPublicKey(privateKey));
|
||||
}
|
||||
|
||||
public List<Dapp> getDapps() {
|
||||
|
@ -155,20 +185,23 @@ public class Profile implements Serializable {
|
|||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.passwordHash = Hex.toHexString(HashUtil.sha3(password.getBytes()));
|
||||
if (!passwordProtectedProfile) {
|
||||
this.passwordHash = hash(password);
|
||||
this.encrypt(password);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean checkPassword(String password) {
|
||||
return passwordHash.equals(Hex.toHexString(HashUtil.sha3(password.getBytes())));
|
||||
return passwordHash.equals(hash(password));
|
||||
}
|
||||
|
||||
public void encrypt(String password) {
|
||||
if (!passwordProtectedProfile) {
|
||||
setPassword(password);
|
||||
List<String> encrypted = new ArrayList<>();
|
||||
for (String privateKey : this.privateKeys) {
|
||||
encrypted.add(encryptPrivateKey(privateKey, password));
|
||||
}
|
||||
this.privateKeys.clear();
|
||||
this.privateKeys = encrypted;
|
||||
passwordProtectedProfile = true;
|
||||
}
|
||||
|
@ -176,7 +209,7 @@ public class Profile implements Serializable {
|
|||
|
||||
public boolean decrypt(String password) {
|
||||
if (passwordProtectedProfile) {
|
||||
if (!passwordHash.equals(Hex.toHexString(HashUtil.sha3(password.getBytes())))) {
|
||||
if (!checkPassword(password)) {
|
||||
return false;
|
||||
}
|
||||
List<String> decrypted = new ArrayList<>();
|
||||
|
@ -190,16 +223,22 @@ public class Profile implements Serializable {
|
|||
}
|
||||
|
||||
protected String encryptPrivateKey(String privateKey, String password) {
|
||||
// TODO: Encrypt private key
|
||||
return privateKey;
|
||||
String encryptedKey = Encryption.encrypt(privateKey, password);
|
||||
if (encryptedKey == null) {
|
||||
Log.w(TAG, "Could not encrypt private key");
|
||||
}
|
||||
return encryptedKey;
|
||||
}
|
||||
|
||||
protected String decryptPrivateKey(String privateKey, String password) {
|
||||
// TODO: Decrypt private key
|
||||
return privateKey;
|
||||
String decryptedKey = Encryption.decrypt(privateKey, password);
|
||||
if (decryptedKey == null) {
|
||||
Log.w(TAG, "Could not decrypt private key");
|
||||
}
|
||||
return decryptedKey;
|
||||
}
|
||||
|
||||
public boolean importWallet(String jsonWallet, String password) {
|
||||
public boolean importWallet(String jsonWallet, String importPassword, String currentPassword) {
|
||||
try {
|
||||
JSONObject json = new JSONObject(jsonWallet);
|
||||
byte[] privateKey = null;
|
||||
|
@ -210,35 +249,51 @@ public class Profile implements Serializable {
|
|||
wallet.setEmail(json.getString("email"));
|
||||
wallet.setBtcaddr(json.getString("btcaddr"));
|
||||
EtherSaleWalletDecoder decoder = new EtherSaleWalletDecoder(wallet);
|
||||
privateKey = decoder.getPrivateKey(password);
|
||||
privateKey = decoder.getPrivateKey(importPassword);
|
||||
} else if (json.has("Crypto")) {
|
||||
wallet.setEncseed(json.getJSONObject("Crypto").getJSONObject("cipherparams").getString("iv") + json.getJSONObject("Crypto").getString("ciphertext"));
|
||||
wallet.setEthaddr(json.getString("address"));
|
||||
EtherSaleWalletDecoder decoder = new EtherSaleWalletDecoder(wallet);
|
||||
privateKey = decoder.getPrivateKey(password);
|
||||
privateKey = decoder.getPrivateKey(importPassword);
|
||||
}
|
||||
if (privateKey == null) {
|
||||
logger.warn("Invalid json wallet file.");
|
||||
Log.w(TAG, "Invalid json wallet file.");
|
||||
return false;
|
||||
}
|
||||
ECKey key = ECKey.fromPrivate(privateKey);
|
||||
String address = Hex.toHexString(key.getAddress());
|
||||
if (address.equals(wallet.getEthaddr())) {
|
||||
privateKeys.add(Hex.toHexString(privateKey));
|
||||
String keyToAdd = Hex.toHexString(privateKey);
|
||||
if (passwordProtectedProfile) {
|
||||
addPrivateKey(keyToAdd, currentPassword);
|
||||
} else {
|
||||
addPrivateKey(keyToAdd, null);
|
||||
}
|
||||
this.publicKeys.add(getPublicKey(keyToAdd));
|
||||
} else {
|
||||
logger.warn("Invalid wallet password.");
|
||||
Log.w(TAG, "Invalid wallet password.");
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Error importing wallet.", e);
|
||||
Log.e(TAG, "Error importing wallet: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void importPrivateKey(String privateKey, String password) {
|
||||
privateKeys.add(decryptPrivateKey(privateKey, password));
|
||||
public boolean importPrivateKey(String privateKey, String importedKeyPassword, String walletPassword) {
|
||||
String decryptedKey = importedKeyPassword == null || importedKeyPassword == "" ? privateKey : decryptPrivateKey(privateKey, importedKeyPassword);
|
||||
if (passwordProtectedProfile) {
|
||||
if (checkPassword(walletPassword)) {
|
||||
addPrivateKey(decryptedKey, walletPassword);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
addPrivateKey(decryptedKey, null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -51,10 +51,6 @@ public class ProfileKeysFragment extends Fragment {
|
|||
View view = inflater.inflate(R.layout.fragment_profile_keys, container, false);
|
||||
|
||||
Profile profile = ProfileManager.getProfileById(mProfileId);
|
||||
if (profile != null) {
|
||||
profile.getPrivateKeys();
|
||||
}
|
||||
|
||||
mRecyclerView = (RecyclerView) view.findViewById(R.id.rv_profile_keys);
|
||||
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity());
|
||||
mRecyclerView.setLayoutManager(layoutManager);
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Jarrad Hope
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package io.syng.util;
|
||||
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.security.spec.KeySpec;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
public class Encryption {
|
||||
|
||||
private static final String TAG = "Encryption";
|
||||
|
||||
private static SecureRandom random = new SecureRandom();
|
||||
private static String delimiter = "}";
|
||||
private static int keyLength = 256;
|
||||
private static int saltLength = keyLength / 8;
|
||||
private static int iterationCount = 20000;
|
||||
|
||||
public static String encrypt(String text, String password) {
|
||||
|
||||
Log.d(TAG, "Encrypting: " + text);
|
||||
String encryptedText = "";
|
||||
byte[] salt = generateSalt(saltLength);
|
||||
SecretKey key = generateKey(password, salt);
|
||||
if (key != null) {
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
byte[] iv = new byte[cipher.getBlockSize()];
|
||||
random.nextBytes(iv);
|
||||
IvParameterSpec ivParams = new IvParameterSpec(iv);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key, ivParams);
|
||||
byte[] encryptedKey = cipher.doFinal(text.getBytes("UTF-8"));
|
||||
|
||||
encryptedText = Base64.encodeToString(salt, Base64.NO_WRAP);
|
||||
encryptedText += delimiter + Base64.encodeToString(iv, Base64.NO_WRAP);
|
||||
encryptedText += delimiter + Base64.encodeToString(encryptedKey, Base64.NO_WRAP);
|
||||
Log.d(TAG, "Encrypted: " + encryptedText);
|
||||
return encryptedText;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "encrypt(): " + e.toString());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static byte[] generateSalt(int saltLength) {
|
||||
|
||||
byte[] salt = new byte[saltLength];
|
||||
random.nextBytes(salt);
|
||||
return salt;
|
||||
}
|
||||
|
||||
private static SecretKey generateKey(String password, byte[] salt) {
|
||||
try {
|
||||
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, iterationCount, keyLength);
|
||||
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
|
||||
byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
|
||||
return new SecretKeySpec(keyBytes, "AES");
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "generateKey(): " + e.toString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String decrypt(String encryptedText, String password) {
|
||||
|
||||
Log.d(TAG, "Decrypting: " + encryptedText);
|
||||
String[] parts = encryptedText.split(Pattern.quote(delimiter));
|
||||
byte[] salt = Base64.decode(parts[0], Base64.NO_WRAP);
|
||||
byte[] iv = Base64.decode(parts[1], Base64.NO_WRAP);
|
||||
byte[] cipherBytes = Base64.decode(parts[2], Base64.NO_WRAP);
|
||||
|
||||
SecretKey key = generateKey(password, salt);
|
||||
if (key != null) {
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
IvParameterSpec ivParams = new IvParameterSpec(iv);
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, ivParams);
|
||||
byte[] decrypted = cipher.doFinal(cipherBytes);
|
||||
String decryptedText = new String(decrypted, "UTF-8");
|
||||
Log.d(TAG, "Decrypted: " + decryptedText);
|
||||
return decryptedText;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "decrypt(): " + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -112,7 +112,7 @@ public final class GeneralUtil {
|
|||
profile.setName(name.getText().toString());
|
||||
profile.setPassword(pass1String);
|
||||
ProfileManager.addProfile(profile);
|
||||
ProfileManager.setCurrentProfile(profile);
|
||||
ProfileManager.setCurrentProfile(profile, pass1String);
|
||||
GeneralUtil.hideKeyBoard(name, context);
|
||||
GeneralUtil.hideKeyBoard(pass1, context);
|
||||
GeneralUtil.hideKeyBoard(pass2, context);
|
||||
|
@ -150,6 +150,33 @@ public final class GeneralUtil {
|
|||
GeneralUtil.showKeyBoard(name, context);
|
||||
}
|
||||
|
||||
public static void showProfilePasswordRequestDialog(final Context context, String profileName, MaterialDialog.ButtonCallback callback) {
|
||||
|
||||
if (callback == null) {
|
||||
callback = new MaterialDialog.ButtonCallback() {
|
||||
@Override
|
||||
public void onPositive(MaterialDialog dialog) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNegative(MaterialDialog dialog) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
};
|
||||
}
|
||||
MaterialDialog dialog = new MaterialDialog.Builder(context)
|
||||
.title((profileName != null ? profileName + " " : "") + context.getResources().getString(R.string.request_profile_password))
|
||||
.positiveText(R.string.ok)
|
||||
.negativeText(R.string.cancel)
|
||||
.customView(R.layout.profile_password, true)
|
||||
.callback(callback)
|
||||
.autoDismiss(false)
|
||||
.show();
|
||||
EditText name = (EditText) dialog.findViewById(R.id.et_pass);
|
||||
GeneralUtil.showKeyBoard(name, context);
|
||||
}
|
||||
|
||||
public static void showDAppEditDialog(final Dapp dapp, final Context context) {
|
||||
MaterialDialog dialog = new MaterialDialog.Builder(context)
|
||||
.title("Edit")
|
||||
|
@ -256,8 +283,10 @@ public final class GeneralUtil {
|
|||
RadioButton importJsonRadio = (RadioButton) dialog.findViewById(R.id.radio_import_json);
|
||||
EditText importPathEdit = (EditText) dialog.findViewById(R.id.wallet_import_path);
|
||||
EditText walletPasswordEdit = (EditText) dialog.findViewById(R.id.wallet_password);
|
||||
EditText currentWalletPasswordEdit = (EditText) dialog.findViewById(R.id.current_wallet_password);
|
||||
String importPath = importPathEdit.getText().toString();
|
||||
String password = walletPasswordEdit.getText().toString();
|
||||
String currentPassword = currentWalletPasswordEdit.getText().toString();
|
||||
String fileContents = null;
|
||||
try {
|
||||
File walletFile = new File(importPath);
|
||||
|
@ -281,15 +310,15 @@ public final class GeneralUtil {
|
|||
}
|
||||
if (importJsonRadio.isChecked()) {
|
||||
Profile profile = ProfileManager.getCurrentProfile();
|
||||
if (profile.importWallet(fileContents, password)) {
|
||||
if (profile.importWallet(fileContents, password, currentPassword)) {
|
||||
ProfileManager.updateProfile(profile);
|
||||
ProfileManager.setCurrentProfile(profile);
|
||||
ProfileManager.setCurrentProfile(profile, currentPassword);
|
||||
} else {
|
||||
Toast.makeText(context, R.string.invalid_wallet_password, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
} else {
|
||||
Profile profile = ProfileManager.getCurrentProfile();
|
||||
profile.importPrivateKey(fileContents, password);
|
||||
profile.importPrivateKey(fileContents, password, currentPassword);
|
||||
ProfileManager.updateProfile(profile);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,8 +110,8 @@ public final class ProfileManager {
|
|||
return new Profile();
|
||||
}
|
||||
|
||||
public static void setCurrentProfile(Profile profile) {
|
||||
List<String> privateKeys = profile.getPrivateKeys();
|
||||
public static void setCurrentProfile(Profile profile, String password) {
|
||||
List<String> privateKeys = profile.getPrivateKeys(password);
|
||||
SyngApplication.sEthereumConnector.init(privateKeys);
|
||||
PrefsUtil.setCurrentProfileId(profile.getId());
|
||||
notifyListener();
|
||||
|
|
|
@ -38,7 +38,15 @@
|
|||
android:id="@+id/wallet_password"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Password"
|
||||
android:hint="Import Password"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/accent"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/current_wallet_password"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Current Wallet Password"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/accent"/>
|
||||
</LinearLayout>
|
Loading…
Reference in New Issue