Răsfoiți Sursa

Merge pull request #1902 from Xwite/master

实现aes/des/3des/digest/Hmac
kunfei 4 ani în urmă
părinte
comite
42dfbb0a25

+ 1 - 1
app/build.gradle

@@ -255,7 +255,7 @@ dependencies {
     implementation('com.github.liuyueyi.quick-chinese-transfer:quick-transfer-core:0.2.3')
 
     //加解密类库
-    implementation('cn.hutool:hutool-crypto:5.8.1')
+    //implementation('cn.hutool:hutool-crypto:5.8.1')
 
     //renderscriptToolkit
     implementation('com.github.android:renderscript-intrinsics-replacement-toolkit:b6363490c3')

+ 30 - 15
app/src/main/assets/help/jsHelp.md

@@ -54,7 +54,11 @@ java.put(key, value)
 java.ajax(urlStr): String
 java.ajaxAll(urlList: Array<String>): Array<StrResponse?>
 //返回Response 方法body() code() message() header() raw() toString() 
-java.connect(urlStr): Response<String>
+java.connect(urlStr): StrResponse
+
+java.post(url: String, body: String, headerMap: Map<String, String>): Connection.Response
+java.get(url: String, headerMap: Map<String, String>): Connection.Response
+java.head(url: String, headerMap: Map<String, String>): Connection.Response
 
 * 使用webView访问网络
 * @param html 直接用webView载入的html, 如果html为空直接访问url
@@ -128,13 +132,11 @@ deleteFile(path: String)
 ```
 ****
 > [常见加密解密算法介绍](https://www.yijiyong.com/algorithm/encryption/01-intro.html)
-> [相关概念](https://blog.csdn.net/OrangeJack/article/details/82913804)  
+> [相关概念](https://blog.csdn.net/OrangeJack/article/details/82913804)
+> [Android支持的transformation](https://developer.android.google.cn/reference/kotlin/javax/crypto/Cipher?hl=en)
 * AES
+> transformation默认实现AES/ECB/PKCS5Padding
 ```
-* @param data 传入的原始数据
-* @param key AES加密的key
-* @param transformation AES加密的方式 例如AES/ECB/PKCS5Padding
-* @param iv ECB模式的偏移向量
 java.aesDecodeToString(str: String, key: String, transformation: String, iv: String)
 
 java.aesBase64DecodeToString(str: String, key: String, transformation: String, iv: String)
@@ -143,24 +145,37 @@ java.aesEncodeToString(str: String, key: String, transformation: String, iv: Str
 
 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
 ```
-* @param data 被加密的字符串
-* @param key 密钥
-* @param mode 模式 ECB/CBC/CFB/OFB/CTR
-* @param padding 补码方式 NoPadding/PKCS5Padding/
-* @param iv 加盐
 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?
 ```
 * 摘要
+> algorithm支持MD5 SHA-1 SHA-224 SHA-256 SHA-384 SHA-512
+```
+java.digestHex(data: String, algorithm: String,): String?
+
+java.digestBase64Str(data: String, algorithm: String,): String?
+```
+* HMac(散列消息鉴别码)
+> algorithm支持DESMAC DESMAC/CFB8 DESedeMAC DESedeMAC/CFB8 DESedeMAC64 DESwithISO9797 HmacMD5 HmacSHA* ISO9797ALG3MAC PBEwithSHA*
 ```
-* @param data 被摘要数据
-* @param algorithm 签名算法 MD5/SHA1/SHA256/SHA512
-java.digestHex(data: String,algorithm: String,): String?
+java.HMacHex(data: String, algorithm: String, key: String): String
 
-java.digestBase64Str(data: String,algorithm: String,): String?
+java.HMacBase64(data: String, algorithm: String, key: String): String
 ```
 * md5
 ```

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

@@ -15,6 +15,8 @@
 
 * 修复部分txt章节结尾乱码bug
 * 优化翻页流畅度
+* js添加des HMac
+* 登录ui用户信息默认加密方式改变,需要重新登录
 
 **2022/05/21**
 
@@ -322,4 +324,4 @@ eval(String(java.cacheFile(url)))
 **2022/01/01**
 
 * 修复本地txt问题,不在拷贝到私有目录,可以正常打开
-* 优化txt目录识别,取目录数量最多的规则
+* 优化txt目录识别,取目录数量最多的规则

+ 152 - 60
app/src/main/java/io/legado/app/help/JsExtensions.kt

@@ -3,9 +3,6 @@ package io.legado.app.help
 import android.net.Uri
 import android.util.Base64
 import androidx.annotation.Keep
-import cn.hutool.crypto.digest.DigestUtil
-import cn.hutool.crypto.symmetric.AES
-import cn.hutool.crypto.symmetric.DESede
 import io.legado.app.constant.AppConst
 import io.legado.app.constant.AppConst.dateFormat
 import io.legado.app.constant.AppLog
@@ -299,14 +296,6 @@ interface JsExtensions {
         return EncoderUtils.base64Encode(str, flags)
     }
 
-    fun md5Encode(str: String): String {
-        return MD5Utils.md5Encode(str)
-    }
-
-    fun md5Encode16(str: String): String {
-        return MD5Utils.md5Encode16(str)
-    }
-
     /**
      * 格式化时间
      */
@@ -602,6 +591,13 @@ interface JsExtensions {
         return UUID.randomUUID().toString()
     }
 
+    fun androidId(): String {
+        return AppConst.androidId
+    }
+
+//******************对称加密解密************************//
+
+    /////AES
     /**
      * AES 解码为 ByteArray
      * @param str 传入的AES加密的数据
@@ -640,6 +636,31 @@ interface JsExtensions {
         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加密的数据
@@ -753,35 +774,78 @@ interface JsExtensions {
         return aesEncodeToBase64ByteArray(data, key, transformation, iv)?.let { String(it) }
     }
 
-    fun androidId(): String {
-        return AppConst.androidId
-    }
 
     /**
-     * AES解密,算法参数经过Base64加密
+     * AES加密并转为Base64,算法参数经过Base64加密
      *
-     * @param data 加密的字符串
+     * @param data 被加密的字符串
      * @param key Base64后的密钥
      * @param mode 模式
      * @param padding 补码方式
      * @param iv Base64后的加盐
-     * @return 解密后的字符串
+     * @return 加密后的Base64
      */
-    fun aesDecodeArgsBase64Str(
+    fun aesEncodeArgsBase64Str(
         data: String,
         key: String,
         mode: String,
         padding: String,
         iv: String
     ): String? {
-        return AES(
-            mode,
-            padding,
+        return EncoderUtils.encryptAES2Base64(
+            data.encodeToByteArray(),
             Base64.decode(key, Base64.NO_WRAP),
+            "AES/${mode}/${padding}",
             Base64.decode(iv, Base64.NO_WRAP)
-        ).decryptStr(data)
+        )?.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解密
      *
@@ -799,7 +863,12 @@ interface JsExtensions {
         padding: String,
         iv: String
     ): String? {
-        return DESede(mode, padding, key.toByteArray(), iv.toByteArray()).decryptStr(data)
+        return EncoderUtils.decryptDESede(
+            data.encodeToByteArray(),
+            key.encodeToByteArray(),
+            "DESede/${mode}/${padding}",
+            iv.encodeToByteArray()
+        )?.let { String(it) }
     }
 
     /**
@@ -819,38 +888,14 @@ interface JsExtensions {
         padding: String,
         iv: String
     ): String? {
-        return DESede(
-            mode,
-            padding,
+        return EncoderUtils.decryptDESede(
+            data.encodeToByteArray(),
             Base64.decode(key, Base64.NO_WRAP),
+            "DESede/${mode}/${padding}",
             Base64.decode(iv, Base64.NO_WRAP)
-        ).decryptStr(data)
+        )?.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 AES(
-            mode,
-            padding,
-            Base64.decode(key, Base64.NO_WRAP),
-            Base64.decode(iv, Base64.NO_WRAP)
-        ).encryptBase64(data)
-    }
 
     /**
      * 3DES加密并转为Base64
@@ -869,7 +914,12 @@ interface JsExtensions {
         padding: String,
         iv: String
     ): String? {
-        return DESede(mode, padding, key.toByteArray(), iv.toByteArray()).encryptBase64(data)
+        return EncoderUtils.encryptDESede2Base64(
+            data.encodeToByteArray(),
+            key.encodeToByteArray(),
+            "DESede/${mode}/${padding}",
+            iv.encodeToByteArray()
+        )?.let { String(it) }
     }
 
     /**
@@ -889,14 +939,16 @@ interface JsExtensions {
         padding: String,
         iv: String
     ): String? {
-        return DESede(
-            mode,
-            padding,
+        return EncoderUtils.encryptDESede2Base64(
+            data.encodeToByteArray(),
             Base64.decode(key, Base64.NO_WRAP),
+            "DESede/${mode}/${padding}",
             Base64.decode(iv, Base64.NO_WRAP)
-        ).encryptBase64(data)
+        )?.let { String(it) }
     }
 
+//******************消息摘要/散列消息鉴别码************************//
+
     /**
      * 生成摘要,并转为16进制字符串
      *
@@ -907,8 +959,8 @@ interface JsExtensions {
     fun digestHex(
         data: String,
         algorithm: String,
-    ): String? {
-        return DigestUtil.digester(algorithm).digestHex(data)
+    ): String {
+        return DigestUtils.getDigest(algorithm, data)
     }
 
     /**
@@ -921,8 +973,48 @@ interface JsExtensions {
     fun digestBase64Str(
         data: String,
         algorithm: String,
-    ): String? {
-        return Base64.encodeToString(DigestUtil.digester(algorithm).digest(data), Base64.NO_WRAP)
+    ): String {
+        return Base64.encodeToString(DigestUtils.getDigest(algorithm, data.toByteArray()), Base64.NO_WRAP)
+    }
+
+    /**
+     * 生成散列消息鉴别码,并转为16进制字符串
+     *
+     * @param data 被摘要数据
+     * @param algorithm 签名算法
+     * @param key 密钥
+     * @return 16进制字符串
+     */
+    fun HMacHex(
+        data: String,
+        algorithm: String,
+        key: String
+    ): String {
+        return DigestUtils.getHMac(algorithm, key, data)
+    }
+
+    /**
+     * 生成散列消息鉴别码,并转为Base64字符串
+     *
+     * @param data 被摘要数据
+     * @param algorithm 签名算法
+     * @param key 密钥
+     * @return Base64字符串
+     */
+    fun HMacBase64(
+        data: String,
+        algorithm: String,
+        key: String
+    ): String {
+        return Base64.encodeToString(DigestUtils.getHMac(algorithm, key.toByteArray(), data.toByteArray()), Base64.NO_WRAP)
+    }
+
+    fun md5Encode(str: String): String {
+        return MD5Utils.md5Encode(str)
+    }
+
+    fun md5Encode16(str: String): String {
+        return MD5Utils.md5Encode16(str)
     }
 
 }

+ 3 - 2
app/src/main/java/io/legado/app/ui/book/remote/RemoteBookAdapter.kt

@@ -2,11 +2,12 @@ package io.legado.app.ui.book.remote
 
 import android.content.Context
 import android.view.ViewGroup
-import cn.hutool.core.date.LocalDateTimeUtil
 import io.legado.app.base.adapter.ItemViewHolder
 import io.legado.app.base.adapter.RecyclerAdapter
 import io.legado.app.databinding.ItemRemoteBookBinding
 import io.legado.app.utils.ConvertUtils
+import java.text.SimpleDateFormat
+import java.util.Date
 
 
 /**
@@ -38,7 +39,7 @@ class RemoteBookAdapter (context: Context, val callBack: CallBack) :
             tvName.text = item.filename.substringBeforeLast(".")
             tvContentType.text = item.contentType
             tvSize.text = ConvertUtils.formatFileSize(item.size)
-            tvDate.text = LocalDateTimeUtil.format(LocalDateTimeUtil.of(item.lastModify), "yyyy-MM-dd")
+            tvDate.text = SimpleDateFormat("yyyy-MM-dd").format(Date(item.lastModify))
         }
     }
 

+ 62 - 0
app/src/main/java/io/legado/app/utils/DigestUtils.kt

@@ -0,0 +1,62 @@
+package io.legado.app.utils
+
+import java.security.MessageDigest
+import javax.crypto.Mac
+import javax.crypto.spec.SecretKeySpec
+
+object DigestUtils {
+
+    /**
+     * 消息摘要
+     * 支持MD5 SHA-1 SHA-224 SHA-256 SHA-384 SHA-512
+     * https://developer.android.google.cn/reference/java/security/MessageDigest?hl=en
+     */
+    fun getDigest(
+        algorithm: String,
+        data: String?
+    ): String {
+        data ?: return ""
+        val bytes = getDigest(algorithm, data.toByteArray())
+        return StringUtils.byteToHexString(bytes)
+    }
+
+    fun getDigest(
+        algorithm: String,
+        data: ByteArray
+    ): ByteArray {
+        return kotlin.runCatching {
+            val messageDigest = MessageDigest.getInstance(algorithm)
+            messageDigest.digest(data)
+        }.getOrThrow()
+    }
+
+    /**
+     * 散列消息鉴别码
+     * 支持DESMAC DESMAC/CFB8 DESedeMAC DESedeMAC/CFB8 DESedeMAC64 DESwithISO9797 HmacMD5 HmacSHA* ISO9797ALG3MAC PBEwithSHA*
+     * https://developer.android.google.cn/reference/kotlin/javax/crypto/Mac?hl=en
+     */
+    fun getHMac(
+        algorithm: String,
+        key: String,
+        data: String?
+    ): String {
+        data ?: return ""
+        val bytes = getHMac(algorithm, key.toByteArray(), data.toByteArray())
+        return StringUtils.byteToHexString(bytes)
+    }
+
+    fun getHMac(
+        algorithm: String,
+        key: ByteArray,
+        data: ByteArray
+    ): ByteArray {
+        return kotlin.runCatching {
+            val mac= Mac.getInstance(algorithm)
+            val keySpec = SecretKeySpec(key, algorithm)
+            mac.init(keySpec)
+            mac.update(data)
+            mac.doFinal()
+        }.getOrThrow()
+    }
+
+}

+ 185 - 9
app/src/main/java/io/legado/app/utils/EncoderUtils.kt

@@ -6,6 +6,9 @@ import javax.crypto.Cipher
 import javax.crypto.spec.IvParameterSpec
 import javax.crypto.spec.SecretKeySpec
 
+/**
+ * transformations https://developer.android.google.cn/reference/kotlin/javax/crypto/Cipher?hl=en
+ */
 @Suppress("unused")
 object EncoderUtils {
 
@@ -47,7 +50,7 @@ object EncoderUtils {
      * @param data           The data.
      * @param key            The key.
      * @param transformation The name of the transformation,
-     * 加密算法/加密模式/填充类型, *DES/CBC/PKCS5Padding*.
+     * 加密算法/加密模式/填充类型, *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
@@ -56,7 +59,7 @@ object EncoderUtils {
     fun encryptAES2Base64(
         data: ByteArray?,
         key: ByteArray?,
-        transformation: String? = "DES/ECB/PKCS5Padding",
+        transformation: String? = "AES/ECB/PKCS5Padding",
         iv: ByteArray? = null
     ): ByteArray? {
         return Base64.encode(encryptAES(data, key, transformation, iv), Base64.NO_WRAP)
@@ -68,7 +71,7 @@ object EncoderUtils {
      * @param data           The data.
      * @param key            The key.
      * @param transformation The name of the transformation,
-     * 加密算法/加密模式/填充类型, *DES/CBC/PKCS5Padding*.
+     * 加密算法/加密模式/填充类型, *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
@@ -77,7 +80,7 @@ object EncoderUtils {
     fun encryptAES(
         data: ByteArray?,
         key: ByteArray?,
-        transformation: String? = "DES/ECB/PKCS5Padding",
+        transformation: String? = "AES/ECB/PKCS5Padding",
         iv: ByteArray? = null
     ): ByteArray? {
         return symmetricTemplate(data, key, "AES", transformation!!, iv, true)
@@ -90,7 +93,7 @@ object EncoderUtils {
      * @param data           The data.
      * @param key            The key.
      * @param transformation The name of the transformation,
-     * 加密算法/加密模式/填充类型, *DES/CBC/PKCS5Padding*.
+     * 加密算法/加密模式/填充类型, *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
@@ -99,7 +102,7 @@ object EncoderUtils {
     fun decryptBase64AES(
         data: ByteArray?,
         key: ByteArray?,
-        transformation: String = "DES/ECB/PKCS5Padding",
+        transformation: String = "AES/ECB/PKCS5Padding",
         iv: ByteArray? = null
     ): ByteArray? {
         return decryptAES(Base64.decode(data, Base64.NO_WRAP), key, transformation, iv)
@@ -111,7 +114,7 @@ object EncoderUtils {
      * @param data           The data.
      * @param key            The key.
      * @param transformation The name of the transformation,
-     * 加密算法/加密模式/填充类型, *DES/CBC/PKCS5Padding*.
+     * 加密算法/加密模式/填充类型, *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
@@ -120,12 +123,185 @@ object EncoderUtils {
     fun decryptAES(
         data: ByteArray?,
         key: ByteArray?,
-        transformation: String = "DES/ECB/PKCS5Padding",
+        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.
@@ -166,4 +342,4 @@ object EncoderUtils {
     }
 
 
-}
+}

+ 1 - 23
app/src/main/java/io/legado/app/utils/MD5Utils.kt

@@ -1,9 +1,5 @@
 package io.legado.app.utils
 
-
-import java.security.MessageDigest
-import java.security.NoSuchAlgorithmException
-
 /**
  * 将字符串转化为MD5
  */
@@ -11,25 +7,7 @@ import java.security.NoSuchAlgorithmException
 object MD5Utils {
 
     fun md5Encode(str: String?): String {
-        if (str == null) return ""
-        var reStr = ""
-        try {
-            val md5: MessageDigest = MessageDigest.getInstance("MD5")
-            val bytes: ByteArray = md5.digest(str.toByteArray())
-            val stringBuffer: StringBuilder = StringBuilder()
-            for (b in bytes) {
-                val bt: Int = b.toInt() and 0xff
-                if (bt < 16) {
-                    stringBuffer.append(0)
-                }
-                stringBuffer.append(Integer.toHexString(bt))
-            }
-            reStr = stringBuffer.toString()
-        } catch (e: NoSuchAlgorithmException) {
-            e.printOnDebug()
-        }
-
-        return reStr
+        return DigestUtils.getDigest("MD5", str)
     }
 
     fun md5Encode16(str: String): String {