Skip to content

Instantly share code, notes, and snippets.

@ishikota
Created July 5, 2018 09:22
Show Gist options
  • Save ishikota/717af194f21a3ea22c0704dc838a6d8e to your computer and use it in GitHub Desktop.
Save ishikota/717af194f21a3ea22c0704dc838a6d8e to your computer and use it in GitHub Desktop.
Medium post for Getting along with credentials in android
val config = TwitterConfig.Builder(context)
.twitterAuthConfig(TwitterAuthConfig("TODO consumer key comes here", "TODO consumer secret comes here"))
.build()
Twitter.initialize(config)
val config = TwitterConfig.Builder(context)
.twitterAuthConfig(TwitterAuthConfig("my-twitter-key", "my-twitter-secret"))
.build()
Twitter.initialize(config)
val config = TwitterConfig.Builder(context)
.twitterAuthConfig(TwitterAuthConfig(BuildConfig.TWITTER_COMSUMER_KEY, BuildConfig.TWITTER_COMSUMER_SECRET))
.build()
Twitter.initialize(config)
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)
}
}
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)
}
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