- 将所有trustlog-sdk文件移动到trustlog/go-trustlog/目录 - 更新README中所有import路径从trustlog-sdk改为go-trustlog - 更新cookiecutter配置文件中的项目名称 - 更新根目录.lefthook.yml以引用新位置的配置 - 添加go.sum文件到版本控制 - 删除过时的示例文件 这次重构与trustlog-server保持一致的目录结构, 为未来支持多语言SDK(Python、Java等)预留空间。
268 lines
6.5 KiB
Go
268 lines
6.5 KiB
Go
package model
|
||
|
||
import (
|
||
"context"
|
||
"crypto/md5"
|
||
"crypto/sha1"
|
||
stdsha256 "crypto/sha256"
|
||
stdsha512 "crypto/sha512"
|
||
"encoding/hex"
|
||
"hash"
|
||
"io"
|
||
"os"
|
||
"strings"
|
||
"sync"
|
||
|
||
miniosha256 "github.com/minio/sha256-simd"
|
||
"github.com/zeebo/blake3"
|
||
"golang.org/x/crypto/blake2b"
|
||
"golang.org/x/crypto/blake2s"
|
||
"golang.org/x/crypto/md4" //nolint:staticcheck // 保留弱加密算法以支持遗留系统兼容性
|
||
"golang.org/x/crypto/ripemd160" //nolint:staticcheck // 保留弱加密算法以支持遗留系统兼容性
|
||
"golang.org/x/crypto/sha3"
|
||
)
|
||
|
||
// HashType 定义支持的哈希算法类型.
|
||
type HashType string
|
||
|
||
const (
|
||
MD5 HashType = "md5"
|
||
SHA1 HashType = "sha1"
|
||
SHA224 HashType = "sha224"
|
||
SHA256 HashType = "sha256"
|
||
SHA384 HashType = "sha384"
|
||
SHA512 HashType = "sha512"
|
||
Sha512224 HashType = "sha512_224"
|
||
Sha512256 HashType = "sha512_256"
|
||
|
||
Sha256Simd HashType = "sha256-simd"
|
||
BLAKE3 HashType = "blake3"
|
||
BLAKE2B HashType = "blake2b"
|
||
BLAKE2S HashType = "blake2s"
|
||
MD4 HashType = "md4"
|
||
RIPEMD160 HashType = "ripemd160"
|
||
Sha3224 HashType = "sha3-224"
|
||
Sha3256 HashType = "sha3-256"
|
||
Sha3384 HashType = "sha3-384"
|
||
Sha3512 HashType = "sha3-512"
|
||
)
|
||
|
||
// 使用 map 来存储支持的算法,提高查找效率.
|
||
//
|
||
//nolint:gochecknoglobals // 全局缓存用于算法查找和实例复用.
|
||
var (
|
||
supportedAlgorithms []string
|
||
supportedAlgorithmsMap map[string]bool
|
||
supportedAlgorithmsOnce sync.Once
|
||
|
||
// 享元模式:存储已创建的 HashTool 实例.
|
||
toolPool = make(map[HashType]*HashTool)
|
||
poolMutex sync.RWMutex
|
||
)
|
||
|
||
// HashTool 哈希工具类.
|
||
type HashTool struct {
|
||
hashType HashType
|
||
}
|
||
|
||
// GetHashTool 获取指定类型的 HashTool.
|
||
func GetHashTool(hashType HashType) *HashTool {
|
||
poolMutex.RLock()
|
||
if tool, exists := toolPool[hashType]; exists {
|
||
poolMutex.RUnlock()
|
||
return tool
|
||
}
|
||
poolMutex.RUnlock()
|
||
|
||
poolMutex.Lock()
|
||
defer poolMutex.Unlock()
|
||
|
||
if tool, exists := toolPool[hashType]; exists {
|
||
return tool
|
||
}
|
||
|
||
tool := &HashTool{hashType: hashType}
|
||
toolPool[hashType] = tool
|
||
return tool
|
||
}
|
||
|
||
// NewHashTool 创建新的哈希工具实例.
|
||
func NewHashTool(hashType HashType) *HashTool {
|
||
return &HashTool{hashType: hashType}
|
||
}
|
||
|
||
// getHasher 根据哈希类型获取对应的哈希器.
|
||
func (h *HashTool) getHasher() hash.Hash {
|
||
switch h.hashType {
|
||
case MD5:
|
||
return md5.New()
|
||
case SHA1:
|
||
return sha1.New()
|
||
case SHA224:
|
||
return stdsha256.New224()
|
||
case SHA256:
|
||
return stdsha256.New()
|
||
case SHA384:
|
||
return stdsha512.New384()
|
||
case SHA512:
|
||
return stdsha512.New()
|
||
case Sha512224:
|
||
return stdsha512.New512_224()
|
||
case Sha512256:
|
||
return stdsha512.New512_256()
|
||
|
||
// 第三方算法
|
||
case Sha256Simd:
|
||
return miniosha256.New()
|
||
case BLAKE3:
|
||
return blake3.New()
|
||
case BLAKE2B:
|
||
hasher, _ := blake2b.New512(nil)
|
||
return hasher
|
||
case BLAKE2S:
|
||
hasher, _ := blake2s.New256(nil)
|
||
return hasher
|
||
case MD4:
|
||
return md4.New()
|
||
case RIPEMD160:
|
||
return ripemd160.New()
|
||
case Sha3224:
|
||
return sha3.New224()
|
||
case Sha3256:
|
||
return sha3.New256()
|
||
case Sha3384:
|
||
return sha3.New384()
|
||
case Sha3512:
|
||
return sha3.New512()
|
||
|
||
default:
|
||
return stdsha256.New() // 默认使用 SHA256
|
||
}
|
||
}
|
||
|
||
// hashData 通用的哈希计算函数.
|
||
func (h *HashTool) hashData(processFunc func(hasher hash.Hash) error) (string, error) {
|
||
hasher := h.getHasher()
|
||
if err := processFunc(hasher); err != nil {
|
||
return "", err
|
||
}
|
||
return hex.EncodeToString(hasher.Sum(nil)), nil
|
||
}
|
||
|
||
// HashString 对字符串进行哈希计算.
|
||
func (h *HashTool) HashString(data string) (string, error) {
|
||
return h.hashData(func(hasher hash.Hash) error {
|
||
_, err := hasher.Write([]byte(data))
|
||
return err
|
||
})
|
||
}
|
||
|
||
// HashBytes 对字节数组进行哈希计算.
|
||
func (h *HashTool) HashBytes(data []byte) (string, error) {
|
||
return h.hashData(func(hasher hash.Hash) error {
|
||
_, err := hasher.Write(data)
|
||
return err
|
||
})
|
||
}
|
||
|
||
// HashBytesRaw 对字节数组进行哈希计算,返回原始字节数组(非hex字符串).
|
||
func (h *HashTool) HashBytesRaw(data []byte) ([]byte, error) {
|
||
hasher := h.getHasher()
|
||
if _, err := hasher.Write(data); err != nil {
|
||
return nil, err
|
||
}
|
||
return hasher.Sum(nil), nil
|
||
}
|
||
|
||
// HashFile 对文件进行哈希计算.
|
||
func (h *HashTool) HashFile(_ context.Context, filePath string) (string, error) {
|
||
file, err := os.Open(filePath)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
defer file.Close()
|
||
|
||
return h.hashData(func(hasher hash.Hash) error {
|
||
_, copyErr := io.Copy(hasher, file)
|
||
return copyErr
|
||
})
|
||
}
|
||
|
||
// HashStream 对流数据进行哈希计算.
|
||
func (h *HashTool) HashStream(reader io.Reader) (string, error) {
|
||
return h.hashData(func(hasher hash.Hash) error {
|
||
_, err := io.Copy(hasher, reader)
|
||
return err
|
||
})
|
||
}
|
||
|
||
// initSupportedAlgorithms 初始化支持的算法数据.
|
||
func initSupportedAlgorithms() {
|
||
algorithms := []HashType{
|
||
MD5, SHA1, SHA224, SHA256, SHA384, SHA512,
|
||
Sha512224, Sha512256, Sha256Simd, BLAKE3,
|
||
BLAKE2B, BLAKE2S, MD4, RIPEMD160,
|
||
Sha3224, Sha3256, Sha3384, Sha3512,
|
||
}
|
||
|
||
supportedAlgorithms = make([]string, len(algorithms))
|
||
supportedAlgorithmsMap = make(map[string]bool, len(algorithms))
|
||
|
||
for i, alg := range algorithms {
|
||
algStr := string(alg)
|
||
supportedAlgorithms[i] = algStr
|
||
supportedAlgorithmsMap[strings.ToLower(algStr)] = true
|
||
}
|
||
}
|
||
|
||
// GetSupportedAlgorithms 获取支持的哈希算法列表.
|
||
func GetSupportedAlgorithms() []string {
|
||
supportedAlgorithmsOnce.Do(initSupportedAlgorithms)
|
||
return supportedAlgorithms
|
||
}
|
||
|
||
// IsAlgorithmSupported 检查算法是否支持 - 使用 map 提高性能.
|
||
func IsAlgorithmSupported(algorithm string) bool {
|
||
supportedAlgorithmsOnce.Do(initSupportedAlgorithms)
|
||
return supportedAlgorithmsMap[strings.ToLower(algorithm)]
|
||
}
|
||
|
||
// CompareHash 比较哈希值.
|
||
func (h *HashTool) CompareHash(data, expectedHash string) (bool, error) {
|
||
actualHash, err := h.HashString(data)
|
||
if err != nil {
|
||
return false, err
|
||
}
|
||
return strings.EqualFold(actualHash, expectedHash), nil
|
||
}
|
||
|
||
// CompareFileHash 比较文件哈希值.
|
||
func (h *HashTool) CompareFileHash(ctx context.Context, filePath, expectedHash string) (bool, error) {
|
||
actualHash, err := h.HashFile(ctx, filePath)
|
||
if err != nil {
|
||
return false, err
|
||
}
|
||
return strings.EqualFold(actualHash, expectedHash), nil
|
||
}
|
||
|
||
// GetHashType 获取当前工具使用的哈希类型.
|
||
func (h *HashTool) GetHashType() HashType {
|
||
return h.hashType
|
||
}
|
||
|
||
type HashData interface {
|
||
Key() string
|
||
Hash() string
|
||
Type() HashType
|
||
}
|
||
|
||
type Hashable interface {
|
||
DoHash(ctx context.Context) (HashData, error)
|
||
}
|
||
|
||
type HashList []HashData
|
||
|
||
func (h HashList) GetHashType() HashType {
|
||
return h[0].Type()
|
||
}
|