Created
November 5, 2016 10:34
-
-
Save rovkinmax/3cbd257027ca5affcce7c13d6c61b44b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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