· 4 years ago · Jun 22, 2021, 11:06 AM
1/*
2 * (c) L-Tech LLC, 2021
3 */
4
5package com.ltech.iti.utils.securemanager.impl
6
7import android.content.Context
8import android.provider.Settings
9import android.security.keystore.KeyGenParameterSpec
10import android.security.keystore.KeyProperties
11import android.util.Base64
12import android.util.Log
13import android.util.Xml
14import androidx.biometric.BiometricPrompt
15import androidx.core.content.ContextCompat
16import androidx.fragment.app.Fragment
17import com.ltech.iti.BuildConfig
18import com.ltech.iti.ItiApplication
19import com.ltech.iti.R
20import com.ltech.iti.data.reply.RepoReply
21import com.ltech.iti.utils.securemanager.interfaces.SecureManager
22import kotlinx.coroutines.CoroutineScope
23import kotlinx.coroutines.Dispatchers
24import kotlinx.coroutines.Job
25import kotlinx.coroutines.launch
26import org.spongycastle.crypto.engines.BlowfishEngine
27import org.spongycastle.crypto.modes.CBCBlockCipher
28import org.spongycastle.crypto.paddings.PKCS7Padding
29import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher
30import org.spongycastle.crypto.params.KeyParameter
31import org.spongycastle.crypto.params.ParametersWithIV
32import org.spongycastle.crypto.util.PrivateKeyFactory
33import org.spongycastle.jcajce.provider.symmetric.Blowfish
34import java.lang.NullPointerException
35import java.math.BigInteger
36import java.nio.charset.Charset
37import java.security.*
38import java.security.cert.Certificate
39import java.security.spec.KeySpec
40import java.util.*
41import javax.crypto.Cipher
42import javax.crypto.KeyGenerator
43import javax.crypto.spec.IvParameterSpec
44import javax.crypto.spec.SecretKeySpec
45import javax.security.auth.x500.X500Principal
46
47class SecureManagerImpl(
48 context: Context
49) : SecureManager {
50
51 private lateinit var password: String
52 private lateinit var subscriber: SecureManager.Subscriber
53
54
55 private val userRepository = (context.applicationContext as ItiApplication).userRepository
56
57 private val sharedPreferences = context.getSharedPreferences(
58 BuildConfig.APPLICATION_ID,
59 Context.MODE_PRIVATE
60 )
61
62 private val androidKeyStore = KeyStore.getInstance("AndroidKeyStore")
63
64
65 init {
66 androidKeyStore.load(null)
67 }
68
69
70 override fun setPassword(password: String) {
71 this.password = password
72 }
73
74 @ExperimentalStdlibApi
75 override fun storePassword(password: String): Unit? = SecureManager.handleError {
76 val passwordKey = SecureManager.MD5_PASSWORD_SHARED_PREFERENCES_KEY
77 val secretKeyKey = SecureManager.BASE64_PASSWORD_SECRET_KEY_PREFERENCES_KEY
78 val ivKey = SecureManager.BASE64_PASSWORD_IV_PREFERENCES_KEY
79
80 val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES)
81 val secretKey = keyGenerator.generateKey()
82 val secretKeyBytes = secretKey.encoded
83 val secretKeyBase64 = Base64.encodeToString(secretKeyBytes, Base64.NO_WRAP)
84
85 val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
86 val iv = cipher.iv
87 val ivBase64 = Base64.encodeToString(iv, Base64.NO_WRAP)
88
89 val digest = MessageDigest.getInstance("MD5")
90
91 digest.update(password.toByteArray())
92
93 val md5Bytes = digest.digest()
94
95 cipher.init(Cipher.ENCRYPT_MODE, secretKey)
96
97 val md5EncryptedBytes = cipher.doFinal(md5Bytes)
98 val md5EncryptedBase64 = Base64.encodeToString(md5EncryptedBytes, Base64.NO_WRAP)
99
100 sharedPreferences.edit()
101 .putString(passwordKey, md5EncryptedBase64)
102 .putString(secretKeyKey, secretKeyBase64)
103 .putString(ivKey, ivBase64)
104 .apply()
105 }
106
107 @ExperimentalStdlibApi
108 override fun getPassword(): String? = SecureManager.handleError {
109 val passwordKey = SecureManager.MD5_PASSWORD_SHARED_PREFERENCES_KEY
110 val secretKeyKey = SecureManager.BASE64_PASSWORD_SECRET_KEY_PREFERENCES_KEY
111 val ivKey = SecureManager.BASE64_PASSWORD_IV_PREFERENCES_KEY
112
113 val passwordMd5EncryptedBase64 = sharedPreferences.getString(passwordKey, null)
114 val secretKeyBase64 = sharedPreferences.getString(secretKeyKey, null)
115 val ivBase64 = sharedPreferences.getString(ivKey, null)
116
117 if (passwordMd5EncryptedBase64 != null && secretKeyBase64 != null && ivBase64 != null) {
118 val passwordEncryptedBytes = Base64.decode(passwordMd5EncryptedBase64, Base64.NO_WRAP)
119 val secretKeyBytes = Base64.decode(secretKeyBase64, Base64.NO_WRAP)
120 val ivBytes = Base64.decode(ivBase64, Base64.NO_WRAP)
121
122 val secretKeySpec = SecretKeySpec(secretKeyBytes, KeyProperties.KEY_ALGORITHM_AES)
123 val ivParameterSpec = IvParameterSpec(ivBytes)
124 val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
125
126 cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec)
127 cipher.doFinal(passwordEncryptedBytes).decodeToString()
128 } else {
129 null
130 }
131 }
132
133
134
135 @ExperimentalStdlibApi
136 override fun matchPassword(password: String): Boolean? = SecureManager.handleError {
137 getPassword()?.let { validMd5 ->
138 val messageDigest = MessageDigest.getInstance("MD5")
139
140 messageDigest.update(password.toByteArray())
141
142 val md5 = messageDigest.digest().decodeToString()
143
144 md5 == validMd5
145 } ?: throw NullPointerException()
146 }
147
148
149
150 override fun getX509KeyPair(): KeyPair? = SecureManager.handleError {
151 val alias = SecureManager.X509_CERTIFICATE_KEYSTORE_ALIAS
152
153 if (!androidKeyStore.containsAlias(alias)) {
154 throw NullPointerException()
155 }
156
157 val privateKeyEntry = androidKeyStore.getEntry(alias, null) as KeyStore.PrivateKeyEntry
158 val privateKey = privateKeyEntry.privateKey
159 val publicKey = privateKeyEntry.certificate.publicKey
160
161 KeyPair(publicKey, privateKey)
162 }
163
164 override fun getX509Certificate(): Certificate? = SecureManager.handleError {
165 val alias = SecureManager.X509_CERTIFICATE_KEYSTORE_ALIAS
166
167 if (!androidKeyStore.containsAlias(alias)) {
168 throw NullPointerException()
169 }
170
171 val privateKeyEntry = androidKeyStore.getEntry(alias, null) as KeyStore.PrivateKeyEntry
172 privateKeyEntry.certificate
173 }
174
175 override fun setX509Certificate(): KeyPair? = SecureManager.handleError {
176 val alias = SecureManager.X509_CERTIFICATE_KEYSTORE_ALIAS
177
178 val notBefore = Calendar.getInstance()
179 val notAfter = Calendar.getInstance()
180
181 notBefore.add(Calendar.MINUTE, -10)
182 notAfter.add(Calendar.YEAR, 1)
183
184 val certificateSerialNumber = BigInteger(System.currentTimeMillis().toString())
185 val x500SubjectPrincipal = X500Principal("CN=${BuildConfig.APPLICATION_ID}")
186 val keyPairGenerator = KeyPairGenerator
187 .getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore")
188 val keyGenerationParameterSpec = KeyGenParameterSpec
189 .Builder(
190 alias,
191 KeyProperties.PURPOSE_DECRYPT or KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
192 )
193 .setRandomizedEncryptionRequired(false)
194 .setDigests(
195 KeyProperties.DIGEST_SHA1,
196 KeyProperties.DIGEST_MD5,
197 KeyProperties.DIGEST_NONE,
198 KeyProperties.DIGEST_SHA224,
199 KeyProperties.DIGEST_SHA256,
200 KeyProperties.DIGEST_SHA384, KeyProperties.DIGEST_SHA512
201 )
202 .setEncryptionPaddings(
203 KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,
204 KeyProperties.ENCRYPTION_PADDING_NONE,
205 KeyProperties.ENCRYPTION_PADDING_RSA_OAEP
206 )
207 .setKeySize(512)
208 .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
209 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
210 .setKeyValidityStart(notBefore.time)
211 .setKeyValidityEnd(notAfter.time)
212 .setCertificateSubject(x500SubjectPrincipal)
213 .setCertificateSerialNumber(certificateSerialNumber)
214 .build()
215
216 keyPairGenerator.initialize(keyGenerationParameterSpec)
217 keyPairGenerator.generateKeyPair()
218 }
219
220 override fun isX509keyPairAvailable(): Boolean? = SecureManager.handleError {
221 val alias = SecureManager.X509_CERTIFICATE_KEYSTORE_ALIAS
222 androidKeyStore.containsAlias(alias)
223 }
224
225
226
227 override fun getMasterToken(): ByteArray? = SecureManager.handleError {
228 val key = SecureManager.MASTER_TOKEN_SHARED_PREFERENCES_KEY
229
230 sharedPreferences.getString(key, null)?.let { base64 ->
231 Base64.decode(base64, Base64.NO_WRAP)
232 } ?: throw NullPointerException()
233 }
234
235 override fun setMasterToken(masterToken: String) = SecureManager.handleError {
236 val key = SecureManager.MASTER_TOKEN_SHARED_PREFERENCES_KEY
237 val bytes = masterToken.toByteArray(Charset.defaultCharset())
238 val base64 = Base64.encodeToString(bytes, Base64.NO_WRAP)
239
240 sharedPreferences
241 .edit()
242 .putString(key, base64)
243 .apply()
244 }
245
246
247
248 override fun getMasterTokenId(): String? = SecureManager.handleError {
249 val key = SecureManager.MASTER_TOKEN_ID_SHARED_PREFERENCES_KEY
250 sharedPreferences.getString(key, null) ?: throw NullPointerException()
251 }
252
253 override fun setMasterTokenId(masterTokenId: String): Unit? = SecureManager.handleError {
254 val key = SecureManager.MASTER_TOKEN_ID_SHARED_PREFERENCES_KEY
255
256 sharedPreferences
257 .edit()
258 .putString(key, masterTokenId)
259 .apply()
260 }
261
262
263 override fun setBiometricEnabled(isEnabled: Boolean) = SecureManager.handleError {
264 val key = SecureManager.BIOMETRIC_ENABLED_FLAG_SHARED_PREFERENCES_KEY
265
266 sharedPreferences.edit()
267 .putBoolean(key, isEnabled)
268 .apply()
269 }
270
271 override fun getBiometricEnabled(): Boolean? = SecureManager.handleError {
272 val key = SecureManager.BIOMETRIC_ENABLED_FLAG_SHARED_PREFERENCES_KEY
273
274 sharedPreferences.getBoolean(key, false)
275 }
276
277
278
279 override fun getSubscriber(): SecureManager.Subscriber? = SecureManager.handleError { subscriber }
280
281 override fun setSubscriber(subscriber: SecureManager.Subscriber) = SecureManager.handleError {
282 this.subscriber = subscriber
283 }
284
285
286
287 override fun installBiometric(
288 fragment: Fragment,
289 onSuccess: () -> Unit,
290 onError: () -> Unit
291 ): Unit? = SecureManager.handleError {
292 val alias = SecureManager.BIOMETRIC_SECRET_KEY_KEYSTORE_ALIAS
293 val passwordKey = SecureManager.BIOMETRIC_ENCRYPTED_PASSWORD_SHARED_PREFERENCES_KEY
294 val ivKey = SecureManager.BIOMETRIC_PASSWORD_IV_SHARED_PREFERENCES_KEY
295
296 val keyGenerationParameterSpec = KeyGenParameterSpec
297 .Builder(alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
298 .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
299 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
300 .setUserAuthenticationRequired(true)
301 .setInvalidatedByBiometricEnrollment(true)
302 .build()
303 val keyGenerator = KeyGenerator.getInstance(
304 KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"
305 )
306
307 keyGenerator.init(keyGenerationParameterSpec)
308
309 val secretKey = keyGenerator.generateKey()
310 val certificates = arrayOf(getX509Certificate()!!)
311
312 androidKeyStore.setKeyEntry(alias, secretKey.encoded, certificates)
313
314 val transformations = arrayListOf(
315 KeyProperties.KEY_ALGORITHM_AES,
316 KeyProperties.BLOCK_MODE_CBC,
317 KeyProperties.ENCRYPTION_PADDING_PKCS7
318 ).joinToString("/")
319
320 val executor = ContextCompat.getMainExecutor(fragment.requireContext())
321 val cipher = Cipher.getInstance(transformations)
322 lateinit var biometricPrompt: BiometricPrompt
323
324 val promptInfo = BiometricPrompt.PromptInfo.Builder()
325 .setTitle(fragment.getString(R.string.biometric_install_title))
326 .setSubtitle(fragment.getString(R.string.biometric_install_subtitle))
327 .setNegativeButtonText(fragment.getString(R.string.biometric_install_negative))
328 .build()
329
330 biometricPrompt = BiometricPrompt(fragment, executor, object:BiometricPrompt.AuthenticationCallback() {
331 override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
332 super.onAuthenticationSucceeded(result)
333
334 val encryptedPasswordBytes = result.cryptoObject?.cipher?.doFinal(password.toByteArray())
335 val ivBytes = result.cryptoObject?.cipher?.iv
336
337 val encryptedPasswordBase64 = Base64.encodeToString(encryptedPasswordBytes, Base64.NO_WRAP)
338 val ivBase64 = Base64.encodeToString(ivBytes, Base64.NO_WRAP)
339
340 sharedPreferences.edit()
341 .putString(passwordKey, encryptedPasswordBase64)
342 .putString(ivKey, ivBase64)
343 .apply()
344
345 onSuccess()
346 }
347
348 override fun onAuthenticationFailed() {
349 super.onAuthenticationFailed()
350 biometricPrompt.authenticate(promptInfo, BiometricPrompt.CryptoObject(cipher))
351 }
352
353 override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
354 super.onAuthenticationError(errorCode, errString)
355
356 val errMessage = "Error #$errorCode: $errString"
357 Log.e(SecureManager.TAG, errMessage)
358
359 onError()
360 }
361 })
362
363 cipher.init(Cipher.ENCRYPT_MODE, secretKey)
364 biometricPrompt.authenticate(promptInfo, BiometricPrompt.CryptoObject(cipher))
365 }
366
367 @ExperimentalStdlibApi
368 override fun loadPasswordByBiometric(
369 fragment: Fragment,
370 onSuccess: (password: String) -> Unit,
371 onError: () -> Unit
372 ): Unit? = SecureManager.handleError {
373 val alias = SecureManager.BIOMETRIC_SECRET_KEY_KEYSTORE_ALIAS
374 val passwordKey = SecureManager.BIOMETRIC_ENCRYPTED_PASSWORD_SHARED_PREFERENCES_KEY
375 val ivKey = SecureManager.BIOMETRIC_PASSWORD_IV_SHARED_PREFERENCES_KEY
376
377 androidKeyStore.getEntry(alias, null)?.let { entry ->
378 entry as KeyStore.SecretKeyEntry
379
380 val secretKey = entry.secretKey
381
382 val ivBase64 = sharedPreferences.getString(ivKey, null)
383 val iv = Base64.decode(ivBase64, Base64.NO_WRAP)
384 val ivParameterSpec = IvParameterSpec(iv)
385
386 val encryptedBase64 = sharedPreferences.getString(passwordKey, null)
387 val encrypted = Base64.decode(encryptedBase64, Base64.NO_WRAP)
388
389 val transformations = arrayListOf(
390 KeyProperties.KEY_ALGORITHM_AES,
391 KeyProperties.BLOCK_MODE_CBC,
392 KeyProperties.ENCRYPTION_PADDING_PKCS7
393 ).joinToString("/")
394 val executor = ContextCompat.getMainExecutor(fragment.requireContext())
395 val cipher = Cipher.getInstance(transformations)
396 lateinit var biometricPrompt: BiometricPrompt
397
398 val promptInfo = BiometricPrompt.PromptInfo.Builder()
399 .setTitle(fragment.getString(R.string.biometric_install_title))
400 .setSubtitle(fragment.getString(R.string.biometric_install_subtitle))
401 .setNegativeButtonText(fragment.getString(R.string.biometric_install_negative))
402 .build()
403
404 biometricPrompt = BiometricPrompt(fragment, executor, object:BiometricPrompt.AuthenticationCallback() {
405 override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
406 super.onAuthenticationSucceeded(result)
407
408 result.cryptoObject?.cipher?.doFinal(encrypted)?.decodeToString()?.let { decrypted ->
409 password = decrypted
410 onSuccess(password)
411 } ?: run {
412 onError()
413 }
414 }
415
416 override fun onAuthenticationFailed() {
417 super.onAuthenticationFailed()
418 biometricPrompt.authenticate(promptInfo, BiometricPrompt.CryptoObject(cipher))
419 }
420
421 override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
422 super.onAuthenticationError(errorCode, errString)
423
424 val errMessage = "Error #$errorCode: $errString"
425 Log.e(SecureManager.TAG, errMessage)
426
427 onError()
428 }
429 })
430
431 cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec)
432 biometricPrompt.authenticate(promptInfo, BiometricPrompt.CryptoObject(cipher))
433 } ?: throw NullPointerException()
434 }
435
436 override fun uninstallBiometric(): Unit? {
437 TODO()
438 }
439
440 @ExperimentalStdlibApi
441 override fun run(password: String, onSuccess: (bearer: String) -> Unit, onError: () -> Unit) {
442 if (isX509keyPairAvailable() != true) {
443 setX509Certificate()
444 }
445
446 val x509KeyPair = getX509KeyPair()
447 val x509PublicKey = x509KeyPair?.public
448 val x509PrivateKey = x509KeyPair?.private
449 val x509PublicKeyBytes = x509PublicKey?.encoded
450 val x509PublicKeyBase64 = Base64.encodeToString(x509PublicKeyBytes, Base64.NO_WRAP)
451
452 val scope = CoroutineScope(Dispatchers.Main + Job())
453
454 val isSecureLoginInstalled = sharedPreferences.getBoolean(SecureManager.APPLICATION_SECURE_LOGIN_INSTALLED_FLAG, false)
455 val isMasterTokenSaved = sharedPreferences.getBoolean(SecureManager.APPLICATION_MASTER_TOKEN_SAVED_FLAG, false)
456
457 if (!isSecureLoginInstalled) {
458 scope.launch {
459 when (val reply = userRepository.registerOpenKey(Settings.Secure.ANDROID_ID, x509PublicKeyBase64)) {
460 is RepoReply.Error -> {
461 onError()
462 }
463
464 is RepoReply.RegisterOpenKey -> {
465 sharedPreferences.edit()
466 .putBoolean(SecureManager.APPLICATION_SECURE_LOGIN_INSTALLED_FLAG, true)
467 .apply()
468 retrieveMasterToken(x509PublicKey!!, x509PrivateKey!!, onSuccess, onError)
469 }
470 }
471 }
472 } else {
473 if (!isMasterTokenSaved) {
474 retrieveMasterToken(x509PublicKey!!, x509PrivateKey!!, onSuccess, onError)
475 } else {
476 //secureLogin()
477 }
478 }
479 }
480
481 @ExperimentalStdlibApi
482 override fun retrieveMasterToken(publicKey: PublicKey, privateKey: PrivateKey, onSuccess: (bearer: String) -> Unit, onError: () -> Unit): Job? = SecureManager.handleError {
483 val scope = CoroutineScope(Dispatchers.Main + Job())
484
485 scope.launch {
486 val currentTime = System.currentTimeMillis()
487 val currentTimeUnix = currentTime / 1000
488 val requestTimeUnix = (currentTimeUnix - 10).toString()
489
490 val messageDigest = MessageDigest.getInstance("MD5")
491 messageDigest.update(requestTimeUnix.toByteArray())
492
493 val salt = Base64.encodeToString(messageDigest.digest(), Base64.NO_WRAP)
494 val signRaw = "${userRepository.getAccountNumber()}$requestTimeUnix$salt"
495
496 val signatureCipher = Signature.getInstance("SHA1WithRSA")
497 signatureCipher.initSign(privateKey)
498 signatureCipher.update(signRaw.toByteArray())
499
500 val signBytes = signatureCipher.sign()
501 val signBase64 = Base64.encodeToString(signBytes, Base64.NO_WRAP)
502
503 val deviceId = Settings.Secure.ANDROID_ID
504
505 when (val reply = userRepository.getMasterToken(salt, requestTimeUnix, deviceId, signBase64)) {
506 is RepoReply.GetMasterToken -> {
507 val masterTokenId = reply.tokenId
508 val masterToken = reply.token
509 val masterCipher = reply.cipher.toUpperCase(Locale.ROOT)
510 val iv = reply.iv
511 val tokenNotValidBefore = reply.tokenNotValidBefore
512 val tokenNotValidAfter = reply.tokenNotValidAfter
513 val encryptedBearer = reply.encryptedBearer
514
515 val masterTokenCipher = Cipher.getInstance("RSA/NONE/PKCS1Padding")
516 val masterTokenBytes = Base64.decode(masterToken, Base64.NO_WRAP)
517
518 masterTokenCipher.init(Cipher.DECRYPT_MODE, privateKey)
519
520 val decryptedMasterTokenBytes = masterTokenCipher.doFinal(masterTokenBytes)
521 val decryptedMasterTokenBase64 = Base64.encodeToString(decryptedMasterTokenBytes, Base64.NO_WRAP)
522
523 sharedPreferences.edit()
524 .putString(SecureManager.APPLICATION_SECURE_MASTER_TOKEN_BASE64_PREFERENCES_KEY, decryptedMasterTokenBase64)
525 .putString(SecureManager.APPLICATION_SECURE_MASTER_TOKEN_IV_PREFERENCES_KEY, iv)
526 .putString(SecureManager.APPLICATION_SECURE_MASTER_TOKEN_NVA_PREFERENCES_KEY, tokenNotValidAfter)
527 .putString(SecureManager.APPLICATION_SECURE_MASTER_TOKEN_NVB_PREFERENCES_KEY, tokenNotValidBefore)
528 .putString(SecureManager.APPLICATION_SECURE_BEARER_TOKEN_CIPHER_PREFERENCES_KEY, masterCipher)
529 .putString(SecureManager.MASTER_TOKEN_ID_SHARED_PREFERENCES_KEY, masterTokenId)
530 .putString(SecureManager.MASTER_TOKEN_SHARED_PREFERENCES_KEY, decryptedMasterTokenBase64)
531 .apply()
532
533 decryptBearerToken(encryptedBearer, onSuccess, onError)
534 }
535 else -> {
536 onError()
537 }
538 }
539 }
540 }
541
542 @ExperimentalStdlibApi
543 override fun decryptBearerToken(encryptedBearer: String, onSuccess: (bearer: String) -> Unit, onError: () -> Unit): Unit? = SecureManager.handleError {
544 val masterTokenBase64 = sharedPreferences.getString(SecureManager.APPLICATION_SECURE_MASTER_TOKEN_BASE64_PREFERENCES_KEY, null)
545 val iv = sharedPreferences.getString(SecureManager.APPLICATION_SECURE_MASTER_TOKEN_IV_PREFERENCES_KEY, null)
546
547 if (masterTokenBase64 != null && iv != null) {
548 val encryptedBearerBytes = encryptedBearer.toByteArray()
549 val masterTokenBytes = Base64.decode(masterTokenBase64.orEmpty(), Base64.NO_WRAP)
550 val ivBytes = iv.toByteArray()
551 val keyParameter = KeyParameter(masterTokenBytes)
552 val keyParameterIV = ParametersWithIV(keyParameter, ivBytes)
553
554 val blowfishEngine = BlowfishEngine()
555 val paddedBufferedBlockCipher = PaddedBufferedBlockCipher(
556 CBCBlockCipher(blowfishEngine),
557 PKCS7Padding()
558 )
559
560 paddedBufferedBlockCipher.init(false, keyParameterIV)
561
562 val outputLength = paddedBufferedBlockCipher.getOutputSize(encryptedBearerBytes.size)
563 val outputBytes = ByteArray(outputLength)
564 var processedBytes = paddedBufferedBlockCipher.processBytes(encryptedBearerBytes, 0, encryptedBearerBytes.size, outputBytes, 0)
565 processedBytes += paddedBufferedBlockCipher.doFinal(outputBytes, processedBytes)
566
567 val bearer = outputBytes.decodeToString()
568
569 onSuccess(bearer)
570 } else {
571 onError()
572 }
573 }
574
575}