Merge pull request #1902 from Xwite/master

实现aes/des/3des/digest/Hmac
This commit is contained in:
kunfei
2022-05-24 20:40:43 +08:00
committed by GitHub
8 changed files with 437 additions and 111 deletions
@@ -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)
}
}
@@ -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))
}
}
@@ -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()
}
}
@@ -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,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 {