Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * Copyright 2020 Punch Through Design LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package com.punchthrough.blestarterappandroid
- import android.util.Base64
- import java.security.KeyFactory
- import java.security.MessageDigest
- import java.security.PrivateKey
- import java.security.spec.PKCS8EncodedKeySpec
- import java.util.Arrays
- import javax.crypto.Cipher
- import javax.crypto.spec.IvParameterSpec
- import javax.crypto.spec.SecretKeySpec
- class TestRsa {
- private var SessionKey: ByteArray? = null
- private var SessionIV: ByteArray? = null
- private val SHA1_LEN = 20 //SHA1 result length
- private val AES_LEN = 16 //AES block size
- private val KEY_LEN = 64 //Length of RSA encoded AES session keys (with SHA1 and padding)
- private val CMD_LEN = 32 //Length of AES encoded command / status (with SHA1 and padding)
- fun getPrivateKey(): PrivateKey? {
- try {
- val kf = KeyFactory.getInstance("RSA")
- val res = kf.generatePrivate(
- PKCS8EncodedKeySpec(
- Base64.decode(
- """
- MIICWwIBAAKBgQDhWLOSU0FxsQkkLY2qghpG4L3/yoTlYJ39acLqHhOBXWWK5wRc
- Ms2Xk54Bo8ZaOmbzf9U+FmWwJzjtyTUcYDUl4WsU8WJ30dC+ncbLWCSeq7ltvL2f
- Jmc3anaYRrvFLJbZljQ1rZKROKcKgLahR4rCeatAhSNjdmZofNW4fWJpQwIDAQAB
- AoGAFYk/Io31x38Zj9oRdTxMdTEKwRS8Dhnlb3yskpuMoxGBRomc7cMzL9HKFeXV
- Ho/NtM0nD/FFbaGjlXuw9jguZY75G0gm6uULLh/k/5Y4Fx+wS7Mp2EOWtyI5rSbW
- DXYuWbcajLyx2+STjppj851Y1NoxDpJzu0QHyeuGv+g51jkCQQDsBbuDUONuPKLB
- KDb6Ff/axCvhTHergD2bFwA7pxDXd10EHvJq0nUFDsZOyxJhfVWgUCz7rba+o/S4
- FeAGIurbAkEA9GujL+BVe57/qyqO48QWL8+u4z0fKkbnZSTeVhD8LYAMnPX2782J
- lqxMkWSpIYmC+gy6chaciaknYmoLJjxjuQJAJ4zWXSziz4gtpbx9ae7hzuDskXZk
- 30JAEIsMKPLX6aNA3P3qlWfq4AwXwwBYdimwfYqx3wK/CrcivO49egnD3QJAPdiq
- nyetma0+1knbhCiO0KRFhXxm0WTFkmNE2xRLKxw2lNTsGfuxL+4DJdsJrNHF0Y28
- 87di/rZNn+pjTdaECQJAIFxoxYwSIUyZpiTF/t7ceNr/7ADQIaJYpgsK8vrS56Fw
- EulO24ONOWs5GwuGp0Gk/PjBb4ZR20tVwGLXZi3/3A==
- """.trimIndent(),
- Base64.DEFAULT
- )
- )
- )
- return res
- } catch (e: Exception) {
- e.printStackTrace()
- }
- return null
- }
- fun setupSession(encodedKey: ByteArray): Boolean {
- SessionKey = null
- SessionIV = null
- val res = false
- try {
- //RSA decryption (used only here)
- val cipher = Cipher.getInstance("RSA")
- cipher.init(Cipher.DECRYPT_MODE, getPrivateKey())
- var decodedKey = cipher.doFinal(encodedKey)
- decodedKey =
- Arrays.copyOfRange(decodedKey, decodedKey.size - KEY_LEN, decodedKey.size)
- if (checkSHA(decodedKey)) {
- SessionKey = Arrays.copyOfRange(decodedKey, 0, AES_LEN)
- SessionIV = Arrays.copyOfRange(decodedKey, AES_LEN, AES_LEN * 2)
- return true
- }
- } catch (e: Exception) {
- e.printStackTrace()
- }
- return false
- }
- private fun checkSHA(`in`: ByteArray?): Boolean {
- try {
- val crypt =
- MessageDigest.getInstance("SHA-1")
- crypt.reset()
- crypt.update(Arrays.copyOfRange(`in`, 0, `in`!!.size - SHA1_LEN))
- val SHA = crypt.digest()
- val inSHA =
- Arrays.copyOfRange(`in`, `in`.size - SHA1_LEN, `in`.size)
- if (!Arrays.equals(SHA, inSHA)) {
- print("Decode fail")
- return false
- }
- return true
- } catch (e: Exception) {
- e.printStackTrace()
- }
- return false
- }
- private fun cryptAES(opmode: Int, `in`: ByteArray?): ByteArray? {
- try {
- val IV = Arrays.copyOf(SessionIV, SessionIV!!.size)
- val cipher = Cipher.getInstance("AES/CBC/NoPadding")
- cipher.init(
- opmode,
- SecretKeySpec(SessionKey, "AES"),
- IvParameterSpec(IV)
- )
- val out = cipher.doFinal(`in`)
- return out
- } catch (e: Exception) {
- e.printStackTrace()
- }
- return null
- }
- private fun cryptAES(mode: Int, base64: String): String {
- val out = cryptAES(mode, Base64.decode(base64, Base64.DEFAULT))
- val res = Base64.encodeToString(out, Base64.DEFAULT).trim('\n')
- return res
- }
- private fun setupSession(base64Encoded: String): Boolean {
- return setupSession(Base64.decode(base64Encoded, Base64.DEFAULT))
- }
- fun test(): Boolean {
- // RSA
- val RSA_BASE64_ENCODED = "hIThGsuxSQDcypPVVijM58KTUo0neU6ESSPf2N1E1JxiYbGdRrTEdNCO2CB73LNl/8Tk2eARhI2U\n" +
- "F2c9Npsf4kYrYAD6SBzwiXkcNEmSIyBibpfAxGHKNCmHPbQHU8ME37rcZ3RLHlQv5IAaZ+H4SXBg\n" +
- "/bb+oEYcw/7UIUyO/T8="
- if (!setupSession(RSA_BASE64_ENCODED)) {
- throw Exception("setupSession fail")
- }
- // AES ENCRYPT
- val AES_ENCRYPT = "zXqCnP0jj6wMDwVtNVMTktqn5jqzTt2mHDxJfMochB0="
- val AES_ENCRYP_COMP = "FlGFXeDrU5A3GPz75FmBhC/sguVvcllloFGh0hT1e5Q="
- if (cryptAES(Cipher.ENCRYPT_MODE, AES_ENCRYPT) != AES_ENCRYP_COMP) {
- throw Exception("cryptAES ENCRYPT_MODE fail")
- }
- // AES DECRYPT
- val AES_DECRYPT = "ch76T/vpXwjZMAN9S4b+DA4+pSs1sGAdqxsQbncW8sA="
- val AES_DECRYPT_COMP = "gODxATvDSPzt8rgr23Ye7xeron3SrBOtfdwWsTcXkJQ="
- if (cryptAES(Cipher.DECRYPT_MODE, AES_DECRYPT) != AES_DECRYPT_COMP) {
- throw Exception("cryptAES DECRYPT_MODE fail")
- }
- return true
- }
- }
Add Comment
Please, Sign In to add comment