@@ -157,34 +157,20 @@ deleteFile(path: String)
|
||||
|
||||
> 其他加密方式 可在js中[调用](https://m.jb51.net/article/92138.htm)[hutool-crypto](https://www.hutool.cn/docs/#/)
|
||||
|
||||
* AES
|
||||
> transformation默认实现AES/ECB/PKCS5Padding
|
||||
* 对称加密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
|
||||
```
|
||||
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?
|
||||
//解密为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
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
* web服务和朗读服务添加唤醒锁
|
||||
* 修复搜索禁用书源的bug
|
||||
* 修复本地书籍很慢的问题
|
||||
* 更改内置对称加密函数,请看文档
|
||||
|
||||
**2022/10/14**
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ object AppPattern {
|
||||
|
||||
//dataURL图片类型
|
||||
val dataUriRegex = Regex("data:.*?;base64,(.*)")
|
||||
//Base64字符串
|
||||
val base64Regex = Regex("^[a-zA-Z0-9\\+\\/=]+$")
|
||||
|
||||
val nameRegex = Regex("\\s+作\\s*者.*|\\s+\\S+\\s+著")
|
||||
val authorRegex = Regex("^\\s*作\\s*者[::\\s]+|\\s+著")
|
||||
|
||||
@@ -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,8 @@ 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 cn.hutool.crypto.symmetric.SymmetricCrypto
|
||||
import io.legado.app.constant.AppConst
|
||||
import io.legado.app.constant.AppConst.dateFormat
|
||||
import io.legado.app.constant.AppLog
|
||||
@@ -174,18 +176,15 @@ interface JsExtensions {
|
||||
|
||||
/**
|
||||
* 缓存以文本方式保存的文件 如.js .txt等
|
||||
* @param urlStr 网络文件的链接
|
||||
* @param saveTime 缓存时间,单位:秒
|
||||
* @return 返回缓存后的文件内容
|
||||
*/
|
||||
fun cacheFile(urlStr: String): String? {
|
||||
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 cache = CacheManager.getFile(key)
|
||||
if (cache.isNullOrBlank()) {
|
||||
@@ -200,7 +199,11 @@ interface JsExtensions {
|
||||
/**
|
||||
*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) {
|
||||
CookieStore.getKey(tag, key)
|
||||
} else {
|
||||
@@ -245,7 +248,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 +513,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,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
|
||||
}
|
||||
* 在js中这样使用
|
||||
* java.createSymmetricCrypto(transformation, key, iv).decrypt(data)
|
||||
* java.createSymmetricCrypto(transformation, key, iv).decryptStr(data)
|
||||
|
||||
* java.createSymmetricCrypto(transformation, key, iv).encrypt(data)
|
||||
* java.createSymmetricCrypto(transformation, key, iv).encryptBase64(data)
|
||||
* java.createSymmetricCrypto(transformation, key, iv).encryptHex(data)
|
||||
*/
|
||||
|
||||
/* 自动转换key iv 到ByteArray 支持base64 hex uft8*/
|
||||
fun createSymmetricCrypto(
|
||||
transformation: String,
|
||||
key: String
|
||||
): SymmetricCrypto {
|
||||
return createSymmetricCrypto(transformation, key, 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,
|
||||
fun createSymmetricCrypto(
|
||||
transformation: 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(),
|
||||
iv: String?
|
||||
): SymmetricCrypto {
|
||||
return createSymmetricCrypto(
|
||||
transformation,
|
||||
iv.encodeToByteArray()
|
||||
)?.let { String(it) }
|
||||
StringUtils.encodeStringToByteArray(key),
|
||||
StringUtils.encodeStringToByteArray(iv)
|
||||
)
|
||||
}
|
||||
|
||||
fun desBase64DecodeToString(
|
||||
data: String, key: String, transformation: String, iv: String
|
||||
): String? {
|
||||
return EncoderUtils.decryptBase64DES(
|
||||
data.encodeToByteArray(),
|
||||
key.encodeToByteArray(),
|
||||
transformation,
|
||||
iv.encodeToByteArray()
|
||||
)?.let { String(it) }
|
||||
/* 调用SymmetricCrypto key为null时使用随机密钥*/
|
||||
fun createSymmetricCrypto(
|
||||
transformation: String
|
||||
): SymmetricCrypto {
|
||||
return createSymmetricCrypto(transformation, null, null)
|
||||
}
|
||||
|
||||
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 createSymmetricCrypto(
|
||||
transformation: String,
|
||||
key: ByteArray
|
||||
): SymmetricCrypto {
|
||||
return createSymmetricCrypto(transformation, key, null)
|
||||
}
|
||||
|
||||
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) }
|
||||
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
|
||||
}
|
||||
|
||||
//******************消息摘要/散列消息鉴别码************************//
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.net.ConnectivityManager
|
||||
import android.net.NetworkCapabilities
|
||||
import android.os.Build
|
||||
import io.legado.app.constant.AppLog
|
||||
import io.legado.app.constant.AppPattern
|
||||
import okhttp3.internal.publicsuffix.PublicSuffixDatabase
|
||||
import splitties.systemservices.connectivityManager
|
||||
|
||||
@@ -13,8 +12,8 @@ import java.net.NetworkInterface
|
||||
import java.net.SocketException
|
||||
import java.net.URL
|
||||
import java.util.*
|
||||
import java.util.regex.Pattern
|
||||
|
||||
import cn.hutool.core.lang.Validator
|
||||
|
||||
@Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
object NetworkUtils {
|
||||
@@ -113,7 +112,7 @@ object NetworkUtils {
|
||||
fun getAbsoluteURL(baseURL: String?, relativePath: String): String {
|
||||
if (baseURL.isNullOrEmpty()) return relativePath
|
||||
if (relativePath.isAbsUrl()) return relativePath
|
||||
if (relativePath.matches(AppPattern.dataUriRegex)) return relativePath
|
||||
if (relativePath.isDataUrl()) return relativePath
|
||||
if (relativePath.startsWith("javascript")) return ""
|
||||
var relativeUrl = relativePath
|
||||
try {
|
||||
@@ -133,7 +132,7 @@ object NetworkUtils {
|
||||
fun getAbsoluteURL(baseURL: URL?, relativePath: String): String {
|
||||
if (baseURL == null) return relativePath
|
||||
if (relativePath.isAbsUrl()) return relativePath
|
||||
if (relativePath.matches(AppPattern.dataUriRegex)) return relativePath
|
||||
if (relativePath.isDataUrl()) return relativePath
|
||||
if (relativePath.startsWith("javascript")) return ""
|
||||
var relativeUrl = relativePath
|
||||
try {
|
||||
@@ -214,14 +213,14 @@ object NetworkUtils {
|
||||
* @return True if the input parameter is a valid IPv4 address.
|
||||
*/
|
||||
fun isIPv4Address(input: String?): Boolean {
|
||||
return input != null && IPV4_PATTERN.matcher(input).matches()
|
||||
return input != null && Validator.isIpv4(input)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if valid IPV6 address.
|
||||
*/
|
||||
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)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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*$"
|
||||
)
|
||||
|
||||
}
|
||||
@@ -6,7 +6,9 @@ import android.icu.text.Collator
|
||||
import android.icu.util.ULocale
|
||||
import android.net.Uri
|
||||
import android.text.Editable
|
||||
import cn.hutool.core.lang.Validator
|
||||
import io.legado.app.constant.AppPattern.dataUriRegex
|
||||
import io.legado.app.constant.AppPattern.base64Regex
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
@@ -37,6 +39,11 @@ fun String?.isDataUrl() =
|
||||
dataUriRegex.matches(it)
|
||||
} ?: false
|
||||
|
||||
fun String?.isBase64() =
|
||||
this?.let {
|
||||
base64Regex.matches(it)
|
||||
} ?: false
|
||||
|
||||
fun String?.isJson(): Boolean =
|
||||
this?.run {
|
||||
val str = this.trim()
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package io.legado.app.utils
|
||||
|
||||
import android.util.Base64
|
||||
import android.annotation.SuppressLint
|
||||
import android.text.TextUtils.isEmpty
|
||||
|
||||
import cn.hutool.core.util.HexUtil
|
||||
import cn.hutool.core.lang.Validator
|
||||
|
||||
import java.text.DecimalFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
@@ -287,30 +291,16 @@ 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))
|
||||
/**
|
||||
* 自动识别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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,9 +46,9 @@ object SvgUtils {
|
||||
}
|
||||
|
||||
/////// 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 wRatio = width.let { size.width / it } ?: -1
|
||||
val wRatio = width?.let { size.width / it } ?: -1
|
||||
val hRatio = height?.let { size.height / it } ?: -1
|
||||
//如果超出指定大小,则缩小相应的比例
|
||||
val ratio = when {
|
||||
|
||||
Reference in New Issue
Block a user