433 lines
10 KiB
Go
433 lines
10 KiB
Go
|
|
package huibo
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"encoding/base64"
|
|||
|
|
"testing"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// 测试 MD5 加密(固定密文对比验证)
|
|||
|
|
func TestMD5Encrypt(t *testing.T) {
|
|||
|
|
appKey := "a6c9935e967894e731c62ecfcd9b7c95"
|
|||
|
|
|
|||
|
|
testCases := []struct {
|
|||
|
|
name string
|
|||
|
|
data string
|
|||
|
|
expected string // 固定密文
|
|||
|
|
}{
|
|||
|
|
{
|
|||
|
|
name: "姓名",
|
|||
|
|
data: "何志勇",
|
|||
|
|
expected: "64d4d5c6457026117a4911acf189e269", // 固定密文
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: "身份证号",
|
|||
|
|
data: "452528197907133014",
|
|||
|
|
expected: "7c6cc77dabb83d95948904dba5a7219d", // 固定密文
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for _, tc := range testCases {
|
|||
|
|
t.Run(tc.name, func(t *testing.T) {
|
|||
|
|
// 加密
|
|||
|
|
result := MD5Encrypt(tc.data, appKey)
|
|||
|
|
|
|||
|
|
// 最核心:对比是否和固定密文一致
|
|||
|
|
if result != tc.expected {
|
|||
|
|
t.Errorf("加密不匹配!\n明文:%s\n期望密文:%s\n实际密文:%s",
|
|||
|
|
tc.data, tc.expected, result)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 打印成功日志
|
|||
|
|
t.Logf("✅ 校验成功\n明文:%s\n密文:%s", tc.data, result)
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 测试 HMAC-SHA256 签名
|
|||
|
|
func TestHMACSHA256Base64(t *testing.T) {
|
|||
|
|
secret := "test_secret_key"
|
|||
|
|
|
|||
|
|
testCases := []struct {
|
|||
|
|
name string
|
|||
|
|
data string
|
|||
|
|
secret string
|
|||
|
|
}{
|
|||
|
|
{
|
|||
|
|
name: "简单字符串",
|
|||
|
|
data: "hello world",
|
|||
|
|
secret: secret,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: "JSON数据",
|
|||
|
|
data: `{"name":"张三","idCard":"110101199003072345"}`,
|
|||
|
|
secret: secret,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: "URL参数",
|
|||
|
|
data: "idCard=110101199003072345&name=张三&productCode=22089",
|
|||
|
|
secret: secret,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: "空字符串",
|
|||
|
|
data: "",
|
|||
|
|
secret: secret,
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for _, tc := range testCases {
|
|||
|
|
t.Run(tc.name, func(t *testing.T) {
|
|||
|
|
result := HMACSHA256Base64(tc.data, tc.secret)
|
|||
|
|
|
|||
|
|
// 验证结果不为空
|
|||
|
|
if result == "" {
|
|||
|
|
t.Error("HMAC-SHA256签名结果为空")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 验证结果是有效的Base64
|
|||
|
|
_, err := base64.StdEncoding.DecodeString(result)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Errorf("HMAC-SHA256结果不是有效的Base64: %v", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 验证相同输入产生相同输出
|
|||
|
|
result2 := HMACSHA256Base64(tc.data, tc.secret)
|
|||
|
|
if result != result2 {
|
|||
|
|
t.Error("相同输入产生的签名不一致")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 验证不同输入产生不同输出
|
|||
|
|
result3 := HMACSHA256Base64(tc.data+"x", tc.secret)
|
|||
|
|
if result == result3 {
|
|||
|
|
t.Error("不同输入产生的签名相同")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
t.Logf("数据: %s, 签名: %s", tc.data, result)
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 测试 AES-GCM 加密解密
|
|||
|
|
func TestEncryptDecryptAESGCMBase64(t *testing.T) {
|
|||
|
|
// 生成一个有效的 Base64 编密的 AES 密钥
|
|||
|
|
key := make([]byte, 32) // AES-256
|
|||
|
|
for i := range key {
|
|||
|
|
key[i] = byte(i)
|
|||
|
|
}
|
|||
|
|
base64Key := base64.StdEncoding.EncodeToString(key)
|
|||
|
|
|
|||
|
|
testCases := []struct {
|
|||
|
|
name string
|
|||
|
|
data string
|
|||
|
|
}{
|
|||
|
|
{
|
|||
|
|
name: "简单文本",
|
|||
|
|
data: "hello world",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: "中文文本",
|
|||
|
|
data: "你好世界",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: "JSON数据",
|
|||
|
|
data: `{"name":"张三","idCard":"110101199003072345"}`,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: "长文本",
|
|||
|
|
data: "这是一个很长的文本,用来测试加密解密功能是否正常工作。包含各种字符:123456789!@#$%^&*()_+-=[]{}|;':\",./<>?",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: "空字符串",
|
|||
|
|
data: "",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: "特殊字符",
|
|||
|
|
data: "\n\t\r\x00",
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for _, tc := range testCases {
|
|||
|
|
t.Run(tc.name, func(t *testing.T) {
|
|||
|
|
// 加密
|
|||
|
|
encrypted, err := EncryptAESGCMBase64(tc.data, base64Key)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("加密失败: %v", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 验证加密结果不为空
|
|||
|
|
if encrypted == "" {
|
|||
|
|
t.Error("加密结果为空")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 验证加密结果是有效的Base64
|
|||
|
|
_, err = base64.StdEncoding.DecodeString(encrypted)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Errorf("加密结果不是有效的Base64: %v", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 验证加密结果与原文不同
|
|||
|
|
if encrypted == tc.data {
|
|||
|
|
t.Error("加密结果与原文相同")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 解密
|
|||
|
|
decrypted, err := DecryptAESGCMBase64(encrypted, base64Key)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("解密失败: %v", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 验证解密结果与原文一致
|
|||
|
|
if decrypted != tc.data {
|
|||
|
|
t.Errorf("解密结果不匹配,期望: %s, 实际: %s", tc.data, decrypted)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
t.Logf("原文: %s", tc.data)
|
|||
|
|
t.Logf("密文: %s", encrypted)
|
|||
|
|
t.Logf("解密: %s", decrypted)
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 测试错误的密钥
|
|||
|
|
func TestEncryptDecryptWithWrongKey(t *testing.T) {
|
|||
|
|
// 生成两个不同的密钥
|
|||
|
|
key1 := make([]byte, 32)
|
|||
|
|
for i := range key1 {
|
|||
|
|
key1[i] = byte(i)
|
|||
|
|
}
|
|||
|
|
base64Key1 := base64.StdEncoding.EncodeToString(key1)
|
|||
|
|
|
|||
|
|
key2 := make([]byte, 32)
|
|||
|
|
for i := range key2 {
|
|||
|
|
key2[i] = byte(i + 1)
|
|||
|
|
}
|
|||
|
|
base64Key2 := base64.StdEncoding.EncodeToString(key2)
|
|||
|
|
|
|||
|
|
data := "sensitive data"
|
|||
|
|
|
|||
|
|
// 用密钥1加密
|
|||
|
|
encrypted, err := EncryptAESGCMBase64(data, base64Key1)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("加密失败: %v", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 用密钥2解密
|
|||
|
|
decrypted, err := DecryptAESGCMBase64(encrypted, base64Key2)
|
|||
|
|
if err == nil {
|
|||
|
|
t.Error("用错误密钥解密应该返回错误")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 验证解密结果与原文不同(如果解密成功的话)
|
|||
|
|
if decrypted == data {
|
|||
|
|
t.Error("用错误密钥解密不应该得到正确结果")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
t.Logf("用错误密钥解密预期失败: %v", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 测试无效的 Base64 密钥
|
|||
|
|
func TestEncryptWithInvalidBase64Key(t *testing.T) {
|
|||
|
|
data := "test data"
|
|||
|
|
|
|||
|
|
invalidKeys := []string{
|
|||
|
|
"", // 空字符串
|
|||
|
|
"not_base64", // 非Base64
|
|||
|
|
"abc", // 解码后太短
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for _, invalidKey := range invalidKeys {
|
|||
|
|
_, err := EncryptAESGCMBase64(data, invalidKey)
|
|||
|
|
if err == nil {
|
|||
|
|
t.Errorf("使用无效密钥 %s 应该返回错误", invalidKey)
|
|||
|
|
}
|
|||
|
|
t.Logf("无效密钥 %s 预期失败: %v", invalidKey, err)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 测试解密无效数据
|
|||
|
|
func TestDecryptWithInvalidData(t *testing.T) {
|
|||
|
|
// 生成一个有效的密钥
|
|||
|
|
key := make([]byte, 32)
|
|||
|
|
for i := range key {
|
|||
|
|
key[i] = byte(i)
|
|||
|
|
}
|
|||
|
|
base64Key := base64.StdEncoding.EncodeToString(key)
|
|||
|
|
|
|||
|
|
invalidData := []string{
|
|||
|
|
"", // 空字符串
|
|||
|
|
"invalid_base64", // 非Base64
|
|||
|
|
"dGVzdA==", // 有效的Base64但不是AES-GCM数据
|
|||
|
|
"short", // 太短
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for _, data := range invalidData {
|
|||
|
|
_, err := DecryptAESGCMBase64(data, base64Key)
|
|||
|
|
if err == nil {
|
|||
|
|
t.Errorf("使用无效数据 %s 应该返回错误", data)
|
|||
|
|
}
|
|||
|
|
t.Logf("无效数据 %s 预期失败: %v", data, err)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 测试加密结果的唯一性
|
|||
|
|
func TestEncryptionUniqueness(t *testing.T) {
|
|||
|
|
// 生成一个有效的密钥
|
|||
|
|
key := make([]byte, 32)
|
|||
|
|
for i := range key {
|
|||
|
|
key[i] = byte(i)
|
|||
|
|
}
|
|||
|
|
base64Key := base64.StdEncoding.EncodeToString(key)
|
|||
|
|
|
|||
|
|
data := "same data"
|
|||
|
|
|
|||
|
|
// 加密多次
|
|||
|
|
results := make([]string, 10)
|
|||
|
|
for i := 0; i < 10; i++ {
|
|||
|
|
encrypted, err := EncryptAESGCMBase64(data, base64Key)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("第%d次加密失败: %v", i, err)
|
|||
|
|
}
|
|||
|
|
results[i] = encrypted
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 验证每次加密结果都不同(因为包含随机IV)
|
|||
|
|
uniqueCount := 0
|
|||
|
|
for i := 0; i < len(results); i++ {
|
|||
|
|
isUnique := true
|
|||
|
|
for j := 0; j < len(results); j++ {
|
|||
|
|
if i != j && results[i] == results[j] {
|
|||
|
|
isUnique = false
|
|||
|
|
break
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if isUnique {
|
|||
|
|
uniqueCount++
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if uniqueCount != len(results) {
|
|||
|
|
t.Errorf("加密结果应该唯一,实际上只有%d个唯一结果,期望%d个", uniqueCount, len(results))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
t.Logf("生成了%d个不同的加密结果", uniqueCount)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 测试使用真实配置的加密解密
|
|||
|
|
func TestEncryptionWithRealConfig(t *testing.T) {
|
|||
|
|
// 使用配置文件中的真实AES密钥
|
|||
|
|
aesKey := "NQYN3YO+pb/GEcCBNX0ptMb7cUlnXSPvcX7VvNofBkc="
|
|||
|
|
appKey := "a6c9935e967894e731c62ecfcd9b7c95"
|
|||
|
|
|
|||
|
|
// 测试数据
|
|||
|
|
testData := `{"name":"张三","idCard":"110101199003072345","productCode":"22089"}`
|
|||
|
|
|
|||
|
|
t.Run("MD5加密", func(t *testing.T) {
|
|||
|
|
// 测试 MD5 加密
|
|||
|
|
md5Result := MD5Encrypt("张三", appKey)
|
|||
|
|
t.Logf("姓名 MD5: %s", md5Result)
|
|||
|
|
|
|||
|
|
md5Result2 := MD5Encrypt("110101199003072345", appKey)
|
|||
|
|
t.Logf("身份证号 MD5: %s", md5Result2)
|
|||
|
|
|
|||
|
|
// 验证格式
|
|||
|
|
if len(md5Result) != 32 {
|
|||
|
|
t.Errorf("MD5结果长度错误,期望32位,实际%d位", len(md5Result))
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
t.Run("HMAC-SHA256签名", func(t *testing.T) {
|
|||
|
|
// 生成排序后的参数
|
|||
|
|
sortedParam := "idCard=110101199003072345&name=张三&productCode=22089"
|
|||
|
|
signature := HMACSHA256Base64(sortedParam, aesKey)
|
|||
|
|
t.Logf("签名参数: %s", sortedParam)
|
|||
|
|
t.Logf("HMAC-SHA256签名: %s", signature)
|
|||
|
|
|
|||
|
|
// 验证格式
|
|||
|
|
_, err := base64.StdEncoding.DecodeString(signature)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Errorf("签名不是有效的Base64: %v", err)
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
t.Run("AES-GCM加密解密", func(t *testing.T) {
|
|||
|
|
// 测试 AES-GCM 加密
|
|||
|
|
encrypted, err := EncryptAESGCMBase64(testData, aesKey)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("加密失败: %v", err)
|
|||
|
|
}
|
|||
|
|
t.Logf("原始数据: %s", testData)
|
|||
|
|
t.Logf("加密结果: %s", encrypted)
|
|||
|
|
|
|||
|
|
// 测试解密
|
|||
|
|
decrypted, err := DecryptAESGCMBase64(encrypted, aesKey)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("解密失败: %v", err)
|
|||
|
|
}
|
|||
|
|
t.Logf("解密结果: %s", decrypted)
|
|||
|
|
|
|||
|
|
// 验证结果
|
|||
|
|
if decrypted != testData {
|
|||
|
|
t.Errorf("解密结果不匹配")
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 基准测试
|
|||
|
|
func BenchmarkMD5Encrypt(b *testing.B) {
|
|||
|
|
data := "张三"
|
|||
|
|
appKey := "a6c9935e967894e731c62ecfcd9b7c95"
|
|||
|
|
|
|||
|
|
b.ResetTimer()
|
|||
|
|
for i := 0; i < b.N; i++ {
|
|||
|
|
MD5Encrypt(data, appKey)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func BenchmarkHMACSHA256Base64(b *testing.B) {
|
|||
|
|
data := "idCard=110101199003072345&name=张三"
|
|||
|
|
secret := "a6c9935e967894e731c62ecfcd9b7c95"
|
|||
|
|
|
|||
|
|
b.ResetTimer()
|
|||
|
|
for i := 0; i < b.N; i++ {
|
|||
|
|
HMACSHA256Base64(data, secret)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func BenchmarkEncryptAESGCMBase64(b *testing.B) {
|
|||
|
|
data := `{"name":"张三","idCard":"110101199003072345","productCode":"22089"}`
|
|||
|
|
|
|||
|
|
// 生成密钥
|
|||
|
|
key := make([]byte, 32)
|
|||
|
|
for i := range key {
|
|||
|
|
key[i] = byte(i)
|
|||
|
|
}
|
|||
|
|
base64Key := base64.StdEncoding.EncodeToString(key)
|
|||
|
|
|
|||
|
|
b.ResetTimer()
|
|||
|
|
for i := 0; i < b.N; i++ {
|
|||
|
|
EncryptAESGCMBase64(data, base64Key)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func BenchmarkDecryptAESGCMBase64(b *testing.B) {
|
|||
|
|
data := `{"name":"张三","idCard":"110101199003072345","productCode":"22089"}`
|
|||
|
|
|
|||
|
|
// 生成密钥
|
|||
|
|
key := make([]byte, 32)
|
|||
|
|
for i := range key {
|
|||
|
|
key[i] = byte(i)
|
|||
|
|
}
|
|||
|
|
base64Key := base64.StdEncoding.EncodeToString(key)
|
|||
|
|
|
|||
|
|
// 先加密一次
|
|||
|
|
encrypted, err := EncryptAESGCMBase64(data, base64Key)
|
|||
|
|
if err != nil {
|
|||
|
|
b.Fatalf("预加密失败: %v", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
b.ResetTimer()
|
|||
|
|
for i := 0; i < b.N; i++ {
|
|||
|
|
DecryptAESGCMBase64(encrypted, base64Key)
|
|||
|
|
}
|
|||
|
|
}
|