--- a/app/src/main/java/com/beem/project/beem/BeemApplication.java Thu Jan 07 16:38:16 2016 +0100
+++ b/app/src/main/java/com/beem/project/beem/BeemApplication.java Fri Jan 08 11:31:18 2016 +0100
@@ -154,7 +154,7 @@
String login = mSettings.getString(BeemApplication.ACCOUNT_USERNAME_KEY, "");
String password = mSettings.getString(BeemApplication.ACCOUNT_PASSWORD_KEY, "");
boolean useSystemAccount = mSettings.getBoolean(BeemApplication.USE_SYSTEM_ACCOUNT_KEY, false);
- mIsAccountConfigured = !TextUtils.isEmpty(login) && (useSystemAccount || !TextUtils.isEmpty((password)));
+ mIsAccountConfigured = !TextUtils.isEmpty(login) && (useSystemAccount || !TextUtils.isEmpty(password));
mSettings.registerOnSharedPreferenceChangeListener(mPreferenceListener);
SmileyParser.init(this);
}
@@ -220,11 +220,12 @@
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- if (BeemApplication.ACCOUNT_USERNAME_KEY.equals(key) || BeemApplication.ACCOUNT_PASSWORD_KEY.equals(key) || BeemApplication.USE_SYSTEM_ACCOUNT_KEY.equals(key)) {
+ if (BeemApplication.ACCOUNT_USERNAME_KEY.equals(key) || BeemApplication.ACCOUNT_PASSWORD_KEY.equals(key)
+ || BeemApplication.USE_SYSTEM_ACCOUNT_KEY.equals(key)) {
String login = mSettings.getString(BeemApplication.ACCOUNT_USERNAME_KEY, "");
String password = mSettings.getString(BeemApplication.ACCOUNT_PASSWORD_KEY, "");
boolean useSystemAccount = mSettings.getBoolean(BeemApplication.USE_SYSTEM_ACCOUNT_KEY, false);
- mIsAccountConfigured = !TextUtils.isEmpty(login) && (useSystemAccount || !TextUtils.isEmpty((password)));
+ mIsAccountConfigured = !TextUtils.isEmpty(login) && (useSystemAccount || !TextUtils.isEmpty(password));
}
}
}
--- a/app/src/main/java/com/beem/project/beem/BeemService.java Thu Jan 07 16:38:16 2016 +0100
+++ b/app/src/main/java/com/beem/project/beem/BeemService.java Fri Jan 08 11:31:18 2016 +0100
@@ -152,7 +152,7 @@
*/
private void initConnectionConfig() {
// TODO add an option for this ?
-// SmackConfiguration.setPacketReplyTimeout(30000);
+ // SmackConfiguration.setPacketReplyTimeout(30000);
ProxyInfo proxyInfo = getProxyConfiguration();
boolean useSystemAccount = mSettings.getBoolean(BeemApplication.USE_SYSTEM_ACCOUNT_KEY, false);
if (useSystemAccount) {
@@ -172,8 +172,8 @@
mConnectionConfiguration = new ConnectionConfiguration(mHost, mPort, mService, proxyInfo);
else
mConnectionConfiguration = new ConnectionConfiguration(mService, proxyInfo);
- PreferenceAuthenticator authenticator = createPreferenceAuthenticator();
- mConnectionConfiguration.setCallbackHandler(authenticator);
+ PreferenceAuthenticator authenticator = createPreferenceAuthenticator();
+ mConnectionConfiguration.setCallbackHandler(authenticator);
}
if (mSettings.getBoolean("settings_key_xmpp_tls_use", false)
@@ -191,13 +191,19 @@
mConnectionConfiguration.setCustomSSLContext(sslContext);
}
- private PreferenceAuthenticator createPreferenceAuthenticator() {
- if (!mSettings.getBoolean(BeemApplication.ACCOUNT_PASSWORD_IS_ENCRYPTED_KEY, false)) {
- return new PreferenceAuthenticator(this);
- }
- String base64Iv = mSettings.getString(BeemApplication.ACCOUNT_PASSWORD_ENCRYPTION_IV_KEY, "");
- return new EncryptedPasswordPreferenceAuthenticator(this, BeemApplication.PASSWORD_ENCRYPTION_KEY_ALIAS, base64Iv);
+ /**
+ * Create the correct preference authenticator (clear or crypted).
+ *
+ * @return the PreferenceAuthenticator
+ */
+ private PreferenceAuthenticator createPreferenceAuthenticator() {
+ if (!mSettings.getBoolean(BeemApplication.ACCOUNT_PASSWORD_IS_ENCRYPTED_KEY, false)) {
+ return new PreferenceAuthenticator(this);
}
+ String base64Iv = mSettings.getString(BeemApplication.ACCOUNT_PASSWORD_ENCRYPTION_IV_KEY, "");
+ return new EncryptedPasswordPreferenceAuthenticator(this,
+ BeemApplication.PASSWORD_ENCRYPTION_KEY_ALIAS, base64Iv);
+ }
/**
* Get the save proxy configuration.
--- a/app/src/main/java/com/beem/project/beem/service/XmppConnectionAdapter.java Thu Jan 07 16:38:16 2016 +0100
+++ b/app/src/main/java/com/beem/project/beem/service/XmppConnectionAdapter.java Fri Jan 08 11:31:18 2016 +0100
@@ -54,7 +54,6 @@
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.support.v4.app.NotificationCompat;
-import android.support.v4.app.NotificationManagerCompat;
import android.util.Log;
import com.beem.project.beem.BeemApplication;
@@ -372,13 +371,13 @@
private void updateNotification(int status, String text) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(mService);
Notification mStatusNotification = builder.setSmallIcon(Status.getIconBarFromStatus(status))
- .setContentText(text)
- .setContentTitle("Beem Status")
- .setDefaults(NotificationCompat.DEFAULT_LIGHTS)
- .setWhen(System.currentTimeMillis())
- .setOngoing(true)
- .setContentIntent(PendingIntent.getActivity(mService, 0, new Intent(mService, ChangeStatus.class), 0))
- .build();
+ .setContentText(text)
+ .setContentTitle("Beem Status")
+ .setDefaults(NotificationCompat.DEFAULT_LIGHTS)
+ .setWhen(System.currentTimeMillis())
+ .setOngoing(true)
+ .setContentIntent(PendingIntent.getActivity(mService, 0, new Intent(mService, ChangeStatus.class), 0))
+ .build();
// bypass the preferences for notification
mService.getNotificationManager().notify(BeemService.NOTIFICATION_STATUS_ID, mStatusNotification);
--- a/app/src/main/java/com/beem/project/beem/service/auth/EncryptedPasswordPreferenceAuthenticator.java Thu Jan 07 16:38:16 2016 +0100
+++ b/app/src/main/java/com/beem/project/beem/service/auth/EncryptedPasswordPreferenceAuthenticator.java Fri Jan 08 11:31:18 2016 +0100
@@ -1,11 +1,39 @@
+/*
+ BEEM is a videoconference application on the Android Platform.
+
+ Copyright (C) 2009-2012 by Frederic-Charles Barthelery,
+ Nikita Kozlov,
+ Vincent Veronis.
+
+ This file is part of BEEM.
+
+ BEEM is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ BEEM is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with BEEM. If not, see <http://www.gnu.org/licenses/>.
+
+ Please send bug reports with examples or suggestions to
+ contact@beem-project.com or http://www.beem-project.com/
+
+*/
package com.beem.project.beem.service.auth;
import android.content.Context;
+
import com.beem.project.beem.utils.EncryptionManager;
+
import org.jivesoftware.smack.util.Base64;
/**
- * Created by darisk on 07/01/16.
+ * An Authenticator which look for credentials stored in preferences and decrypt them.
*/
public class EncryptedPasswordPreferenceAuthenticator extends PreferenceAuthenticator {
private final String encryptionKeyAlias;
@@ -16,6 +44,8 @@
* Create a PreferenceAuthenticator.
*
* @param context the Android context.
+ * @param encryptionKeyAlias the alias of the encryption key in the Android keystore
+ * @param base64Iv the encryption IV encoded in base64
*/
public EncryptedPasswordPreferenceAuthenticator(Context context, String encryptionKeyAlias, String base64Iv) {
super(context);
--- a/app/src/main/java/com/beem/project/beem/service/auth/PreferenceAuthenticator.java Thu Jan 07 16:38:16 2016 +0100
+++ b/app/src/main/java/com/beem/project/beem/service/auth/PreferenceAuthenticator.java Fri Jan 08 11:31:18 2016 +0100
@@ -55,7 +55,7 @@
*/
public PreferenceAuthenticator(final Context context) {
settings = PreferenceManager.getDefaultSharedPreferences(context);
- }
+ }
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
@@ -89,9 +89,14 @@
}
}
- protected String getPassword() {
- String password = settings.getString(BeemApplication.ACCOUNT_PASSWORD_KEY, "");
- return password;
- }
+ /**
+ * Returns the password stored.
+ *
+ * @return the password
+ */
+ protected String getPassword() {
+ String password = settings.getString(BeemApplication.ACCOUNT_PASSWORD_KEY, "");
+ return password;
+ }
}
--- a/app/src/main/java/com/beem/project/beem/ui/wizard/AccountConfigureFragment.java Thu Jan 07 16:38:16 2016 +0100
+++ b/app/src/main/java/com/beem/project/beem/ui/wizard/AccountConfigureFragment.java Fri Jan 08 11:31:18 2016 +0100
@@ -85,8 +85,6 @@
import org.jivesoftware.smack.util.Base64;
import org.jivesoftware.smack.util.StringUtils;
-import static com.beem.project.beem.BeemApplication.PASSWORD_ENCRYPTION_KEY_ALIAS;
-
/**
* Fragment to enter the information required in order to configure a XMPP account.
*
@@ -114,7 +112,7 @@
private String mSelectedAccountType;
private SharedPreferences settings;
private boolean useSystemAccount;
- private EncryptionManager encryptionManager;
+ private EncryptionManager encryptionManager;
private com.beem.project.beem.ui.wizard.AccountConfigureFragment.ConnectionTestTask task;
@@ -133,9 +131,9 @@
Log.d(TAG, "onCreate");
setRetainInstance(true);
- settings = PreferenceManager.getDefaultSharedPreferences(getActivity());
- encryptionManager = new EncryptionManager();
- }
+ settings = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ encryptionManager = new EncryptionManager();
+ }
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@@ -208,17 +206,17 @@
} else if (v == mManualConfigButton) {
onManualConfigurationSelected();
} else if (v == mSelectAccountButton) {
- Intent i = null;
- if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
- i = AccountManager.newChooseAccountIntent(null, null,
- new String[]{GOOGLE_ACCOUNT_TYPE},
- null, null, null, null);
- } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
- i = AccountManager.newChooseAccountIntent(null, null,
- new String[]{GOOGLE_ACCOUNT_TYPE},
- true, null, null, null, null);
- }
- startActivityForResult(i, SELECT_ACCOUNT_CODE);
+ Intent i = null;
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
+ i = AccountManager.newChooseAccountIntent(null, null,
+ new String[]{GOOGLE_ACCOUNT_TYPE},
+ null, null, null, null);
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ i = AccountManager.newChooseAccountIntent(null, null,
+ new String[]{GOOGLE_ACCOUNT_TYPE},
+ true, null, null, null, null);
+ }
+ startActivityForResult(i, SELECT_ACCOUNT_CODE);
}
}
@@ -299,24 +297,24 @@
*
*/
private void saveCredential(String jid, String pass) {
- SharedPreferences.Editor edit = settings.edit();
- String encryptedPass = pass;
- boolean isEncryptedPass = false;
- if (encryptionManager.isEncryptionAvailable()) {
- if (!encryptionManager.hasEncryptionKey(PASSWORD_ENCRYPTION_KEY_ALIAS)) {
- encryptionManager.generateEncryptionKey(PASSWORD_ENCRYPTION_KEY_ALIAS);
- }
- encryptedPass = encryptionManager.encryptString(encryptedPass, PASSWORD_ENCRYPTION_KEY_ALIAS);
- if (encryptedPass != null) {
- String encryptionIV = Base64.encodeBytes(encryptionManager.getLatestEncryptionIv());
- edit.putString(BeemApplication.ACCOUNT_PASSWORD_ENCRYPTION_IV_KEY, encryptionIV);
- isEncryptedPass = true;
- }
- }
+ SharedPreferences.Editor edit = settings.edit();
+ String encryptedPass = pass;
+ boolean isEncryptedPass = false;
+ if (encryptionManager.isEncryptionAvailable()) {
+ if (!encryptionManager.hasEncryptionKey(BeemApplication.PASSWORD_ENCRYPTION_KEY_ALIAS)) {
+ encryptionManager.generateEncryptionKey(BeemApplication.PASSWORD_ENCRYPTION_KEY_ALIAS);
+ }
+ encryptedPass = encryptionManager.encryptString(encryptedPass,
+ BeemApplication.PASSWORD_ENCRYPTION_KEY_ALIAS);
+ if (encryptedPass != null) {
+ String encryptionIV = Base64.encodeBytes(encryptionManager.getLatestEncryptionIv());
+ edit.putString(BeemApplication.ACCOUNT_PASSWORD_ENCRYPTION_IV_KEY, encryptionIV);
+ isEncryptedPass = true;
+ }
+ }
edit.putString(BeemApplication.ACCOUNT_USERNAME_KEY, jid);
edit.putString(BeemApplication.ACCOUNT_PASSWORD_KEY, encryptedPass);
-
- edit.putBoolean(BeemApplication.ACCOUNT_PASSWORD_IS_ENCRYPTED_KEY, isEncryptedPass);
+ edit.putBoolean(BeemApplication.ACCOUNT_PASSWORD_IS_ENCRYPTED_KEY, isEncryptedPass);
edit.putBoolean(BeemApplication.USE_SYSTEM_ACCOUNT_KEY, false);
edit.commit();
}
--- a/app/src/main/java/com/beem/project/beem/utils/EncryptionManager.java Thu Jan 07 16:38:16 2016 +0100
+++ b/app/src/main/java/com/beem/project/beem/utils/EncryptionManager.java Fri Jan 08 11:31:18 2016 +0100
@@ -1,13 +1,35 @@
+/*
+ BEEM is a videoconference application on the Android Platform.
+
+ Copyright (C) 2009-2012 by Frederic-Charles Barthelery,
+ Nikita Kozlov,
+ Vincent Veronis.
+
+ This file is part of BEEM.
+
+ BEEM is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ BEEM is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with BEEM. If not, see <http://www.gnu.org/licenses/>.
+
+ Please send bug reports with examples or suggestions to
+ contact@beem-project.com or http://www.beem-project.com/
+
+*/
package com.beem.project.beem.utils;
-import android.annotation.TargetApi;
-import android.os.Build;
-import android.security.keystore.KeyGenParameterSpec;
-import android.security.keystore.KeyProperties;
+import static com.google.android.apps.iosched.util.LogUtils.LOGD;
+import static com.google.android.apps.iosched.util.LogUtils.LOGW;
+import static com.google.android.apps.iosched.util.LogUtils.makeLogTag;
-import com.google.android.apps.iosched.util.LogUtils;
-
-import org.jivesoftware.smack.util.Base64;
import java.io.IOException;
import java.security.GeneralSecurityException;
@@ -24,12 +46,19 @@
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
-import static com.google.android.apps.iosched.util.LogUtils.LOGD;
-import static com.google.android.apps.iosched.util.LogUtils.LOGW;
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import org.jivesoftware.smack.util.Base64;
+
+/**
+ * Allows to encrypt and decrypt some strings using the Android Keystore.
+ */
public class EncryptionManager {
- private static final String TAG = LogUtils.makeLogTag(EncryptionManager.class);
+ private static final String TAG = makeLogTag(EncryptionManager.class);
private static final String ANDROID_KEY_STORE = "AndroidKeyStore";
private static final String CIPHER_TRANSFORMATION = String.format("%s/%s/%s",
KeyProperties.KEY_ALGORITHM_AES, KeyProperties.BLOCK_MODE_CBC,
@@ -40,8 +69,10 @@
private Cipher aesCipher;
private byte[] latestEncryptionIv;
+ /**
+ * Create an EncryptionManager.
+ */
public EncryptionManager() {
-
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
keystore = KeyStore.getInstance(ANDROID_KEY_STORE);
@@ -52,16 +83,28 @@
} else {
isEncryptionAvailable = false;
}
- } catch (NoSuchPaddingException | KeyStoreException | IOException | NoSuchProviderException | NoSuchAlgorithmException | CertificateException e) {
+ } catch (NoSuchPaddingException | KeyStoreException | IOException
+ | NoSuchProviderException | NoSuchAlgorithmException | CertificateException e) {
LOGW(TAG, "Unable to load AndroidKeyStore", e);
isEncryptionAvailable = false;
}
}
+ /**
+ * Test if the device supports encryption.
+ *
+ * @return true if encryption is available, false otherwise
+ */
public boolean isEncryptionAvailable() {
return isEncryptionAvailable;
}
+ /**
+ * Test if there is an encryption key stored with the alias.
+ *
+ * @param alias the alias to test for
+ * @return true if a key is available, false otherwise
+ */
public boolean hasEncryptionKey(String alias) {
if (!isEncryptionAvailable) {
return false;
@@ -74,24 +117,38 @@
}
}
+ /**
+ * Generate a random encryption key and store it in the keystore under alias.
+ *
+ * @param alias the alias use to retrieve the key
+ * @return true if the key was generate, false otherwise
+ */
@TargetApi(Build.VERSION_CODES.M)
public boolean generateEncryptionKey(String alias) {
- if (!isEncryptionAvailable)
- return false;
- KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
- .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
- .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
- .setUserAuthenticationRequired(false)
- .build();
- try {
- keyGenerator.init(spec);
- return keyGenerator.generateKey() != null;
- } catch (InvalidAlgorithmParameterException e) {
- LOGW(TAG, "Unable to generate key", e);
- return false;
- }
+ if (!isEncryptionAvailable)
+ return false;
+ KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(alias,
+ KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+ .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
+ .setUserAuthenticationRequired(false)
+ .build();
+ try {
+ keyGenerator.init(spec);
+ return keyGenerator.generateKey() != null;
+ } catch (InvalidAlgorithmParameterException e) {
+ LOGW(TAG, "Unable to generate key", e);
+ return false;
+ }
}
+ /**
+ * Encrypt a string with the key stored with keyAlias.
+ *
+ * @param cleartext the clear text to encrypt
+ * @param keyAlias the alias of the key to use
+ * @return the encrypted string
+ */
public String encryptString(String cleartext, String keyAlias) {
if (!isEncryptionAvailable())
return null;
@@ -107,16 +164,29 @@
}
}
+ /**
+ * Get the encryption IV used with the latest encryption operation.
+ *
+ * @return the encryption IV or null if no encryption operation has been done
+ */
public byte[] getLatestEncryptionIv() {
return latestEncryptionIv;
}
- public String decryptString(String password, String keyAlias, byte[] encryptionIv) {
+ /**
+ * Decrypt an encrypted text using the key stored with alias keyAlias and the specified encryption IV.
+ *
+ * @param encryptedText the encrypted text to decrypt
+ * @param keyAlias the alias of the key to use
+ * @param encryptionIv the encryption IV
+ * @return the clear text
+ */
+ public String decryptString(String encryptedText, String keyAlias, byte[] encryptionIv) {
if (!isEncryptionAvailable())
return null;
try {
Key key = keystore.getKey(keyAlias, null);
- byte[] passwordByte = Base64.decode(password);
+ byte[] passwordByte = Base64.decode(encryptedText);
aesCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(encryptionIv));
byte[] clear = aesCipher.doFinal(passwordByte);
return new String(clear);