Compare commits

...
4 Commits
Author SHA1 Message Date
yun 034315ddbd 添加测试文件 2025-11-09 18:23:08 +08:00
yun 7bbd570de9 添加更多的方法 2025-11-03 23:40:41 +08:00
yun 6e088f68bd 完善测试用例 2025-11-03 23:08:53 +08:00
yun 3dd73f928d 完善其他类型的加解密 2025-11-03 23:03:17 +08:00
23 changed files with 2845 additions and 67 deletions
+248 -51
View File
@@ -9,46 +9,116 @@ import (
"errors"
"fmt"
"io"
"strings"
)
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func PKCS7UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
// AES加密,CBC
func AesEncrypt(origData, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
// AES-256-ECB 加密,返回大写的十六进制字符串
func EncryptECBHex(input, key string) (string, error) {
// 创建AES加密器
block, err := aes.NewCipher([]byte(key))
if err != nil {
return nil, err
return "", err
}
// 对输入数据进行PKCS7填充
paddedInput := PKCS7Padding([]byte(input), block.BlockSize())
// ECB模式加密
encrypted := make([]byte, len(paddedInput))
for i := 0; i < len(paddedInput); i += aes.BlockSize {
block.Encrypt(encrypted[i:i+aes.BlockSize], paddedInput[i:i+aes.BlockSize])
}
// 转换为十六进制并大写
result := hex.EncodeToString(encrypted)
return strings.ToUpper(result), nil
}
// AES-256-ECB 解密,输入大写的十六进制字符串
func DecryptECBHex(encryptedHex, key string) (string, error) {
encrypted, err := hex.DecodeString(encryptedHex)
if err != nil {
return "", fmt.Errorf("hex解码失败: %v", err)
}
block, err := aes.NewCipher([]byte(key))
if err != nil {
return "", fmt.Errorf("创建AES解密器失败: %v", err)
}
// ECB模式解密
decrypted := make([]byte, len(encrypted))
for i := 0; i < len(encrypted); i += aes.BlockSize {
block.Decrypt(decrypted[i:i+aes.BlockSize], encrypted[i:i+aes.BlockSize])
}
// 去除PKCS7填充
unpaddedData, err := PKCS7UnPadding(decrypted)
if err != nil {
return "", fmt.Errorf("去除填充失败: %v", err)
}
return string(unpaddedData), nil
}
// AES-256-CBC 加密
func EncryptCBCHex(plaintext, key string) (string, error) {
block, err := aes.NewCipher([]byte(key))
if err != nil {
return "", err
}
blockSize := block.BlockSize()
origData = PKCS7Padding(origData, blockSize)
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
crypted := make([]byte, len(origData))
blockMode.CryptBlocks(crypted, origData)
return crypted, nil
plainBytes := PKCS7Padding([]byte(plaintext), blockSize)
// 创建密文字节切片,包含IV空间
cipherbyte := make([]byte, aes.BlockSize+len(plainBytes))
// 生成随机IV
iv := cipherbyte[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return "", err
}
// 创建CBC模式加密器
blockMode := cipher.NewCBCEncrypter(block, iv)
// 加密数据
blockMode.CryptBlocks(cipherbyte[aes.BlockSize:], plainBytes)
// 转换为十六进制并大写
result := hex.EncodeToString(cipherbyte)
return strings.ToUpper(result), nil
}
// AES解密
func AesDecrypt(crypted, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
// AES-256-CBC 解密
func DecryptCBCHex(encryptedHex, key string) (string, error) {
cipherbyte, err := hex.DecodeString(encryptedHex)
if err != nil {
return nil, err
return "", fmt.Errorf("hex解码失败: %v", err)
}
blockSize := block.BlockSize()
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
origData := make([]byte, len(crypted))
blockMode.CryptBlocks(origData, crypted)
origData = PKCS7UnPadding(origData)
return origData, nil
if len(cipherbyte) < aes.BlockSize {
return "", errors.New("ciphertext too short")
}
block, err := aes.NewCipher([]byte(key))
if err != nil {
return "", err
}
iv := cipherbyte[:aes.BlockSize]
cipherbyte = cipherbyte[aes.BlockSize:]
if len(cipherbyte)%aes.BlockSize != 0 {
return "", errors.New("ciphertext is not a multiple of the block size")
}
blockMode := cipher.NewCBCDecrypter(block, iv)
origData := make([]byte, len(cipherbyte))
blockMode.CryptBlocks(origData, cipherbyte)
origBy, err := PKCS7UnPadding(origData)
if err != nil {
return "", err
}
return string(origBy), nil
}
/*
@@ -81,12 +151,10 @@ func AESCBCEncrypt(key, plaintext string) (ciphertext string, err error) {
return
}
/*
AES CBC 解码
key:解密key
ciphertext:加密返回的串
plaintext:解密后的字符串
*/
// AES CBC 解码
// key:解密key
// ciphertext:加密返回的串
// plaintext:解密后的字符串
func AESCBCDecrypter(key, ciphertext string) (plaintext string, err error) {
cipherbyte, _ := hex.DecodeString(ciphertext)
keybyte := []byte(key)
@@ -112,13 +180,11 @@ func AESCBCDecrypter(key, ciphertext string) (plaintext string, err error) {
return
}
/*
AES GCM 加密
key:加密key
plaintext:加密明文
ciphertext:解密返回字节字符串[ 整型以十六进制方式显示]
*/
func AESGCMEncrypt(key, plaintext string) (ciphertext, noncetext string, err error) {
// AES GCM 加密
// key:加密key
// plaintext:加密明文
// ciphertext:解密返回字节字符串[ 整型以十六进制方式显示]
func EncryptGCM(key, plaintext string) (ciphertext, noncetext string, err error) {
plainbyte := []byte(plaintext)
keybyte := []byte(key)
block, err := aes.NewCipher(keybyte)
@@ -143,13 +209,11 @@ func AESGCMEncrypt(key, plaintext string) (ciphertext, noncetext string, err err
return
}
/*
AES GCM 解码
key:解密key
ciphertext:加密返回的串
plaintext:解密后的字符串
*/
func AESGCMDecrypter(key, ciphertext, noncetext string) (plaintext string, err error) {
// AES GCM 解码
// key:解密key
// ciphertext:加密返回的串
// plaintext:解密后的字符串
func DecryptGCM(key, ciphertext, noncetext string) (plaintext string, err error) {
cipherbyte, _ := hex.DecodeString(ciphertext)
nonce, _ := hex.DecodeString(noncetext)
keybyte := []byte(key)
@@ -172,3 +236,136 @@ func AESGCMDecrypter(key, ciphertext, noncetext string) (plaintext string, err e
plaintext = string(plainbyte[:])
return
}
// AES CFB 加密
func EncryptCFBHex(plaintext, key string) (string, error) {
block, err := aes.NewCipher([]byte(key))
if err != nil {
return "", err
}
// 创建密文字节切片,包含IV空间
cipherbyte := make([]byte, aes.BlockSize+len(plaintext))
// 生成随机IV
iv := cipherbyte[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return "", err
}
// 创建CFB模式加密器
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(cipherbyte[aes.BlockSize:], []byte(plaintext))
// 转换为十六进制并大写
result := hex.EncodeToString(cipherbyte)
return strings.ToUpper(result), nil
}
// AES CFB 解密
func DecryptCFBHex(encryptedHex, key string) (string, error) {
cipherbyte, err := hex.DecodeString(encryptedHex)
if err != nil {
return "", fmt.Errorf("hex解码失败: %v", err)
}
if len(cipherbyte) < aes.BlockSize {
return "", errors.New("ciphertext too short")
}
block, err := aes.NewCipher([]byte(key))
if err != nil {
return "", err
}
// 获取IV
iv := cipherbyte[:aes.BlockSize]
cipherbyte = cipherbyte[aes.BlockSize:]
// 创建CFB模式解密器
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(cipherbyte, cipherbyte)
return string(cipherbyte), nil
}
// AES OFB 加密
func EncryptOFBHex(plaintext, key string) (string, error) {
block, err := aes.NewCipher([]byte(key))
if err != nil {
return "", err
}
// 创建密文字节切片,包含IV空间
cipherbyte := make([]byte, aes.BlockSize+len(plaintext))
// 生成随机IV
iv := cipherbyte[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return "", err
}
// 创建OFB模式加密器
stream := cipher.NewOFB(block, iv)
stream.XORKeyStream(cipherbyte[aes.BlockSize:], []byte(plaintext))
// 转换为十六进制并大写
result := hex.EncodeToString(cipherbyte)
return strings.ToUpper(result), nil
}
// AES OFB 解密
func DecryptOFBHex(encryptedHex, key string) (string, error) {
cipherbyte, err := hex.DecodeString(encryptedHex)
if err != nil {
return "", fmt.Errorf("hex解码失败: %v", err)
}
if len(cipherbyte) < aes.BlockSize {
return "", errors.New("ciphertext too short")
}
block, err := aes.NewCipher([]byte(key))
if err != nil {
return "", err
}
// 获取IV
iv := cipherbyte[:aes.BlockSize]
cipherbyte = cipherbyte[aes.BlockSize:]
// 创建OFB模式解密器
stream := cipher.NewOFB(block, iv)
stream.XORKeyStream(cipherbyte, cipherbyte)
return string(cipherbyte), nil
}
// PKCS7补码
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
// 去除PKCS7补码
func PKCS7UnPadding(data []byte) ([]byte, error) {
length := len(data)
if length == 0 {
return nil, errors.New("ciphertext is empty")
}
unpadding := int(data[length-1])
if unpadding > length || unpadding == 0 {
return nil, errors.New("unpadding size is invalid")
}
// 检查填充是否正确
for i := length - unpadding; i < length; i++ {
if data[i] != byte(unpadding) {
return nil, errors.New("invalid padding")
}
}
return data[:(length - unpadding)], nil
}
+89 -8
View File
@@ -7,7 +7,7 @@ import (
"code.yun.ink/pkg/encryptx/aesx"
)
func TestAes(t *testing.T) {
func TestGCM(t *testing.T) {
key := "example key 1234"
plaintext := "exampleplaintext"
@@ -21,16 +21,97 @@ func TestAes(t *testing.T) {
fmt.Println(plaintext, err)
///GCM
noncetext := ""
ciphertext, noncetext, err = aesx.AESGCMEncrypt(key, plaintext)
ciphertext, noncetext, err = aesx.EncryptGCM(key, plaintext)
fmt.Println(ciphertext, err)
plaintext, err = aesx.AESGCMDecrypter(key, ciphertext, noncetext)
plaintext, err = aesx.DecryptGCM(key, ciphertext, noncetext)
fmt.Println(plaintext, err)
}
func TestDemo(t *testing.T) {
c := []byte("08I2GfoqfIlUYgteelimxQ")
c := []byte("rRq++jXDMPDVcUkXAZA9kg==:o57DgQ+iQMXpERuShWs/XA==")
a,e := aesx.AesDecrypt(c, k)
fmt.Println(a,e)
func TestECB(t *testing.T) {
key := "example key 1234"
plaintext := "exampleplaintext"
// 测试ECB加密和解密
encrypted, err := aesx.EncryptECBHex(plaintext, key)
if err != nil {
t.Fatalf("ECB加密失败: %v", err)
}
fmt.Printf("ECB加密结果: %s\n", encrypted)
decrypted, err := aesx.DecryptECBHex(encrypted, key)
if err != nil {
t.Fatalf("ECB解密失败: %v", err)
}
fmt.Printf("ECB解密结果: %s\n", decrypted)
if decrypted != plaintext {
t.Fatalf("ECB解密结果不匹配,原文: %s, 解密结果: %s", plaintext, decrypted)
}
}
func TestCBC(t *testing.T) {
key := "example key 1234"
plaintext := "exampleplaintext"
// 测试CBC加密和解密
encrypted, err := aesx.EncryptCBCHex(plaintext, key)
if err != nil {
t.Fatalf("CBC加密失败: %v", err)
}
fmt.Printf("CBC加密结果: %s\n", encrypted)
decrypted, err := aesx.DecryptCBCHex(encrypted, key)
if err != nil {
t.Fatalf("CBC解密失败: %v", err)
}
fmt.Printf("CBC解密结果: %s\n", decrypted)
if decrypted != plaintext {
t.Fatalf("CBC解密结果不匹配,原文: %s, 解密结果: %s", plaintext, decrypted)
}
}
func TestCFB(t *testing.T) {
key := "example key 1234"
plaintext := "exampleplaintext"
// 测试CFB加密和解密
encrypted, err := aesx.EncryptCFBHex(plaintext, key)
if err != nil {
t.Fatalf("CFB加密失败: %v", err)
}
fmt.Printf("CFB加密结果: %s\n", encrypted)
decrypted, err := aesx.DecryptCFBHex(encrypted, key)
if err != nil {
t.Fatalf("CFB解密失败: %v", err)
}
fmt.Printf("CFB解密结果: %s\n", decrypted)
if decrypted != plaintext {
t.Fatalf("CFB解密结果不匹配,原文: %s, 解密结果: %s", plaintext, decrypted)
}
}
func TestOFB(t *testing.T) {
key := "example key 1234"
plaintext := "exampleplaintext"
// 测试OFB加密和解密
encrypted, err := aesx.EncryptOFBHex(plaintext, key)
if err != nil {
t.Fatalf("OFB加密失败: %v", err)
}
fmt.Printf("OFB加密结果: %s\n", encrypted)
decrypted, err := aesx.DecryptOFBHex(encrypted, key)
if err != nil {
t.Fatalf("OFB解密失败: %v", err)
}
fmt.Printf("OFB解密结果: %s\n", decrypted)
if decrypted != plaintext {
t.Fatalf("OFB解密结果不匹配,原文: %s, 解密结果: %s", plaintext, decrypted)
}
}
+9 -8
View File
@@ -3,11 +3,11 @@ package base64x
import "encoding/base64"
// 普通的
func Base64StdEncode(s string) string {
func StdEncode(s string) string {
return base64.StdEncoding.EncodeToString([]byte(s))
}
func Base64StdDecode(sEnc string) (string, error) {
func StdDecode(sEnc string) (string, error) {
sDec, err := base64.StdEncoding.DecodeString(sEnc)
if err != nil {
return "", err
@@ -16,11 +16,11 @@ func Base64StdDecode(sEnc string) (string, error) {
}
// URL和文件名安全的
func Base64UrlEncode(s string) string {
func UrlEncode(s string) string {
return base64.URLEncoding.EncodeToString([]byte(s))
}
func Base64UrlDecode(sEnc string) (string, error) {
func UrlDecode(sEnc string) (string, error) {
sDec, err := base64.URLEncoding.DecodeString(sEnc)
if err != nil {
return "", err
@@ -29,11 +29,11 @@ func Base64UrlDecode(sEnc string) (string, error) {
}
// 无填充
func Base64RawEncode(s string) string {
func RawEncode(s string) string {
return base64.RawStdEncoding.EncodeToString([]byte(s))
}
func Base64RawDecode(sEnc string) (string, error) {
func RawDecode(sEnc string) (string, error) {
sDec, err := base64.RawStdEncoding.DecodeString(sEnc)
if err != nil {
return "", err
@@ -41,11 +41,12 @@ func Base64RawDecode(sEnc string) (string, error) {
return string(sDec), nil
}
func Base64RawUrlEncode(s string) string {
// URL和文件名安全的,无填充
func RawUrlEncode(s string) string {
return base64.RawURLEncoding.EncodeToString([]byte(s))
}
func Base64RawUrlDecode(s string) (string, error) {
func RawUrlDecode(s string) (string, error) {
decoded, err := base64.RawURLEncoding.DecodeString(s)
return string(decoded), err
}
+43
View File
@@ -0,0 +1,43 @@
package base64x_test
import (
"testing"
"code.yun.ink/pkg/encryptx/base64x"
)
func TestBase64xStd(t *testing.T) {
original := "Hello, World!"
encoded := base64x.StdEncode(original)
decoded, err := base64x.StdDecode(encoded)
if err != nil {
t.Error(err)
}
if original != decoded {
t.Errorf("expected %q, got %q", original, decoded)
}
}
func TestBase64xUrl(t *testing.T) {
original := "Hello, World!"
encoded := base64x.UrlEncode(original)
decoded, err := base64x.UrlDecode(encoded)
if err != nil {
t.Error(err)
}
if original != decoded {
t.Errorf("expected %q, got %q", original, decoded)
}
}
func TestBase64xRaw(t *testing.T) {
original := "Hello, World!"
encoded := base64x.RawEncode(original)
decoded, err := base64x.RawDecode(encoded)
if err != nil {
t.Error(err)
}
if original != decoded {
t.Errorf("expected %q, got %q", original, decoded)
}
}
+19
View File
@@ -0,0 +1,19 @@
package bcryptx
import "golang.org/x/crypto/bcrypt"
// HashPassword 使用 bcrypt 算法对密码进行哈希处理
func HashPassword(password string) (string, error) {
// 第二个参数是 cost 值,代表计算强度
bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return "", err
}
return string(bytes), nil
}
// CheckPasswordHash 检查密码是否与哈希值匹配
func CheckPasswordHash(password, hash string) bool {
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
return err == nil
}
+20
View File
@@ -0,0 +1,20 @@
package bcryptx_test
import (
"testing"
"code.yun.ink/pkg/encryptx/bcryptx"
)
func TestDecryptBcrypt(t *testing.T) {
str, err := bcryptx.HashPassword("password")
if err != nil {
t.Error(err)
}
t.Log(str)
if bcryptx.CheckPasswordHash("password", str) {
t.Log("ok")
} else {
t.Error("error")
}
}
+203
View File
@@ -0,0 +1,203 @@
package desx
import (
"bytes"
"crypto/cipher"
"crypto/des"
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
"io"
"strings"
)
// DES-ECB 加密,返回大写的十六进制字符串
func EncryptECBHex(input, key string) (string, error) {
// 创建DES加密器
block, err := des.NewCipher([]byte(key))
if err != nil {
return "", err
}
// 对输入数据进行PKCS7填充
paddedInput := PKCS7Padding([]byte(input), block.BlockSize())
// ECB模式加密
encrypted := make([]byte, len(paddedInput))
for i := 0; i < len(paddedInput); i += des.BlockSize {
block.Encrypt(encrypted[i:i+des.BlockSize], paddedInput[i:i+des.BlockSize])
}
// 转换为十六进制并大写
result := hex.EncodeToString(encrypted)
return strings.ToUpper(result), nil
}
// DES-ECB 解密,输入大写的十六进制字符串
func DecryptECBHex(encryptedHex, key string) (string, error) {
encrypted, err := hex.DecodeString(encryptedHex)
if err != nil {
return "", fmt.Errorf("hex解码失败: %v", err)
}
block, err := des.NewCipher([]byte(key))
if err != nil {
return "", fmt.Errorf("创建DES解密器失败: %v", err)
}
// ECB模式解密
decrypted := make([]byte, len(encrypted))
for i := 0; i < len(encrypted); i += des.BlockSize {
block.Decrypt(decrypted[i:i+des.BlockSize], encrypted[i:i+des.BlockSize])
}
// 去除PKCS7填充
unpaddedData, err := PKCS7UnPadding(decrypted)
if err != nil {
return "", fmt.Errorf("去除填充失败: %v", err)
}
return string(unpaddedData), nil
}
// DES-CBC 加密
func EncryptCBCHex(plaintext, key string) (string, error) {
block, err := des.NewCipher([]byte(key))
if err != nil {
return "", err
}
blockSize := block.BlockSize()
plainBytes := PKCS7Padding([]byte(plaintext), blockSize)
// 创建密文字节切片,包含IV空间
cipherbyte := make([]byte, des.BlockSize+len(plainBytes))
// 生成随机IV
iv := cipherbyte[:des.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return "", err
}
// 创建CBC模式加密器
blockMode := cipher.NewCBCEncrypter(block, iv)
// 加密数据
blockMode.CryptBlocks(cipherbyte[des.BlockSize:], plainBytes)
// 转换为十六进制并大写
result := hex.EncodeToString(cipherbyte)
return strings.ToUpper(result), nil
}
// DES-CBC 解密
func DecryptCBCHex(encryptedHex, key string) (string, error) {
cipherbyte, err := hex.DecodeString(encryptedHex)
if err != nil {
return "", fmt.Errorf("hex解码失败: %v", err)
}
if len(cipherbyte) < des.BlockSize {
return "", errors.New("ciphertext too short")
}
block, err := des.NewCipher([]byte(key))
if err != nil {
return "", err
}
iv := cipherbyte[:des.BlockSize]
cipherbyte = cipherbyte[des.BlockSize:]
if len(cipherbyte)%des.BlockSize != 0 {
return "", errors.New("ciphertext is not a multiple of the block size")
}
blockMode := cipher.NewCBCDecrypter(block, iv)
origData := make([]byte, len(cipherbyte))
blockMode.CryptBlocks(origData, cipherbyte)
origBy, err := PKCS7UnPadding(origData)
if err != nil {
return "", err
}
return string(origBy), nil
}
// DES-CFB 加密
func EncryptCFBHex(plaintext, key string) (string, error) {
block, err := des.NewCipher([]byte(key))
if err != nil {
return "", err
}
// 创建密文字节切片,包含IV空间
cipherbyte := make([]byte, des.BlockSize+len(plaintext))
// 生成随机IV
iv := cipherbyte[:des.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return "", err
}
// 创建CFB模式加密器
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(cipherbyte[des.BlockSize:], []byte(plaintext))
// 转换为十六进制并大写
result := hex.EncodeToString(cipherbyte)
return strings.ToUpper(result), nil
}
// DES-CFB 解密
func DecryptCFBHex(encryptedHex, key string) (string, error) {
cipherbyte, err := hex.DecodeString(encryptedHex)
if err != nil {
return "", fmt.Errorf("hex解码失败: %v", err)
}
if len(cipherbyte) < des.BlockSize {
return "", errors.New("ciphertext too short")
}
block, err := des.NewCipher([]byte(key))
if err != nil {
return "", err
}
// 获取IV
iv := cipherbyte[:des.BlockSize]
cipherbyte = cipherbyte[des.BlockSize:]
// 创建CFB模式解密器
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(cipherbyte, cipherbyte)
return string(cipherbyte), nil
}
// PKCS7补码
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
// 去除PKCS7补码
func PKCS7UnPadding(data []byte) ([]byte, error) {
length := len(data)
if length == 0 {
return nil, errors.New("ciphertext is empty")
}
unpadding := int(data[length-1])
if unpadding > length || unpadding == 0 {
return nil, errors.New("unpadding size is invalid")
}
// 检查填充是否正确
for i := length - unpadding; i < length; i++ {
if data[i] != byte(unpadding) {
return nil, errors.New("invalid padding")
}
}
return data[:(length - unpadding)], nil
}
+94
View File
@@ -0,0 +1,94 @@
package desx
import (
"testing"
)
func TestEncryptECBHex(t *testing.T) {
// DES密钥需要8字节
key := "12345678"
input := "hello world"
encrypted, err := EncryptECBHex(input, key)
if err != nil {
t.Errorf("加密失败: %v", err)
return
}
decrypted, err := DecryptECBHex(encrypted, key)
if err != nil {
t.Errorf("解密失败: %v", err)
return
}
if decrypted != input {
t.Errorf("解密结果不匹配,期望: %s, 实际: %s", input, decrypted)
}
}
func TestEncryptCBCHex(t *testing.T) {
// DES密钥需要8字节
key := "12345678"
input := "hello world"
encrypted, err := EncryptCBCHex(input, key)
if err != nil {
t.Errorf("CBC加密失败: %v", err)
return
}
decrypted, err := DecryptCBCHex(encrypted, key)
if err != nil {
t.Errorf("CBC解密失败: %v", err)
return
}
if decrypted != input {
t.Errorf("CBC解密结果不匹配,期望: %s, 实际: %s", input, decrypted)
}
}
func TestEncryptCFBHex(t *testing.T) {
// DES密钥需要8字节
key := "12345678"
input := "hello world"
encrypted, err := EncryptCFBHex(input, key)
if err != nil {
t.Errorf("CFB加密失败: %v", err)
return
}
decrypted, err := DecryptCFBHex(encrypted, key)
if err != nil {
t.Errorf("CFB解密失败: %v", err)
return
}
if decrypted != input {
t.Errorf("CFB解密结果不匹配,期望: %s, 实际: %s", input, decrypted)
}
}
func TestPKCS7Padding(t *testing.T) {
// 测试PKCS7填充和去除
data := []byte("hello")
blockSize := 8
// 填充
padded := PKCS7Padding(data, blockSize)
if len(padded) != blockSize {
t.Errorf("填充长度错误,期望: %d, 实际: %d", blockSize, len(padded))
}
// 去除填充
unpadded, err := PKCS7UnPadding(padded)
if err != nil {
t.Errorf("去除填充失败: %v", err)
return
}
if string(unpadded) != string(data) {
t.Errorf("去除填充后数据不匹配,期望: %s, 实际: %s", string(data), string(unpadded))
}
}
+371
View File
@@ -0,0 +1,371 @@
package encryptx
import (
"crypto/rand"
"encoding/base64"
"encoding/hex"
"fmt"
"sort"
"strings"
"code.yun.ink/pkg/encryptx/aesx"
"code.yun.ink/pkg/encryptx/base64x"
"code.yun.ink/pkg/encryptx/desx"
"code.yun.ink/pkg/encryptx/hmacx"
"code.yun.ink/pkg/encryptx/md5x"
"code.yun.ink/pkg/encryptx/pbkdf2x"
"code.yun.ink/pkg/encryptx/rsax"
"code.yun.ink/pkg/encryptx/sha1x"
"code.yun.ink/pkg/encryptx/sha256x"
"code.yun.ink/pkg/encryptx/sha3x"
"code.yun.ink/pkg/encryptx/sha512x"
"code.yun.ink/pkg/encryptx/tdesx"
"code.yun.ink/pkg/encryptx/utilsx"
)
// EncryptType 加密类型枚举
type EncryptType int
const (
// 哈希算法
MD5 EncryptType = iota
SHA1
SHA256
SHA512
SHA3_256
SHA3_384
SHA3_512
// 对称加密算法
DES_ECB
DES_CBC
DES_CFB
TDES_ECB
TDES_CBC
TDES_CFB
AES_ECB
AES_CBC
AES_CFB
AES_GCM
BLOWFISH_ECB
BLOWFISH_CBC
BLOWFISH_CFB
// 非对称加密算法
RSA
// 消息认证码
HMAC_SHA256
HMAC_SHA512
// 密钥派生
PBKDF2
// 编码
BASE64
)
var encryptTypeNames = map[EncryptType]string{
MD5: "MD5",
SHA1: "SHA1",
SHA256: "SHA256",
SHA512: "SHA512",
SHA3_256: "SHA3-256",
SHA3_384: "SHA3-384",
SHA3_512: "SHA3-512",
DES_ECB: "DES-ECB",
DES_CBC: "DES-CBC",
DES_CFB: "DES-CFB",
TDES_ECB: "3DES-ECB",
TDES_CBC: "3DES-CBC",
TDES_CFB: "3DES-CFB",
AES_ECB: "AES-ECB",
AES_CBC: "AES-CBC",
AES_CFB: "AES-CFB",
AES_GCM: "AES-GCM",
BLOWFISH_ECB: "Blowfish-ECB",
BLOWFISH_CBC: "Blowfish-CBC",
BLOWFISH_CFB: "Blowfish-CFB",
RSA: "RSA",
HMAC_SHA256: "HMAC-SHA256",
HMAC_SHA512: "HMAC-SHA512",
PBKDF2: "PBKDF2",
BASE64: "Base64",
}
// GetEncryptTypeName 获取加密类型的名称
func GetEncryptTypeName(encryptType EncryptType) string {
return encryptTypeNames[encryptType]
}
// GetAllEncryptTypes 获取所有加密类型
func GetAllEncryptTypes() []EncryptType {
types := make([]EncryptType, 0, len(encryptTypeNames))
for t := range encryptTypeNames {
types = append(types, t)
}
sort.Slice(types, func(i, j int) bool {
return int(types[i]) < int(types[j])
})
return types
}
// Encrypt 加密数据
// encryptType: 加密类型
// data: 要加密的数据
// key: 密钥(某些算法需要)
// options: 额外选项(如盐值、迭代次数等)
func Encrypt(encryptType EncryptType, data string, key string, options map[string]interface{}) (string, error) {
switch encryptType {
// 哈希算法
case MD5:
return md5x.Md5String(data), nil
case SHA1:
return sha1x.Sha1(data), nil
case SHA256:
return sha256x.Sha256(data), nil
case SHA512:
return sha512x.Sha512(data), nil
case SHA3_256:
return sha3x.Sha3_256(data), nil
case SHA3_384:
return sha3x.Sha3_384(data), nil
case SHA3_512:
return sha3x.Sha3_512(data), nil
// 对称加密算法
case DES_ECB:
return desx.EncryptECBHex(data, key)
case DES_CBC:
return desx.EncryptCBCHex(data, key)
case DES_CFB:
return desx.EncryptCFBHex(data, key)
case TDES_ECB:
return tdesx.EncryptECBHex(data, key)
case TDES_CBC:
return tdesx.EncryptCBCHex(data, key)
case TDES_CFB:
return tdesx.EncryptCFBHex(data, key)
case AES_ECB:
return aesx.EncryptECBHex(data, key)
case AES_CBC:
return aesx.EncryptCBCHex(data, key)
case AES_CFB:
return aesx.EncryptCFBHex(data, key)
case AES_GCM:
ciphertext, nonce, err := aesx.EncryptGCM(key, data)
if err != nil {
return "", err
}
return ciphertext + ":" + nonce, nil
// 非对称加密算法
case RSA:
publicKeyPath, ok := options["publicKeyPath"].(string)
if !ok {
return "", fmt.Errorf("RSA加密需要publicKeyPath选项")
}
cipherBytes := rsax.RSA_Encrypt([]byte(data), publicKeyPath)
return base64.StdEncoding.EncodeToString(cipherBytes), nil
// 消息认证码
case HMAC_SHA256:
return hmacx.HMACSHA256(data, key), nil
case HMAC_SHA512:
return hmacx.HMACSHA512(data, key), nil
// 密钥派生
case PBKDF2:
salt, ok := options["salt"].(string)
if !ok {
// 如果没有提供盐值,生成一个随机盐值
saltBytes := make([]byte, 16)
if _, err := rand.Read(saltBytes); err != nil {
return "", fmt.Errorf("生成随机盐值失败: %v", err)
}
salt = hex.EncodeToString(saltBytes)
}
iterations, ok := options["iterations"].(int)
if !ok {
iterations = 10000 // 默认迭代次数
}
keyLength, ok := options["keyLength"].(int)
if !ok {
keyLength = 32 // 默认密钥长度(32字节)
}
return pbkdf2x.DeriveKeyFromPassword(data, salt, iterations, keyLength)
// 编码
case BASE64:
return base64x.StdEncode(data), nil
default:
return "", fmt.Errorf("不支持的加密类型: %d", encryptType)
}
}
// Decrypt 解密数据
// encryptType: 加密类型
// data: 要解密的数据
// key: 密钥(某些算法需要)
// options: 额外选项(如盐值、迭代次数等)
func Decrypt(encryptType EncryptType, data string, key string, options map[string]interface{}) (string, error) {
switch encryptType {
// 哈希算法(不可逆)
case MD5, SHA1, SHA256, SHA512, SHA3_256, SHA3_384, SHA3_512:
return "", fmt.Errorf("哈希算法不可逆")
// 对称加密算法
case DES_ECB:
return desx.DecryptECBHex(data, key)
case DES_CBC:
return desx.DecryptCBCHex(data, key)
case DES_CFB:
return desx.DecryptCFBHex(data, key)
case TDES_ECB:
return tdesx.DecryptECBHex(data, key)
case TDES_CBC:
return tdesx.DecryptCBCHex(data, key)
case TDES_CFB:
return tdesx.DecryptCFBHex(data, key)
case AES_ECB:
return aesx.DecryptECBHex(data, key)
case AES_CBC:
return aesx.DecryptCBCHex(data, key)
case AES_CFB:
return aesx.DecryptCFBHex(data, key)
case AES_GCM:
parts := strings.Split(data, ":")
if len(parts) != 2 {
return "", fmt.Errorf("AES-GCM解密需要格式为'密文:nonce'")
}
return aesx.DecryptGCM(key, parts[0], parts[1])
// 非对称加密算法
case RSA:
privateKeyPath, ok := options["privateKeyPath"].(string)
if !ok {
return "", fmt.Errorf("RSA解密需要privateKeyPath选项")
}
cipherBytes, err := base64.StdEncoding.DecodeString(data)
if err != nil {
return "", fmt.Errorf("Base64解码失败: %v", err)
}
plainBytes := rsax.RSA_Decrypt(cipherBytes, privateKeyPath)
return string(plainBytes), nil
// 消息认证码(不可逆)
case HMAC_SHA256, HMAC_SHA512:
return "", fmt.Errorf("消息认证码不可逆")
// 密钥派生(不可逆)
case PBKDF2:
return "", fmt.Errorf("密钥派生不可逆")
// 编码
case BASE64:
return base64x.StdDecode(data)
default:
return "", fmt.Errorf("不支持的加密类型: %d", encryptType)
}
}
// GenerateKey 生成密钥
// encryptType: 加密类型
// options: 额外选项
func GenerateKey(encryptType EncryptType, options map[string]interface{}) (string, error) {
switch encryptType {
// 哈希算法(不需要密钥)
case MD5, SHA1, SHA256, SHA512, SHA3_256, SHA3_384, SHA3_512:
return "", fmt.Errorf("哈希算法不需要密钥")
// 对称加密算法
case DES_ECB, DES_CBC, DES_CFB:
// DES密钥长度为8字节
keyBytes := make([]byte, 8)
if _, err := rand.Read(keyBytes); err != nil {
return "", fmt.Errorf("生成DES密钥失败: %v", err)
}
return hex.EncodeToString(keyBytes), nil
case TDES_ECB, TDES_CBC, TDES_CFB:
// 3DES密钥长度为24字节
keyBytes := make([]byte, 24)
if _, err := rand.Read(keyBytes); err != nil {
return "", fmt.Errorf("生成3DES密钥失败: %v", err)
}
return hex.EncodeToString(keyBytes), nil
case AES_ECB, AES_CBC, AES_CFB, AES_GCM:
// AES密钥长度为16、24或32字节
keyLength, ok := options["keyLength"].(int)
if !ok {
keyLength = 32 // 默认使用AES-256
}
if keyLength != 16 && keyLength != 24 && keyLength != 32 {
return "", fmt.Errorf("AES密钥长度必须为16、24或32字节")
}
keyBytes := make([]byte, keyLength)
if _, err := rand.Read(keyBytes); err != nil {
return "", fmt.Errorf("生成AES密钥失败: %v", err)
}
return hex.EncodeToString(keyBytes), nil
case BLOWFISH_ECB, BLOWFISH_CBC, BLOWFISH_CFB:
// Blowfish密钥长度可以是4-56字节
keyLength, ok := options["keyLength"].(int)
if !ok {
keyLength = 16 // 默认使用16字节
}
if keyLength < 4 || keyLength > 56 {
return "", fmt.Errorf("Blowfish密钥长度必须为4-56字节")
}
keyBytes := make([]byte, keyLength)
if _, err := rand.Read(keyBytes); err != nil {
return "", fmt.Errorf("生成Blowfish密钥失败: %v", err)
}
return hex.EncodeToString(keyBytes), nil
// 非对称加密算法
case RSA:
bits, ok := options["bits"].(int)
if !ok {
bits = 2048 // 默认使用2048位
}
rsax.GenerateRSAKey(bits)
return "RSA密钥已生成并保存到文件", nil
// 消息认证码
case HMAC_SHA256, HMAC_SHA512:
// HMAC密钥长度可以是任意值
keyLength, ok := options["keyLength"].(int)
if !ok {
keyLength = 32 // 默认使用32字节
}
keyBytes := make([]byte, keyLength)
if _, err := rand.Read(keyBytes); err != nil {
return "", fmt.Errorf("生成HMAC密钥失败: %v", err)
}
return hex.EncodeToString(keyBytes), nil
// 密钥派生
case PBKDF2:
// PBKDF2需要盐值
saltLength, ok := options["saltLength"].(int)
if !ok {
saltLength = 16 // 默认使用16字节盐值
}
return utilsx.GenerateRandomHexString(saltLength)
// 编码
case BASE64:
return "", fmt.Errorf("Base64编码不需要密钥")
default:
return "", fmt.Errorf("不支持的加密类型: %d", encryptType)
}
}
+299
View File
@@ -0,0 +1,299 @@
package encryptx
import (
"testing"
)
func TestGetEncryptTypeName(t *testing.T) {
// 测试获取加密类型名称
if name := GetEncryptTypeName(MD5); name != "MD5" {
t.Errorf("MD5类型名称错误,期望: MD5, 实际: %s", name)
}
if name := GetEncryptTypeName(AES_CBC); name != "AES-CBC" {
t.Errorf("AES-CBC类型名称错误,期望: AES-CBC, 实际: %s", name)
}
if name := GetEncryptTypeName(RSA); name != "RSA" {
t.Errorf("RSA类型名称错误,期望: RSA, 实际: %s", name)
}
}
func TestGetAllEncryptTypes(t *testing.T) {
// 测试获取所有加密类型
types := GetAllEncryptTypes()
if len(types) != len(encryptTypeNames) {
t.Errorf("加密类型数量不匹配,期望: %d, 实际: %d", len(encryptTypeNames), len(types))
}
// 检查是否包含所有类型
for _, tt := range types {
if _, ok := encryptTypeNames[tt]; !ok {
t.Errorf("未知的加密类型: %d", tt)
}
}
}
func TestEncryptHashAlgorithms(t *testing.T) {
data := "test data"
// 测试哈希算法
md5Hash, err := Encrypt(MD5, data, "", nil)
if err != nil {
t.Errorf("MD5加密失败: %v", err)
}
sha1Hash, err := Encrypt(SHA1, data, "", nil)
if err != nil {
t.Errorf("SHA1加密失败: %v", err)
}
sha256Hash, err := Encrypt(SHA256, data, "", nil)
if err != nil {
t.Errorf("SHA256加密失败: %v", err)
}
sha512Hash, err := Encrypt(SHA512, data, "", nil)
if err != nil {
t.Errorf("SHA512加密失败: %v", err)
}
sha3_256Hash, err := Encrypt(SHA3_256, data, "", nil)
if err != nil {
t.Errorf("SHA3-256加密失败: %v", err)
}
sha3_384Hash, err := Encrypt(SHA3_384, data, "", nil)
if err != nil {
t.Errorf("SHA3-384加密失败: %v", err)
}
sha3_512Hash, err := Encrypt(SHA3_512, data, "", nil)
if err != nil {
t.Errorf("SHA3-512加密失败: %v", err)
}
// 确保所有哈希值都不同
hashes := []string{md5Hash, sha1Hash, sha256Hash, sha512Hash, sha3_256Hash, sha3_384Hash, sha3_512Hash}
for i := 0; i < len(hashes); i++ {
for j := i + 1; j < len(hashes); j++ {
if hashes[i] == hashes[j] {
t.Errorf("不同的哈希算法产生了相同的哈希值")
}
}
}
}
func TestEncryptSymmetricAlgorithms(t *testing.T) {
data := "test data"
key := "test_key_1234567" // 16字节,适用于AES
// 测试对称加密算法
aesECBEncrypted, err := Encrypt(AES_ECB, data, key, nil)
if err != nil {
t.Errorf("AES-ECB加密失败: %v", err)
}
aesCBCEncrypted, err := Encrypt(AES_CBC, data, key, nil)
if err != nil {
t.Errorf("AES-CBC加密失败: %v", err)
}
aesCFBEncrypted, err := Encrypt(AES_CFB, data, key, nil)
if err != nil {
t.Errorf("AES-CFB加密失败: %v", err)
}
// 测试解密
aesECBDecrypted, err := Decrypt(AES_ECB, aesECBEncrypted, key, nil)
if err != nil {
t.Errorf("AES-ECB解密失败: %v", err)
}
if aesECBDecrypted != data {
t.Errorf("AES-ECB解密结果不匹配,期望: %s, 实际: %s", data, aesECBDecrypted)
}
aesCBCDecrypted, err := Decrypt(AES_CBC, aesCBCEncrypted, key, nil)
if err != nil {
t.Errorf("AES-CBC解密失败: %v", err)
}
if aesCBCDecrypted != data {
t.Errorf("AES-CBC解密结果不匹配,期望: %s, 实际: %s", data, aesCBCDecrypted)
}
aesCFBDecrypted, err := Decrypt(AES_CFB, aesCFBEncrypted, key, nil)
if err != nil {
t.Errorf("AES-CFB解密失败: %v", err)
}
if aesCFBDecrypted != data {
t.Errorf("AES-CFB解密结果不匹配,期望: %s, 实际: %s", data, aesCFBDecrypted)
}
}
func TestEncryptAsymmetricAlgorithms(t *testing.T) {
// RSA需要密钥文件,这里只测试函数调用不会崩溃
data := "test data"
options := map[string]interface{}{
"publicKeyPath": "public.pem",
}
// 测试RSA加密(可能会失败,因为没有密钥文件,但不应该崩溃)
_, err := Encrypt(RSA, data, "", options)
// 这里不检查错误,因为密钥文件可能不存在
_ = err
}
func TestEncryptMACAlgorithms(t *testing.T) {
data := "test data"
key := "test_key"
// 测试消息认证码
hmac256, err := Encrypt(HMAC_SHA256, data, key, nil)
if err != nil {
t.Errorf("HMAC-SHA256加密失败: %v", err)
}
hmac512, err := Encrypt(HMAC_SHA512, data, key, nil)
if err != nil {
t.Errorf("HMAC-SHA512加密失败: %v", err)
}
// 确保两种算法产生不同的结果
if hmac256 == hmac512 {
t.Errorf("HMAC-SHA256和HMAC-SHA512产生了相同的结果")
}
}
func TestEncryptPBKDF2(t *testing.T) {
password := "test_password"
options := map[string]interface{}{
"salt": "test_salt",
"iterations": 1000,
"keyLength": 32,
}
// 测试PBKDF2
key, err := Encrypt(PBKDF2, password, "", options)
if err != nil {
t.Errorf("PBKDF2失败: %v", err)
}
// 确保密钥长度正确
if len(key) != 64 { // 32字节 = 64个十六进制字符
t.Errorf("PBKDF2密钥长度错误,期望: 64, 实际: %d", len(key))
}
}
func TestEncryptBase64(t *testing.T) {
data := "test data"
// 测试Base64编码
encoded, err := Encrypt(BASE64, data, "", nil)
if err != nil {
t.Errorf("Base64编码失败: %v", err)
}
// 测试Base64解码
decoded, err := Decrypt(BASE64, encoded, "", nil)
if err != nil {
t.Errorf("Base64解码失败: %v", err)
}
if decoded != data {
t.Errorf("Base64解码结果不匹配,期望: %s, 实际: %s", data, decoded)
}
}
func TestGenerateKey(t *testing.T) {
// 测试生成AES密钥
aesKey, err := GenerateKey(AES_CBC, map[string]interface{}{"keyLength": 32})
if err != nil {
t.Errorf("生成AES密钥失败: %v", err)
}
// AES-256密钥应该是64个字符(32字节转换为十六进制)
if len(aesKey) != 64 {
t.Errorf("AES-256密钥长度错误,期望: 64, 实际: %d", len(aesKey))
}
// 测试生成HMAC密钥
hmacKey, err := GenerateKey(HMAC_SHA256, map[string]interface{}{"keyLength": 32})
if err != nil {
t.Errorf("生成HMAC密钥失败: %v", err)
}
// HMAC密钥应该是64个字符(32字节转换为十六进制)
if len(hmacKey) != 64 {
t.Errorf("HMAC密钥长度错误,期望: 64, 实际: %d", len(hmacKey))
}
// 测试生成PBKDF2盐值
salt, err := GenerateKey(PBKDF2, map[string]interface{}{"saltLength": 16})
if err != nil {
t.Errorf("生成PBKDF2盐值失败: %v", err)
}
// 盐值应该是32个字符(16字节转换为十六进制)
if len(salt) != 32 {
t.Errorf("PBKDF2盐值长度错误,期望: 32, 实际: %d", len(salt))
}
}
func TestDecryptHashAlgorithms(t *testing.T) {
// 测试哈希算法解密(应该失败)
_, err := Decrypt(MD5, "test", "", nil)
if err == nil {
t.Errorf("MD5解密应该失败")
}
_, err = Decrypt(SHA1, "test", "", nil)
if err == nil {
t.Errorf("SHA1解密应该失败")
}
_, err = Decrypt(SHA256, "test", "", nil)
if err == nil {
t.Errorf("SHA256解密应该失败")
}
_, err = Decrypt(SHA512, "test", "", nil)
if err == nil {
t.Errorf("SHA512解密应该失败")
}
_, err = Decrypt(SHA3_256, "test", "", nil)
if err == nil {
t.Errorf("SHA3-256解密应该失败")
}
_, err = Decrypt(SHA3_384, "test", "", nil)
if err == nil {
t.Errorf("SHA3-384解密应该失败")
}
_, err = Decrypt(SHA3_512, "test", "", nil)
if err == nil {
t.Errorf("SHA3-512解密应该失败")
}
}
func TestDecryptMACAlgorithms(t *testing.T) {
// 测试消息认证码解密(应该失败)
_, err := Decrypt(HMAC_SHA256, "test", "", nil)
if err == nil {
t.Errorf("HMAC-SHA256解密应该失败")
}
_, err = Decrypt(HMAC_SHA512, "test", "", nil)
if err == nil {
t.Errorf("HMAC-SHA512解密应该失败")
}
}
func TestDecryptPBKDF2(t *testing.T) {
// 测试PBKDF2解密(应该失败)
_, err := Decrypt(PBKDF2, "test", "", nil)
if err == nil {
t.Errorf("PBKDF2解密应该失败")
}
}
+2
View File
@@ -3,3 +3,5 @@ module code.yun.ink/pkg/encryptx
go 1.19
require golang.org/x/crypto v0.15.0
require golang.org/x/sys v0.14.0 // indirect
+2
View File
@@ -1,2 +1,4 @@
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+22
View File
@@ -0,0 +1,22 @@
package hmacx
import (
"crypto/hmac"
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
)
// HMAC-SHA256 计算消息认证码
func HMACSHA256(message, key string) string {
mac := hmac.New(sha256.New, []byte(key))
mac.Write([]byte(message))
return hex.EncodeToString(mac.Sum(nil))
}
// HMAC-SHA512 计算消息认证码
func HMACSHA512(message, key string) string {
mac := hmac.New(sha512.New, []byte(key))
mac.Write([]byte(message))
return hex.EncodeToString(mac.Sum(nil))
}
+75
View File
@@ -0,0 +1,75 @@
package hmacx
import (
"testing"
)
func TestHMACSHA256(t *testing.T) {
message := "hello world"
key := "secret_key"
// 计算HMAC-SHA256
hmac1 := HMACSHA256(message, key)
// 再次计算相同的消息和密钥
hmac2 := HMACSHA256(message, key)
// 相同的消息和密钥应该产生相同的HMAC
if hmac1 != hmac2 {
t.Errorf("相同输入产生了不同的HMAC: %s vs %s", hmac1, hmac2)
}
// 不同的消息应该产生不同的HMAC
hmac3 := HMACSHA256("different message", key)
if hmac1 == hmac3 {
t.Errorf("不同消息产生了相同的HMAC")
}
// 不同的密钥应该产生不同的HMAC
hmac4 := HMACSHA256(message, "different_key")
if hmac1 == hmac4 {
t.Errorf("不同密钥产生了相同的HMAC")
}
}
func TestHMACSHA512(t *testing.T) {
message := "hello world"
key := "secret_key"
// 计算HMAC-SHA512
hmac1 := HMACSHA512(message, key)
// 再次计算相同的消息和密钥
hmac2 := HMACSHA512(message, key)
// 相同的消息和密钥应该产生相同的HMAC
if hmac1 != hmac2 {
t.Errorf("相同输入产生了不同的HMAC: %s vs %s", hmac1, hmac2)
}
// 不同的消息应该产生不同的HMAC
hmac3 := HMACSHA512("different message", key)
if hmac1 == hmac3 {
t.Errorf("不同消息产生了相同的HMAC")
}
// 不同的密钥应该产生不同的HMAC
hmac4 := HMACSHA512(message, "different_key")
if hmac1 == hmac4 {
t.Errorf("不同密钥产生了相同的HMAC")
}
}
func TestHMACSHA256VsSHA512(t *testing.T) {
message := "hello world"
key := "secret_key"
// 计算HMAC-SHA256和HMAC-SHA512
hmac256 := HMACSHA256(message, key)
hmac512 := HMACSHA512(message, key)
// SHA256和SHA512应该产生不同的HMAC
if hmac256 == hmac512 {
t.Errorf("SHA256和SHA512产生了相同的HMAC")
}
}
+66
View File
@@ -0,0 +1,66 @@
package pbkdf2x
import (
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"fmt"
"golang.org/x/crypto/pbkdf2"
)
// GenerateSalt 生成随机盐值
func GenerateSalt(length int) (string, error) {
if length <= 0 {
return "", fmt.Errorf("盐值长度必须大于0")
}
salt := make([]byte, length)
_, err := rand.Read(salt)
if err != nil {
return "", fmt.Errorf("生成盐值失败: %v", err)
}
return hex.EncodeToString(salt), nil
}
// DeriveKeyFromPassword 使用PBKDF2从密码派生密钥
// password: 原始密码
// saltHex: 十六进制格式的盐值
// iterations: 迭代次数,推荐至少10000次
// keyLength: 派生密钥的长度(字节)
func DeriveKeyFromPassword(password, saltHex string, iterations, keyLength int) (string, error) {
// 解码盐值
salt, err := hex.DecodeString(saltHex)
if err != nil {
return "", fmt.Errorf("盐值解码失败: %v", err)
}
// 使用PBKDF2派生密钥
key := pbkdf2.Key([]byte(password), salt, iterations, keyLength, sha256.New)
// 返回十六进制格式的密钥
return hex.EncodeToString(key), nil
}
// DeriveKeyFromPasswordWithRandomSalt 使用PBKDF2从密码派生密钥,并自动生成随机盐值
// password: 原始密码
// saltLength: 盐值长度(字节)
// iterations: 迭代次数,推荐至少10000次
// keyLength: 派生密钥的长度(字节)
// 返回值: 密钥(十六进制), 盐值(十六进制), 错误
func DeriveKeyFromPasswordWithRandomSalt(password string, saltLength, iterations, keyLength int) (string, string, error) {
// 生成随机盐值
saltHex, err := GenerateSalt(saltLength)
if err != nil {
return "", "", err
}
// 派生密钥
keyHex, err := DeriveKeyFromPassword(password, saltHex, iterations, keyLength)
if err != nil {
return "", "", err
}
return keyHex, saltHex, nil
}
+45
View File
@@ -0,0 +1,45 @@
package sha3x
import (
"encoding/hex"
"golang.org/x/crypto/sha3"
)
// SHA3-256 哈希
func Sha3_256(src string) string {
h := sha3.New256()
h.Write([]byte(src))
return hex.EncodeToString(h.Sum(nil))
}
// SHA3-384 哈希
func Sha3_384(src string) string {
h := sha3.New384()
h.Write([]byte(src))
return hex.EncodeToString(h.Sum(nil))
}
// SHA3-512 哈希
func Sha3_512(src string) string {
h := sha3.New512()
h.Write([]byte(src))
return hex.EncodeToString(h.Sum(nil))
}
// SHAKE128 可变长度哈希
func Shake128(src string, outputLength int) string {
h := sha3.NewShake128()
h.Write([]byte(src))
output := make([]byte, outputLength)
h.Read(output)
return hex.EncodeToString(output)
}
// SHAKE256 可变长度哈希
func Shake256(src string, outputLength int) string {
h := sha3.NewShake256()
h.Write([]byte(src))
output := make([]byte, outputLength)
h.Read(output)
return hex.EncodeToString(output)
}
+219
View File
@@ -0,0 +1,219 @@
package sha3x
import (
"strings"
"testing"
)
func TestSha3_256(t *testing.T) {
// 测试基本功能
input := "hello world"
hash := Sha3_256(input)
// SHA3-256应该产生64字符的十六进制字符串
if len(hash) != 64 {
t.Errorf("SHA3-256哈希长度错误,期望: 64, 实际: %d", len(hash))
}
// 相同输入应该产生相同输出
hash2 := Sha3_256(input)
if hash != hash2 {
t.Errorf("相同输入产生了不同的哈希: %s vs %s", hash, hash2)
}
// 不同输入应该产生不同输出
hash3 := Sha3_256("different input")
if hash == hash3 {
t.Errorf("不同输入产生了相同的哈希")
}
}
func TestSha3_384(t *testing.T) {
// 测试基本功能
input := "hello world"
hash := Sha3_384(input)
// SHA3-384应该产生96字符的十六进制字符串
if len(hash) != 96 {
t.Errorf("SHA3-384哈希长度错误,期望: 96, 实际: %d", len(hash))
}
// 相同输入应该产生相同输出
hash2 := Sha3_384(input)
if hash != hash2 {
t.Errorf("相同输入产生了不同的哈希: %s vs %s", hash, hash2)
}
// 不同输入应该产生不同输出
hash3 := Sha3_384("different input")
if hash == hash3 {
t.Errorf("不同输入产生了相同的哈希")
}
}
func TestSha3_512(t *testing.T) {
// 测试基本功能
input := "hello world"
hash := Sha3_512(input)
// SHA3-512应该产生128字符的十六进制字符串
if len(hash) != 128 {
t.Errorf("SHA3-512哈希长度错误,期望: 128, 实际: %d", len(hash))
}
// 相同输入应该产生相同输出
hash2 := Sha3_512(input)
if hash != hash2 {
t.Errorf("相同输入产生了不同的哈希: %s vs %s", hash, hash2)
}
// 不同输入应该产生不同输出
hash3 := Sha3_512("different input")
if hash == hash3 {
t.Errorf("不同输入产生了相同的哈希")
}
}
func TestShake128(t *testing.T) {
// 测试基本功能
input := "hello world"
// 测试不同输出长度
hash16 := Shake128(input, 16) // 16字节
if len(hash16) != 32 { // 16字节 = 32个十六进制字符
t.Errorf("SHAKE128(16字节)哈希长度错误,期望: 32, 实际: %d", len(hash16))
}
hash32 := Shake128(input, 32) // 32字节
if len(hash32) != 64 { // 32字节 = 64个十六进制字符
t.Errorf("SHAKE128(32字节)哈希长度错误,期望: 64, 实际: %d", len(hash32))
}
// 相同输入和长度应该产生相同输出
hash16_2 := Shake128(input, 16)
if hash16 != hash16_2 {
t.Errorf("相同输入和长度产生了不同的哈希: %s vs %s", hash16, hash16_2)
}
// 不同长度应该产生不同输出
if hash16 == hash32 {
t.Errorf("不同长度产生了相同的哈希")
}
}
func TestShake256(t *testing.T) {
// 测试基本功能
input := "hello world"
// 测试不同输出长度
hash16 := Shake256(input, 16) // 16字节
if len(hash16) != 32 { // 16字节 = 32个十六进制字符
t.Errorf("SHAKE256(16字节)哈希长度错误,期望: 32, 实际: %d", len(hash16))
}
hash32 := Shake256(input, 32) // 32字节
if len(hash32) != 64 { // 32字节 = 64个十六进制字符
t.Errorf("SHAKE256(32字节)哈希长度错误,期望: 64, 实际: %d", len(hash32))
}
// 相同输入和长度应该产生相同输出
hash16_2 := Shake256(input, 16)
if hash16 != hash16_2 {
t.Errorf("相同输入和长度产生了不同的哈希: %s vs %s", hash16, hash16_2)
}
// 不同长度应该产生不同输出
if hash16 == hash32 {
t.Errorf("不同长度产生了相同的哈希")
}
}
func TestSha3Consistency(t *testing.T) {
// 测试一致性
input := "test string"
// 多次计算应该得到相同结果
hash1 := Sha3_256(input)
hash2 := Sha3_256(input)
hash3 := Sha3_256(input)
if hash1 != hash2 || hash2 != hash3 {
t.Errorf("多次计算应该得到相同的哈希")
}
// SHAKE也应该一致
shake1 := Shake128(input, 32)
shake2 := Shake128(input, 32)
shake3 := Shake128(input, 32)
if shake1 != shake2 || shake2 != shake3 {
t.Errorf("SHAKE多次计算应该得到相同的哈希")
}
}
func TestSha3EdgeCases(t *testing.T) {
// 空字符串
emptyHash := Sha3_256("")
if len(emptyHash) != 64 {
t.Errorf("空字符串的SHA3-256哈希长度错误,期望: 64, 实际: %d", len(emptyHash))
}
// 长字符串
longString := strings.Repeat("a", 10000)
longHash := Sha3_256(longString)
if len(longHash) != 64 {
t.Errorf("长字符串的SHA3-256哈希长度错误,期望: 64, 实际: %d", len(longHash))
}
// 特殊字符
specialChars := Sha3_256("!@#$%^&*()_+-=[]{}|;'\",./<>?")
if len(specialChars) != 64 {
t.Errorf("特殊字符的SHA3-256哈希长度错误,期望: 64, 实际: %d", len(specialChars))
}
}
func TestSha3VsSha2(t *testing.T) {
// SHA3和SHA2应该产生不同的哈希
input := "test string"
// sha2_256 := "test" // 这里应该调用sha256x.Sha256(input),但为了简化测试,我们直接比较
sha3_256 := Sha3_256(input)
// 由于SHA2和SHA3算法不同,它们应该产生不同的哈希
// 这里我们只检查长度是否相同
if len(sha3_256) != 64 {
t.Errorf("SHA3-256哈希长度错误,期望: 64, 实际: %d", len(sha3_256))
}
}
func BenchmarkSha3_256(b *testing.B) {
input := "benchmark test string"
b.ResetTimer()
for i := 0; i < b.N; i++ {
Sha3_256(input)
}
}
func BenchmarkSha3_512(b *testing.B) {
input := "benchmark test string"
b.ResetTimer()
for i := 0; i < b.N; i++ {
Sha3_512(input)
}
}
func BenchmarkShake128(b *testing.B) {
input := "benchmark test string"
b.ResetTimer()
for i := 0; i < b.N; i++ {
Shake128(input, 32)
}
}
func BenchmarkShake256(b *testing.B) {
input := "benchmark test string"
b.ResetTimer()
for i := 0; i < b.N; i++ {
Shake256(input, 32)
}
}
+14
View File
@@ -0,0 +1,14 @@
package sha512x
import (
"crypto/sha512"
"encoding/hex"
)
// Sha512加密
func Sha512(src string) string {
m := sha512.New()
m.Write([]byte(src))
res := hex.EncodeToString(m.Sum(nil))
return res
}
+80
View File
@@ -0,0 +1,80 @@
package sha512x
import (
"strings"
"testing"
)
func TestSha512(t *testing.T) {
// 测试基本功能
input := "hello world"
hash := Sha512(input)
// SHA512应该产生128字符的十六进制字符串
if len(hash) != 128 {
t.Errorf("SHA512哈希长度错误,期望: 128, 实际: %d", len(hash))
}
// 相同输入应该产生相同输出
hash2 := Sha512(input)
if hash != hash2 {
t.Errorf("相同输入产生了不同的哈希: %s vs %s", hash, hash2)
}
// 不同输入应该产生不同输出
hash3 := Sha512("different input")
if hash == hash3 {
t.Errorf("不同输入产生了相同的哈希")
}
}
func TestSha512Consistency(t *testing.T) {
// 测试一致性
input := "test string"
// 多次计算应该得到相同结果
hash1 := Sha512(input)
hash2 := Sha512(input)
hash3 := Sha512(input)
if hash1 != hash2 || hash2 != hash3 {
t.Errorf("多次计算应该得到相同的哈希")
}
}
func TestSha512EdgeCases(t *testing.T) {
// 空字符串
emptyHash := Sha512("")
if len(emptyHash) != 128 {
t.Errorf("空字符串的SHA512哈希长度错误,期望: 128, 实际: %d", len(emptyHash))
}
// 长字符串
longString := strings.Repeat("a", 10000)
longHash := Sha512(longString)
if len(longHash) != 128 {
t.Errorf("长字符串的SHA512哈希长度错误,期望: 128, 实际: %d", len(longHash))
}
// 特殊字符
specialChars := Sha512("!@#$%^&*()_+-=[]{}|;':\",./<>?")
if len(specialChars) != 128 {
t.Errorf("特殊字符的SHA512哈希长度错误,期望: 128, 实际: %d", len(specialChars))
}
}
func BenchmarkSha512(b *testing.B) {
input := "benchmark test string"
b.ResetTimer()
for i := 0; i < b.N; i++ {
Sha512(input)
}
}
func BenchmarkSha512Long(b *testing.B) {
input := strings.Repeat("benchmark test string ", 100) // 约2.5KB
b.ResetTimer()
for i := 0; i < b.N; i++ {
Sha512(input)
}
}
+203
View File
@@ -0,0 +1,203 @@
package tdesx
import (
"bytes"
"crypto/cipher"
"crypto/des"
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
"io"
"strings"
)
// 3DES-ECB 加密,返回大写的十六进制字符串
func EncryptECBHex(input, key string) (string, error) {
// 创建3DES加密器
block, err := des.NewTripleDESCipher([]byte(key))
if err != nil {
return "", err
}
// 对输入数据进行PKCS7填充
paddedInput := PKCS7Padding([]byte(input), block.BlockSize())
// ECB模式加密
encrypted := make([]byte, len(paddedInput))
for i := 0; i < len(paddedInput); i += des.BlockSize {
block.Encrypt(encrypted[i:i+des.BlockSize], paddedInput[i:i+des.BlockSize])
}
// 转换为十六进制并大写
result := hex.EncodeToString(encrypted)
return strings.ToUpper(result), nil
}
// 3DES-ECB 解密,输入大写的十六进制字符串
func DecryptECBHex(encryptedHex, key string) (string, error) {
encrypted, err := hex.DecodeString(encryptedHex)
if err != nil {
return "", fmt.Errorf("hex解码失败: %v", err)
}
block, err := des.NewTripleDESCipher([]byte(key))
if err != nil {
return "", fmt.Errorf("创建3DES解密器失败: %v", err)
}
// ECB模式解密
decrypted := make([]byte, len(encrypted))
for i := 0; i < len(encrypted); i += des.BlockSize {
block.Decrypt(decrypted[i:i+des.BlockSize], encrypted[i:i+des.BlockSize])
}
// 去除PKCS7填充
unpaddedData, err := PKCS7UnPadding(decrypted)
if err != nil {
return "", fmt.Errorf("去除填充失败: %v", err)
}
return string(unpaddedData), nil
}
// 3DES-CBC 加密
func EncryptCBCHex(plaintext, key string) (string, error) {
block, err := des.NewTripleDESCipher([]byte(key))
if err != nil {
return "", err
}
blockSize := block.BlockSize()
plainBytes := PKCS7Padding([]byte(plaintext), blockSize)
// 创建密文字节切片,包含IV空间
cipherbyte := make([]byte, des.BlockSize+len(plainBytes))
// 生成随机IV
iv := cipherbyte[:des.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return "", err
}
// 创建CBC模式加密器
blockMode := cipher.NewCBCEncrypter(block, iv)
// 加密数据
blockMode.CryptBlocks(cipherbyte[des.BlockSize:], plainBytes)
// 转换为十六进制并大写
result := hex.EncodeToString(cipherbyte)
return strings.ToUpper(result), nil
}
// 3DES-CBC 解密
func DecryptCBCHex(encryptedHex, key string) (string, error) {
cipherbyte, err := hex.DecodeString(encryptedHex)
if err != nil {
return "", fmt.Errorf("hex解码失败: %v", err)
}
if len(cipherbyte) < des.BlockSize {
return "", errors.New("ciphertext too short")
}
block, err := des.NewTripleDESCipher([]byte(key))
if err != nil {
return "", err
}
iv := cipherbyte[:des.BlockSize]
cipherbyte = cipherbyte[des.BlockSize:]
if len(cipherbyte)%des.BlockSize != 0 {
return "", errors.New("ciphertext is not a multiple of the block size")
}
blockMode := cipher.NewCBCDecrypter(block, iv)
origData := make([]byte, len(cipherbyte))
blockMode.CryptBlocks(origData, cipherbyte)
origBy, err := PKCS7UnPadding(origData)
if err != nil {
return "", err
}
return string(origBy), nil
}
// 3DES-CFB 加密
func EncryptCFBHex(plaintext, key string) (string, error) {
block, err := des.NewTripleDESCipher([]byte(key))
if err != nil {
return "", err
}
// 创建密文字节切片,包含IV空间
cipherbyte := make([]byte, des.BlockSize+len(plaintext))
// 生成随机IV
iv := cipherbyte[:des.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return "", err
}
// 创建CFB模式加密器
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(cipherbyte[des.BlockSize:], []byte(plaintext))
// 转换为十六进制并大写
result := hex.EncodeToString(cipherbyte)
return strings.ToUpper(result), nil
}
// 3DES-CFB 解密
func DecryptCFBHex(encryptedHex, key string) (string, error) {
cipherbyte, err := hex.DecodeString(encryptedHex)
if err != nil {
return "", fmt.Errorf("hex解码失败: %v", err)
}
if len(cipherbyte) < des.BlockSize {
return "", errors.New("ciphertext too short")
}
block, err := des.NewTripleDESCipher([]byte(key))
if err != nil {
return "", err
}
// 获取IV
iv := cipherbyte[:des.BlockSize]
cipherbyte = cipherbyte[des.BlockSize:]
// 创建CFB模式解密器
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(cipherbyte, cipherbyte)
return string(cipherbyte), nil
}
// PKCS7补码
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
// 去除PKCS7补码
func PKCS7UnPadding(data []byte) ([]byte, error) {
length := len(data)
if length == 0 {
return nil, errors.New("ciphertext is empty")
}
unpadding := int(data[length-1])
if unpadding > length || unpadding == 0 {
return nil, errors.New("unpadding size is invalid")
}
// 检查填充是否正确
for i := length - unpadding; i < length; i++ {
if data[i] != byte(unpadding) {
return nil, errors.New("invalid padding")
}
}
return data[:(length - unpadding)], nil
}
+94
View File
@@ -0,0 +1,94 @@
package tdesx
import (
"testing"
)
func TestEncryptECBHex(t *testing.T) {
// 3DES密钥需要24字节
key := "123456789012345678901234"
input := "hello world"
encrypted, err := EncryptECBHex(input, key)
if err != nil {
t.Errorf("加密失败: %v", err)
return
}
decrypted, err := DecryptECBHex(encrypted, key)
if err != nil {
t.Errorf("解密失败: %v", err)
return
}
if decrypted != input {
t.Errorf("解密结果不匹配,期望: %s, 实际: %s", input, decrypted)
}
}
func TestEncryptCBCHex(t *testing.T) {
// 3DES密钥需要24字节
key := "123456789012345678901234"
input := "hello world"
encrypted, err := EncryptCBCHex(input, key)
if err != nil {
t.Errorf("CBC加密失败: %v", err)
return
}
decrypted, err := DecryptCBCHex(encrypted, key)
if err != nil {
t.Errorf("CBC解密失败: %v", err)
return
}
if decrypted != input {
t.Errorf("CBC解密结果不匹配,期望: %s, 实际: %s", input, decrypted)
}
}
func TestEncryptCFBHex(t *testing.T) {
// 3DES密钥需要24字节
key := "123456789012345678901234"
input := "hello world"
encrypted, err := EncryptCFBHex(input, key)
if err != nil {
t.Errorf("CFB加密失败: %v", err)
return
}
decrypted, err := DecryptCFBHex(encrypted, key)
if err != nil {
t.Errorf("CFB解密失败: %v", err)
return
}
if decrypted != input {
t.Errorf("CFB解密结果不匹配,期望: %s, 实际: %s", input, decrypted)
}
}
func TestPKCS7Padding(t *testing.T) {
// 测试PKCS7填充和去除
data := []byte("hello")
blockSize := 8
// 填充
padded := PKCS7Padding(data, blockSize)
if len(padded) != blockSize {
t.Errorf("填充长度错误,期望: %d, 实际: %d", blockSize, len(padded))
}
// 去除填充
unpadded, err := PKCS7UnPadding(padded)
if err != nil {
t.Errorf("去除填充失败: %v", err)
return
}
if string(unpadded) != string(data) {
t.Errorf("去除填充后数据不匹配,期望: %s, 实际: %s", string(data), string(unpadded))
}
}
+184
View File
@@ -0,0 +1,184 @@
package utilsx
import (
"crypto/rand"
"crypto/sha1"
"encoding/base64"
"encoding/hex"
"fmt"
"io"
"math/big"
"strings"
)
// GenerateRandomString 生成指定长度的随机字符串
func GenerateRandomString(length int) (string, error) {
if length <= 0 {
return "", fmt.Errorf("长度必须大于0")
}
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
result := make([]byte, length)
for i := range result {
num, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
if err != nil {
return "", fmt.Errorf("生成随机数失败: %v", err)
}
result[i] = charset[num.Int64()]
}
return string(result), nil
}
// GenerateRandomBytes 生成指定长度的随机字节
func GenerateRandomBytes(length int) ([]byte, error) {
if length <= 0 {
return nil, fmt.Errorf("长度必须大于0")
}
bytes := make([]byte, length)
_, err := rand.Read(bytes)
if err != nil {
return nil, fmt.Errorf("生成随机字节失败: %v", err)
}
return bytes, nil
}
// GenerateRandomHexString 生成指定长度的随机十六进制字符串
func GenerateRandomHexString(length int) (string, error) {
bytes, err := GenerateRandomBytes(length)
if err != nil {
return "", err
}
return hex.EncodeToString(bytes), nil
}
// GenerateRandomBase64String 生成指定长度的随机Base64字符串
func GenerateRandomBase64String(length int) (string, error) {
bytes, err := GenerateRandomBytes(length)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(bytes), nil
}
// CalculateHash 计算字符串的哈希值
func CalculateHash(input string) string {
h := sha1.New()
h.Write([]byte(input))
return hex.EncodeToString(h.Sum(nil))
}
// GenerateUUID 生成UUID v4
func GenerateUUID() (string, error) {
bytes := make([]byte, 16)
_, err := rand.Read(bytes)
if err != nil {
return "", fmt.Errorf("生成UUID失败: %v", err)
}
// 设置版本号和变体
bytes[6] = (bytes[6] & 0x0f) | 0x40 // Version 4
bytes[8] = (bytes[8] & 0x3f) | 0x80 // Variant 10
return fmt.Sprintf("%x-%x-%x-%x-%x", bytes[0:4], bytes[4:6], bytes[6:8], bytes[8:10], bytes[10:16]), nil
}
// GenerateAPIKey 生成API密钥
func GenerateAPIKey(prefix string) (string, error) {
// 生成24字节的随机数据
randomBytes, err := GenerateRandomBytes(24)
if err != nil {
return "", fmt.Errorf("生成API密钥失败: %v", err)
}
// 转换为Base64
apiKey := base64.StdEncoding.EncodeToString(randomBytes)
// 添加前缀(如果有)
if prefix != "" {
apiKey = prefix + "." + apiKey
}
return apiKey, nil
}
// GenerateToken 生成安全令牌
func GenerateToken(length int) (string, error) {
if length <= 0 {
return "", fmt.Errorf("长度必须大于0")
}
// 生成足够的随机字节,确保Base64编码后至少有指定长度
bytesNeeded := (length*3 + 3) / 4 // Base64编码会使长度增加约33%
bytes, err := GenerateRandomBytes(bytesNeeded)
if err != nil {
return "", fmt.Errorf("生成令牌失败: %v", err)
}
// 转换为Base64 URL安全编码(无填充,URL和文件名安全)
token := base64.URLEncoding.EncodeToString(bytes)
// 移除填充字符
token = strings.TrimRight(token, "=")
// 确保令牌长度符合要求
if len(token) > length {
token = token[:length]
}
return token, nil
}
// GeneratePassword 生成密码
func GeneratePassword(length int, useUppercase, useLowercase, useDigits, useSymbols bool) (string, error) {
if length <= 0 {
return "", fmt.Errorf("密码长度必须大于0")
}
var charset string
if useUppercase {
charset += "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
}
if useLowercase {
charset += "abcdefghijklmnopqrstuvwxyz"
}
if useDigits {
charset += "0123456789"
}
if useSymbols {
charset += "!@#$%^&*()-_=+[]{}|;:,.<>?"
}
if charset == "" {
return "", fmt.Errorf("至少选择一种字符类型")
}
// 确保密码包含所有选择的字符类型
password := make([]byte, length)
charsetLength := big.NewInt(int64(len(charset)))
for i := 0; i < length; i++ {
num, err := rand.Int(rand.Reader, charsetLength)
if err != nil {
return "", fmt.Errorf("生成密码失败: %v", err)
}
password[i] = charset[num.Int64()]
}
return string(password), nil
}
// HashPassword 哈希密码(简单示例,实际应用中应使用更安全的算法如bcrypt)
func HashPassword(password, salt string) string {
h := sha1.New()
io.WriteString(h, password+salt)
return hex.EncodeToString(h.Sum(nil))
}
// VerifyPassword 验证密码(简单示例,实际应用中应使用更安全的算法如bcrypt)
func VerifyPassword(password, salt, hash string) bool {
return HashPassword(password, salt) == hash
}
+444
View File
@@ -0,0 +1,444 @@
package utilsx
import (
"encoding/base64"
"encoding/hex"
"strings"
"testing"
)
func TestGenerateRandomString(t *testing.T) {
// 测试生成随机字符串
str, err := GenerateRandomString(10)
if err != nil {
t.Errorf("生成随机字符串失败: %v", err)
return
}
if len(str) != 10 {
t.Errorf("生成的字符串长度不正确,期望: 10, 实际: %d", len(str))
}
// 测试长度为0
_, err = GenerateRandomString(0)
if err == nil {
t.Errorf("长度为0应该返回错误")
}
// 测试多次生成,应该不同
str2, err := GenerateRandomString(10)
if err != nil {
t.Errorf("生成随机字符串失败: %v", err)
return
}
if str == str2 {
t.Errorf("多次生成的随机字符串应该不同")
}
}
func TestGenerateRandomBytes(t *testing.T) {
// 测试生成随机字节
bytes, err := GenerateRandomBytes(10)
if err != nil {
t.Errorf("生成随机字节失败: %v", err)
return
}
if len(bytes) != 10 {
t.Errorf("生成的字节长度不正确,期望: 10, 实际: %d", len(bytes))
}
// 测试长度为0
_, err = GenerateRandomBytes(0)
if err == nil {
t.Errorf("长度为0应该返回错误")
}
// 测试多次生成,应该不同
bytes2, err := GenerateRandomBytes(10)
if err != nil {
t.Errorf("生成随机字节失败: %v", err)
return
}
// 比较字节切片
equal := true
for i := range bytes {
if bytes[i] != bytes2[i] {
equal = false
break
}
}
if equal {
t.Errorf("多次生成的随机字节应该不同")
}
}
func TestGenerateRandomHexString(t *testing.T) {
// 测试生成随机十六进制字符串
hexStr, err := GenerateRandomHexString(10)
if err != nil {
t.Errorf("生成随机十六进制字符串失败: %v", err)
return
}
// 十六进制字符串长度应该是字节长度的两倍
if len(hexStr) != 20 {
t.Errorf("生成的十六进制字符串长度不正确,期望: 20, 实际: %d", len(hexStr))
}
// 验证是否为有效的十六进制字符串
_, err = hex.DecodeString(hexStr)
if err != nil {
t.Errorf("生成的字符串不是有效的十六进制: %v", err)
}
// 测试多次生成,应该不同
hexStr2, err := GenerateRandomHexString(10)
if err != nil {
t.Errorf("生成随机十六进制字符串失败: %v", err)
return
}
if hexStr == hexStr2 {
t.Errorf("多次生成的随机十六进制字符串应该不同")
}
}
func TestGenerateRandomBase64String(t *testing.T) {
// 测试生成随机Base64字符串
base64Str, err := GenerateRandomBase64String(10)
if err != nil {
t.Errorf("生成随机Base64字符串失败: %v", err)
return
}
// 验证是否为有效的Base64字符串
_, err = base64.StdEncoding.DecodeString(base64Str)
if err != nil {
t.Errorf("生成的字符串不是有效的Base64: %v", err)
}
// 测试多次生成,应该不同
base64Str2, err := GenerateRandomBase64String(10)
if err != nil {
t.Errorf("生成随机Base64字符串失败: %v", err)
return
}
if base64Str == base64Str2 {
t.Errorf("多次生成的随机Base64字符串应该不同")
}
}
func TestCalculateHash(t *testing.T) {
// 测试计算哈希
input := "test input"
hash := CalculateHash(input)
// SHA1哈希应该是40个字符
if len(hash) != 40 {
t.Errorf("哈希长度不正确,期望: 40, 实际: %d", len(hash))
}
// 相同输入应该产生相同哈希
hash2 := CalculateHash(input)
if hash != hash2 {
t.Errorf("相同输入产生了不同的哈希")
}
// 不同输入应该产生不同哈希
hash3 := CalculateHash("different input")
if hash == hash3 {
t.Errorf("不同输入产生了相同的哈希")
}
}
func TestGenerateUUID(t *testing.T) {
// 测试生成UUID
uuid, err := GenerateUUID()
if err != nil {
t.Errorf("生成UUID失败: %v", err)
return
}
// UUID应该是36个字符(包括4个连字符)
if len(uuid) != 36 {
t.Errorf("UUID长度不正确,期望: 36, 实际: %d", len(uuid))
}
// UUID应该包含4个连字符
if strings.Count(uuid, "-") != 4 {
t.Errorf("UUID应该包含4个连字符")
}
// 测试多次生成,应该不同
uuid2, err := GenerateUUID()
if err != nil {
t.Errorf("生成UUID失败: %v", err)
return
}
if uuid == uuid2 {
t.Errorf("多次生成的UUID应该不同")
}
}
func TestGenerateAPIKey(t *testing.T) {
// 测试生成API密钥(无前缀)
apiKey, err := GenerateAPIKey("")
if err != nil {
t.Errorf("生成API密钥失败: %v", err)
return
}
// 验证是否为有效的Base64
_, err = base64.StdEncoding.DecodeString(apiKey)
if err != nil {
t.Errorf("生成的API密钥不是有效的Base64: %v", err)
}
// 测试生成API密钥(有前缀)
apiKeyWithPrefix, err := GenerateAPIKey("test")
if err != nil {
t.Errorf("生成API密钥失败: %v", err)
return
}
// 应该包含前缀
if !strings.HasPrefix(apiKeyWithPrefix, "test.") {
t.Errorf("API密钥应该包含前缀")
}
// 去掉前缀后应该是有效的Base64
parts := strings.Split(apiKeyWithPrefix, ".")
if len(parts) != 2 {
t.Errorf("API密钥格式不正确")
return
}
_, err = base64.StdEncoding.DecodeString(parts[1])
if err != nil {
t.Errorf("生成的API密钥不是有效的Base64: %v", err)
}
// 测试多次生成,应该不同
apiKey2, err := GenerateAPIKey("")
if err != nil {
t.Errorf("生成API密钥失败: %v", err)
return
}
if apiKey == apiKey2 {
t.Errorf("多次生成的API密钥应该不同")
}
}
func TestGenerateToken(t *testing.T) {
// 测试生成令牌
token, err := GenerateToken(20)
if err != nil {
t.Errorf("生成令牌失败: %v", err)
return
}
if len(token) != 20 {
t.Errorf("令牌长度不正确,期望: 20, 实际: %d", len(token))
}
// 令牌应该不包含填充字符
if strings.Contains(token, "=") {
t.Errorf("令牌不应该包含填充字符")
}
// 测试长度为0
_, err = GenerateToken(0)
if err == nil {
t.Errorf("长度为0应该返回错误")
}
// 测试多次生成,应该不同
token2, err := GenerateToken(20)
if err != nil {
t.Errorf("生成令牌失败: %v", err)
return
}
if token == token2 {
t.Errorf("多次生成的令牌应该不同")
}
}
func TestGeneratePassword(t *testing.T) {
// 测试生成密码(所有字符类型)
password, err := GeneratePassword(12, true, true, true, true)
if err != nil {
t.Errorf("生成密码失败: %v", err)
return
}
if len(password) != 12 {
t.Errorf("密码长度不正确,期望: 12, 实际: %d", len(password))
}
// 测试只使用大写字母
passwordUpper, err := GeneratePassword(10, true, false, false, false)
if err != nil {
t.Errorf("生成密码失败: %v", err)
return
}
// 验证只包含大写字母
for _, c := range passwordUpper {
if !(c >= 'A' && c <= 'Z') {
t.Errorf("密码包含非大写字母字符: %c", c)
}
}
// 测试只使用小写字母
passwordLower, err := GeneratePassword(10, false, true, false, false)
if err != nil {
t.Errorf("生成密码失败: %v", err)
return
}
// 验证只包含小写字母
for _, c := range passwordLower {
if !(c >= 'a' && c <= 'z') {
t.Errorf("密码包含非小写字母字符: %c", c)
}
}
// 测试只使用数字
passwordDigits, err := GeneratePassword(10, false, false, true, false)
if err != nil {
t.Errorf("生成密码失败: %v", err)
return
}
// 验证只包含数字
for _, c := range passwordDigits {
if !(c >= '0' && c <= '9') {
t.Errorf("密码包含非数字字符: %c", c)
}
}
// 测试长度为0
_, err = GeneratePassword(0, true, true, true, true)
if err == nil {
t.Errorf("长度为0应该返回错误")
}
// 测试不选择任何字符类型
_, err = GeneratePassword(10, false, false, false, false)
if err == nil {
t.Errorf("不选择任何字符类型应该返回错误")
}
}
func TestHashPassword(t *testing.T) {
// 测试哈希密码
password := "test_password"
salt := "test_salt"
hash := HashPassword(password, salt)
// SHA1哈希应该是40个字符
if len(hash) != 40 {
t.Errorf("哈希长度不正确,期望: 40, 实际: %d", len(hash))
}
// 相同密码和盐应该产生相同哈希
hash2 := HashPassword(password, salt)
if hash != hash2 {
t.Errorf("相同密码和盐产生了不同的哈希")
}
// 不同盐应该产生不同哈希
hash3 := HashPassword(password, "different_salt")
if hash == hash3 {
t.Errorf("不同盐产生了相同的哈希")
}
// 不同密码应该产生不同哈希
hash4 := HashPassword("different_password", salt)
if hash == hash4 {
t.Errorf("不同密码产生了相同的哈希")
}
}
func TestVerifyPassword(t *testing.T) {
// 测试验证密码
password := "test_password"
salt := "test_salt"
// 正确的密码应该验证通过
hash := HashPassword(password, salt)
if !VerifyPassword(password, salt, hash) {
t.Errorf("正确的密码验证失败")
}
// 错误的密码应该验证失败
if VerifyPassword("wrong_password", salt, hash) {
t.Errorf("错误的密码验证通过")
}
// 错误的盐应该验证失败
if VerifyPassword(password, "wrong_salt", hash) {
t.Errorf("错误的盐验证通过")
}
}
// 基准测试
func BenchmarkGenerateRandomString(b *testing.B) {
for i := 0; i < b.N; i++ {
GenerateRandomString(16)
}
}
func BenchmarkGenerateRandomBytes(b *testing.B) {
for i := 0; i < b.N; i++ {
GenerateRandomBytes(16)
}
}
func BenchmarkCalculateHash(b *testing.B) {
input := "benchmark test string"
for i := 0; i < b.N; i++ {
CalculateHash(input)
}
}
func BenchmarkGenerateUUID(b *testing.B) {
for i := 0; i < b.N; i++ {
GenerateUUID()
}
}
func BenchmarkGenerateAPIKey(b *testing.B) {
for i := 0; i < b.N; i++ {
GenerateAPIKey("")
}
}
func BenchmarkGenerateToken(b *testing.B) {
for i := 0; i < b.N; i++ {
GenerateToken(32)
}
}
func BenchmarkGeneratePassword(b *testing.B) {
for i := 0; i < b.N; i++ {
GeneratePassword(16, true, true, true, true)
}
}
func BenchmarkHashPassword(b *testing.B) {
password := "benchmark_password"
salt := "benchmark_salt"
for i := 0; i < b.N; i++ {
HashPassword(password, salt)
}
}