Skip to content

Instantly share code, notes, and snippets.

@rovkinmax
Created November 5, 2016 10:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rovkinmax/3cbd257027ca5affcce7c13d6c61b44b to your computer and use it in GitHub Desktop.
Save rovkinmax/3cbd257027ca5affcce7c13d6c61b44b to your computer and use it in GitHub Desktop.
class EncryptionManager(val alias: String, context: Context) {
companion object {
private const val KEY_STORE_PROVIDER = "AndroidKeyStore"
private const val CIPHER_PROVIDER = "AndroidOpenSSL"
private const val DISTINGUISHED = "CN=Company,O=Android Authority"
private const val TRANSFORMATION = "${KeyProperties.KEY_ALGORITHM_RSA}/${KeyProperties.BLOCK_MODE_ECB}/${KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1}"
}
private val context: Context
init {
this.context = context.applicationContext
}
fun encryptData(data: ByteArray): ByteArray {
val entry = getOrCreateKey(context)
return processByteArrayWithCipher(entry.certificate.publicKey, data, Cipher.ENCRYPT_MODE)
}
fun decryptData(data: ByteArray): ByteArray {
val entry = getOrCreateKey(context)
return processByteArrayWithCipher(entry.privateKey, data, Cipher.DECRYPT_MODE)
}
private fun processByteArrayWithCipher(key: Key, byteArray: ByteArray, mode: Int): ByteArray {
val cipher = provideCipher()
cipher.init(mode, key)
val outputStream = ByteArrayOutputStream()
val cipherStream = CipherOutputStream(outputStream, cipher)
cipherStream.write(byteArray)
cipherStream.close()
val processedKey = outputStream.toByteArray()
outputStream.close()
return processedKey
}
private fun provideCipher(): Cipher {
return if (isPreM())
Cipher.getInstance(TRANSFORMATION, CIPHER_PROVIDER)
else
Cipher.getInstance(TRANSFORMATION)
}
private fun getOrCreateKey(context: Context): KeyStore.PrivateKeyEntry {
val keystore = KeyStore.getInstance(KEY_STORE_PROVIDER)
keystore.load(null)
if (keystore.containsAlias(alias).not()) {
val generator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, KEY_STORE_PROVIDER)
val spec = if (isPreM()) keyPairGeneratorSpecPreM(context) else keyPairGeneratorSpecM()
generator.initialize(spec)
generator.generateKeyPair()
}
return keystore.getEntry(alias, null) as KeyStore.PrivateKeyEntry
}
private fun isPreM() = Build.VERSION.SDK_INT < Build.VERSION_CODES.M
private fun keyPairGeneratorSpecPreM(context: Context): KeyPairGeneratorSpec {
val start = Calendar.getInstance()
val end = Calendar.getInstance()
end.add(Calendar.YEAR, 10)
return KeyPairGeneratorSpec.Builder(context)
.setAlias(alias)
.setSerialNumber(BigInteger.ONE)
.setStartDate(start.time)
.setEndDate(end.time)
.setSubject(X500Principal(DISTINGUISHED))
.build()
}
@TargetApi(Build.VERSION_CODES.M)
private fun keyPairGeneratorSpecM(): KeyGenParameterSpec {
return KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
or KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY)
.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
.setBlockModes(KeyProperties.BLOCK_MODE_ECB)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
.build()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment