From 3dd73f928d4ee07ccd4ddc4cdbbf602aee9042fe Mon Sep 17 00:00:00 2001 From: Yun Date: Mon, 3 Nov 2025 23:03:17 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=85=B6=E4=BB=96=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E7=9A=84=E5=8A=A0=E8=A7=A3=E5=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aesx/aesx.go | 299 +++++++++++++++++++++++++++++++++++++-------- aesx/aesx_test.go | 97 +++++++++++++-- desx/desx.go | 203 ++++++++++++++++++++++++++++++ hmacx/hmacx.go | 22 ++++ pbkdf2x/pbkdf2x.go | 66 ++++++++++ tdesx/tdesx.go | 203 ++++++++++++++++++++++++++++++ 6 files changed, 831 insertions(+), 59 deletions(-) create mode 100644 desx/desx.go create mode 100644 hmacx/hmacx.go create mode 100644 pbkdf2x/pbkdf2x.go create mode 100644 tdesx/tdesx.go diff --git a/aesx/aesx.go b/aesx/aesx.go index b86362b..d53df07 100644 --- a/aesx/aesx.go +++ b/aesx/aesx.go @@ -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 +} \ No newline at end of file diff --git a/aesx/aesx_test.go b/aesx/aesx_test.go index b850083..82ce40e 100644 --- a/aesx/aesx_test.go +++ b/aesx/aesx_test.go @@ -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) + } +} \ No newline at end of file diff --git a/desx/desx.go b/desx/desx.go new file mode 100644 index 0000000..b847900 --- /dev/null +++ b/desx/desx.go @@ -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 +} diff --git a/hmacx/hmacx.go b/hmacx/hmacx.go new file mode 100644 index 0000000..167a03b --- /dev/null +++ b/hmacx/hmacx.go @@ -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)) +} diff --git a/pbkdf2x/pbkdf2x.go b/pbkdf2x/pbkdf2x.go new file mode 100644 index 0000000..7d51845 --- /dev/null +++ b/pbkdf2x/pbkdf2x.go @@ -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 +} diff --git a/tdesx/tdesx.go b/tdesx/tdesx.go new file mode 100644 index 0000000..c383770 --- /dev/null +++ b/tdesx/tdesx.go @@ -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 +}