Skip to content
alex [dot] kramer [at] g_m_a_i_l [dot] com edited this page Oct 11, 2018 · 6 revisions

Cryptography for serialized objects (AES ECB)

Use ECB for short payloads. Use CBC with an IV (initialization vector) for longer payloads.

import com.google.gson.Gson
import org.junit.Assert.assertEquals
import org.junit.Test
import java.util.*
import javax.crypto.*
import javax.crypto.spec.SecretKeySpec

class EncryptionTest {
    data class Thingy(
        val field1: String,
        val field2: Double,
        val field3: Long
    )

    private fun generateAesKey(): SecretKey {
        val keyGen = KeyGenerator.getInstance("AES")
        keyGen.init(256)
        val secretKey = keyGen.generateKey()
        return secretKey
    }

    private fun decodeAesKeyBase64(keyEncodedAsBase64: String): SecretKey {
        val keyData = byteDataFromBase64(keyEncodedAsBase64)
        return SecretKeySpec(keyData, 0, keyData.size, "AES")
    }

    private fun byteDataToBase64(data: ByteArray): String {
        return Base64.getEncoder().encodeToString(data)
    }

    private fun byteDataFromBase64(base64Data: String): ByteArray {
        return Base64.getDecoder().decode(base64Data)
    }

    private fun encryptToBase64Ciphertext(key: SecretKey, stringToEncrypt: String): String {
        val aesCipher = Cipher.getInstance("AES/ECB/PKCS5PADDING")
        aesCipher.init(Cipher.ENCRYPT_MODE, key)
        val stringToEncryptBytes = stringToEncrypt.toByteArray()
        val ciphertextBytes = aesCipher.doFinal(stringToEncryptBytes)
        return byteDataToBase64(ciphertextBytes)
    }

    private fun decrypt(key: SecretKey, base64Ciphertext: String): String {
        val cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING")
        cipher.init(Cipher.DECRYPT_MODE, key)
        val ciphertext = byteDataFromBase64(base64Ciphertext)
        val decryptedBytes = cipher.doFinal(ciphertext)
        return String(decryptedBytes)
    }

    @Test
    fun `encrypt all the things`() {
        val key = generateAesKey()

        // Thingy to serialize and encrypt
        val thingy = Thingy("eleventeen", 3.14159, 42)

        // Serialize thingy
        val thingyJson = Gson().toJson(thingy)

        // Encrypt serialized thingy
        val thingyJsonCiphertextBase64 = encryptToBase64Ciphertext(key, thingyJson)

        // Encode key (in case )
        val encodedKeyBase64 = byteDataToBase64(key.getEncoded())

        
        val decodedKey = decodeAesKeyBase64(encodedKeyBase64)
        val decryptedThingyJson = decrypt(decodedKey, userDataJsonCiphertextBase64)
        val deserializedThingy = Gson().fromJson(decryptedThingyJson, Thingy::class.java)

        assertEquals(key, decodedKey)
        assertEquals(decryptedThingyJson, thingyJson)
        assertEquals(thingy, deserializedThingy)

        println(deserializedThingy)
    }
}

Clone this wiki locally