78 lines
2.1 KiB
Go
78 lines
2.1 KiB
Go
package utils
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/sha256"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"log"
|
|
randa "math/rand"
|
|
"time"
|
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
type Crypto struct{}
|
|
|
|
func (*Crypto) PasswordEncryption(password string) (string, error) {
|
|
cost := 10
|
|
hashedBytes, err := bcrypt.GenerateFromPassword([]byte(password), cost)
|
|
if err != nil {
|
|
log.Fatal("加密失败:", err)
|
|
return "", err
|
|
}
|
|
|
|
hashedPassword := string(hashedBytes)
|
|
|
|
fmt.Println("加密后的哈希值:", hashedPassword)
|
|
return hashedPassword, nil
|
|
}
|
|
|
|
func (*Crypto) PasswordVerify(hash, password string) bool {
|
|
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
|
|
return err == nil
|
|
}
|
|
|
|
func (*Crypto) GenerateStateToken(tokenLength int) (string, error) {
|
|
// 1. 生成密码学安全的随机字节
|
|
randomBytes := make([]byte, tokenLength)
|
|
_, err := rand.Read(randomBytes)
|
|
if err != nil {
|
|
return "", fmt.Errorf("生成随机数失败: %w", err)
|
|
}
|
|
|
|
// 2. (可选) 加入时间戳作为额外熵源,进一步降低碰撞和重放风险
|
|
// 注意:如果你需要验证 token 的新鲜度(如设置有效期),时间戳信息需要单独存储,因为哈希本身不可逆。
|
|
currentTime := time.Now().UnixNano()
|
|
timeBytes := make([]byte, 8)
|
|
// 简单地将时间戳转为字节序列,这里使用大端序
|
|
for i := 0; i < 8; i++ {
|
|
timeBytes[i] = byte(currentTime >> (56 - i*8))
|
|
}
|
|
|
|
// 将随机字节和时间戳字节组合
|
|
dataToHash := append(randomBytes, timeBytes...)
|
|
|
|
// 3. 对组合后的数据进行 SHA-256 哈希
|
|
hash := sha256.Sum256(dataToHash)
|
|
|
|
// 4. 将哈希结果转换为字符串(这里使用 Base64 编码)
|
|
token := base64.URLEncoding.EncodeToString(hash[:])
|
|
return token, nil
|
|
}
|
|
|
|
func (*Crypto) GetRandString(length int) string {
|
|
// 初始化随机数种子
|
|
randa.Seed(time.Now().UnixNano())
|
|
|
|
const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
|
|
|
// 方法1: 使用字节切片
|
|
b := make([]byte, length)
|
|
for i := range b {
|
|
b[i] = letters[randa.Intn(len(letters))] // 随机选取一个字符
|
|
}
|
|
randomString := string(b)
|
|
return randomString
|
|
}
|