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()
|
|||
|
|
}
|