如何保护Android共享首选项?

SharedPreferences存储在Android应用程序中的常见位置是:

 /data/data/<package name>/shared_prefs/<filename.xml> 

具有root权限的用户可以导航到这个位置并且可以改变它的值。保护它的需求是非常重要的。

有多less种方法可以encryption整个shared_pref's xml文件?

我们都知道我们可以在shared_pref's xml文件中encryption和保存数据,但这不仅是100%安全的,所以需要用一个密钥来encryption整个文件。 需要帮助知道各种方式来encryption整个xml文件。 这是一个通用的问题,在这里讨论的各种encryption方法可以帮助所有开发者保护应用程序。

你应该注意到Android的共享偏好是基于XML键值的。 你不能改变这个事实(因为它会破坏它的parsing器),至多你可以encryption键和值,所以root用户可以阅读,但是不会有丝毫的想法。

要做到这一点,你可以使用这样一个简单的encryption

 public static String encrypt(String input) { // This is base64 encoding, which is not an encryption return Base64.encodeToString(input.getBytes(), Base64.DEFAULT); } public static String decrypt(String input) { return new String(Base64.decode(input, Base64.DEFAULT)); } 

这是你如何使用这个

 // Write SharedPreferences preferences = getSharedPreferences("some_prefs_name", MODE_PRIVATE); SharedPreferences.Editor editor = preferences.edit(); editor.putString(encrypt("password"), encrypt("dummypass")); editor.apply(); // Or commit if targeting old devices // Read SharedPreferences preferences = getSharedPreferences("some_prefs_name", MODE_PRIVATE); String passEncrypted = preferences.getString(encrypt("password"), encrypt("default")); String pass = decrypt(passEncrypted); 

你应该知道, SharedPreferences从来没有build立起来是安全的,这只是一个简单的方法来保存数据。

你也应该知道,我使用的encryption不是最安全的,但很简单。

有几个库提供更好的encryption,就像这些

但是他们都认为文件的格式仍然是XML,而且是基于键值的。 你不能改变这个事实。 见下文。

 cat /data/data/your.package.application/shared_prefs/prefs-test.xml <?xml version='1.0' encoding='utf-8' standalone='yes' ?> <map> <string name="JopRH053b7Ogw17Yxmh7Og==">0AB7Y28XEvbQcnXpEZ4j9PtqzFLtm2V3KBXjTO1V704=</string> </map> The key is "hemmelighet" and the value is "dette er en hemmelighet". 

如果安全性超出了SharedPreferences仍然是基于键值和XML格式的事实,则需要完全避免它。

 public class NodeCrypto { private String iv = "fedcba9876543210";//Dummy iv (CHANGE IT!) private IvParameterSpec ivspec; private SecretKeySpec keyspec; private Cipher cipher; private String SecretKey = "0123456789abcdef";//Dummy secretKey (CHANGE IT!) public void doKey(String key) { ivspec = new IvParameterSpec(iv.getBytes()); key = padRight(key,16); Log.d("hi",key); keyspec = new SecretKeySpec(key.getBytes(), "AES"); try { cipher = Cipher.getInstance("AES/CBC/NoPadding"); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchPaddingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public byte[] encrypt(String text,String key) throws Exception { if(text == null || text.length() == 0) throw new Exception("Empty string"); doKey(key); byte[] encrypted = null; try { cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec); encrypted = cipher.doFinal(padString(text).getBytes()); } catch (Exception e) { throw new Exception("[encrypt] " + e.getMessage()); } return encrypted; } public byte[] decrypt(String code,String key) throws Exception { if(code == null || code.length() == 0) throw new Exception("Empty string"); byte[] decrypted = null; doKey(key); try { cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec); decrypted = cipher.doFinal(hexToBytes(code)); } catch (Exception e) { throw new Exception("[decrypt] " + e.getMessage()); } return decrypted; } public static String bytesToHex(byte[] data) { if (data==null) { return null; } int len = data.length; String str = ""; for (int i=0; i<len; i++) { if ((data[i]&0xFF)<16) str = str + "0" + java.lang.Integer.toHexString(data[i]&0xFF); else str = str + java.lang.Integer.toHexString(data[i]&0xFF); } return str; } public static byte[] hexToBytes(String str) { if (str==null) { return null; } else if (str.length() < 2) { return null; } else { int len = str.length() / 2; byte[] buffer = new byte[len]; for (int i=0; i<len; i++) { buffer[i] = (byte) Integer.parseInt(str.substring(i*2,i*2+2),16); } return buffer; } } private static String padString(String source) { char paddingChar = ' '; int size = 16; int x = source.length() % size; int padLength = size - x; for (int i = 0; i < padLength; i++) { source += paddingChar; } return source; } public static String padRight(String s, int n) { return String.format("%1$-" + n + "s", s); } } ----------------------------------------------- from your activity or class call encrypt or decrypt method before saving or retriving from SharedPreference