Files
cmii-uav-watchdog-project/cmii-uav-watchdog-common/totp_tier_one/crypto.go
2025-12-06 11:26:05 +08:00

170 lines
4.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package totp_tier_one
import (
"cmii-uav-watchdog-common/models"
"cmii-uav-watchdog-common/wdd_log"
"crypto/aes"
"crypto/cipher"
"crypto/sha256"
"encoding/base64"
"errors"
"fmt"
"strconv"
"strings"
)
// Encrypt 加密字符串
// 保证使用相同的plaintext和key进行加密在不同时间、不同机器上输出的加密字符串都是固定的
func Encrypt(plaintext string, key string) (encryptedPlaintext string, encryptError error) {
// 创建hash
hasher := sha256.New()
hasher.Write([]byte(key))
keyBytes := hasher.Sum(nil)
// 创建cipher
block, err := aes.NewCipher(keyBytes)
if err != nil {
return "", err
}
// 创建gcm
gcm, err := cipher.NewGCM(block)
if err != nil {
return "", err
}
// 生成确定性nonce - 使用plaintext和key的组合生成确保对相同输入产生相同nonce
nonceHasher := sha256.New()
nonceHasher.Write([]byte(key + "fixed_salt_for_deterministic_result" + plaintext[:min(10, len(plaintext))]))
nonceSource := nonceHasher.Sum(nil)
// 创建合适大小的nonce
nonce := nonceSource[:gcm.NonceSize()]
// 加密
ciphertext := gcm.Seal(nil, nonce, []byte(plaintext), nil)
// 将nonce和密文连接起来
result := append(nonce, ciphertext...)
// 编码为base64
return base64.StdEncoding.EncodeToString(result), nil
}
// Decrypt 解密字符串
// 可以使用加密字符串和key在不同时间、不同机器上解密出原始plaintext
func Decrypt(encrypted string, key string) (decryptedPlaintext string, decryptError error) {
// 解码base64
data, err := base64.StdEncoding.DecodeString(encrypted)
if err != nil {
return "", err
}
// 创建hash
hasher := sha256.New()
hasher.Write([]byte(key))
keyBytes := hasher.Sum(nil)
// 创建cipher
block, err := aes.NewCipher(keyBytes)
if err != nil {
return "", err
}
// 创建gcm
gcm, err := cipher.NewGCM(block)
if err != nil {
return "", err
}
// 检查长度
if len(data) < gcm.NonceSize() {
return "", errors.New("密文太短")
}
// 分离nonce和密文
nonce, ciphertext := data[:gcm.NonceSize()], data[gcm.NonceSize():]
// 解密
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return "", err
}
return string(plaintext), nil
}
// min 返回两个整数中较小的一个
func min(a, b int) int {
if a < b {
return a
}
return b
}
// EncryptHostInfo 加密主机信息
func EncryptHostInfo(hostInfo models.HostInfo, key string) (encryptedHostInfo string, encryptError error) {
// 生成主机唯一标识作为加密密钥
info := generateHostUniqueID(hostInfo)
// 加密主机信息
encrypted, err := Encrypt(info, key)
if err != nil {
return "", err
}
return encrypted, nil
}
// DecryptHostInfo 解密主机信息
func DecryptHostInfo(encrypted string, hostInfo models.HostInfo, key string) (decryptedOK bool, decryptError error) {
// 解密主机信息
decryptedStr, err := Decrypt(encrypted, key)
if err != nil {
wdd_log.Error("[DecryptHostInfo] - Decrypt失败: %v", err)
return false, err
}
// wdd_log.Info("[DecryptHostInfo] - Decrypt成功: %s", decryptedStr)
// 生成主机唯一标识作为加密密钥
hostUniqueID := generateHostUniqueID(hostInfo)
if hostUniqueID != decryptedStr {
wdd_log.Error("[DecryptHostInfo] - 主机信息篡改")
return false, errors.New("主机信息篡改")
}
return true, nil
}
// generateHostUniqueID 生成主机唯一标识作为加密密钥
func generateHostUniqueID(hostInfo models.HostInfo) string {
// hostinfo.SystemInfo.MachineID
machineID := hostInfo.SystemInfo.MachineID
// hostinfo.SystemInfo.KernelVersion
kernelVersion := hostInfo.SystemInfo.KernelVersion
// 将CPU信息中的ModelName Cores Hypervisor 拼接起来
cpuCores := hostInfo.CPUInfo.Cores
cpuHypervisor := hostInfo.CPUInfo.Hypervisor
cpuModelName := hostInfo.CPUInfo.ModelName
cpuInfo := fmt.Sprintf("%s-%d-%s", cpuModelName, cpuCores, cpuHypervisor)
// 不能使用 mac 地址,因为 每个Pod 的 mac 地址会变化
// hostinfo.SystemInfo.MachineSerial
machineSerial := hostInfo.SystemInfo.MachineSerial
// 将memory中的total 和 used 拼接起来
memoryTotal := hostInfo.MemoryInfo.Total
// 将上述的全部信息拼接起来
info := strings.Join([]string{machineID, kernelVersion, cpuInfo, machineSerial, strconv.FormatUint(memoryTotal, 10)}, "==")
return info
}