SHARE
TWEET

Untitled

a guest Apr 20th, 2019 77 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import android.os.Build
  2. import android.security.keystore.KeyGenParameterSpec
  3. import android.security.keystore.KeyProperties
  4. import android.util.Base64
  5. import androidx.annotation.RequiresApi
  6. import java.nio.ByteBuffer
  7. import java.security.InvalidKeyException
  8. import java.security.Key
  9. import java.security.KeyStore
  10. import java.security.SecureRandom
  11. import javax.crypto.Cipher
  12. import javax.crypto.KeyGenerator
  13. import javax.crypto.spec.GCMParameterSpec
  14.  
  15. abstract class Cryptor {
  16.     fun encryptString(input: String, keyAlias: String): String {
  17.         val inputBytes = input.toByteArray(Charsets.UTF_8)
  18.         val encrypted = encrypt(inputBytes, keyAlias)
  19.         return Base64.encodeToString(encrypted, Base64.NO_WRAP)
  20.     }
  21.  
  22.     fun decryptString(input: String, keyAlias: String): String {
  23.         val inputBytes = Base64.decode(input, Base64.DEFAULT)
  24.         val decrypted = decrypt(inputBytes, keyAlias)
  25.         return String(decrypted, Charsets.UTF_8)
  26.     }
  27.  
  28.     abstract fun encrypt(input: ByteArray, keyAlias: String): ByteArray
  29.  
  30.     abstract fun decrypt(input: ByteArray, keyAlias: String): ByteArray
  31.  
  32.     companion object {
  33.         fun create(): Cryptor {
  34.             return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  35.                 Api23Cryptor()
  36.             } else {
  37.                 NoCryptor()
  38.             }
  39.         }
  40.     }
  41. }
  42.  
  43. private class NoCryptor : Cryptor() {
  44.     override fun encrypt(input: ByteArray, keyAlias: String): ByteArray = input
  45.  
  46.     override fun decrypt(input: ByteArray, keyAlias: String): ByteArray = input
  47. }
  48.  
  49. @RequiresApi(Build.VERSION_CODES.M)
  50. private class Api23Cryptor : Cryptor() {
  51.     private val keyStore = KeyStore.getInstance(KEYSTORE_PROVIDER)
  52.  
  53.     init {
  54.         keyStore.load(null)
  55.     }
  56.  
  57.     override fun encrypt(input: ByteArray, keyAlias: String): ByteArray {
  58.         val iv = generateIv(12)
  59.         var secretKey = keyStore.getKey(keyAlias, null) ?: generateSecretKey(keyAlias)
  60.  
  61.         val cipherText = try {
  62.             val cipher = getCipher(Cipher.ENCRYPT_MODE, secretKey, iv)
  63.             cipher.doFinal(input)
  64.         } catch (e: InvalidKeyException) {
  65.             keyStore.deleteEntry(keyAlias)
  66.             secretKey = generateSecretKey(keyAlias)
  67.  
  68.             val cipher = getCipher(Cipher.ENCRYPT_MODE, secretKey, iv)
  69.             cipher.doFinal(input)
  70.         }
  71.  
  72.         val result = ByteBuffer.allocate(4 + iv.size + cipherText.size)
  73.         result.putInt(iv.size)
  74.         result.put(iv)
  75.         result.put(cipherText)
  76.         return result.array()
  77.     }
  78.  
  79.     override fun decrypt(input: ByteArray, keyAlias: String): ByteArray {
  80.         val secretKey = keyStore.getKey(keyAlias, null)
  81.                 ?: throw IllegalStateException("Secret key with alias '$keyAlias' doesn't exist")
  82.  
  83.         val buffer = ByteBuffer.wrap(input)
  84.         val ivLength = buffer.int
  85.         if (ivLength != 12 && ivLength != 16) {
  86.             throw IllegalArgumentException("Invalid IV length: $ivLength")
  87.         }
  88.         val iv = ByteArray(ivLength)
  89.         buffer.get(iv)
  90.  
  91.         val cipherText = ByteArray(buffer.remaining())
  92.         buffer.get(cipherText)
  93.  
  94.         try {
  95.             val cipher = getCipher(Cipher.DECRYPT_MODE, secretKey, iv)
  96.             return cipher.doFinal(cipherText)
  97.         } catch (e: InvalidKeyException) {
  98.             keyStore.deleteEntry(keyAlias)
  99.             throw e
  100.         }
  101.     }
  102.  
  103.     private fun getCipher(mode: Int, secretKey: Key, iv: ByteArray): Cipher {
  104.         val cipher = Cipher.getInstance("AES/GCM/NoPadding")
  105.         cipher.init(mode, secretKey, GCMParameterSpec(128, iv))
  106.         return cipher
  107.     }
  108.  
  109.     private fun generateIv(length: Int): ByteArray {
  110.         val iv = ByteArray(length)
  111.         SecureRandom().nextBytes(iv)
  112.         return iv
  113.     }
  114.  
  115.     private fun generateSecretKey(alias: String): Key {
  116.         val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES)
  117.         keyGenerator.init(KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
  118.                 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
  119.                 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
  120.                 .setRandomizedEncryptionRequired(false)
  121.                 .build())
  122.         return keyGenerator.generateKey()
  123.     }
  124.  
  125.     companion object {
  126.         private const val KEYSTORE_PROVIDER = "AndroidKeyStore"
  127.     }
  128. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top