0

I have just started working on the Kotlin and my code is performing a normal operation. I need to call a function from a class which is defined in another file and this file does not have class. For example,

File1.kt

The main function is called from this file and defining an object of a class and accessing the class functions here but this class is defined in the File2.kt file.

fun main(args: Array<String>) {
    val secretKey: String = "662ede816988e58fb6d057d9d85605e0"
    val initVector = "de816988e58f"

    var encryptor: AESEncryptor = AESEncryptor()
    val encryptedValue: String? =encryptor.encrypt("This is the first code for encryption in Kotlin.", secretKey, initVector)
    println(encryptedValue)

    val decryptedValue: String? =encryptor.decryptWithAES(secretKey, encryptedValue, initVector)
    println(decryptedValue)
}

File2.kt

A class is defined in this file and this class needs to access the functions which are defined in the File3.kt file.

import java.io.UnsupportedEncodingException
import java.security.InvalidKeyException
import java.security.NoSuchAlgorithmException
import javax.crypto.*
import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.SecretKeySpec

class AESEncryptor {

    fun encrypt(strToEncrypt: String, secret_key: String, iv_key: String): String? {

        var keyBytes: ByteArray
        var ivKeyBytes: ByteArray

        try {
            keyBytes = secret_key.toByteArray(charset("UTF8"))
            ivKeyBytes = iv_key.toByteArray(charset("UTF8"))
            val skey = SecretKeySpec(keyBytes, "AES")

            val iv = GCMParameterSpec(128, ivKeyBytes, 0, 12)
            val input = strToEncrypt.toByteArray(charset("UTF8"))

            synchronized(Cipher::class.java) {
                val cipher = Cipher.getInstance("AES/GCM/NoPadding")
                cipher.init(Cipher.ENCRYPT_MODE, skey, iv)

                val cipherText = ByteArray(cipher.getOutputSize(input.size))
                var ctLength = cipher.update(
                    input, 0, input.size,
                    cipherText, 0
                )
                ctLength += cipher.doFinal(cipherText, ctLength)
                return cipherText.encodeBase64ToString()
            }
        } catch (uee: UnsupportedEncodingException) {
            uee.printStackTrace()
        } catch (ibse: IllegalBlockSizeException) {
            ibse.printStackTrace()
        } catch (bpe: BadPaddingException) {
            bpe.printStackTrace()
        } catch (ike: InvalidKeyException) {
            ike.printStackTrace()
        } catch (nspe: NoSuchPaddingException) {
            nspe.printStackTrace()
        } catch (nsae: NoSuchAlgorithmException) {
            nsae.printStackTrace()
        } catch (e: ShortBufferException) {
            e.printStackTrace()
        }

        return null
    }

    fun decryptWithAES(key: String, strToDecrypt: String?, iv_key: String): String? {
        //Security.addProvider(BouncyCastleProvider())
        var keyBytes: ByteArray
        var ivKeyBytes: ByteArray
        var encryptor: AESEncryptor = AESEncryptor()
        try {
            keyBytes = key.toByteArray(charset("UTF8"))
            ivKeyBytes = iv_key.toByteArray(charset("UTF8"))
            val skey = SecretKeySpec(keyBytes, "AES")
            //val iv = GCMParameterSpec(ivKeyBytes)
            val iv = GCMParameterSpec(128, ivKeyBytes, 0, 12)

            val input = (strToDecrypt?.trim { it <= ' ' }?.toByteArray(charset("UTF8")))?.decodeBase64()

            synchronized(Cipher::class.java) {
                val cipher = Cipher.getInstance("AES/GCM/NoPadding")
                cipher.init(Cipher.DECRYPT_MODE, skey, iv)

                val plainText = ByteArray(cipher.getOutputSize(input?.size!!))
                var ptLength = cipher.update(input, 0, input?.size!!, plainText, 0)
                ptLength += cipher.doFinal(plainText, ptLength)
                val decryptedString = String(plainText)
                return decryptedString.trim { it <= ' ' }
            }
        } catch (uee: UnsupportedEncodingException) {
            uee.printStackTrace()
        } catch (ibse: IllegalBlockSizeException) {
            ibse.printStackTrace()
        } catch (bpe: BadPaddingException) {
            bpe.printStackTrace()
        } catch (ike: InvalidKeyException) {
            ike.printStackTrace()
        } catch (nspe: NoSuchPaddingException) {
            nspe.printStackTrace()
        } catch (nsae: NoSuchAlgorithmException) {
            nsae.printStackTrace()
        } catch (e: ShortBufferException) {
            e.printStackTrace()
        }

        return null
    }
}

File3.kt

Only a group of functions are defined in this form.

import java.io.ByteArrayOutputStream

public fun String.encodeBase64ToString(): String = String(this.toByteArray().encodeBase64())
fun String.encodeBase64ToByteArray(): ByteArray = this.toByteArray().encodeBase64()
fun ByteArray.encodeBase64ToString(): String = String(this.encodeBase64())

fun String.decodeBase64(): String = String(this.toByteArray().decodeBase64())
fun String.decodeBase64ToByteArray(): ByteArray = this.toByteArray().decodeBase64()
fun ByteArray.decodeBase64ToString(): String = String(this.decodeBase64())

public fun ByteArray.encodeBase64(): ByteArray {
    val table = (CharRange('A', 'Z') + CharRange('a', 'z') + CharRange('0', '9') + '+' + '/').toCharArray()
    val output = ByteArrayOutputStream()
    var padding = 0
    var position = 0
    while (position < this.size) {
        var b = this[position].toInt() and 0xFF shl 16 and 0xFFFFFF
        if (position + 1 < this.size) b = b or (this[position + 1].toInt() and 0xFF shl 8) else padding++
        if (position + 2 < this.size) b = b or (this[position + 2].toInt() and 0xFF) else padding++
        for (i in 0 until 4 - padding) {
            val c = b and 0xFC0000 shr 18
            output.write(table[c].toInt())
            b = b shl 6
        }
        position += 3
    }
    for (i in 0 until padding) {
        output.write('='.toInt())
    }
    return output.toByteArray()
}

fun ByteArray.decodeBase64(): ByteArray {
    val table = intArrayOf(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1,
        -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
        -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)

    val output = ByteArrayOutputStream()
    var position = 0
    while (position < this.size) {
        var b: Int
        if (table[this[position].toInt()] != -1) {
            b = table[this[position].toInt()] and 0xFF shl 18
        } else {
            position++
            continue
        }
        var count = 0
        if (position + 1 < this.size && table[this[position + 1].toInt()] != -1) {
            b = b or (table[this[position + 1].toInt()] and 0xFF shl 12)
            count++
        }
        if (position + 2 < this.size && table[this[position + 2].toInt()] != -1) {
            b = b or (table[this[position + 2].toInt()] and 0xFF shl 6)
            count++
        }
        if (position + 3 < this.size && table[this[position + 3].toInt()] != -1) {
            b = b or (table[this[position + 3].toInt()] and 0xFF)
            count++
        }
        while (count > 0) {
            val c = b and 0xFF0000 shr 16
            output.write(c.toChar().toInt())
            b = b shl 8
            count--
        }
        position += 4
    }
    return output.toByteArray()
}

I need to use encodeBase64ToString function and other functions in the File2.kt (AESEncryptor.kt). Can I do this or not?

Can anyone help me with this?

Amit Raj
  • 1,358
  • 3
  • 22
  • 47
  • Please include some code, even not working so far – Nikolai Shevchenko Dec 11 '19 at 11:08
  • @NikolaiShevchenko I have added the code. Can you please help me with this? – Amit Raj Dec 11 '19 at 11:19
  • @NikolaiShevchenko, Thanks for your reply. I have edited the code which is working properly with fixed key and fixed vector. Can you please help me to use random generated key and random generated vector in my code? – Amit Raj Dec 13 '19 at 10:11

1 Answers1

4

Since you declare functions from File3.kt as extension functions, you should use them with proper syntax.

So, not

return encodeBase64ToString(cipherText)

but

return cipherText.encodeBase64ToString()
Nikolai Shevchenko
  • 7,083
  • 8
  • 33
  • 42