docs: 添加管理平台标准加密算法 Kotlin 参考实现
This commit is contained in:
129
docs/工具箱端-授权对接指南/utils/DeviceSignatureUtil.kt
Normal file
129
docs/工具箱端-授权对接指南/utils/DeviceSignatureUtil.kt
Normal file
@@ -0,0 +1,129 @@
|
||||
package top.tangyh.lamp.filing.utils
|
||||
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.security.MessageDigest
|
||||
import java.util.*
|
||||
import javax.crypto.Mac
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
|
||||
private val logger = KotlinLogging.logger {}
|
||||
|
||||
/**
|
||||
* 设备签名工具类
|
||||
* 用于生成和验证设备报告签名
|
||||
*
|
||||
* 签名算法:HMAC-SHA256
|
||||
* 签名数据(严格顺序):
|
||||
* sign_payload = taskId + inspectionId +
|
||||
* SHA256(assets.json) +
|
||||
* SHA256(vulnerabilities.json) +
|
||||
* SHA256(weakPasswords.json) +
|
||||
* SHA256(漏洞评估报告.html)
|
||||
*
|
||||
* 安全设计说明:
|
||||
* - 使用 HMAC-SHA256 提供消息认证,防止伪造和篡改
|
||||
* - 签名包含 taskId 和 inspectionId,确保签名与特定任务绑定
|
||||
* - 包含多个报告文件的 SHA256,确保报告内容完整性
|
||||
* - 只有拥有正确 licence + fingerprint 的设备才能生成有效签名
|
||||
*/
|
||||
object DeviceSignatureUtil {
|
||||
|
||||
private const val HMAC_ALGORITHM = "HmacSHA256"
|
||||
|
||||
/**
|
||||
* 签名数据文件列表(严格顺序)
|
||||
*/
|
||||
data class SignatureFileHashes(
|
||||
val assetsJsonSha256: String,
|
||||
val vulnerabilitiesJsonSha256: String,
|
||||
val weakPasswordsJsonSha256: String,
|
||||
val reportHtmlSha256: String
|
||||
)
|
||||
|
||||
/**
|
||||
* 生成设备签名
|
||||
*
|
||||
* @param key 派生密钥(32字节)
|
||||
* @param taskId 任务ID
|
||||
* @param inspectionId 检查ID
|
||||
* @param fileHashes 各个文件的 SHA256 哈希值(hex字符串)
|
||||
* @return Base64 编码的签名
|
||||
*/
|
||||
fun generateSignature(
|
||||
key: ByteArray,
|
||||
taskId: String,
|
||||
inspectionId: Long,
|
||||
fileHashes: SignatureFileHashes
|
||||
): String {
|
||||
return try {
|
||||
// 组装签名数据(严格顺序):
|
||||
// taskId + inspectionId + SHA256(assets.json) + SHA256(vulnerabilities.json) +
|
||||
// SHA256(weakPasswords.json) + SHA256(漏洞评估报告.html)
|
||||
val signatureData = buildString {
|
||||
append(taskId)
|
||||
append(inspectionId)
|
||||
append(fileHashes.assetsJsonSha256)
|
||||
append(fileHashes.vulnerabilitiesJsonSha256)
|
||||
append(fileHashes.weakPasswordsJsonSha256)
|
||||
append(fileHashes.reportHtmlSha256)
|
||||
}
|
||||
val dataBytes = signatureData.toByteArray(StandardCharsets.UTF_8)
|
||||
|
||||
// 使用 HMAC-SHA256 计算签名
|
||||
val mac = Mac.getInstance(HMAC_ALGORITHM)
|
||||
val secretKey = SecretKeySpec(key, HMAC_ALGORITHM)
|
||||
mac.init(secretKey)
|
||||
val signatureBytes = mac.doFinal(dataBytes)
|
||||
|
||||
// Base64 编码返回
|
||||
Base64.getEncoder().encodeToString(signatureBytes)
|
||||
} catch (e: Exception) {
|
||||
logger.error(e) { "生成设备签名失败: taskId=$taskId, inspectionId=$inspectionId" }
|
||||
throw RuntimeException("生成设备签名失败: ${e.message}", e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证设备签名
|
||||
*
|
||||
* @param key 派生密钥(32字节)
|
||||
* @param taskId 任务ID
|
||||
* @param inspectionId 检查ID
|
||||
* @param fileHashes 各个文件的 SHA256 哈希值(hex字符串)
|
||||
* @param expectedSignature Base64 编码的期望签名
|
||||
* @return true 如果签名匹配,false 否则
|
||||
*/
|
||||
fun verifySignature(
|
||||
key: ByteArray,
|
||||
taskId: String,
|
||||
inspectionId: Long,
|
||||
fileHashes: SignatureFileHashes,
|
||||
expectedSignature: String
|
||||
): Boolean {
|
||||
return try {
|
||||
val calculatedSignature = generateSignature(key, taskId, inspectionId, fileHashes)
|
||||
// 使用时间安全的比较,防止时序攻击
|
||||
MessageDigest.isEqual(
|
||||
Base64.getDecoder().decode(expectedSignature),
|
||||
Base64.getDecoder().decode(calculatedSignature)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
logger.error(e) { "验证设备签名失败: taskId=$taskId, inspectionId=$inspectionId" }
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算文件的 SHA256 哈希值(hex字符串)
|
||||
*
|
||||
* @param fileContent 文件内容
|
||||
* @return SHA256 哈希值的 hex 字符串
|
||||
*/
|
||||
fun calculateSha256(fileContent: ByteArray): String {
|
||||
val digest = MessageDigest.getInstance("SHA-256")
|
||||
val hashBytes = digest.digest(fileContent)
|
||||
return hashBytes.joinToString("") { "%02x".format(it) }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user