· 4 years ago · Jun 18, 2021, 02:34 PM
1/*
2 * (c) L-Tech LLC, 2021
3 */
4
5package com.ltech.iti.utils.securemanager.impl
6
7import android.content.Context
8import android.security.keystore.KeyGenParameterSpec
9import android.security.keystore.KeyProperties
10import android.util.Base64
11import com.ltech.iti.BuildConfig
12import com.ltech.iti.utils.securemanager.interfaces.SecureManager
13import java.lang.NullPointerException
14import java.math.BigInteger
15import java.nio.charset.Charset
16import java.security.KeyPair
17import java.security.KeyPairGenerator
18import java.security.KeyStore
19import java.security.cert.Certificate
20import java.util.*
21import javax.crypto.Cipher
22import javax.crypto.KeyGenerator
23import javax.security.auth.x500.X500Principal
24
25class SecureManagerImpl(
26 context: Context
27) : SecureManager {
28
29 private lateinit var password: String
30 private lateinit var subscriber: SecureManager.Subscriber
31
32 private val sharedPreferences = context.getSharedPreferences(
33 BuildConfig.APPLICATION_ID,
34 Context.MODE_PRIVATE
35 )
36
37 private val androidKeyStore = KeyStore.getInstance("AndroidKeyStore")
38
39
40 init {
41 androidKeyStore.load(null)
42 }
43
44
45 override fun setPassword(password: String) {
46 this.password = password
47 }
48
49
50
51 override fun getX509KeyPair(): KeyPair? = SecureManager.handleError {
52 val alias = SecureManager.X509_CERTIFICATE_KEYSTORE_ALIAS
53
54 if (!androidKeyStore.containsAlias(alias)) {
55 throw NullPointerException()
56 }
57
58 val privateKeyEntry = androidKeyStore.getEntry(alias, null) as KeyStore.PrivateKeyEntry
59 val privateKey = privateKeyEntry.privateKey
60 val publicKey = privateKeyEntry.certificate.publicKey
61
62 KeyPair(publicKey, privateKey)
63 }
64
65 override fun getX509Certificate(): Certificate? = SecureManager.handleError {
66 val alias = SecureManager.X509_CERTIFICATE_KEYSTORE_ALIAS
67
68 if (!androidKeyStore.containsAlias(alias)) {
69 throw NullPointerException()
70 }
71
72 val privateKeyEntry = androidKeyStore.getEntry(alias, null) as KeyStore.PrivateKeyEntry
73 privateKeyEntry.certificate
74 }
75
76 override fun setX509Certificate(): KeyPair? = SecureManager.handleError {
77 val alias = SecureManager.X509_CERTIFICATE_KEYSTORE_ALIAS
78
79 val notBefore = Calendar.getInstance()
80 val notAfter = Calendar.getInstance()
81
82 notBefore.add(Calendar.MINUTE, -10)
83 notAfter.add(Calendar.YEAR, 1)
84
85 val certificateSerialNumber = BigInteger(System.currentTimeMillis().toString())
86 val x500SubjectPrincipal = X500Principal("CN=${BuildConfig.APPLICATION_ID}")
87 val keyPairGenerator = KeyPairGenerator
88 .getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore")
89 val keyGenerationParameterSpec = KeyGenParameterSpec
90 .Builder(alias,KeyProperties.PURPOSE_DECRYPT or KeyProperties.PURPOSE_ENCRYPT)
91 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
92 .setKeySize(512)
93 .setKeyValidityStart(notBefore.time)
94 .setKeyValidityEnd(notAfter.time)
95 .setCertificateSubject(x500SubjectPrincipal)
96 .setCertificateSerialNumber(certificateSerialNumber)
97 .build()
98
99 keyPairGenerator.initialize(keyGenerationParameterSpec)
100 keyPairGenerator.generateKeyPair()
101 }
102
103 override fun isX509keyPairAvailable(): Boolean? = SecureManager.handleError {
104 val alias = SecureManager.X509_CERTIFICATE_KEYSTORE_ALIAS
105 androidKeyStore.containsAlias(alias)
106 }
107
108
109
110 override fun getMasterToken(): ByteArray? = SecureManager.handleError {
111 val key = SecureManager.MASTER_TOKEN_SHARED_PREFERENCES_KEY
112
113 sharedPreferences.getString(key, null)?.let { base64 ->
114 Base64.decode(base64, Base64.NO_WRAP)
115 } ?: throw NullPointerException()
116 }
117
118 override fun setMasterToken(masterToken: String) = SecureManager.handleError {
119 val key = SecureManager.MASTER_TOKEN_SHARED_PREFERENCES_KEY
120 val bytes = masterToken.toByteArray(Charset.defaultCharset())
121 val base64 = Base64.encodeToString(bytes, Base64.NO_WRAP)
122
123 sharedPreferences
124 .edit()
125 .putString(key, base64)
126 .apply()
127 }
128
129
130
131 override fun getMasterTokenId(): String? = SecureManager.handleError {
132 val key = SecureManager.MASTER_TOKEN_ID_SHARED_PREFERENCES_KEY
133 sharedPreferences.getString(key, null) ?: throw NullPointerException()
134 }
135
136 override fun setMasterTokenId(masterTokenId: String): Unit? = SecureManager.handleError {
137 val key = SecureManager.MASTER_TOKEN_ID_SHARED_PREFERENCES_KEY
138
139 sharedPreferences
140 .edit()
141 .putString(key, masterTokenId)
142 .apply()
143 }
144
145
146 override fun setBiometricEnabled(isEnabled: Boolean) = SecureManager.handleError {
147 val key = SecureManager.BIOMETRIC_ENABLED_FLAG_SHARED_PREFERENCES_KEY
148
149 sharedPreferences.edit()
150 .putBoolean(key, isEnabled)
151 .apply()
152 }
153
154 override fun getBiometricEnabled(): Boolean? = SecureManager.handleError {
155 val key = SecureManager.BIOMETRIC_ENABLED_FLAG_SHARED_PREFERENCES_KEY
156
157 sharedPreferences.getBoolean(key, false)
158 }
159
160
161
162 override fun getSubscriber(): SecureManager.Subscriber? = SecureManager.handleError { subscriber }
163
164 override fun setSubscriber(subscriber: SecureManager.Subscriber) = SecureManager.handleError {
165 this.subscriber = subscriber
166 }
167
168
169
170 override fun installBiometric(): Unit? = SecureManager.handleError {
171 val alias = SecureManager.BIOMETRIC_ENCRYPTED_PASSWORD_KEYSTORE_ALIAS
172
173 val keyGenerationParameterSpec = KeyGenParameterSpec
174 .Builder(alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
175 .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
176 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
177 .setUserAuthenticationRequired(true)
178 .setInvalidatedByBiometricEnrollment(true)
179 .build()
180 val keyGenerator = KeyGenerator.getInstance(
181 KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"
182 )
183
184 keyGenerator.init(keyGenerationParameterSpec)
185
186 val secretKey = keyGenerator.generateKey()
187 val certificates = arrayOf(getX509Certificate()!!)
188
189 androidKeyStore.setKeyEntry(alias, secretKey.encoded, certificates)
190
191 val transformations = arrayListOf(
192 KeyProperties.KEY_ALGORITHM_AES,
193 KeyProperties.BLOCK_MODE_CBC,
194 KeyProperties.ENCRYPTION_PADDING_PKCS7
195 ).joinToString("/")
196 val cipher = Cipher.getInstance(transformations)
197 val biometricPrompt =
198
199 cipher.init(Cipher.ENCRYPT_MODE, secretKey)
200
201 }
202
203}