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