Interface usada para criptografia de ponta a ponta.
interface MessageCryptManager {
fun getPublicKey(): String
fun messageDecrypt(encryptMessageString: String): String
fun messageEncrypt(publicKeyString: String, message: String): String
}
Classe usada para criptografia de ponta a ponta.
class MessageCryptManagerImpl : MessageCryptManager {
companion object {
private const val KEY_PAIR_ALIAS = "privateMessageKey"
}
private fun generateKeyPairIfNotExist() {
val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
if (!keyStore.containsAlias(KEY_PAIR_ALIAS)) {
val keyGenParameterSpec = KeyGenParameterSpec.Builder(
KEY_PAIR_ALIAS,
KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_DECRYPT
).setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
.build()
val keyPairGenerator = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_RSA,
"AndroidKeyStore"
)
keyPairGenerator.initialize(keyGenParameterSpec)
keyPairGenerator.generateKeyPair()
}
}
private fun encodeToBase64(data: ByteArray): String {
return Base64.encodeToString(data, Base64.DEFAULT)
}
private fun decodeFromBase64(base64String: String): ByteArray? {
return try {
Base64.decode(base64String, Base64.DEFAULT)
} catch (e: IllegalArgumentException) {
null
}
}
private fun getPrivateKey(): PrivateKey? {
val keyStore = KeyStore.getInstance("AndroidKeyStore")
keyStore.load(null)
return keyStore.getKey(KEY_PAIR_ALIAS, null) as? PrivateKey
}
override fun getPublicKey(): String {
val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
if (!keyStore.containsAlias(KEY_PAIR_ALIAS)) generateKeyPairIfNotExist()
val certificate = keyStore.getCertificate(KEY_PAIR_ALIAS)
return encodeToBase64(certificate.publicKey.encoded)
}
override fun messageEncrypt(publicKeyString: String, message: String): String {
val keyBytes = decodeFromBase64(publicKeyString)
val keySpec = X509EncodedKeySpec(keyBytes)
val keyFactory = KeyFactory.getInstance("RSA")
val publicKey = keyFactory.generatePublic(keySpec)
val cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")
cipher.init(Cipher.ENCRYPT_MODE, publicKey)
val encryptByteArray = cipher.doFinal(message.toByteArray(Charsets.UTF_8))
return encodeToBase64(encryptByteArray)
}
override fun messageDecrypt(encryptMessageString: String): String {
return try {
val encryptMessage = decodeFromBase64(encryptMessageString) ?: return "Error Base64"
val cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")
cipher.init(Cipher.DECRYPT_MODE, getPrivateKey())
String(cipher.doFinal(encryptMessage), Charsets.UTF_8)
} catch (e: InvalidKeyException) {
"Invalid Key"
} catch (e: IllegalBlockSizeException) {
"Decryption Error - Block Size"
} catch (e: BadPaddingException) {
"Decryption Error - Padding"
} catch (e: Exception) {
"Decryption Error - Unknown"
}
}
}