Skip to content

Instantly share code, notes, and snippets.

@XuNeal
Created December 20, 2018 03:43
Show Gist options
  • Save XuNeal/bbcdd44f9f4825525ee9de89f02ed4ed to your computer and use it in GitHub Desktop.
Save XuNeal/bbcdd44f9f4825525ee9de89f02ed4ed to your computer and use it in GitHub Desktop.
Show How to use keystore in android
val HEX = "37158399CB98DCD114D873E06EBF4BCC"
val KEYSTORE_ALIAS = "imTokenDerivedKey"
val ANDROID_KEYSTORE_PROVIDER = "AndroidKeyStore"
val TAG = "Keychain"
var isEncrypt: Boolean = true
var encrypted: String = ""
var iv: ByteArray = ByteArray(0)
// 指纹验证相关回调方法
class AuthenticationCallback(val textView: TextView) :
BiometricPrompt.AuthenticationCallback() {
fun onAuthenticationSucceeded(result: FingerprintManagerCompat.AuthenticationResult?) {
// 只有指纹验证成功之后才可以获取相应的cipher,里面已经包含私钥
val cipher = result!!.cryptoObject.cipher!!
try {
val stringBuilder = StringBuilder()
if (isEncrypt) {
stringBuilder.append("Encrypt: \n")
val b = hexStringToByteArray(HEX)
encrypted = byteArrayToHex(cipher.doFinal(b))
iv = cipher.iv
stringBuilder.append("Data: ${HEX} \n")
stringBuilder.append("IV: ${byteArrayToHex(cipher.iv)} \n")
stringBuilder.append("CipherText: ${encrypted} \n")
} else {
stringBuilder.append("Decrypt: \n")
val b = hexStringToByteArray(encrypted)
val original = byteArrayToHex(cipher.doFinal(b))
stringBuilder.append("IV: ${byteArrayToHex(cipher.iv)}\n")
stringBuilder.append("Decrypt Result: ${original} \n")
}
textView.text = stringBuilder.toString()
} catch (error: java.lang.Exception) {
Log.e("FP", error.message)
}
}
override fun onAuthenticationError(errorCode: Int, errString: CharSequence?) {
super.onAuthenticationError(errorCode, errString)
Log.e(TAG, errString.toString())
}
override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
Log.e(TAG, "Authentication Failed")
}
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult?) {
super.onAuthenticationSucceeded(result)
}
}
class MainActivity : AppCompatActivity() {
@RequiresApi(Build.VERSION_CODES.M)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 加载keystore实例
val keystore = KeyStore.getInstance(ANDROID_KEYSTORE_PROVIDER)
keystore.load(null)
// 根据aes/cbc/pkcs7算法初始化cipher,此时尚未填充私钥
val cipher = Cipher.getInstance(
KeyProperties.KEY_ALGORITHM_AES + "/"
+ KeyProperties.BLOCK_MODE_CBC + "/"
+ KeyProperties.ENCRYPTION_PADDING_PKCS7
)
fun doCrypt() {
try {
// 获取指定alias的私钥,SecretKey类型的私钥无法看到原始内容
val key = keystore.getKey(KEYSTORE_ALIAS, null) as SecretKey
val factory = SecretKeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore");
val keyInfo = factory.getKeySpec(key, KeyInfo::class.java) as KeyInfo
// 确认该私钥是存储在SE设备中,否则抛出异常
if (keyInfo.isInsideSecureHardware || isInSimulator()) {
throw Exception("Your device not support SE or TEE")
}
if (isEncrypt) cipher.init(Cipher.ENCRYPT_MODE, key) else cipher.init(Cipher.DECRYPT_MODE, key, IvParameterSpec(iv))
val cancellationSignal = CancellationSignal()
val onClickListener = DialogInterface.OnClickListener {dialog, witch -> Log.i(TAG, "User cancel") }
// 构造指纹签名提示框
val bioPrompt = BiometricPrompt.Builder(this)
.setTitle("Verify your Fingerprint")
.setDescription("Pls touch your Fingerprint sensor")
.setNegativeButton("Use Password", mainExecutor, onClickListener)
.build()
// val dialog = AlertDialog.Builder(this)
// .setTitle("Input FP")
// .show()
val callback = AuthenticationCallback(tvLog)
bioPrompt.authenticate(BiometricPrompt.CryptoObject(cipher), cancellationSignal, mainExecutor,callback)
// FingerprintManagerCompat.from(this).authenticate(
// FingerprintManagerCompat.CryptoObject(cipher),
// 0, // flags
// cancellationSignal, // authentication callback
// callback,
// null
// )
} catch (e: Exception) {
Log.e(TAG, e.localizedMessage)
}
}
btnEncrypt.setOnClickListener {
isEncrypt = true
val aliases = keystore.aliases().toList()
// 判断之前是否生成或相应的alias的私钥,没有则申请系统生成
if (!aliases.contains(KEYSTORE_ALIAS)) {
val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEYSTORE_PROVIDER)
keyGenerator.init(
KeyGenParameterSpec.Builder(
KEYSTORE_ALIAS,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setUserAuthenticationRequired(true) // 指定鉴权之后才能使用
.setEncryptionPaddings(
KeyProperties.ENCRYPTION_PADDING_PKCS7
)
.build()
)
keyGenerator.generateKey()
}
doCrypt()
}
btnDecrypt.setOnClickListener {
isEncrypt = false
doCrypt()
}
}
fun isInSimulator(): Boolean {
return android.os.Build.MODEL.contains("google_sdk") ||
android.os.Build.MODEL.contains("Emulator")
}
}
// utils method
fun byteArrayToHex(a: ByteArray): String {
val sb = StringBuilder(a.size * 2)
for (b in a)
sb.append(String.format("%02x", b))
return sb.toString()
}
fun hexStringToByteArray(s: String): ByteArray {
val b = ByteArray(s.length / 2)
for (i in b.indices) {
val index = i * 2
val v = Integer.parseInt(s.substring(index, index + 2), 16)
b[i] = v.toByte()
}
return b
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment