Encryption Tutorial For Android: Getting Started | raywenderlich.com

Ever wondered how you can use data encryption to secure your private user data from hackers? Look no more, in this tutorial you’ll do just that!


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/778533-encryption-tutorial-for-android-getting-started

Hi @nsdestr0yer ,
thanks for the tutorial.
Do you have any hint on how tu create a new secret key on Android versions prior to 23? Unfortunately KeyGenParameterSpec was added on that version of Android.

Thanks, Francesco

@francesco_pedron-omn Yes, AES symmetric keys are not supported but RSA asymmetric keys are so you could use that. The main difference here is that an asymmetric keypair contains two keys, a private and a public key, where the public key encrypts the data and the private key decrypts it. So in this case you’d use a KeyPairGeneratorSpec - passed into the KeyPairGenerator that is initialized with KEY_ALGORITHM_RSA and the “AndroidKeyStore” provider. To encrypt, you’d get the RSAPublicKey from the keypair. Decryption is done using the RSAPrivateKey object. I can paste a quick and dirty example…

@francesco_pedron-omn rough example might be:

private fun testPreMEncryption() {
  try {
    //Generate a keypair and store it in the KeyStore
    val keyStore = KeyStore.getInstance("AndroidKeyStore")
    keyStore.load(null)

    val start = Calendar.getInstance()
    val end = Calendar.getInstance()
    end.add(Calendar.YEAR, 10)
    val spec = KeyPairGeneratorSpec.Builder(this)
        .setAlias("MyKeyAlias")
        .setSubject(X500Principal("CN=MyKeyName, O=Android Authority"))
        .setSerialNumber(BigInteger(1024, Random()))
        .setStartDate(start.time)
        .setEndDate(end.time)
        .setEncryptionRequired() //on API level 18, encrypted at rest, requires lock screen to be set up, changing lock screen removes key
        .build()
    val keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore")
    keyPairGenerator.initialize(spec)
    keyPairGenerator.generateKeyPair()

    //Encryption test
    val encryptedBytes = rsaEncrypt("My secret string!".toByteArray(charset("UTF-8")))
    val decryptedBytes = rsaDecrypt(encryptedBytes!!)
    val decryptedString = String(decryptedBytes!!, Charsets.UTF_8)
    Log.e("MyApp", "Decrypted string is $decryptedString")
  } catch (e: Throwable) {
    e.printStackTrace()
  }

}

fun rsaEncrypt(decryptedBytes: ByteArray): ByteArray? {
  var encryptedBytes: ByteArray? = null
  try {
    val keyStore = KeyStore.getInstance("AndroidKeyStore")
    keyStore.load(null)
    val privateKeyEntry = keyStore.getEntry("MyKeyAlias", null) as KeyStore.PrivateKeyEntry
    val publicKey = privateKeyEntry.certificate.publicKey as RSAPublicKey

    val cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL")
    cipher.init(Cipher.ENCRYPT_MODE, publicKey)

    val outputStream = ByteArrayOutputStream()
    val cipherOutputStream = CipherOutputStream(outputStream, cipher)
    cipherOutputStream.write(decryptedBytes)
    cipherOutputStream.close()

    encryptedBytes = outputStream.toByteArray()

  } catch (e: Throwable) {
    e.printStackTrace()
  }

  return encryptedBytes
}

fun rsaDecrypt(encryptedBytes: ByteArray): ByteArray? {
  var decryptedBytes: ByteArray? = null
  try {
    val keyStore = KeyStore.getInstance("AndroidKeyStore")
    keyStore.load(null)
    val privateKeyEntry = keyStore.getEntry("MyKeyAlias", null) as KeyStore.PrivateKeyEntry
    //val privateKey = privateKeyEntry.privateKey as RSAPrivateKey

    val cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")
    cipher.init(Cipher.DECRYPT_MODE, privateKeyEntry.privateKey)

    val cipherInputStream = CipherInputStream(ByteArrayInputStream(encryptedBytes), cipher)
    val arrayList: ArrayList<Byte> = ArrayList()
    var nextByte: Int

    do {
      nextByte = cipherInputStream.read()
      if (nextByte == -1) {
        break
      }
      arrayList.add(nextByte.toByte())
    } while (true)

    decryptedBytes = ByteArray(arrayList.size)
    for (i in decryptedBytes.indices) {
      decryptedBytes[i] = arrayList[i]
    }
  } catch (e: Throwable) {
    e.printStackTrace()
  }

  return decryptedBytes
}

Thank you very much.
To other people with same requirements I’ve found also useful this series of articles from Yakiv Mospan

This tutorial is more than six months old so questions are no longer supported at the moment for it. Thank you!