tydata-server/pkg/lzkit/md5/md5.go
2025-04-08 12:49:19 +08:00

207 lines
4.2 KiB
Go
Raw Permalink 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 md5
import (
"bufio"
"crypto/md5"
"encoding/hex"
"io"
"os"
"strings"
)
// MD5结构体可用于链式调用
type MD5 struct {
data []byte
}
// New 创建一个新的MD5实例
func New() *MD5 {
return &MD5{
data: []byte{},
}
}
// FromString 从字符串创建MD5
func FromString(s string) *MD5 {
return &MD5{
data: []byte(s),
}
}
// FromBytes 从字节切片创建MD5
func FromBytes(b []byte) *MD5 {
return &MD5{
data: b,
}
}
// Add 向MD5中添加字符串
func (m *MD5) Add(s string) *MD5 {
m.data = append(m.data, []byte(s)...)
return m
}
// AddBytes 向MD5中添加字节切片
func (m *MD5) AddBytes(b []byte) *MD5 {
m.data = append(m.data, b...)
return m
}
// Sum 计算并返回MD5哈希值(16进制字符串)
func (m *MD5) Sum() string {
hash := md5.New()
hash.Write(m.data)
return hex.EncodeToString(hash.Sum(nil))
}
// SumBytes 计算并返回MD5哈希值(字节切片)
func (m *MD5) SumBytes() []byte {
hash := md5.New()
hash.Write(m.data)
return hash.Sum(nil)
}
// 直接调用的工具函数
// EncryptString 加密字符串
func EncryptString(s string) string {
hash := md5.New()
hash.Write([]byte(s))
return hex.EncodeToString(hash.Sum(nil))
}
// EncryptBytes 加密字节切片
func EncryptBytes(b []byte) string {
hash := md5.New()
hash.Write(b)
return hex.EncodeToString(hash.Sum(nil))
}
// EncryptFile 加密文件内容
func EncryptFile(filePath string) (string, error) {
file, err := os.Open(filePath)
if err != nil {
return "", err
}
defer file.Close()
hash := md5.New()
if _, err := io.Copy(hash, file); err != nil {
return "", err
}
return hex.EncodeToString(hash.Sum(nil)), nil
}
// EncryptFileChunk 对大文件分块计算MD5提高效率
func EncryptFileChunk(filePath string, chunkSize int) (string, error) {
if chunkSize <= 0 {
chunkSize = 1024 * 1024 // 默认1MB
}
file, err := os.Open(filePath)
if err != nil {
return "", err
}
defer file.Close()
hash := md5.New()
buf := make([]byte, chunkSize)
reader := bufio.NewReader(file)
for {
n, err := reader.Read(buf)
if err != nil && err != io.EOF {
return "", err
}
if n == 0 {
break
}
hash.Write(buf[:n])
}
return hex.EncodeToString(hash.Sum(nil)), nil
}
// EncryptStringWithSalt 使用盐值加密字符串
func EncryptStringWithSalt(s, salt string) string {
return EncryptString(s + salt)
}
// EncryptStringWithPrefix 使用前缀加密字符串
func EncryptStringWithPrefix(s, prefix string) string {
return EncryptString(prefix + s)
}
// VerifyMD5 验证字符串的MD5哈希是否匹配
func VerifyMD5(s, hash string) bool {
return EncryptString(s) == strings.ToLower(hash)
}
// VerifyMD5WithSalt 验证带盐值的字符串MD5哈希是否匹配
func VerifyMD5WithSalt(s, salt, hash string) bool {
return EncryptStringWithSalt(s, salt) == strings.ToLower(hash)
}
// VerifyFileMD5 验证文件的MD5哈希是否匹配
func VerifyFileMD5(filePath, hash string) (bool, error) {
fileHash, err := EncryptFile(filePath)
if err != nil {
return false, err
}
return fileHash == strings.ToLower(hash), nil
}
// MD5格式化为指定位数
// Get16 获取16位MD5值(取32位结果的中间16位)
func Get16(s string) string {
result := EncryptString(s)
return result[8:24]
}
// Get8 获取8位MD5值
func Get8(s string) string {
result := EncryptString(s)
return result[12:20]
}
// MD5主要用于校验而非安全存储对于需要高安全性的场景应考虑:
// 1. bcrypt, scrypt或Argon2等专门为密码设计的算法
// 2. HMAC-MD5等方式以防御彩虹表攻击
// 3. 加盐并使用多次哈希迭代提高安全性
// MD5HMAC 使用HMAC-MD5算法
func MD5HMAC(message, key string) string {
hash := md5.New()
// 如果key长度超出block size先进行哈希
if len(key) > 64 {
hash.Write([]byte(key))
key = hex.EncodeToString(hash.Sum(nil))
hash.Reset()
}
// 内部填充
k_ipad := make([]byte, 64)
k_opad := make([]byte, 64)
copy(k_ipad, []byte(key))
copy(k_opad, []byte(key))
for i := 0; i < 64; i++ {
k_ipad[i] ^= 0x36
k_opad[i] ^= 0x5c
}
// 内部哈希
hash.Write(k_ipad)
hash.Write([]byte(message))
innerHash := hash.Sum(nil)
hash.Reset()
// 外部哈希
hash.Write(k_opad)
hash.Write(innerHash)
return hex.EncodeToString(hash.Sum(nil))
}