Android官方推荐的安全组件:使用Jetpack Security为数据加密

开发者全社区

共 5101字,需浏览 11分钟

 ·

2020-08-06 01:59

作者:fundroid_方卓

链接https://blog.csdn.net/vitaviva/article/details/104828195


 Jetpack Security 是什么? 


Jetpack Security 是 Google I/O 2019 发布的安全组件库。Security构成简单,主要包含EncryptedFileEncryptedSharedPreferences两个类,分别用来对File和SharedPreferences的读写进行加密解密处理。Security要求min SDK version 23。


图片源:Google开发者


  EncryptedFile 封装了Google的加密库tink的逻辑,提供FileInputStream和FileOutputStream,可以更安全的进行流的读写。

    EncryptedSharedPreferences 是SharedPreferences包装类,通过两种方式自动加密键/值:

  • Key加密使用的是确定性的加密算法,使得秘钥可以被加密

  • Value加密使用AES-256 GCM加密,不确定加密


 秘钥管理 


Security库秘钥管理分为两个部分:

  • 秘钥集合(Key set)

    包含一个或多个秘钥来加密文件或SharedPreferences数据,存储在SharedPreferences中。

  • 主密钥(Master Key)

        用来加密所有秘钥集合,存储在Android Keystore系统中


使用Android Keystore的包装类MasterKeys只用两行就可以制作Master Key。

val keyGenParameterSpec = MasterKeys.AES256_GCM_SPECval masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)



 EncryptedSharedPreferences 


1,普通SharedPreferences

val data = getSharedPreferences("Sample", Context.MODE_PRIVATE)
val editor = data.edit()editor.putInt("IntSave"10)editor.apply()
val intSaved = data.getInt("IntSave"1)Log.d("IntSave", intSaved.toString())


key和value都被明文保存在xml中




2,使用EncryptedSharedPreferences

val keyGenParameterSpec = MasterKeys.AES256_GCM_SPECval masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)
val sharedPreferences = EncryptedSharedPreferences      .create(        "Sample",        masterKeyAlias,        context,        EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,        EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM      )
val editor = sharedPreferences.edit()editor.putInt("IntSave"10)editor.apply()
val intSaved = sharedPreferences.getInt("IntSave"1)Log.d("IntSave", intSaved.toString())



key和value被加密保存



3,性能对比

3.1 SharedPreference TestCase

@RunWith(AndroidJUnit4::class)class SharedPreferenceTest {  private lateinit var data: SharedPreferences  private lateinit var editor: SharedPreferences.Editor
  @Before  fun setup() {    // Context of the app under test.    val appContext = InstrumentationRegistry.getInstrumentation().targetContext        data = appContext.getSharedPreferences("Sample", Context.MODE_PRIVATE)    editor = data.edit()}
  @Test  fun sharedPreference() {    for (i in 1..10000) {      editor.putInt("IntSave", i)      editor.apply()
      val intSaved = data.getInt("IntSave", 1)      assertEquals(intSaved, i)    }  }}


3.2 EncryptedSharedPreference TestCase

@RunWith(AndroidJUnit4::class)class EncryptedSharedPreferenceTest {  private lateinit var data: SharedPreferences  private lateinit var editor: SharedPreferences.Editor
  @Before  fun setup() {    val appContext = InstrumentationRegistry.getInstrumentation().targetContext
    val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC    val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)
    data = EncryptedSharedPreferences      .create(        "Sample",        masterKeyAlias,        appContext,        EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,        EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM      )
    editor = data.edit()}
  @Test  fun encryptedSharedPreference() {    for (i in 1..10000) {      editor.putInt("IntSave", i)      editor.apply()
      val intSaved = data.getInt("IntSave"1)      Assert.assertEquals(intSaved, i)    }  }}




使用pixel3的测试结果如上,性能上有10倍以上的劣化,但是作为加密库来说已经不错了。


 EncryptedFile 


Write File

例如向text文件中中写入 ”MY SUPER SECRET INFORMATION“字符串

val fileToWrite = "my_other_sensitive_data.txt"val encryptedFile = EncryptedFile.Builder(    File(context.getFilesDir(), fileToWrite),    context,    masterKeyAlias,    EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB).build()
// Write to a file.try {    val outputStream: FileOutputStream? = encryptedFile.openFileOutput()    outputStream?.apply {        write("MY SUPER SECRET INFORMATION"            .toByteArray(Charset.forName("UTF-8")))        flush()        close()    }catch (ex: IOException) {    // Error occurred opening file for writing.}


Read File

通过EncryptedFile可以输出明文”MY SUPER SECRET INFORMATION“;

仅使用BufferedReader则会输出不可读的密文(�]�}�Wr<������q1Bv����B��|)��j_��>��uBLN#���Y�w���;�̴?�w��M���;�K�M�Ƕ�



val fileToRead = "my_sensitive_data.txt"lateinit var byteStream: ByteArrayOutputStreamval encryptedFile = EncryptedFile.Builder(    File(context.getFilesDir(), fileToRead),    context,    masterKeyAlias,    EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB).build()
try {    encryptedFile.openFileInput().use { fileInputStream ->        try {            val sb = StringBuilder()            val br = BufferedReader(InputStreamReader(fileInputStream) as Reader?)            br.readLine()                .forEach {                    sb.append(it)                }            br.close()            // 输出 MY SUPER SECRET INFORMATION             Log.d("fileContents", sb.toString())        } catch (ex: Exception) {            // Error occurred opening raw file for reading.        } finally {            fileInputStream.close()        }    }catch (ex: IOException) {    // Error occurred opening encrypted file for reading.}
浏览 19
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报