Kaynağa Gözat

Merge pull request #2436 from Xwite/master

移除和hutool重复的实现
Xwite 4 yıl önce
ebeveyn
işleme
11bcb3d3f6

+ 14 - 28
app/src/main/assets/help/jsHelp.md

@@ -157,34 +157,20 @@ deleteFile(path: String)
 
 
 > 其他加密方式 可在js中[调用](https://m.jb51.net/article/92138.htm)[hutool-crypto](https://www.hutool.cn/docs/#/)
 > 其他加密方式 可在js中[调用](https://m.jb51.net/article/92138.htm)[hutool-crypto](https://www.hutool.cn/docs/#/)
 
 
-* AES
-> transformation默认实现AES/ECB/PKCS5Padding
-```
-java.aesDecodeToString(str: String, key: String, transformation: String, iv: String)
-
-java.aesBase64DecodeToString(str: String, key: String, transformation: String, iv: String)
-
-java.aesEncodeToString(str: String, key: String, transformation: String, iv: String)
-
-java.aesEncodeToBase64String(str: String, key: String, transformation: String, iv: String)
-```
-* DES
-> transformation默认实现DES/ECB/PKCS5Padding
-```
-java.desDecodeToString(str: String, key: String, transformation: String, iv: String)
-
-java.desBase64DecodeToString(str: String, key: String, transformation: String, iv: String)
-
-java.desEncodeToString(str: String, key: String, transformation: String, iv: String)
-
-java.desEncodeToBase64String(str: String, key: String, transformation: String, iv: String)
-```
-* 3DES
-> tansformation默认实现DESede/ECB/PKCS5Padding
-```
-java.tripleDESEncodeBase64Str(data: String,key: String,mode: String,padding: String,iv: String): String?
-
-java.tripleDESDecodeStr(data: String,key: String,mode: String,padding: String,iv: String): String?
+* 对称加密AES/DES/TripleDES
+> AES transformation默认实现AES/ECB/PKCS5Padding  
+> DES transformation默认实现DES/ECB/PKCS5Padding  
+> TripleDES tansformation默认实现DESede/ECB/PKCS5Padding  
+> 内部实现为cn.hutool.crypto 解密加密接口支持ByteArray|Base64String|HexString|InputStream  
+> 输入参数key iv 支持ByteArray|Base64String|HexString|Utf8String
+```
+//解密为ByteArray 字符串
+java.createSymmetricCrypto(transformation, key, iv).decrypt(data)
+java.createSymmetricCrypto(transformation, key, iv).decryptStr(data)
+//加密为ByteArray Base64字符 HEX字符
+java.createSymmetricCrypto(transformation, key, iv).encrypt(data)
+java.createSymmetricCrypto(transformation, key, iv).encryptBase64(data)
+java.createSymmetricCrypto(transformation, key, iv).encryptHex(data)
 ```
 ```
 * 摘要
 * 摘要
 > MD5 SHA-1 SHA-224 SHA-256 SHA-384 SHA-512
 > MD5 SHA-1 SHA-224 SHA-256 SHA-384 SHA-512

+ 1 - 0
app/src/main/assets/updateLog.md

@@ -17,6 +17,7 @@
 * web服务和朗读服务添加唤醒锁
 * web服务和朗读服务添加唤醒锁
 * 修复搜索禁用书源的bug
 * 修复搜索禁用书源的bug
 * 修复本地书籍很慢的问题
 * 修复本地书籍很慢的问题
+* 更改内置对称加密函数,请看文档
 
 
 **2022/10/14**
 **2022/10/14**
 
 

+ 2 - 0
app/src/main/java/io/legado/app/constant/AppPattern.kt

@@ -13,6 +13,8 @@ object AppPattern {
 
 
     //dataURL图片类型
     //dataURL图片类型
     val dataUriRegex = Regex("data:.*?;base64,(.*)")
     val dataUriRegex = Regex("data:.*?;base64,(.*)")
+    //Base64字符串
+    val base64Regex = Regex("^[a-zA-Z0-9\\+\\/=]+$")
 
 
     val nameRegex = Regex("\\s+作\\s*者.*|\\s+\\S+\\s+著")
     val nameRegex = Regex("\\s+作\\s*者.*|\\s+\\S+\\s+著")
     val authorRegex = Regex("^\\s*作\\s*者[::\\s]+|\\s+著")
     val authorRegex = Regex("^\\s*作\\s*者[::\\s]+|\\s+著")

+ 3 - 6
app/src/main/java/io/legado/app/data/entities/BaseSource.kt

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

+ 51 - 345
app/src/main/java/io/legado/app/help/JsExtensions.kt

@@ -5,6 +5,8 @@ import android.util.Base64
 import androidx.annotation.Keep
 import androidx.annotation.Keep
 import cn.hutool.crypto.digest.DigestUtil
 import cn.hutool.crypto.digest.DigestUtil
 import cn.hutool.crypto.digest.HMac
 import cn.hutool.crypto.digest.HMac
+import cn.hutool.core.util.HexUtil
+import cn.hutool.crypto.symmetric.SymmetricCrypto
 import io.legado.app.constant.AppConst
 import io.legado.app.constant.AppConst
 import io.legado.app.constant.AppConst.dateFormat
 import io.legado.app.constant.AppConst.dateFormat
 import io.legado.app.constant.AppLog
 import io.legado.app.constant.AppLog
@@ -174,18 +176,15 @@ interface JsExtensions {
 
 
     /**
     /**
      * 缓存以文本方式保存的文件 如.js .txt等
      * 缓存以文本方式保存的文件 如.js .txt等
+     * @param urlStr 网络文件的链接
+     * @param saveTime 缓存时间,单位:秒
+     * @return 返回缓存后的文件内容
      */
      */
     fun cacheFile(urlStr: String): String? {
     fun cacheFile(urlStr: String): String? {
         return cacheFile(urlStr, 0)
         return cacheFile(urlStr, 0)
     }
     }
 
 
-    /**
-     * 缓存以文本方式保存的文件 如.js .txt等
-     * @param urlStr 网络文件的链接
-     * @param saveTime 缓存时间,单位:秒
-     * @return 返回缓存后的文件内容
-     */
-    fun cacheFile(urlStr: String, saveTime: Int = 0): String? {
+    fun cacheFile(urlStr: String, saveTime: Int): String? {
         val key = md5Encode16(urlStr)
         val key = md5Encode16(urlStr)
         val cache = CacheManager.getFile(key)
         val cache = CacheManager.getFile(key)
         if (cache.isNullOrBlank()) {
         if (cache.isNullOrBlank()) {
@@ -200,7 +199,11 @@ interface JsExtensions {
     /**
     /**
      *js实现读取cookie
      *js实现读取cookie
      */
      */
-    fun getCookie(tag: String, key: String? = null): String {
+    fun getCookie(tag: String): String {
+        return getCookie(tag, null)
+    }
+
+    fun getCookie(tag: String, key: String?): String {
         return if (key != null) {
         return if (key != null) {
             CookieStore.getKey(tag, key)
             CookieStore.getKey(tag, key)
         } else {
         } else {
@@ -245,7 +248,7 @@ interface JsExtensions {
         )
         )
         FileUtils.delete(path)
         FileUtils.delete(path)
         val file = FileUtils.createFileIfNotExist(path)
         val file = FileUtils.createFileIfNotExist(path)
-        StringUtils.hexStringToByte(content).let {
+        HexUtil.decodeHex(content).let {
             if (it.isNotEmpty()) {
             if (it.isNotEmpty()) {
                 file.writeBytes(it)
                 file.writeBytes(it)
             }
             }
@@ -510,7 +513,7 @@ interface JsExtensions {
         val bytes = if (url.isAbsUrl()) {
         val bytes = if (url.isAbsUrl()) {
             AnalyzeUrl(url, source = getSource()).getByteArray()
             AnalyzeUrl(url, source = getSource()).getByteArray()
         } else {
         } else {
-            StringUtils.hexStringToByte(url)
+            HexUtil.decodeHex(url)
         }
         }
         val bos = ByteArrayOutputStream()
         val bos = ByteArrayOutputStream()
         val zis = ZipInputStream(ByteArrayInputStream(bytes))
         val zis = ZipInputStream(ByteArrayInputStream(bytes))
@@ -647,354 +650,57 @@ 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
-        }
-    }
+     * 在js中这样使用
+     * java.createSymmetricCrypto(transformation, key, iv).decrypt(data)
+     * java.createSymmetricCrypto(transformation, key, iv).decryptStr(data)
 
 
-    /**
-     * 加密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) }
-    }
+     * java.createSymmetricCrypto(transformation, key, iv).encrypt(data)
+     * java.createSymmetricCrypto(transformation, key, iv).encryptBase64(data)
+     * java.createSymmetricCrypto(transformation, key, iv).encryptHex(data)
+    */
 
 
-    /**
-     * 加密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) }
+    /* 自动转换key iv 到ByteArray 支持base64 hex uft8*/
+    fun createSymmetricCrypto(
+        transformation: String,
+        key: String
+    ): SymmetricCrypto {
+        return createSymmetricCrypto(transformation, key, null)
     }
     }
 
 
-
-    /**
-     * AES加密并转为Base64,算法参数经过Base64加密
-     *
-     * @param data 被加密的字符串
-     * @param key Base64后的密钥
-     * @param mode 模式
-     * @param padding 补码方式
-     * @param iv Base64后的加盐
-     * @return 加密后的Base64
-     */
-    fun aesEncodeArgsBase64Str(
-        data: String,
+    fun createSymmetricCrypto(
+        transformation: String,
         key: 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(),
+        iv: String?
+    ): SymmetricCrypto {
+        return createSymmetricCrypto(
             transformation,
             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) }
+            StringUtils.encodeStringToByteArray(key),
+            StringUtils.encodeStringToByteArray(iv)
+        )
     }
     }
 
 
-    /**
-     * 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) }
+    /* 调用SymmetricCrypto key为null时使用随机密钥*/
+    fun createSymmetricCrypto(
+        transformation: String
+    ): SymmetricCrypto {
+        return createSymmetricCrypto(transformation, null, null)
     }
     }
 
 
-
-    /**
-     * 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) }
+    fun createSymmetricCrypto(
+        transformation: String,
+        key: ByteArray
+    ): SymmetricCrypto {
+        return createSymmetricCrypto(transformation, key, null)
     }
     }
 
 
-    /**
-     * 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) }
+    fun createSymmetricCrypto(
+        transformation: String,
+        key: ByteArray?,
+        iv: ByteArray?
+    ): SymmetricCrypto {
+        val symmetricCrypto = SymmetricCrypto(transformation, key)
+        return if (iv != null && !iv.isEmpty()) symmetricCrypto.setIv(iv) else symmetricCrypto
     }
     }
 
 
 //******************消息摘要/散列消息鉴别码************************//
 //******************消息摘要/散列消息鉴别码************************//

+ 2 - 1
app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt

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

+ 1 - 303
app/src/main/java/io/legado/app/utils/EncoderUtils.kt

@@ -1,13 +1,9 @@
 package io.legado.app.utils
 package io.legado.app.utils
 
 
 import android.util.Base64
 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")
 @Suppress("unused")
 object EncoderUtils {
 object EncoderUtils {
@@ -42,302 +38,4 @@ object EncoderUtils {
         return Base64.encodeToString(str.toByteArray(), flags)
         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)
-        }
-    }
-
-
 }
 }

+ 5 - 21
app/src/main/java/io/legado/app/utils/NetworkUtils.kt

@@ -4,7 +4,6 @@ import android.net.ConnectivityManager
 import android.net.NetworkCapabilities
 import android.net.NetworkCapabilities
 import android.os.Build
 import android.os.Build
 import io.legado.app.constant.AppLog
 import io.legado.app.constant.AppLog
-import io.legado.app.constant.AppPattern
 import okhttp3.internal.publicsuffix.PublicSuffixDatabase
 import okhttp3.internal.publicsuffix.PublicSuffixDatabase
 import splitties.systemservices.connectivityManager
 import splitties.systemservices.connectivityManager
 
 
@@ -13,8 +12,8 @@ import java.net.NetworkInterface
 import java.net.SocketException
 import java.net.SocketException
 import java.net.URL
 import java.net.URL
 import java.util.*
 import java.util.*
-import java.util.regex.Pattern
 
 
+import cn.hutool.core.lang.Validator
 
 
 @Suppress("unused", "MemberVisibilityCanBePrivate")
 @Suppress("unused", "MemberVisibilityCanBePrivate")
 object NetworkUtils {
 object NetworkUtils {
@@ -113,7 +112,7 @@ object NetworkUtils {
     fun getAbsoluteURL(baseURL: String?, relativePath: String): String {
     fun getAbsoluteURL(baseURL: String?, relativePath: String): String {
         if (baseURL.isNullOrEmpty()) return relativePath
         if (baseURL.isNullOrEmpty()) return relativePath
         if (relativePath.isAbsUrl()) return relativePath
         if (relativePath.isAbsUrl()) return relativePath
-        if (relativePath.matches(AppPattern.dataUriRegex)) return relativePath
+        if (relativePath.isDataUrl()) return relativePath
         if (relativePath.startsWith("javascript")) return ""
         if (relativePath.startsWith("javascript")) return ""
         var relativeUrl = relativePath
         var relativeUrl = relativePath
         try {
         try {
@@ -133,7 +132,7 @@ object NetworkUtils {
     fun getAbsoluteURL(baseURL: URL?, relativePath: String): String {
     fun getAbsoluteURL(baseURL: URL?, relativePath: String): String {
         if (baseURL == null) return relativePath
         if (baseURL == null) return relativePath
         if (relativePath.isAbsUrl()) return relativePath
         if (relativePath.isAbsUrl()) return relativePath
-        if (relativePath.matches(AppPattern.dataUriRegex)) return relativePath
+        if (relativePath.isDataUrl()) return relativePath
         if (relativePath.startsWith("javascript")) return ""
         if (relativePath.startsWith("javascript")) return ""
         var relativeUrl = relativePath
         var relativeUrl = relativePath
         try {
         try {
@@ -214,14 +213,14 @@ object NetworkUtils {
      * @return True if the input parameter is a valid IPv4 address.
      * @return True if the input parameter is a valid IPv4 address.
      */
      */
     fun isIPv4Address(input: String?): Boolean {
     fun isIPv4Address(input: String?): Boolean {
-        return input != null && IPV4_PATTERN.matcher(input).matches()
+        return input != null && Validator.isIpv4(input)
     }
     }
 
 
     /**
     /**
      * Check if valid IPV6 address.
      * Check if valid IPV6 address.
      */
      */
     fun isIPv6Address(input: String?): Boolean {
     fun isIPv6Address(input: String?): Boolean {
-        return input != null && IPV6_PATTERN.matcher(input).matches()
+        return input != null && Validator.isIpv6(input)
     }
     }
 
 
     /**
     /**
@@ -231,19 +230,4 @@ object NetworkUtils {
         return isIPv4Address(input) || isIPv6Address(input)
         return isIPv4Address(input) || isIPv6Address(input)
     }
     }
 
 
-    /**
-     * Ipv4 address check.
-     */
-    private val IPV4_PATTERN = Pattern.compile(
-        "^(" + "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}" +
-                "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"
-    )
-
-    /**
-     * Ipv6 address check.
-     */
-    private val IPV6_PATTERN = Pattern.compile(
-        "^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:)(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$"
-    )
-
 }
 }

+ 7 - 0
app/src/main/java/io/legado/app/utils/StringExtensions.kt

@@ -6,7 +6,9 @@ import android.icu.text.Collator
 import android.icu.util.ULocale
 import android.icu.util.ULocale
 import android.net.Uri
 import android.net.Uri
 import android.text.Editable
 import android.text.Editable
+import cn.hutool.core.lang.Validator
 import io.legado.app.constant.AppPattern.dataUriRegex
 import io.legado.app.constant.AppPattern.dataUriRegex
+import io.legado.app.constant.AppPattern.base64Regex
 import java.io.File
 import java.io.File
 import java.util.*
 import java.util.*
 
 
@@ -37,6 +39,11 @@ fun String?.isDataUrl() =
         dataUriRegex.matches(it)
         dataUriRegex.matches(it)
     } ?: false
     } ?: false
 
 
+fun String?.isBase64() =
+    this?.let {
+        base64Regex.matches(it)
+    } ?: false
+
 fun String?.isJson(): Boolean =
 fun String?.isJson(): Boolean =
     this?.run {
     this?.run {
         val str = this.trim()
         val str = this.trim()

+ 13 - 23
app/src/main/java/io/legado/app/utils/StringUtils.kt

@@ -1,8 +1,12 @@
 package io.legado.app.utils
 package io.legado.app.utils
 
 
+import android.util.Base64
 import android.annotation.SuppressLint
 import android.annotation.SuppressLint
 import android.text.TextUtils.isEmpty
 import android.text.TextUtils.isEmpty
 
 
+import cn.hutool.core.util.HexUtil
+import cn.hutool.core.lang.Validator
+
 import java.text.DecimalFormat
 import java.text.DecimalFormat
 import java.text.SimpleDateFormat
 import java.text.SimpleDateFormat
 import java.util.*
 import java.util.*
@@ -287,30 +291,16 @@ object StringUtils {
         return buf.toString()
         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))
+    /**
+     * 自动识别Base64 Hex Utf8字符串 并转成ByteArray
+     */
+    fun encodeStringToByteArray(str: String?): ByteArray? {
+        return when {
+            str.isNullOrBlank() -> null
+            Validator.isHex(str) -> HexUtil.decodeHex(str)
+            str.isBase64() -> Base64.decode(str, Base64.DEFAULT)
+            else -> str.encodeToByteArray()
         }
         }
-        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
-    }
 }
 }

+ 2 - 2
app/src/main/java/io/legado/app/utils/SvgUtils.kt

@@ -46,9 +46,9 @@ object SvgUtils {
     }
     }
 
 
     /////// private method
     /////// private method
-    private fun createBitmap(svg: SVG, width: Int, height: Int? = null): Bitmap {
+    private fun createBitmap(svg: SVG, width: Int? = null, height: Int? = null): Bitmap {
         val size = getSize(svg)
         val size = getSize(svg)
-        val wRatio = width.let { size.width / it } ?: -1
+        val wRatio = width?.let { size.width / it } ?: -1
         val hRatio = height?.let { size.height / it } ?: -1
         val hRatio = height?.let { size.height / it } ?: -1
         //如果超出指定大小,则缩小相应的比例
         //如果超出指定大小,则缩小相应的比例
         val ratio = when {
         val ratio = when {