docs: 添加管理平台标准加密算法 Kotlin 参考实现
This commit is contained in:
120
docs/工具箱端-授权对接指南/utils/TaskEncryptionUtil.kt
Normal file
120
docs/工具箱端-授权对接指南/utils/TaskEncryptionUtil.kt
Normal file
@@ -0,0 +1,120 @@
|
||||
package top.tangyh.lamp.filing.utils
|
||||
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.security.MessageDigest
|
||||
import java.security.SecureRandom
|
||||
import java.util.*
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.spec.GCMParameterSpec
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
|
||||
private val logger = KotlinLogging.logger {}
|
||||
|
||||
/**
|
||||
* 任务加密工具类
|
||||
* 使用 licence + fingerprint 作为密钥对任务数据进行 AES-256-GCM 对称加密
|
||||
*
|
||||
* GCM 模式提供认证加密,比 ECB 模式更安全
|
||||
* 加密数据格式:IV(12字节) + 加密数据 + 认证标签(16字节)
|
||||
*/
|
||||
object TaskEncryptionUtil {
|
||||
|
||||
private const val ALGORITHM = "AES"
|
||||
private const val TRANSFORMATION = "AES/GCM/NoPadding"
|
||||
private const val GCM_IV_LENGTH = 12 // GCM 推荐使用 12 字节 IV
|
||||
private const val GCM_TAG_LENGTH = 16 // GCM 认证标签长度(128位)
|
||||
private const val KEY_LENGTH = 32 // AES-256 密钥长度(256位 = 32字节)
|
||||
|
||||
private val secureRandom = SecureRandom()
|
||||
|
||||
/**
|
||||
* 使用 licence + fingerprint 加密任务数据(AES-256-GCM)
|
||||
* @param data 待加密的数据(JSON字符串)
|
||||
* @param licence 授权码
|
||||
* @param fingerprint 硬件指纹
|
||||
* @return Base64编码的加密数据(包含IV + 加密数据 + 认证标签)
|
||||
*/
|
||||
fun encrypt(data: String, licence: String, fingerprint: String): String {
|
||||
return try {
|
||||
// 使用 licence + fingerprint 生成密钥
|
||||
val key = generateKey(licence, fingerprint)
|
||||
|
||||
// 生成随机 IV(12字节)
|
||||
val iv = ByteArray(GCM_IV_LENGTH)
|
||||
secureRandom.nextBytes(iv)
|
||||
|
||||
// 创建加密器
|
||||
val cipher = Cipher.getInstance(TRANSFORMATION)
|
||||
val parameterSpec = GCMParameterSpec(GCM_TAG_LENGTH * 8, iv) // 标签长度以位为单位
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key, parameterSpec)
|
||||
|
||||
// 加密数据
|
||||
val encryptedBytes = cipher.doFinal(data.toByteArray(StandardCharsets.UTF_8))
|
||||
|
||||
// 组合:IV + 加密数据(包含认证标签)
|
||||
val combined = ByteArray(iv.size + encryptedBytes.size)
|
||||
System.arraycopy(iv, 0, combined, 0, iv.size)
|
||||
System.arraycopy(encryptedBytes, 0, combined, iv.size, encryptedBytes.size)
|
||||
|
||||
// 返回 Base64 编码的加密数据
|
||||
Base64.getEncoder().encodeToString(combined)
|
||||
} catch (e: Exception) {
|
||||
logger.error(e) { "AES-256-GCM加密任务数据失败" }
|
||||
throw RuntimeException("加密任务数据失败: ${e.message}", e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 licence + fingerprint 解密任务数据(AES-256-GCM)
|
||||
* @param encryptedData Base64编码的加密数据(包含IV + 加密数据 + 认证标签)
|
||||
* @param licence 授权码
|
||||
* @param fingerprint 硬件指纹
|
||||
* @return 解密后的数据(JSON字符串)
|
||||
*/
|
||||
fun decrypt(encryptedData: String, licence: String, fingerprint: String): String {
|
||||
return try {
|
||||
// 使用 licence + fingerprint 生成密钥
|
||||
val key = generateKey(licence, fingerprint)
|
||||
|
||||
// Base64 解码
|
||||
val combined = Base64.getDecoder().decode(encryptedData)
|
||||
|
||||
// 分离 IV 和加密数据
|
||||
if (combined.size < GCM_IV_LENGTH) {
|
||||
throw IllegalArgumentException("加密数据格式错误:数据长度不足")
|
||||
}
|
||||
|
||||
val iv = combined.sliceArray(0 until GCM_IV_LENGTH)
|
||||
val cipherText = combined.sliceArray(GCM_IV_LENGTH until combined.size)
|
||||
|
||||
// 创建解密器
|
||||
val cipher = Cipher.getInstance(TRANSFORMATION)
|
||||
val parameterSpec = GCMParameterSpec(GCM_TAG_LENGTH * 8, iv)
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, parameterSpec)
|
||||
|
||||
// 解密数据(GCM 会自动验证认证标签)
|
||||
val decryptedBytes = cipher.doFinal(cipherText)
|
||||
|
||||
// 返回解密后的字符串
|
||||
String(decryptedBytes, StandardCharsets.UTF_8)
|
||||
} catch (e: Exception) {
|
||||
logger.error(e) { "AES-256-GCM解密任务数据失败" }
|
||||
throw RuntimeException("解密任务数据失败: ${e.message}", e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 licence + fingerprint 生成 AES-256 密钥(256位 = 32字节)
|
||||
* 使用 SHA-256 哈希的全部32字节作为密钥
|
||||
*/
|
||||
private fun generateKey(licence: String, fingerprint: String): SecretKeySpec {
|
||||
val combined = "$licence$fingerprint"
|
||||
val digest = MessageDigest.getInstance("SHA-256")
|
||||
val hash = digest.digest(combined.toByteArray(StandardCharsets.UTF_8))
|
||||
|
||||
// 使用全部32字节作为 AES-256 密钥
|
||||
return SecretKeySpec(hash, ALGORITHM)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user