Cryptography in Kotlin: Encryption and Hashing
Kotlin, being a modern language for the JVM, provides access to all the capabilities of the Java Cryptography Architecture (JCA). This allows implementing both symmetric (AES, DES) and asymmetric (RSA) encryption, as well as cryptographic hash functions (SHA-256, MD5) and digital signatures. In this article, we will explore practical examples of using cryptography in Kotlin that are useful for protecting data in web applications, mobile development, and backend services.
All code examples use built-in Java capabilities, making them cross-platform and requiring no additional libraries.
1. Symmetric AES Encryption in Kotlin
Symmetric encryption uses the same key for encryption and decryption. The AES (Advanced Encryption Standard) algorithm is the gold standard for security. Let's look at an example of encrypting a string using CBC mode and PKCS5Padding.
import javax.crypto.Cipherimport javax.crypto.KeyGeneratorimport javax.crypto.SecretKeyimport javax.crypto.spec.IvParameterSpecimport javax.crypto.spec.SecretKeySpecimport java.util.Base64
fun generateAESKey(): SecretKey { val keyGen = KeyGenerator.getInstance("AES") keyGen.init(256) // Key length: 128, 192, or 256 bits return keyGen.generateKey()}
fun encryptAES(plainText: String, secretKey: SecretKey, iv: ByteArray): String { val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") val ivSpec = IvParameterSpec(iv) cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec) val encrypted = cipher.doFinal(plainText.toByteArray()) return Base64.getEncoder().encodeToString(encrypted)}
fun decryptAES(encryptedText: String, secretKey: SecretKey, iv: ByteArray): String { val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") val ivSpec = IvParameterSpec(iv) cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec) val decoded = Base64.getDecoder().decode(encryptedText) val decrypted = cipher.doFinal(decoded) return String(decrypted)}
fun main() { val key = generateAESKey() val iv = ByteArray(16) // Initialization vector (16 bytes for AES) // In a real project, iv should be random and transmitted together with the ciphertext val original = "Hello, Kotlin!" val encrypted = encryptAES(original, key, iv) val decrypted = decryptAES(encrypted, key, iv) println("Original: $original") println("Encrypted: $encrypted") println("Decrypted: $decrypted")}Important: The initialization vector (IV) must be random for each encryption and transmitted openly along with the encrypted data. Never use a fixed IV in production.
2. Asymmetric RSA Encryption in Kotlin
RSA uses a key pair: a public key for encryption and a private key for decryption. This is ideal for secure data transfer between parties.
import java.security.KeyPairGeneratorimport java.security.PrivateKeyimport java.security.PublicKeyimport javax.crypto.Cipherimport java.util.Base64
fun generateRSAKeyPair(): Pair<PublicKey, PrivateKey> { val keyGen = KeyPairGenerator.getInstance("RSA") keyGen.initialize(2048) // Recommended key size val keyPair = keyGen.generateKeyPair() return Pair(keyPair.public, keyPair.private)}
fun encryptRSA(plainText: String, publicKey: PublicKey): String { val cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding") cipher.init(Cipher.ENCRYPT_MODE, publicKey) val encrypted = cipher.doFinal(plainText.toByteArray()) return Base64.getEncoder().encodeToString(encrypted)}
fun decryptRSA(encryptedText: String, privateKey: PrivateKey): String { val cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding") cipher.init(Cipher.DECRYPT_MODE, privateKey