Поскольку веб-сайт моей школы слишком сложен в использовании, в прошлом году я решил написать мобильное приложение, чтобы сделать его более удобным для пользователей. Для этого я использовал Jsoup и другие утилиты.
Я обнаружил, что в последнее время им стало намного сложнее пользоваться, и на веб-сайте появилось больше страниц авторизации. Я потратил целый день, чтобы узнать, как перевести код с JS на Kotlin.
Есть ли способ получить зашифрованный текст значений или как сделать код работоспособным в оценщике JavaScript Rhino.
Код encryptBase64
такой, я не знаю, как получить ciphertext
в Котлине
encryptBase64: function (e) {//e=password
var r = f();
var t = s.default.MD5(r);
console.info("r = "+r);//r=GN12MVOFWVZJ51KZ
console.info("t = "+t);//r=GN12MVOFWVZJ51KZ
console.info("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.info("o = "+o)//o=tAzMY2LKjgC96ZJHXYjorazfL56s//vgFgoerDmaH3g=
console.info("n = "+n)//n=GQNoFJVGL5qdLyb7KxFXAA==
var o_cipher=o.ciphertext
var n_cipher=n.ciphertext
console.info("o_cipher = "+o_cipher)o_cipher=b40ccc6362ca8e00bde992475d88e8adacdf2f9eacfffbe0160a1eac399a1f78
console.info("n_cipher = "+n_cipher)//n_cipher=1903681495462f9a9d2f26fb2b115700
var i = s.default.lib.WordArray.create([].concat(c(o_cipher.words), c(n_cipher.words)));
console.info("i = "+i)//i=b40ccc6362ca8e00bde992475d88e8adacdf2f9eacfffbe0160a1eac399a1f781903681495462f9a9d2f26fb2b115700
var stringifiedI=s.default.enc.Base64.stringify(i)
console.info("stringified i = "+stringifiedI)//stringified i=tAzMY2LKjgC96ZJHXYjorazfL56s//vgFgoerDmaH3gZA2gUlUYvmp0vJvsrEVcA
return stringifiedI
}
Я подумал, что ciphertext
может быть чем-то вроде AES, а не RSA или MD5, потому что сервер может расшифровать его без ключа (я не нашел ничего, кроме зашифрованного пароля).
Просить школу о помощи невозможно, моя школа это не одобряет.
Полный код приведен ниже (я думаю, это что-то вроде CryptoJS): Полный код на GitHub
Я создал функцию расширения шифрования/дешифрования aes следующим образом: aes.kt
И js.kt, содержащий callJs()
функцию.
Я пытался использовать 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
}
И не дает правильного результата.
encryptBase64()
в Котлине или Java🤔 А знаете ли вы, что...
JavaScript можно использовать для создания видеоигр, как 2D, так и 3D, с использованием библиотеки Three.js.
Для корректного выполнения функции h.encryptBase64()
требуется WordArray l
, который либо устанавливается равным MD5-хешу пароля e
с помощью функции h.setSecret(e)
, либо альтернативно может быть определен непосредственно как любой 16-байтовый WordArray, например l = CryptoJS.enc.Utf8.parse('0123456789012345')
.
Затем функция h.encryptBase64()
выполняет следующее:
f()
генерируется случайная строка из 16 символов r
, состоящая из последовательности символов из p
.r
генерируется хеш MD5 t
.r
шифруется с помощью AES в режиме CBC с дополнением PKCS#7 (зашифрованный текст o_cipher
). l
используется как для ключа, так и для капельницы.n_cipher
). t
используется как для ключа, так и для капельницы.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()
}
Следующим шагом является определение функции, которая выполняет шифрование с использованием AES в режиме CBC и заполнения PKCS#7, например:
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. Код Kotlin можно считать совместимым, если этот код дешифрования JavaScript также расшифровывает зашифрованный текст, сгенерированный кодом 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.info("r = "+r);
console.info("t = "+t);
console.info("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.info("o = "+o)
console.info("n = "+n)
var o_cipher=o.ciphertext
var n_cipher=n.ciphertext
console.info("o_cipher = "+o_cipher)
console.info("n_cipher = "+n_cipher)
var i = CryptoJS.lib.WordArray.create([].concat(c(o_cipher.words), c(n_cipher.words)));
console.info("i = "+i)
var stringifiedI=CryptoJS.enc.Base64.stringify(i)
console.info("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.info('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.info('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.info('Decrypted:', e.toString(CryptoJS.enc.Utf8))
<script src = "https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js"></script>