Enkripsi ECC Kotlin
Apakah ada informasi tentang Enkripsi Kurva Elliptic di dalam Kotlin?
Untuk membuat pasangan kunci dan mengenkripsi, mendekripsi pesan.
Ada sangat sedikit informasi non tentang topik ini.
Saya ingin menerapkan kurva elips ECC P-521 misalnya.
Apakah mungkin menggunakan versi Java dalam Kotlin?
Dan bagaimana kita menerapkan ini?
Jawaban
ECC menawarkan ECIES, skema enkripsi hybrid yang menggabungkan enkripsi asimetris berbasis ECC dengan enkripsi simetris. Di sini rahasia bersama dihasilkan dari mana kunci untuk enkripsi simetris data diturunkan. MAC digunakan untuk otentikasi. ECIES ditentukan dalam berbagai standar kripto. Detail selengkapnya dapat ditemukan di sini .
ECIES menggunakan komponen yang Anda daftarkan dalam pertanyaan Anda (rahasia bersama melalui ECC, enkripsi simetris, MAC untuk otentikasi). Namun, algoritme tertentu bergantung pada standar atau implementasi yang digunakan, jadi Anda tidak memiliki kendali langsung atas algoritme tersebut. Jika ini cukup untuk Anda, ECIES akan menjadi pilihan yang baik.
ECIES didukung misalnya oleh BouncyCastle, yang mengimplementasikan standar IEEE P 1363a. Untuk menggunakan ECIES, BouncyCastle harus ditambahkan terlebih dahulu (misalnya untuk Android Studio di bagian dependensi app / gradle), lihat juga di sini :
implementation 'org.bouncycastle:bcprov-jdk15to18:1.67'
Kode Kotlin berikut kemudian melakukan enkripsi / dekripsi dengan ECIES dan NIST P-521:
// Add BouncyCastle
Security.removeProvider("BC")
Security.addProvider(BouncyCastleProvider())
// Key Pair Generation
val keyPairGenerator = KeyPairGenerator.getInstance("ECDH")
keyPairGenerator.initialize(ECGenParameterSpec("secp521r1"))
val keyPair = keyPairGenerator.generateKeyPair()
// Encryption
val plaintext = "The quick brown fox jumps over the lazy dog".toByteArray(StandardCharsets.UTF_8)
val cipherEnc = Cipher.getInstance("ECIES")
cipherEnc.init(Cipher.ENCRYPT_MODE, keyPair.public) // In practice, the public key of the recipient side is used
val ciphertext = cipherEnc.doFinal(plaintext)
// Decryption
val cipherDec = Cipher.getInstance("ECIES")
cipherDec.init(Cipher.DECRYPT_MODE, keyPair.private)
val decrypted = cipherDec.doFinal(ciphertext)
println(String(decrypted, StandardCharsets.UTF_8))
diuji dengan API level 28 / Android 9 Pie.
Jika Anda ingin lebih mengontrol algoritme yang digunakan, masing-masing komponen dapat diimplementasikan secara manual, mis
- ECDH dengan NIST P-521 untuk menentukan rahasia bersama
- SHA-512 untuk menentukan kunci AES-256 sebagai 32 byte pertama dari hash (lihat juga di sini untuk penggunaan KDF seperti dalam konteks ECIES)
- AES-256 / GCM untuk enkripsi simetris ( GCM sudah diautentikasi sebagai enkripsi, jadi MAC eksplisit tidak diperlukan)
Kode Kotlin berikut kemudian melakukan enkripsi / dekripsi dengan komponen berikut:
// Generate Keys
val keyPairA = generateKeyPair()
val keyPairB = generateKeyPair()
// Generate shared secrets
val sharedSecretA = getSharedSecret(keyPairA.private, keyPairB.public)
val sharedSecretB = getSharedSecret(keyPairB.private, keyPairA.public)
// Generate AES-keys
val aesKeyA = getAESKey(sharedSecretA)
val aesKeyB = getAESKey(sharedSecretB)
// Encryption (WLOG by A)
val plaintextA = "The quick brown fox jumps over the lazy dog".toByteArray(StandardCharsets.UTF_8)
val ciphertextA = encrypt(aesKeyA, plaintextA)
// Decryption (WLOG by B)
val plaintextB = decrypt(aesKeyB, ciphertextA)
println(String(plaintextB, StandardCharsets.UTF_8))
dengan:
private fun generateKeyPair(): KeyPair {
val keyPairGenerator = KeyPairGenerator.getInstance("EC")
keyPairGenerator.initialize(ECGenParameterSpec("secp521r1"))
return keyPairGenerator.generateKeyPair()
}
private fun getSharedSecret(privateKey: PrivateKey, publicKey: PublicKey): ByteArray {
val keyAgreement = KeyAgreement.getInstance("ECDH")
keyAgreement.init(privateKey)
keyAgreement.doPhase(publicKey, true)
return keyAgreement.generateSecret()
}
private fun getAESKey(sharedSecret: ByteArray): ByteArray {
val digest = MessageDigest.getInstance("SHA-512")
return digest.digest(sharedSecret).copyOfRange(0, 32)
}
private fun encrypt(aesKey: ByteArray, plaintext: ByteArray): ByteArray {
val secretKeySpec = SecretKeySpec(aesKey, "AES")
val iv = ByteArray(12) // Create random IV, 12 bytes for GCM
SecureRandom().nextBytes(iv)
val gCMParameterSpec = GCMParameterSpec(128, iv)
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, gCMParameterSpec)
val ciphertext = cipher.doFinal(plaintext)
val ivCiphertext = ByteArray(iv.size + ciphertext.size) // Concatenate IV and ciphertext (the MAC is implicitly appended to the ciphertext)
System.arraycopy(iv, 0, ivCiphertext, 0, iv.size)
System.arraycopy(ciphertext, 0, ivCiphertext, iv.size, ciphertext.size)
return ivCiphertext
}
private fun decrypt(aesKey: ByteArray, ivCiphertext: ByteArray): ByteArray {
val secretKeySpec = SecretKeySpec(aesKey, "AES")
val iv = ivCiphertext.copyOfRange(0, 12) // Separate IV
val ciphertext = ivCiphertext.copyOfRange(12, ivCiphertext.size) // Separate ciphertext (the MAC is implicitly separated from the ciphertext)
val gCMParameterSpec = GCMParameterSpec(128, iv)
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, gCMParameterSpec)
return cipher.doFinal(ciphertext)
}
diuji lagi dengan API Level 28 / Android 9 Pie.