Пакетное шифрование
Представлен пример пакетного шифрования данных. Во-первых, напишем сам класс шифрования, RSAencryption: class RSAencryption(context: Context) { companion object { private const val ALIAS = "yourCompany" private const val KEYSTORE_TYPE = "AndroidKeyStore" private const val ALGORITHM = "RSA" private const val BLOCK_MODE = "ECB" private const val PADDING = "PKCS1Padding" const val KEY_SIZE = 512 const val PADDING_OFFSET = 11 } private val keyStore: KeyStore private val context: Context init { this.context = context keyStore = KeyStore.getInstance(KEYSTORE_TYPE) keyStore.load(null) } @Throws(KeyStoreException::class) fun isExistsKeyPair(): Boolean { return keyStore.containsAlias(ALIAS) } @Throws(KeyStoreException::class) fun deleteEntry(): Boolean { if (!isExistsKeyPair()) return false keyStore.deleteEntry(ALIAS) return true } @Throws(KeyStoreException::class) fun getExpiredDate(): Date? { if (!isExistsKeyPair()) return null val privateKeyEntry = keyStore.getEntry(ALIAS, null) as KeyStore.PrivateKeyEntry val cerificate = privateKeyEntry.certificate as X509Certificate return cerificate.notAfter } fun generateKeyPair(): Single{ val notBefore = Calendar.getInstance() val notAfter = Calendar.getInstance() notAfter.add(Calendar.YEAR, 1) return Single.create() { try { val generator: KeyPairGenerator = KeyPairGenerator.getInstance( ALGORITHM, KEYSTORE_TYPE ) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { val spec = KeyGenParameterSpec.Builder( ALIAS, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT ) .setCertificateSubject(X500Principal("CN=" + ALIAS)) .setDigests(KeyProperties.DIGEST_SHA256) .setCertificateSerialNumber(BigInteger.TEN) .setCertificateNotBefore(notBefore.getTime()) .setCertificateNotAfter(notAfter.getTime()) .setKeySize(KEY_SIZE) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1) .build() generator.initialize(spec) } else { @Suppress("DEPRECATION") @SuppressLint("WrongConstant") val spec = KeyPairGeneratorSpec.Builder(context) .setAlias(ALIAS) .setKeyType(ALGORITHM) .setKeySize(KEY_SIZE) .setSubject(X500Principal("CN=" + ALIAS)) .setSerialNumber(BigInteger.TEN) .setStartDate(notBefore.getTime()) .setEndDate(notAfter.getTime()) .build() generator.initialize(spec) } val keyPair = generator.generateKeyPair() it.onSuccess(keyPair) } catch (e: NoSuchAlgorithmException) { it.onError(e) } catch (e: InvalidAlgorithmParameterException) { it.onError(e) } catch (e: Exception) { it.onError(e) } } } fun encrypt(inBytes: ByteArray): ByteArray { if (inBytes.isEmpty()) return ByteArray(0) val privateKeyEntry = keyStore.getEntry(ALIAS, null) as KeyStore.PrivateKeyEntry val cerificate = privateKeyEntry.certificate val publicKey = cerificate.publicKey val inCipher = Cipher.getInstance("$ALGORITHM/$BLOCK_MODE/$PADDING") inCipher.init(Cipher.ENCRYPT_MODE, publicKey) val encodedBytes = inCipher.doFinal(inBytes) return encodedBytes } fun decrypt(encodedBytes: ByteArray): ByteArray { if (encodedBytes.isEmpty()) return ByteArray(0) val privateKeyEntry = keyStore.getEntry(ALIAS, null) as KeyStore.PrivateKeyEntry val privateKey = privateKeyEntry.privateKey val outCipher = Cipher.getInstance("$ALGORITHM/$BLOCK_MODE/$PADDING") outCipher.init(Cipher.DECRYPT_MODE, privateKey) val decodedBytes = outCipher.doFinal(encodedBytes) return decodedBytes } } Далее создадим класс с исходным текстом для шифрования, MainModel: object MainModel { const val plainText = "Сегодня утром на Брикстон-Роуд, между\n" + "трактиром \"Белый олень\" и Холленд-Грув,\n" + "найдено золотое кольцо. Обращаться к\n" + "доктору Уотсону, Бейкер-Стрит, 221-Б, от\n" + "восьми до десяти вечера." } Потом напишем класс обработки ViewModel: class MainViewModel : ViewModel() { private var disposables: CompositeDisposable var plainText: MutableLiveData var encodingText: MutableLiveData var decodingText: MutableLiveData private lateinit var rsaEncryption: RSAencryption init { disposables = CompositeDisposable() plainText = MutableLiveData() encodingText = MutableLiveData() decodingText = MutableLiveData() } fun afterInit(appContext: Context) { plainText.value = MainModel.plainText rsaEncryption = RSAencryption(appContext) if (!rsaEncryption.isExistsKeyPair()) { rsaEncryption.deleteEntry() disposables.add( rsaEncryption.generateKeyPair() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe() ) } } fun onEncodeClick(s: String) { if (!rsaEncryption.isExistsKeyPair()) return if (s.isNotEmpty()) { val blockSize = RSAencryption.KEY_SIZE / 8 - RSAencryption.PADDING_OFFSET val list = splitByteArray(s.toByteArray(), blockSize) val output = ByteArrayOutputStream() for (item in list) { val enc = rsaEncryption.encrypt(item) output.write(enc) } encodingText.value = Base64.encodeToString(output.toByteArray(), Base64.NO_WRAP) decodingText.value = "" output.close() } } fun onDecodeClick(s: String) { if (!rsaEncryption.isExistsKeyPair()) return if (s.isNotEmpty()) { val blockSize = RSAencryption.KEY_SIZE / 8 val list = splitByteArray(Base64.decode(s, Base64.NO_WRAP) , blockSize) val output = ByteArrayOutputStream() for (item in list) { val dec = rsaEncryption.decrypt(item) output.write(dec) } decodingText.value = String(output.toByteArray()) output.close() } } private fun splitByteArray(array: ByteArray, blockSize: Int): MutableList { val result = mutableListOf () var offset = 0 while (offset < array.size) { val a = Arrays.copyOfRange(array, offset, Math.min(offset + blockSize, array.size)) result.add(a) offset += blockSize } return result } override fun onCleared() { super.onCleared() disposables.clear() } } Ну, а теперь, сама Activity: class MainActivity : AppCompatActivity() { private lateinit var viewModel: MainViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) initViewModel() } private fun initViewModel() { viewModel = ViewModelProviders.of(this@MainActivity).get(MainViewModel::class.java) viewModel.plainText.observe(this@MainActivity, Observer { s-> et_plain_text.setText(s) }) viewModel.encodingText.observe(this@MainActivity, Observer { s-> tv_encoding_text.setText(s) }) viewModel.decodingText.observe(this@MainActivity, Observer { s-> tv_decoding_text.setText(s) }) btn_encode.setOnClickListener { viewModel.onEncodeClick(et_plain_text.text.toString()) } btn_decode.setOnClickListener { viewModel.onDecodeClick(tv_encoding_text.text.toString()) } viewModel.afterInit(this@MainActivity.applicationContext) } }
Запускаем программу и получаем:
Автор статьи: Дмитрий Изергин