207 lines
4.2 KiB
Go
207 lines
4.2 KiB
Go
|
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))
|
|||
|
}
|