Created
July 5, 2018 09:22
-
-
Save ishikota/717af194f21a3ea22c0704dc838a6d8e to your computer and use it in GitHub Desktop.
Medium post for Getting along with credentials in android
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
val config = TwitterConfig.Builder(context) | |
.twitterAuthConfig(TwitterAuthConfig("TODO consumer key comes here", "TODO consumer secret comes here")) | |
.build() | |
Twitter.initialize(config) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
val config = TwitterConfig.Builder(context) | |
.twitterAuthConfig(TwitterAuthConfig("my-twitter-key", "my-twitter-secret")) | |
.build() | |
Twitter.initialize(config) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
val config = TwitterConfig.Builder(context) | |
.twitterAuthConfig(TwitterAuthConfig(BuildConfig.TWITTER_COMSUMER_KEY, BuildConfig.TWITTER_COMSUMER_SECRET)) | |
.build() | |
Twitter.initialize(config) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import okhttp3.Authenticator | |
class MyAppAuthenticator(private val preference: SharedPreferences): Authenticator { | |
// This callback is called when api request failed in 401. | |
override fun authenticate(route: Route?, response: Response?): Request? { | |
val currentRefreshToken = preference.getString("REFRESH_TOKEN_KEY", "") | |
val (newAccessToken, newRefreshToken) = requestNewTokensToServer(currentRefreshToken).blockingGet() // TODO error handling | |
preference.edit().putString("ACCESS_TOKEN_KEY", newAccessToken).apply() | |
preference.edit().putString("REFRESH_TOKEN_KEY", newRefreshToken).apply() | |
return attachNewTokenOnRequest(response.request(), newAccessToken) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
companion object { | |
private const val ALGORITHM = "AES" | |
private const val MODE = "CBC" | |
private const val PADDING = "PKCS5Padding" | |
} | |
fun savePrivateString(key: String, value: String) { | |
prefs.edit().putString(key, encrypt(value)).apply() | |
} | |
fun getPrivateString(key: String): String { | |
val encrypted = prefs.getString(key, "") | |
return decrypt(encrypted) | |
} | |
private fun encrypt(plain: String): String { | |
val cipher = initializeCipher(Cipher.ENCRYPT_MODE) | |
val encrypted = cipher.doFinal(plain.toByteArray()) ?: byteArrayOf() // TODO catch exception | |
return Base64.encodeToString(encrypted, Base64.DEFAULT) | |
} | |
private fun decrypt(encrypted: String): String { | |
val cipher = initializeCipher(Cipher.DECRYPT_MODE) | |
val decrypted = cipher.doFinal(plain.toByteArray()) ?: byteArrayOf() // TODO catch exception | |
return String(decrypted) | |
} | |
private fun initializeCipher(mode: Int) = Cipher.getInstance("$ALGORITHM/$MODE/$PADDING").apply { | |
val key = BuildConfig.CIPHER_KEY // !!NOTICE!! Secret key is necessarry for encryption/decryption. | |
val iv = BuildConfig.CIPHER_IV // InitializationVector. 16bytes string. | |
val secretKeySpec = SecretKeySpec(key.toByteArray(), ALGORITHM) | |
val ivSpec = IvParameterSpec(iv.toByteArray()) | |
init(mode, secretKeySpec, ivSpec) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fun savePrivateString(key: String, value: String) { | |
prefs.edit().putString(key, encrypt(key, value)).apply() | |
} | |
fun getPrivateString(key: String): String { | |
val encrypted = prefs.getString(key, "") | |
return decrypt(key, encrypted) | |
} | |
private fun encrypt(alias: String, plain: String): String { | |
val cipher = initializeCipher(alias, Cipher.ENCRYPT_MODE) | |
val encrypted = cipher.doFinal(plain.toByteArray()) ?: byteArrayOf() // TODO catch exception | |
return Base64.encodeToString(encrypted, Base64.DEFAULT) | |
} | |
private fun decrypt(alias: String, encrypted: String): String { | |
val cipher = initializeCipher(alias, Cipher.DECRYPT_MODE) | |
val decrypted = cipher.doFinal(plain.toByteArray()) ?: byteArrayOf() // TODO catch exception | |
return String(decrypted) | |
} | |
private fun initializeCipher(alias: String, mode: Int) = Cipher.getInstance("$ALGORITHM/$MODE/$PADDING").apply { | |
val iv = BuildConfig.CIPHER_IV // InitializationVector. 16bytes string. | |
val secretKeySpec = buildSecretKey(alias) | |
val ivSpec = IvParameterSpec(iv.toByteArray()) | |
init(mode, secretKeySpec, ivSpec) | |
} | |
private fun buildSecretKey(alias: String): SecretKey { | |
val keystore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) } | |
return if (keystore.containsAlias(alias)) { // use saved secretKey | |
val entry = (keystore.getEntry(keyAlias, null) as KeyStore.SecretKeyEntry) | |
entry.secretKey | |
} else { // generate new secretKey and save it into AndroidKeyStore | |
val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore") | |
keyGenerator.init(KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) | |
.setBlockModes(KeyProperties.BLOCK_MODE_CBC) | |
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) | |
.build()) | |
return keyGenerator.generateKey() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment