이전에 작성된 내용으로 DataStore protobuf Read/Write를 사용하게 되면 저장된 파일을 봤을 때 평문으로 저장되는 타입이 생깁니다.
저장되는 데이터를 직접 확인해보기 위해서 test_data.proto 파일에
string 타입을 추가해보았습니다.
syntax = "proto3";
option java_package = "com.example.sampleapp.core.datastore";
option java_multiple_files = true;
message TestData {
bool isTest = 1;
string test = 2;
}
그리고 string 테스트 값을 넣어보았습니다.
viewModel.updateTestString("hi")
Android Studio Tool의 View > Device Explorer를 선택합니다.
/data/data/App Package(설치한 앱 패키지명)/files/datastore/.pb 파일
해당 경로에 파일을 더블클릭해서 열게되면 데이터를 확인해볼 수 있습니다.
boolean 값은 알아볼 수 없는 값으로 저장되었지만, string type 경우 평문으로 저장된 것을 확인해 볼 수 있습니다.
protoBuf 방식으로 저장하는 부분에서 암호화/복호화를 넣어서 Access Token 같은 값들을 보안 처리를 하고 싶었습니다.
이를 위해 구글 tink 라이브러리를 세팅을 해서 처리하였습니다. (완벽한 방법인지 좀 더 조사가 필요합니다.)
1. libs.version.toml 파일에 암호화/복호화 라이브러리 추가
tink="1.7.0"
crypto-tink-android = { group = "com.google.crypto.tink", name = "tink-android", version.ref = "tink"}
2. tink 라이브러리의 암호화/복호화를 이용한 처리
Crpyo.kt File
interface Crypto {
fun encrypt(text: ByteArray): ByteArray
fun decrypt(encryptedData: ByteArray): ByteArray
}
class CryptoImpl @Inject constructor(
private val aead: Aead
) : Crypto {
override fun encrypt(text: ByteArray): ByteArray {
return aead.encrypt(text, null)
}
override fun decrypt(encryptedData: ByteArray): ByteArray {
return if (encryptedData.isNotEmpty()) {
aead.decrypt(encryptedData, null)
} else {
encryptedData
}
}
}
TestSerializer.kt File
class TestSerializer @Inject constructor(
private val crypto: Crypto
) : Serializer<TestData> {
override val defaultValue: TestData get() = TestData.getDefaultInstance()
override suspend fun readFrom(input: InputStream): TestData {
return try {
TestData.parseFrom(
input
.readBytes()
.let(crypto::decrypt)
)
} catch (e: InvalidProtocolBufferException) {
throw CorruptionException("Cannot read proto.", e)
}
}
override suspend fun writeTo(t: TestData, output: OutputStream) {
output.write(crypto.encrypt(t.toByteArray()))
output.flush()
}
}
DataStoreModule.kt File
@Module
@InstallIn(SingletonComponent::class)
object DataStoreModule {
private const val TEST_DATASTORE_FILE_NAME = "TEST_DATA.pb"
private const val KEYSET_NAME = "__androidx_encrypted_prefs_keyset__"
private const val PREF_FILE_NAME = "androidx_secret_prefs"
private const val MASTER_KEY_URI =
"${AndroidKeystoreKmsClient.PREFIX}androidx_secret_sample_master_key"
@Provides
@Singleton
@Named("test")
fun provideTestDataStore(
@ApplicationContext context: Context,
aead: Aead
): DataStore<TestData> = DataStoreFactory.create(
produceFile = { File(context.filesDir, "datastore/$TEST_DATASTORE_FILE_NAME") },
serializer = TestSerializer(CryptoImpl(aead))
)
@Provides
@Singleton
fun aead(@ApplicationContext context: Context): Aead {
AeadConfig.register()
return AndroidKeysetManager
.Builder()
.withSharedPref(context, KEYSET_NAME, PREF_FILE_NAME)
.withKeyTemplate(KeyTemplates.get("AES256_GCM"))
.withMasterKeyUri(MASTER_KEY_URI)
.build()
.keysetHandle
.getPrimitive(Aead::class.java)
}
}
빌드해서 테스트 해보면
Preference 파일에 keyset 내용이 생성됩니다. (이 부분에 대해서는 추후에 좀 더 자세히 작성을 해보려고 합니다.)
다시 TEST_DATA.pb 파일을 접속해서 보면 암호화 부분이 적용되어 알 수 없는 내용으로 적용되며 파일의 용량 크기가 암호화로 인해서 늘어남을 확인해볼 수 있습니다.
sample : https://github.com/woohyun-jeong/AndroidSampleApp/tree/datastore_test1
Reference
'Android > Module' 카테고리의 다른 글
[Android Multi module] DataStore protobuf 적용 테스트 (0) | 2024.09.13 |
---|---|
[Android Multi module] local.properties 파일로 API Key 관리 (1) | 2024.09.13 |
[Android Multi module] DataStore protobuf 라이브러리 추가 방법 (0) | 2024.09.13 |
[Android Multi module] feature module 생성 방법 (0) | 2024.09.13 |
[Android build-logic] 모듈화 kts 구성 (0) | 2024.09.13 |