如何在 Kotlin 中获取密文?

问题描述 投票:0回答:1

由于我学校的网站太难使用,去年我决定编写一个移动应用程序以获得更好的用户体验。 我已经使用 Jsoup 和其他实用程序来制作它。

最近发现使用起来比较困难,而且网站的授权页面也多了。 我花了一整天的时间才找到如何将代码从 JS 翻译成 Kotlin。


有没有办法可以获取值的密文或如何使代码在Rhino JavaScript评估器中运行

encryptBase64
代码是这样的,我不知道如何在Kotlin中获得
ciphertext

encryptBase64: function (e) {//e=password
    var r = f();
    var t = s.default.MD5(r);
    console.log("r="+r);//r=GN12MVOFWVZJ51KZ
    console.log("t="+t);//r=GN12MVOFWVZJ51KZ
    console.log("l="+l);//l=c2df1fd689074ff84521cea43a677bbf

    var o = s.default.AES.encrypt(r, l, {iv: l, mode: a, padding: d});
    var n = s.default.AES.encrypt(e, t, {iv: t, mode: a, padding: d});
    console.log("o="+o)//o=tAzMY2LKjgC96ZJHXYjorazfL56s//vgFgoerDmaH3g=
    console.log("n="+n)//n=GQNoFJVGL5qdLyb7KxFXAA==
    var o_cipher=o.ciphertext

    var n_cipher=n.ciphertext
    console.log("o_cipher="+o_cipher)o_cipher=b40ccc6362ca8e00bde992475d88e8adacdf2f9eacfffbe0160a1eac399a1f78
    console.log("n_cipher="+n_cipher)//n_cipher=1903681495462f9a9d2f26fb2b115700
    var i = s.default.lib.WordArray.create([].concat(c(o_cipher.words), c(n_cipher.words)));

    console.log("i="+i)//i=b40ccc6362ca8e00bde992475d88e8adacdf2f9eacfffbe0160a1eac399a1f781903681495462f9a9d2f26fb2b115700
    var stringifiedI=s.default.enc.Base64.stringify(i)
    console.log("stringified i="+stringifiedI)//stringified i=tAzMY2LKjgC96ZJHXYjorazfL56s//vgFgoerDmaH3gZA2gUlUYvmp0vJvsrEVcA
    return stringifiedI
}

我认为

ciphertext
可能是类似AES的东西,而不是RSA或MD5,因为服务器可以在没有密钥的情况下解密它(除了加密的密码之外我没有找到其他任何东西)。

向学校求助是不可能的,我的学校不批准。

完整代码如下(我认为它类似于CryptoJS): GitHub 中的完整代码

我尝试了什么

  • 我尝试用 Kotlin 编写一些代码来执行类似的功能,但它无法正常工作。

我创建了一个 aes 加密/解密扩展函数,如下所示: aes.kt

还有一个包含 callJs()函数的

js.kt

我尝试使用

callJs()
来获得结果。

//fun main
    val a= callJs(JS.encryptCode,"aesOene","encryptBase64","password")
    println(a)
object JS{
    val encryptCode: String by lazy {
        val bytes = this::class.java.getResourceAsStream("/aesOene.js")!!.readBytes()
        String(bytes)
    }
}

我得到了这个

Exception in thread "main" org.mozilla.javascript.EcmaError: ReferenceError: "window" is not defined. (aesOene#1)

比我尝试用这个来实现

encryptBase64()

// fun main
    val b=encryptBase64("password")
    println(b)

fun aesKeyBuilder():String{
    val p= arrayListOf("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z")
    val builder=StringBuilder()
    for (t in 0 until 16){
        val o= ceil(35*Math.random()).toInt()
        builder.append(p[o])
    }
    return builder.toString()
}
fun encryptBase64(e:String):String{
    val r=aesKeyBuilder()
    val l="ass-apex".md5
    val t=r.md5
    val o=r.encryptByAES(l,)
    val n=e.encryptByAES(t,)
    val i=o+n
    return i.base64
}

并且没有得到正确的结果。

我在期待什么

  • 在 Kotlin 或 Java 中获取
    encryptBase64()
    结果的方法
javascript kotlin encryption
1个回答
0
投票

为了正确执行,

h.encryptBase64()
函数需要一个WordArray
l
,它可以使用函数
e
设置为等于密码
h.setSecret(e)
的MD5哈希值,也可以直接定义为任何16个字节WordArray,例如
l = CryptoJS.enc.Utf8.parse('0123456789012345')

h.encryptBase64()
函数执行以下操作:

  • 通过函数
    f()
    生成一个随机的16个字符的字符串
    r
    ,它由
    p
    中的字符序列组成。
  • r
    生成 MD5 哈希值
    t
  • r
    在 CBC 模式下使用 AES 进行加密,并使用 PKCS#7 填充(密文
    o_cipher
    )。
    l
    用于密钥和 IV。
  • 明文使用 CBC 模式下的 AES 进行加密,并使用 PKCS#7 填充(密文
    n_cipher
    )。
    t
    用于密钥和 IV。
  • 将密文
    o_cipher
    n_cipher
    连接起来(结果
    i
    )。
  • i
    经过 Base64 编码并返回。

请注意,当前的 JavaScript 代码过于复杂且充满漏洞(例如 MD5、

Math.Random
)。
通常的方法是使用可靠的密钥派生函数(至少 PBKDF2)与随机的非秘密盐结合使用来生成用于加密明文的密钥。
盐将与密文一起传递到解密方,以便重建密钥。
实际上,在移植之前修改 JavaScript 代码是有意义的,但由于您可能对未更改的代码进行 1:1 移植感兴趣,因此描述如下:

  • 您发布的

    aesKeyBuilder()
    功能原则上可以用作
    f()
    的对应功能。但是,
    Math.random()
    应替换为
    SecureRandom#nextDouble()
    ,因为
    Math.random()
    不具有加密安全性:

    import java.security.SecureRandom
    ...
    fun aesKeyBuilder(): String {
        val p = arrayListOf("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z")
        val builder = StringBuilder()
        val secureRandom = SecureRandom()
        for (t in 0 until 16){
            val o= ceil(35 * secureRandom.nextDouble()).toInt()
            builder.append(p[o])
        }
        return builder.toString()
    }
    
  • 下一步是定义一个函数,以 CBC 模式和 PKCS#7 填充执行 AES 加密,例如:

    import javax.crypto.Cipher
    import javax.crypto.spec.IvParameterSpec
    import javax.crypto.spec.SecretKeySpec
    ...
    fun aesEncrypt(key: ByteArray, data: ByteArray): ByteArray {
        val secretKeySpec = SecretKeySpec(key, "AES")
        val ivParameterSpec = IvParameterSpec(key)
        val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec)
        return cipher.doFinal(data)
    }
    
  • 这样,JavaScript 代码的逻辑就可以移植到 Kotlin 中,如下所示:

    import android.util.Base64
    import java.security.MessageDigest
    ...
    val password = "my passphrase"
    val plaintext = "The quick brown fox jumps over the lazy dog"
    val key_l = MessageDigest.getInstance("MD5").digest(password.toByteArray())
    val key_r = aesKeyBuilder().toByteArray()
    val key_t = MessageDigest.getInstance("MD5").digest(key_r)
    val encKey_o = aesEncrypt(key_l, key_r)
    val ciphertext_n = aesEncrypt(key_t, plaintext.toByteArray())
    val result_i = encKey_o + ciphertext_n
    val resultB64 = Base64.encodeToString(result_i, Base64.NO_WRAP);
    

测试:

为了进行测试,最好实现一段 JavaScript 解密代码,对 JavaScript 代码生成的密文进行解密。如果这段 JavaScript 解密代码也能解密 Kotlin 代码生成的密文,则可以认为 Kotlin 代码是兼容的。

以下 JavaScript 代码成功执行了此类测试:

var a = CryptoJS.mode.CBC, 
    d = CryptoJS.pad.Pkcs7, l = "", u = "",
    p = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"],
    f = function () { 
        return function (e) {
            for (var r = "", t = 0; t < e; t++) {
                var o = Math.ceil(35 * Math.random());
                r += p[o]
            }
            return r
        }(16)
    }, 
    h = { 
        encryptBase64: function (e) {
            var r = f();
            var t = CryptoJS.MD5(r);
            console.log("r="+r);
            console.log("t="+t);
            console.log("l="+l);
                        
            var o = CryptoJS.AES.encrypt(r, l, {iv: l, mode: a, padding: d});
            var n = CryptoJS.AES.encrypt(e, t, {iv: t, mode: a, padding: d});
            console.log("o="+o)
            console.log("n="+n)
            var o_cipher=o.ciphertext
                        
            var n_cipher=n.ciphertext
            console.log("o_cipher="+o_cipher)
            console.log("n_cipher="+n_cipher)
            var i = CryptoJS.lib.WordArray.create([].concat(c(o_cipher.words), c(n_cipher.words)));
                        
            console.log("i="+i)
            var stringifiedI=CryptoJS.enc.Base64.stringify(i)
            console.log("stringified i="+stringifiedI)
            return stringifiedI
        }, 
        setSecret: function (e) {
            u = e, l = CryptoJS.MD5(u)
        }
    };

function c(e) {
    if (Array.isArray(e)) {
        for (var r = 0, t = Array(e.length); r < e.length; r++) t[r] = e[r];
        return t
    }
    return Array.from(e)
}
      
// encryption
h.setSecret('my passphrase') 
var ciphertext = h.encryptBase64('The quick brown fox jumps over the lazy dog')
console.log('Ciphertext:', ciphertext)

// decryption from JavaScript ciphertext
var ciphertextWA = CryptoJS.enc.Base64.parse(ciphertext)
var encryptedKeyWA = CryptoJS.lib.WordArray.create(ciphertextWA.words.slice(0, 256 / 32))
var encryptedDataWA = CryptoJS.lib.WordArray.create(ciphertextWA.words.slice(256 / 32))
var l = CryptoJS.MD5('my passphrase') // apply passphrase from setSecret
var r = CryptoJS.AES.decrypt({ciphertext: encryptedKeyWA}, l, {iv: l, mode: a, padding: d})
var t = CryptoJS.MD5(r)
var e = CryptoJS.AES.decrypt({ciphertext: encryptedDataWA}, t, {iv: t, mode: a, padding: d})
console.log('Decrypted:', e.toString(CryptoJS.enc.Utf8))

// decryption from Kotlin ciphertext 
var ciphertextFromKotlin = 'rFXxMQjsIhfCOPiIbgLTJJioVqb7ONCp9Tx3WoTpbF9QxlJNdpR4r6mPtBbnSsEl9PL30hoER6P+RJS9hVUbs/i7ipxhwqiFEbbH97ryZmM='
var ciphertextWA = CryptoJS.enc.Base64.parse(ciphertextFromKotlin)
var encryptedKeyWA = CryptoJS.lib.WordArray.create(ciphertextWA.words.slice(0, 256 / 32))
var encryptedDataWA = CryptoJS.lib.WordArray.create(ciphertextWA.words.slice(256 / 32))
var l = CryptoJS.MD5('my passphrase') // apply passphrase from Kotlin code
var r = CryptoJS.AES.decrypt({ciphertext: encryptedKeyWA}, l, {iv: l, mode: a, padding: d})
var t = CryptoJS.MD5(r)
var e = CryptoJS.AES.decrypt({ciphertext: encryptedDataWA}, t, {iv: t, mode: a, padding: d})
console.log('Decrypted:', e.toString(CryptoJS.enc.Utf8))
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js"></script>

© www.soinside.com 2019 - 2024. All rights reserved.