android preference内容加密,Android SharePreference 加密存储及 AndroidKeyStore密钥存储

Android SharePreference 加密存储及 AndroidKeyStore密钥存储

前言

最近由于项目中对数据存储特别是SharePreference部分数据存储这块有所需求,在查询了少量资料后对这部分内容做了少量封装。框架主要实现了两方面的需求,一是密钥安全存储方面,二就是SharePreference加解密方面的使用。下面会从这两部分进行讲解。

简单粗暴上代码

假如大家不想看废话可以直接点这里GitHub

使用时候可以直接导入:compile 'com.dongdong.animal:Toroise:0.0.2'

密钥篇(AndroidKeyStore)

技术思路

Android从4.0(api 14)开始支持Keystore,开始只支持RSA加密。从6.0(api 23)后引入AES,因此密钥生成思路如下。通过随机获取随机字符串作为AES种子。

通过AndroidKeyStore生成RSA密钥,并通过公钥加密随机字符串进行保存。

使用时获取加密字符串,而后通过AndroidKeyStore进行解密获取原字符串使用。

关键代码

通过别名创立RSA密钥private static KeyPair createKeyPair(String alias) { try { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties .KEY_ALGORITHM_RSA, AndroidKeyStore); Calendar start = Calendar.getInstance(); Calendar end = Calendar.getInstance(); end.add(Calendar.YEAR, 30); AlgorithmParameterSpec spec; spec = new KeyPairGeneratorSpec.Builder(appContext) //使用别名来检索的关键。这是一个关键的关键! .setAlias(alias) // 用于生成自签名证书的主题 X500Principal 接受 RFC 1779/2253的专有名词 .setSubject(new X500Principal("CN=" + alias)) //用于自签名证书的序列号生成的一对。 .setSerialNumber(BigInteger.TEN) // 签名在有效日期范围内 .setStartDate(start.getTime()) .setEndDate(end.getTime()) .build(); keyPairGenerator.initialize(spec); return keyPairGenerator.generateKeyPair(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchProviderException e) { e.printStackTrace(); } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); } return null; }

加密随机种子/** * 进行RSA加密 * @param plainText 被加密数据 * @param key 公钥值 * @return * @throws Exception */ private static String encryptRSA(String plainText, PublicKey key) throws Exception { Cipher cipher = Cipher.getInstance(RSA_MODE_OAEP); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] encryptedByte = cipher.doFinal(plainText.getBytes("UTF-8")); return Base64.encodeToString(encryptedByte, Base64.NO_WRAP); }

解密复原/** * * @param alias Rsa别名 * @param enseed 加密的种子 * @return 解密数据 */ private static String deSeed(String alias, String enseed) { KeyStore.PrivateKeyEntry privateKeyEntry = null; try { Cipher cipher = Cipher.getInstance(RSA_MODE_OAEP); privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore .getEntry(alias, null); PrivateKey privateKey = privateKeyEntry.getPrivateKey(); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] encryptedByte = Base64.decode(enseed, Base64.NO_WRAP); return new String(cipher.doFinal(encryptedByte)); } catch (KeyStoreException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (UnrecoverableEntryException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } return enseed; } }

存储篇(SafeSpManager)

技术思路

封装SharePreference的存取过程在保存数据时候,key进行md5加密,value进行Aes加密存储。

获取数据时候,通过md5后的key获取存储的value值,而后在通过AES解密后返回相应数据。

关键代码

初始化时候传入sp文件名称及Aes密钥或者者种子。public static void turnInit(Context context, String spname, SecretKey key) { if (context == null) { throw new NullPointerException("The context can not be Null!"); } if (key == null) { throw new NullPointerException("The key can not be Null!"); } if (TextUtils.isEmpty(spname)) { spname = context.getApplicationContext().getPackageName(); } if (instanceMap == null) { instanceMap = new HashMap<>(); SafeSpManager controller = new SafeSpManager(context, spname, key,null); instanceMap.put(spname, controller); } else { if (!instanceMap.containsKey(spname)) { instanceMap.put(spname, new SafeSpManager(context, spname, key,null)); } } }protected SafeSpManager(Context context, String spname, SecretKey key, String strkey) { appContext = context.getApplicationContext(); this.spName = spname; this.aesKey = key; this.aesKeyStr = strkey; if (aesKey == null && TextUtils.isEmpty(aesKeyStr)) { throw new RuntimeException("Key error, initialization failed"); } if (aesKey == null && !TextUtils.isEmpty(aesKeyStr)) { try { this.aesKey = AESUtil.getRawKey(aesKeyStr.getBytes()); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("Key error, initialization failed"); } } String key_md5 = getShardPreferences().getString(KEY_AES_MD5, ""); if (!TextUtils.isEmpty(key_md5)) { if (!key_md5.equals(MD5Util.bytes2Md5(aesKey.getEncoded()))) { throw new RuntimeException("Key error, initialization failed"); } } else { if (isOldData()) { upOldData(); } else { //存的只是key的MD5值 用于识别能否是同一个Key mSetSp.edit().putString(KEY_AES_MD5, MD5Util.bytes2Md5(aesKey.getEncoded())).commit(); } } }

初始化后根据spname获取对象进行就可存取操作public static SafeSpManager getInstance(String spName) { if (instanceMap == null) { return null; } else { if (TextUtils.isEmpty(spName)) { spName = appContext.getPackageName(); } if (instanceMap.containsKey(spName)) { return instanceMap.get(spName); } else { return null; } } }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值