refactor: remove duplicate implements in `StringUtils EncoerUtils`

Break Changes:
- this commit remove symmetric function in `JsExtensions`

Duplicate Implements:
- cn.hutool.core.util.HexUtil
io.legado.app.utils.StringUtils.hexStringToByte
io.legado.app.utils.StringUtils.byteToHexString
cn.hutool.core.util.HexUtil
- cn.hutool.crypto.symmetric.*
io.legado.app.utils.EncoderUtils
pull/2436/head
Xwite 2 years ago
parent 2f6cb17b4d
commit e8cca9b20d
  1. 9
      app/src/main/java/io/legado/app/data/entities/BaseSource.kt
  2. 355
      app/src/main/java/io/legado/app/help/JsExtensions.kt
  3. 3
      app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt
  4. 304
      app/src/main/java/io/legado/app/utils/EncoderUtils.kt
  5. 26
      app/src/main/java/io/legado/app/utils/StringUtils.kt

@ -2,6 +2,7 @@ package io.legado.app.data.entities
import android.util.Base64
import com.script.SimpleBindings
import cn.hutool.crypto.symmetric.AES
import io.legado.app.constant.AppConst
import io.legado.app.constant.AppLog
import io.legado.app.data.entities.rule.RowUi
@ -119,10 +120,7 @@ interface BaseSource : JsExtensions {
try {
val key = AppConst.androidId.encodeToByteArray(0, 16)
val cache = CacheManager.get("userInfo_${getKey()}") ?: return null
val encodeBytes = Base64.decode(cache, Base64.DEFAULT)
val decodeBytes = EncoderUtils.decryptAES(encodeBytes, key)
?: return null
return String(decodeBytes)
return AES(key).decryptStr(cache)
} catch (e: Exception) {
AppLog.put("获取登陆信息出错", e)
return null
@ -139,8 +137,7 @@ interface BaseSource : JsExtensions {
fun putLoginInfo(info: String): Boolean {
return try {
val key = (AppConst.androidId).encodeToByteArray(0, 16)
val encodeBytes = EncoderUtils.encryptAES(info.toByteArray(), key)
val encodeStr = Base64.encodeToString(encodeBytes, Base64.DEFAULT)
val encodeStr = AES(key).encryptBase64(info)
CacheManager.put("userInfo_${getKey()}", encodeStr)
true
} catch (e: Exception) {

@ -5,6 +5,7 @@ import android.util.Base64
import androidx.annotation.Keep
import cn.hutool.crypto.digest.DigestUtil
import cn.hutool.crypto.digest.HMac
import cn.hutool.core.util.HexUtil
import io.legado.app.constant.AppConst
import io.legado.app.constant.AppConst.dateFormat
import io.legado.app.constant.AppLog
@ -245,7 +246,7 @@ interface JsExtensions {
)
FileUtils.delete(path)
val file = FileUtils.createFileIfNotExist(path)
StringUtils.hexStringToByte(content).let {
HexUtil.decodeHex(content).let {
if (it.isNotEmpty()) {
file.writeBytes(it)
}
@ -510,7 +511,7 @@ interface JsExtensions {
val bytes = if (url.isAbsUrl()) {
AnalyzeUrl(url, source = getSource()).getByteArray()
} else {
StringUtils.hexStringToByte(url)
HexUtil.decodeHex(url)
}
val bos = ByteArrayOutputStream()
val zis = ZipInputStream(ByteArrayInputStream(bytes))
@ -647,356 +648,6 @@ interface JsExtensions {
//******************对称加密解密************************//
/////AES
/**
* AES 解码为 ByteArray
* @param str 传入的AES加密的数据
* @param key AES 解密的key
* @param transformation AES加密的方式
* @param iv ECB模式的偏移向量
*/
fun aesDecodeToByteArray(
str: String, key: String, transformation: String, iv: String
): ByteArray? {
return try {
EncoderUtils.decryptAES(
data = str.encodeToByteArray(),
key = key.encodeToByteArray(),
transformation,
iv.encodeToByteArray()
)
} catch (e: Exception) {
e.printOnDebug()
log(e.localizedMessage ?: "aesDecodeToByteArrayERROR")
null
}
}
/**
* AES 解码为 String
* @param str 传入的AES加密的数据
* @param key AES 解密的key
* @param transformation AES加密的方式
* @param iv ECB模式的偏移向量
*/
fun aesDecodeToString(
str: String, key: String, transformation: String, iv: String
): String? {
return aesDecodeToByteArray(str, key, transformation, iv)?.let { String(it) }
}
/**
* AES解码为String算法参数经过Base64加密
*
* @param data 加密的字符串
* @param key Base64后的密钥
* @param mode 模式
* @param padding 补码方式
* @param iv Base64后的加盐
* @return 解密后的字符串
*/
fun aesDecodeArgsBase64Str(
data: String,
key: String,
mode: String,
padding: String,
iv: String
): String? {
return EncoderUtils.decryptAES(
data.encodeToByteArray(),
Base64.decode(key, Base64.NO_WRAP),
"AES/${mode}/${padding}",
Base64.decode(iv, Base64.NO_WRAP)
)?.let { String(it) }
}
/**
* 已经base64的AES 解码为 ByteArray
* @param str 传入的AES Base64加密的数据
* @param key AES 解密的key
* @param transformation AES加密的方式
* @param iv ECB模式的偏移向量
*/
fun aesBase64DecodeToByteArray(
str: String, key: String, transformation: String, iv: String
): ByteArray? {
return try {
EncoderUtils.decryptBase64AES(
str.encodeToByteArray(),
key.encodeToByteArray(),
transformation,
iv.encodeToByteArray()
)
} catch (e: Exception) {
e.printOnDebug()
log(e.localizedMessage ?: "aesDecodeToByteArrayERROR")
null
}
}
/**
* 已经base64的AES 解码为 String
* @param str 传入的AES Base64加密的数据
* @param key AES 解密的key
* @param transformation AES加密的方式
* @param iv ECB模式的偏移向量
*/
fun aesBase64DecodeToString(
str: String, key: String, transformation: String, iv: String
): String? {
return aesBase64DecodeToByteArray(str, key, transformation, iv)?.let { String(it) }
}
/**
* 加密aes为ByteArray
* @param data 传入的原始数据
* @param key AES加密的key
* @param transformation AES加密的方式
* @param iv ECB模式的偏移向量
*/
fun aesEncodeToByteArray(
data: String, key: String, transformation: String, iv: String
): ByteArray? {
return try {
EncoderUtils.encryptAES(
data.encodeToByteArray(),
key = key.encodeToByteArray(),
transformation,
iv.encodeToByteArray()
)
} catch (e: Exception) {
e.printOnDebug()
log(e.localizedMessage ?: "aesEncodeToByteArrayERROR")
null
}
}
/**
* 加密aes为String
* @param data 传入的原始数据
* @param key AES加密的key
* @param transformation AES加密的方式
* @param iv ECB模式的偏移向量
*/
fun aesEncodeToString(
data: String, key: String, transformation: String, iv: String
): String? {
return aesEncodeToByteArray(data, key, transformation, iv)?.let { String(it) }
}
/**
* 加密aes后Base64化的ByteArray
* @param data 传入的原始数据
* @param key AES加密的key
* @param transformation AES加密的方式
* @param iv ECB模式的偏移向量
*/
fun aesEncodeToBase64ByteArray(
data: String, key: String, transformation: String, iv: String
): ByteArray? {
return try {
EncoderUtils.encryptAES2Base64(
data.encodeToByteArray(),
key.encodeToByteArray(),
transformation,
iv.encodeToByteArray()
)
} catch (e: Exception) {
e.printOnDebug()
log(e.localizedMessage ?: "aesEncodeToBase64ByteArrayERROR")
null
}
}
/**
* 加密aes后Base64化的String
* @param data 传入的原始数据
* @param key AES加密的key
* @param transformation AES加密的方式
* @param iv ECB模式的偏移向量
*/
fun aesEncodeToBase64String(
data: String, key: String, transformation: String, iv: String
): String? {
return aesEncodeToBase64ByteArray(data, key, transformation, iv)?.let { String(it) }
}
/**
* AES加密并转为Base64算法参数经过Base64加密
*
* @param data 被加密的字符串
* @param key Base64后的密钥
* @param mode 模式
* @param padding 补码方式
* @param iv Base64后的加盐
* @return 加密后的Base64
*/
fun aesEncodeArgsBase64Str(
data: String,
key: String,
mode: String,
padding: String,
iv: String
): String? {
return EncoderUtils.encryptAES2Base64(
data.encodeToByteArray(),
Base64.decode(key, Base64.NO_WRAP),
"AES/${mode}/${padding}",
Base64.decode(iv, Base64.NO_WRAP)
)?.let { String(it) }
}
/////DES
fun desDecodeToString(
data: String, key: String, transformation: String, iv: String
): String? {
return EncoderUtils.decryptDES(
data.encodeToByteArray(),
key.encodeToByteArray(),
transformation,
iv.encodeToByteArray()
)?.let { String(it) }
}
fun desBase64DecodeToString(
data: String, key: String, transformation: String, iv: String
): String? {
return EncoderUtils.decryptBase64DES(
data.encodeToByteArray(),
key.encodeToByteArray(),
transformation,
iv.encodeToByteArray()
)?.let { String(it) }
}
fun desEncodeToString(
data: String, key: String, transformation: String, iv: String
): String? {
return EncoderUtils.encryptDES(
data.encodeToByteArray(),
key.encodeToByteArray(),
transformation,
iv.encodeToByteArray()
)?.let { String(it) }
}
fun desEncodeToBase64String(
data: String, key: String, transformation: String, iv: String
): String? {
return EncoderUtils.encryptDES2Base64(
data.encodeToByteArray(),
key.encodeToByteArray(),
transformation,
iv.encodeToByteArray()
)?.let { String(it) }
}
//////3DES
/**
* 3DES解密
*
* @param data 加密的字符串
* @param key 密钥
* @param mode 模式
* @param padding 补码方式
* @param iv 加盐
* @return 解密后的字符串
*/
fun tripleDESDecodeStr(
data: String,
key: String,
mode: String,
padding: String,
iv: String
): String? {
return EncoderUtils.decryptDESede(
data.encodeToByteArray(),
key.encodeToByteArray(),
"DESede/${mode}/${padding}",
iv.encodeToByteArray()
)?.let { String(it) }
}
/**
* 3DES解密算法参数经过Base64加密
*
* @param data 加密的字符串
* @param key Base64后的密钥
* @param mode 模式
* @param padding 补码方式
* @param iv Base64后的加盐
* @return 解密后的字符串
*/
fun tripleDESDecodeArgsBase64Str(
data: String,
key: String,
mode: String,
padding: String,
iv: String
): String? {
return EncoderUtils.decryptDESede(
data.encodeToByteArray(),
Base64.decode(key, Base64.NO_WRAP),
"DESede/${mode}/${padding}",
Base64.decode(iv, Base64.NO_WRAP)
)?.let { String(it) }
}
/**
* 3DES加密并转为Base64
*
* @param data 被加密的字符串
* @param key 密钥
* @param mode 模式
* @param padding 补码方式
* @param iv 加盐
* @return 加密后的Base64
*/
fun tripleDESEncodeBase64Str(
data: String,
key: String,
mode: String,
padding: String,
iv: String
): String? {
return EncoderUtils.encryptDESede2Base64(
data.encodeToByteArray(),
key.encodeToByteArray(),
"DESede/${mode}/${padding}",
iv.encodeToByteArray()
)?.let { String(it) }
}
/**
* 3DES加密并转为Base64算法参数经过Base64加密
*
* @param data 被加密的字符串
* @param key Base64后的密钥
* @param mode 模式
* @param padding 补码方式
* @param iv Base64后的加盐
* @return 加密后的Base64
*/
fun tripleDESEncodeArgsBase64Str(
data: String,
key: String,
mode: String,
padding: String,
iv: String
): String? {
return EncoderUtils.encryptDESede2Base64(
data.encodeToByteArray(),
Base64.decode(key, Base64.NO_WRAP),
"DESede/${mode}/${padding}",
Base64.decode(iv, Base64.NO_WRAP)
)?.let { String(it) }
}
//******************消息摘要/散列消息鉴别码************************//
/**

@ -5,6 +5,7 @@ import android.util.Base64
import androidx.annotation.Keep
import com.bumptech.glide.load.model.GlideUrl
import com.script.SimpleBindings
import cn.hutool.core.util.HexUtil
import io.legado.app.constant.AppConst.SCRIPT_ENGINE
import io.legado.app.constant.AppConst.UA_NAME
import io.legado.app.constant.AppPattern.JS_PATTERN
@ -350,7 +351,7 @@ class AnalyzeUrl(
useWebView: Boolean = true,
): StrResponse {
if (type != null) {
return StrResponse(url, StringUtils.byteToHexString(getByteArrayAwait()))
return StrResponse(url, HexUtil.encodeHexStr(getByteArrayAwait()))
}
val concurrentRecord = fetchStart()
setCookie(source?.getKey())

@ -1,13 +1,9 @@
package io.legado.app.utils
import android.util.Base64
import cn.hutool.crypto.symmetric.SymmetricCrypto
import java.security.spec.AlgorithmParameterSpec
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
/**
* transformations https://developer.android.google.cn/reference/kotlin/javax/crypto/Cipher?hl=en
* 编码工具 escape base64
*/
@Suppress("unused")
object EncoderUtils {
@ -42,302 +38,4 @@ object EncoderUtils {
return Base64.encodeToString(str.toByteArray(), flags)
}
//////////AES Start
/**
* Return the Base64-encode bytes of AES encryption.
*
* @param data The data.
* @param key The key.
* @param transformation The name of the transformation,
* 加密算法/加密模式/填充类型, *AES/CBC/PKCS5Padding*.
* @param iv The buffer with the IV. The contents of the
* buffer are copied to protect against subsequent modification.
* @return the Base64-encode bytes of AES encryption
*/
@Throws(Exception::class)
fun encryptAES2Base64(
data: ByteArray?,
key: ByteArray?,
transformation: String? = "AES/ECB/PKCS5Padding",
iv: ByteArray? = null
): ByteArray? {
return Base64.encode(encryptAES(data, key, transformation, iv), Base64.NO_WRAP)
}
/**
* Return the bytes of AES encryption.
*
* @param data The data.
* @param key The key.
* @param transformation The name of the transformation,
* 加密算法/加密模式/填充类型, *AES/CBC/PKCS5Padding*.
* @param iv The buffer with the IV. The contents of the
* buffer are copied to protect against subsequent modification.
* @return the bytes of AES encryption
*/
@Throws(Exception::class)
fun encryptAES(
data: ByteArray?,
key: ByteArray?,
transformation: String? = "AES/ECB/PKCS5Padding",
iv: ByteArray? = null
): ByteArray? {
return symmetricTemplate(data, key, "AES", transformation!!, iv, true)
}
/**
* Return the bytes of AES decryption for Base64-encode bytes.
*
* @param data The data.
* @param key The key.
* @param transformation The name of the transformation,
* 加密算法/加密模式/填充类型, *AES/CBC/PKCS5Padding*.
* @param iv The buffer with the IV. The contents of the
* buffer are copied to protect against subsequent modification.
* @return the bytes of AES decryption for Base64-encode bytes
*/
@Throws(Exception::class)
fun decryptBase64AES(
data: ByteArray?,
key: ByteArray?,
transformation: String = "AES/ECB/PKCS5Padding",
iv: ByteArray? = null
): ByteArray? {
return decryptAES(Base64.decode(data, Base64.NO_WRAP), key, transformation, iv)
}
/**
* Return the bytes of AES decryption.
*
* @param data The data.
* @param key The key.
* @param transformation The name of the transformation,
* 加密算法/加密模式/填充类型, *AES/CBC/PKCS5Padding*.
* @param iv The buffer with the IV. The contents of the
* buffer are copied to protect against subsequent modification.
* @return the bytes of AES decryption
*/
@Throws(Exception::class)
fun decryptAES(
data: ByteArray?,
key: ByteArray?,
transformation: String = "AES/ECB/PKCS5Padding",
iv: ByteArray? = null
): ByteArray? {
return symmetricTemplate(data, key, "AES", transformation, iv, false)
}
//////////DES Start
/**
* Return the Base64-encode bytes of DES encryption.
*
* @param data The data.
* @param key The key.
* @param transformation The name of the transformation,
* 加密算法/加密模式/填充类型, *DES/CBC/PKCS5Padding*.
* @param iv The buffer with the IV. The contents of the
* buffer are copied to protect against subsequent modification.
* @return the Base64-encode bytes of AES encryption
*/
@Throws(Exception::class)
fun encryptDES2Base64(
data: ByteArray?,
key: ByteArray?,
transformation: String? = "DES/ECB/PKCS5Padding",
iv: ByteArray? = null
): ByteArray? {
return Base64.encode(encryptDES(data, key, transformation, iv), Base64.NO_WRAP)
}
/**
* Return the bytes of DES encryption.
*
* @param data The data.
* @param key The key.
* @param transformation The name of the transformation,
* 加密算法/加密模式/填充类型, *DES/CBC/PKCS5Padding*.
* @param iv The buffer with the IV. The contents of the
* buffer are copied to protect against subsequent modification.
* @return the bytes of AES encryption
*/
@Throws(Exception::class)
fun encryptDES(
data: ByteArray?,
key: ByteArray?,
transformation: String? = "DES/ECB/PKCS5Padding",
iv: ByteArray? = null
): ByteArray? {
return symmetricTemplate(data, key, "DES", transformation!!, iv, true)
}
/**
* Return the bytes of DES decryption for Base64-encode bytes.
*
* @param data The data.
* @param key The key.
* @param transformation The name of the transformation,
* 加密算法/加密模式/填充类型, *DES/CBC/PKCS5Padding*.
* @param iv The buffer with the IV. The contents of the
* buffer are copied to protect against subsequent modification.
* @return the bytes of AES decryption for Base64-encode bytes
*/
@Throws(Exception::class)
fun decryptBase64DES(
data: ByteArray?,
key: ByteArray?,
transformation: String = "DES/ECB/PKCS5Padding",
iv: ByteArray? = null
): ByteArray? {
return decryptDES(Base64.decode(data, Base64.NO_WRAP), key, transformation, iv)
}
/**
* Return the bytes of DES decryption.
*
* @param data The data.
* @param key The key.
* @param transformation The name of the transformation,
* 加密算法/加密模式/填充类型, *DES/CBC/PKCS5Padding*.
* @param iv The buffer with the IV. The contents of the
* buffer are copied to protect against subsequent modification.
* @return the bytes of AES decryption
*/
@Throws(Exception::class)
fun decryptDES(
data: ByteArray?,
key: ByteArray?,
transformation: String = "DES/ECB/PKCS5Padding",
iv: ByteArray? = null
): ByteArray? {
return symmetricTemplate(data, key, "DES", transformation, iv, false)
}
//////////DESede Start
/**
* Return the Base64-encode bytes of DESede encryption.
*
* @param data The data.
* @param key The key.
* @param transformation The name of the transformation,
* 加密算法/加密模式/填充类型, *DESede/CBC/PKCS5Padding*.
* @param iv The buffer with the IV. The contents of the
* buffer are copied to protect against subsequent modification.
* @return the Base64-encode bytes of AES encryption
*/
@Throws(Exception::class)
fun encryptDESede2Base64(
data: ByteArray?,
key: ByteArray?,
transformation: String? = "DESede/ECB/PKCS5Padding",
iv: ByteArray? = null
): ByteArray? {
return Base64.encode(encryptDESede(data, key, transformation, iv), Base64.NO_WRAP)
}
/**
* Return the bytes of DESede encryption.
*
* @param data The data.
* @param key The key.
* @param transformation The name of the transformation,
* 加密算法/加密模式/填充类型, *DESede/CBC/PKCS5Padding*.
* @param iv The buffer with the IV. The contents of the
* buffer are copied to protect against subsequent modification.
* @return the bytes of AES encryption
*/
@Throws(Exception::class)
fun encryptDESede(
data: ByteArray?,
key: ByteArray?,
transformation: String? = "DESede/ECB/PKCS5Padding",
iv: ByteArray? = null
): ByteArray? {
return symmetricTemplate(data, key, "DESede", transformation!!, iv, true)
}
/**
* Return the bytes of DESede decryption for Base64-encode bytes.
*
* @param data The data.
* @param key The key.
* @param transformation The name of the transformation,
* 加密算法/加密模式/填充类型, *DESede/CBC/PKCS5Padding*.
* @param iv The buffer with the IV. The contents of the
* buffer are copied to protect against subsequent modification.
* @return the bytes of AES decryption for Base64-encode bytes
*/
@Throws(Exception::class)
fun decryptBase64DESede(
data: ByteArray?,
key: ByteArray?,
transformation: String = "DESede/ECB/PKCS5Padding",
iv: ByteArray? = null
): ByteArray? {
return decryptDESede(Base64.decode(data, Base64.NO_WRAP), key, transformation, iv)
}
/**
* Return the bytes of DESede decryption.
*
* @param data The data.
* @param key The key.
* @param transformation The name of the transformation,
* 加密算法/加密模式/填充类型, *DESede/CBC/PKCS5Padding*.
* @param iv The buffer with the IV. The contents of the
* buffer are copied to protect against subsequent modification.
* @return the bytes of AES decryption
*/
@Throws(Exception::class)
fun decryptDESede(
data: ByteArray?,
key: ByteArray?,
transformation: String = "DESede/ECB/PKCS5Padding",
iv: ByteArray? = null
): ByteArray? {
return symmetricTemplate(data, key, "DESede", transformation, iv, false)
}
/**
* Return the bytes of symmetric encryption or decryption.
*
* @param data The data.
* @param key The key.
* @param algorithm The name of algorithm.
* @param transformation The name of the transformation,
* 加密算法/加密模式/填充类型, <i>DES/CBC/PKCS5Padding</i>.
* @param iv The buffer with the IV. The contents of the
* buffer are copied to protect against subsequent modification.
* @param isEncrypt True to encrypt, false otherwise.
* @return the bytes of symmetric encryption or decryption
*/
@Suppress("SameParameterValue")
@Throws(Exception::class)
private fun symmetricTemplate(
data: ByteArray?,
key: ByteArray?,
algorithm: String,
transformation: String,
iv: ByteArray?,
isEncrypt: Boolean
): ByteArray? {
return if (data == null || data.isEmpty() || key == null || key.isEmpty()) null
else {
//hutool support zeropadding
val keySpec = SecretKeySpec(key, algorithm)
var params: AlgorithmParameterSpec? = null
if (iv != null && !iv.isEmpty()) {
params = IvParameterSpec(iv)
}
val symmetricCrypto = SymmetricCrypto(transformation, keySpec, params)
if (isEncrypt) symmetricCrypto.encrypt(data) else symmetricCrypto.decrypt(data)
}
}
}

@ -287,30 +287,4 @@ object StringUtils {
return buf.toString()
}
fun byteToHexString(bytes: ByteArray?): String {
if (bytes == null) return ""
val sb = StringBuilder(bytes.size * 2)
for (b in bytes) {
val hex = 0xff and b.toInt()
if (hex < 16) {
sb.append('0')
}
sb.append(Integer.toHexString(hex))
}
return sb.toString()
}
fun hexStringToByte(hexString: String): ByteArray {
val hexStr = hexString.replace(" ", "")
val len = hexStr.length
val bytes = ByteArray(len / 2)
var i = 0
while (i < len) {
// 两位一组,表示一个字节,把这样表示的16进制字符串,还原成一个字节
bytes[i / 2] = ((Character.digit(hexString[i], 16) shl 4) +
Character.digit(hexString[i + 1], 16)).toByte()
i += 2
}
return bytes
}
}

Loading…
Cancel
Save