@@ -2,7 +2,7 @@ package at.favre.lib.armadillo.datastore
22
33import android.content.Context
44import android.os.Build
5- import androidx.datastore.Serializer
5+ import androidx.datastore.core. Serializer
66import at.favre.lib.armadillo.*
77import at.favre.lib.armadillo.Armadillo.CONTENT_KEY_OUT_BYTE_LENGTH
88import at.favre.lib.armadillo.BuildConfig
@@ -12,116 +12,119 @@ import java.security.Provider
1212import java.security.SecureRandom
1313
1414class ArmadilloSerializer <T >(
15- context : Context ,
16- private val protocol : ProtobufProtocol <T >,
17- password : CharArray? = null ,
18- fingerprintData : List <String > = emptyList(),
19- secureRandom : SecureRandom = SecureRandom (),
20- additionalDecryptionConfigs : List <EncryptionProtocolConfig > = listOf(),
21- enabledKitkatSupport : Boolean = false ,
22- provider : Provider ? = null ,
23- preferencesSalt : ByteArray = BuildConfig .PREF_SALT
15+ context : Context ,
16+ private val protocol : ProtobufProtocol <T >,
17+ password : CharArray? = null ,
18+ fingerprintData : List <String > = emptyList(),
19+ secureRandom : SecureRandom = SecureRandom (),
20+ additionalDecryptionConfigs : List <EncryptionProtocolConfig > = listOf(),
21+ enabledKitkatSupport : Boolean = false ,
22+ provider : Provider ? = null ,
23+ preferencesSalt : ByteArray = BuildConfig .PREF_SALT
2424) : Serializer<T> {
2525
26- private val serializerPassword: ByteArrayRuntimeObfuscator ?
27- private val encryptionProtocol: EncryptionProtocol
28- private val fingerprint: EncryptionFingerprint = EncryptionFingerprintFactory .create(
29- context,
30- buildString { fingerprintData.forEach(::append) }
31- )
32- private val defaultConfig = EncryptionProtocolConfig .newDefaultConfig()
33- private val kitKatConfig by lazy {
34- @Suppress(" DEPRECATION" )
35- EncryptionProtocolConfig .newBuilder(defaultConfig.build())
36- .authenticatedEncryption(AesCbcEncryption (secureRandom, provider))
37- .protocolVersion(Armadillo .KITKAT_PROTOCOL_VERSION )
38- .build()
39- }
40-
41- init {
42-
43- val stringMessageDigest = HkdfMessageDigest (
44- BuildConfig .PREF_SALT ,
45- CONTENT_KEY_OUT_BYTE_LENGTH
26+ private val serializerPassword: ByteArrayRuntimeObfuscator ?
27+ private val encryptionProtocol: EncryptionProtocol
28+ private val fingerprint: EncryptionFingerprint = EncryptionFingerprintFactory .create(
29+ context,
30+ buildString { fingerprintData.forEach(::append) }
4631 )
32+ private val defaultConfig = EncryptionProtocolConfig .newDefaultConfig()
33+ private val kitKatConfig by lazy {
34+ @Suppress(" DEPRECATION" )
35+ EncryptionProtocolConfig .newBuilder(defaultConfig.build())
36+ .authenticatedEncryption(AesCbcEncryption (secureRandom, provider))
37+ .protocolVersion(Armadillo .KITKAT_PROTOCOL_VERSION )
38+ .build()
39+ }
40+
41+ init {
42+
43+ val stringMessageDigest = HkdfMessageDigest (
44+ BuildConfig .PREF_SALT ,
45+ CONTENT_KEY_OUT_BYTE_LENGTH
46+ )
47+
48+ val config =
49+ if (Build .VERSION .SDK_INT < Build .VERSION_CODES .LOLLIPOP ) {
50+ kitKatConfig
51+ } else {
52+ EncryptionProtocolConfig
53+ .newBuilder(defaultConfig.build())
54+ .authenticatedEncryption(AesGcmEncryption (secureRandom, provider))
55+ .build()
56+ }
57+ checkKitKatSupport(config.authenticatedEncryption)
58+
59+ val factory = DefaultEncryptionProtocol .Factory (
60+ config,
61+ fingerprint,
62+ stringMessageDigest,
63+ secureRandom,
64+ false , // enableDerivedPasswordCache,
65+ if (enabledKitkatSupport) {
66+ additionalDecryptionConfigs + kitKatConfig
67+ } else {
68+ additionalDecryptionConfigs
69+ },
70+ )
71+
72+ encryptionProtocol = factory.create(preferencesSalt)
73+ serializerPassword = password?.let (factory::obfuscatePassword)
74+ }
4775
48- val config =
49- if (Build .VERSION .SDK_INT < Build .VERSION_CODES .LOLLIPOP ) {
50- kitKatConfig
51- } else {
52- EncryptionProtocolConfig
53- .newBuilder(defaultConfig.build())
54- .authenticatedEncryption(AesGcmEncryption (secureRandom, provider))
55- .build()
76+
77+ private fun checkKitKatSupport (authenticatedEncryption : AuthenticatedEncryption ) {
78+ if (Build .VERSION .SDK_INT == Build .VERSION_CODES .KITKAT && authenticatedEncryption.javaClass == AesGcmEncryption ::class .java) {
79+ throw UnsupportedOperationException (" aes gcm is not supported with KitKat, add support " +
80+ " manually with Armadillo.Builder.enableKitKatSupport()" )
5681 }
57- checkKitKatSupport(config.authenticatedEncryption)
58-
59- val factory = DefaultEncryptionProtocol .Factory (
60- config,
61- fingerprint,
62- stringMessageDigest,
63- secureRandom,
64- false , // enableDerivedPasswordCache,
65- if (enabledKitkatSupport) {
66- additionalDecryptionConfigs + kitKatConfig
67- } else {
68- additionalDecryptionConfigs
69- },
70- )
82+ }
7183
72- encryptionProtocol = factory.create(preferencesSalt)
73- serializerPassword = password?. let (factory::obfuscatePassword)
74- }
84+ companion object {
85+ private const val CRYPTO_KEY = " ArmadilloStoreSerializer "
86+ }
7587
7688
77- private fun checkKitKatSupport (authenticatedEncryption : AuthenticatedEncryption ) {
78- if (Build .VERSION .SDK_INT == Build .VERSION_CODES .KITKAT && authenticatedEncryption.javaClass == AesGcmEncryption ::class .java) {
79- throw UnsupportedOperationException (" aes gcm is not supported with KitKat, add support " +
80- " manually with Armadillo.Builder.enableKitKatSupport()" )
89+ private fun encrypt (content : ByteArray ): ByteArray = with (encryptionProtocol) {
90+ encrypt(
91+ deriveContentKey(CRYPTO_KEY ),
92+ deobfuscatePassword(serializerPassword),
93+ content
94+ )
8195 }
82- }
8396
84- companion object {
85- private const val CRYPTO_KEY = " ArmadilloStoreSerializer"
86- }
8797
98+ private fun decrypt (encrypted : ByteArray ): ByteArray? =
99+ if (encrypted.isEmpty()) {
100+ null
101+ } else {
102+ encryptionProtocol
103+ .decrypt(
104+ encryptionProtocol.deriveContentKey(CRYPTO_KEY ),
105+ encryptionProtocol.deobfuscatePassword(serializerPassword),
106+ encrypted
107+ )
108+ }
109+
110+ override fun readFrom (input : InputStream ): T =
111+ input
112+ .readBytes()
113+ .let (::decrypt)
114+ .let {
115+ val bytes = it ? : byteArrayOf()
116+ if (bytes.isEmpty()) defaultValue
117+ else protocol.decode(bytes)
118+ }
119+
120+
121+ override fun writeTo (t : T , output : OutputStream ) {
122+ protocol
123+ .encode(t)
124+ .let (::encrypt)
125+ .also (output::write)
126+ }
88127
89- private fun encrypt (content : ByteArray ): ByteArray = with (encryptionProtocol) {
90- encrypt(
91- deriveContentKey(CRYPTO_KEY ),
92- deobfuscatePassword(serializerPassword),
93- content
94- )
95- }
96-
97-
98- private fun decrypt (encrypted : ByteArray ): ByteArray? =
99- if (encrypted.isEmpty()) {
100- null
101- } else {
102- encryptionProtocol
103- .decrypt(
104- encryptionProtocol.deriveContentKey(CRYPTO_KEY ),
105- encryptionProtocol.deobfuscatePassword(serializerPassword),
106- encrypted
107- )
108- }
109-
110- override fun readFrom (input : InputStream ): T =
111- input
112- .readBytes()
113- .let (::decrypt)
114- .let {
115- val bytes = it ? : byteArrayOf()
116- if (bytes.isEmpty()) protocol.default()
117- else protocol.decode(bytes)
118- }
119-
120-
121- override fun writeTo (t : T , output : OutputStream ) {
122- protocol
123- .encode(t)
124- .let (::encrypt)
125- .also (output::write)
126- }
128+ override val defaultValue: T
129+ get() = protocol.default()
127130}
0 commit comments