安全共享偏好android

时间:2015-10-29 20:40:42

标签: android performance encryption android-preferences

在我的应用中,我必须保存用户名,密码,令牌,以便重复使用它们。最初我将这些数据保存在普通的共享首选项中,但是在root设备上,它可以轻松阅读所有首选项,我认为这不是一件好事。

现在我尝试使用SecurePreferences库(this),但如果我以这种方式初始化此首选项:

SharedPreferences prefs = new SecurePreferences(context);     

当我打开一个活动或在一个片段onCreateView时,初始化通常需要大约2-3秒(我用TraceView测试它)这会减慢我的活动或片段打开。

有一种方法可以将SecurePreferences放在Singleton中并在我的应用程序中只实例化一次吗? 或者还有另一种保存此数据并将其隐藏到所有外部应用程序的最佳方法?

更新#1:

我找到了这个解决方案。要仅实例化一次SecurePreferences,您应该创建一个以这种方式扩展Application的App类:

public class App extends Application {


private static final String TAG = "secureprefsample";
protected static App instance;
private SecurePreferences mSecurePrefs;
private SecurePreferences mUserPrefs;
public App(){
    super();
    instance = this;
}
public static App get() {
    return instance;
}

/**
 * Single point for the app to get the secure prefs object
 * @return
 */

public SharedPreferences getSharedPreferences() {
    if(mSecurePrefs==null){
        mSecurePrefs = new SecurePreferences(this, "", "my_prefs.xml");
        SecurePreferences.setLoggingEnabled(true);
    }
    return mSecurePrefs;
}


/**
 * This is just an example of how you might want to create your own key with less iterations 1,000 rather than default 10,000. This makes it quicker but less secure.
 * @return
 */

public SharedPreferences getSharedPreferences1000() {
    try {
        AesCbcWithIntegrity.SecretKeys myKey = AesCbcWithIntegrity.generateKeyFromPassword(Build.SERIAL,AesCbcWithIntegrity.generateSalt(),1000);
        SharedPreferences securePrefs1000 = new SecurePreferences(this, myKey, "my_prefs_1000.xml");
        return securePrefs1000;
    } catch (GeneralSecurityException e) {
        Log.e(TAG, "Failed to create custom key for SecurePreferences", e);
    }
    return null;
}


public SharedPreferences getDefaultSharedPreferences() {
    return PreferenceManager.getDefaultSharedPreferences(this);
}

public SecurePreferences getUserPinBasedSharedPreferences(String password){
    if(mUserPrefs==null) {
        mUserPrefs = new SecurePreferences(this, password, "user_prefs.xml");
    }
    return mUserPrefs;
}

public boolean changeUserPrefPassword(String newPassword){
    if(mUserPrefs!=null){
        try {
            mUserPrefs.handlePasswordChange(newPassword, this);
            return true;
        } catch (GeneralSecurityException e) {
            Log.e(TAG, "Error during password change", e);
        }
    }
    return false;
}

}

然后你必须以这种方式获得活动中的SecurePreferences:

SharedPreferences preferences =App.get().getSharedPreferences();

2 个答案:

答案 0 :(得分:1)

您可能想尝试https://prashantsolanki3.github.io/Secure-Pref-Manager/以获得简单安全的共享偏好设置。 您可以使用给定的AES加密或实施自己的加密算法。

添加新偏好的示例代码:

SecurePrefManager.with(this)
            .set("user_name")
            .value("LoremIpsum")
            .go();

答案 1 :(得分:0)

您必须制作自己的安全算法

我有这个班级

public class AESEncryption {
private static final int KEY_SIZE = 128;

private static final String KEY_GENERATOR_ALGORITHM = "AES";

private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";

public static final byte[] iv = {1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8};

private static SecretKey getSecretKey(Context context) throws NoSuchAlgorithmException {
    String secretKeyString = PreferenceUtils.getSharedPreferences(context).getString(PreferenceUtils.SECRET_KEY, null);
    if (secretKeyString != null) {
        byte[] bytes = Base64.decode(secretKeyString, Base64.DEFAULT);
        return new SecretKeySpec(bytes, AESEncryption.KEY_GENERATOR_ALGORITHM);
    } else {
        SecretKey secretKey = newSecretKey();
        secretKeyString = Base64.encodeToString(secretKey.getEncoded(), Base64.DEFAULT);
        PreferenceUtils.getSharedPreferences(context).edit().putString(PreferenceUtils.SECRET_KEY, secretKeyString).commit();

        return secretKey;
    }
}

private static SecretKey newSecretKey() throws NoSuchAlgorithmException {
    KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_GENERATOR_ALGORITHM);
    keyGenerator.init(KEY_SIZE);
    return keyGenerator.generateKey();
}

public static String encrypt(Context context, String data) {
    try {
        SecretKey secretKey = getSecretKey(context);

        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
        byte[] transformedBytes = cipher.doFinal(data.getBytes());

        return Base64.encodeToString(transformedBytes, Base64.DEFAULT);
    } catch(NoSuchAlgorithmException e) {
        return data;
    } catch(NoSuchPaddingException e){
        return data;
    } catch (InvalidKeyException e) {
        return data;
    } catch(IllegalBlockSizeException e) {
        return data;
    } catch(BadPaddingException e) {
        return data;
    } catch(InvalidAlgorithmParameterException e) {
        return data;
    }
}

public static String decrypt(Context context, String data) {
    byte[] bytes = null;
    try {
        bytes = Base64.decode(data, Base64.DEFAULT);
    } catch(IllegalArgumentException e) {
        return data;
    }

    try {
        SecretKey secretKey = getSecretKey(context);
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));

        return new String(cipher.doFinal(bytes));
    } catch(NoSuchAlgorithmException e){
        return data;
    } catch(NoSuchPaddingException e) {
        return data;
    } catch(IllegalBlockSizeException e) {
        return data;
    } catch(BadPaddingException e) {
        return data;
    } catch(InvalidKeyException e) {
        return data;
    } catch(InvalidAlgorithmParameterException e) {
        return data;
    }
}

}

然后在我们保存或从共享偏好中获取数据之后,我们只需使用下面的内容 //获取数据

 public static String getUser(Context context) {
    String encryptedUser = getSharedPreferences(context).getString(USERNAME, null);
    return encryptedUser != null ? AESEncryption.decrypt(context, encryptedUser) : null;
}

//保存数据

public static void setLoginUser(Context context, String user, String password, String nickname) {
    String encryptedUser = AESEncryption.encrypt(context, user);
    String encryptedPassword = AESEncryption.encrypt(context, password);
    getSharedPreferences(context).edit().putString(USERNAME, encryptedUser).putString(PASSWORD, encryptedPassword)
            .putString(NICKNAME, nickname).commit();
}

你可以改变你自己的关键或逻辑敌人。

谢谢