Implementation of Asymmetric Algorithm in Android
In these types of algorithms, two keys are created: one for encryption and another for decryption. Unlike symmetric algorithms, encryption and decryption keys are different. Similar to symmetric algorithms, our aim is to maximize the security of the keys. (Sample project Github link , Main article link)
Let’s move on to implementation…
- Our chosen asymmetric algorithm is EC, which is among the well-known and recognized algorithms. We generate this key using AndroidKeyStore:
KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore")
2. We select a name for this key. Additionally, we assign our goal of signing and verification to this key:
KeyGenParameterSpec.Builder(
"sample_asymmetric_key_alias",
KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
)
3. We set the key length and the type of digest:
setKeySize(256)
setDigests(KeyProperties.DIGEST_SHA256)
4. We set a parameter to make this key accessible only through biometrics. Therefore, when signing and verifying, the user must have an active fingerprint. We use the OS’s fingerprint dialog prompt to ensure the user’s ownership of the device:
setUserAuthenticationRequired(true)
5. Each time a signature is generated, a random encrypted text is created to prevent potential attacks:
setRandomizedEncryptionRequired(true)
6. We set the precise type of the standard EC key generation algorithm:
setAlgorithmParameterSpec(ECGenParameterSpec("secp256r1"))
7. The validity period of the key after a successful biometric authentication:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
setUserAuthenticationParameters(10, KeyProperties.AUTH_BIOMETRIC_STRONG)
} else {
setUserAuthenticationValidityDurationSeconds(10)
}
8. If a new fingerprint is added to the device, this key becomes invalidated:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
setInvalidatedByBiometricEnrollment(true)
}
9. During decryption, the screen must be locked, and if the device supports StrongBox, the key generation process must occur inside it (having two key creation spaces: TEE, StrongBox):
val hasStrongBox = context.packageManager.hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
setUnlockedDeviceRequired(true)
if(hasStrongBox) setIsStrongBoxBacked(true)
}
- In the next step, we use the following code for signing:
val plainMessage = ... // user input text
val signature = Signature.getInstance("SHA256withECDSA").run {
initSign(getPrivateKey())
update(plainMessage.toByteArray())
sign()
}
- We also use the following code to verify:
val plainMessage = ... // user input text
val signature = ... // signed message of user input
val isVerified = Signature.getInstance("SHA256withECDSA").run {
initVerify(getPublicKey())
update(plainMessage.toByteArray())
verify(signature.toByteArray())
}
In conclusion, we learned how to generate a secure asymmetric key with various security features in Android. Additionally, we learned the process of signing and verifying using the combination of these keys. If you have further questions or need more assistance, feel free to ask!