diff --git a/encrypt/aes.go b/encrypt/aes.go new file mode 100644 index 0000000..2eeebc6 --- /dev/null +++ b/encrypt/aes.go @@ -0,0 +1,106 @@ +package encrypt + +import ( + "bytes" + "crypto/aes" + "encoding/base64" + "encoding/hex" +) + +// AESEncrypt AES加密 +func AESEncrypt(key string, plaintext string) string { + // create cipher + c, err := aes.NewCipher([]byte(key)) + if err != nil { + return "" + } + // allocate space for ciphered data + out := make([]byte, len(plaintext)) + + // encrypt + c.Encrypt(out, []byte(plaintext)) + + // return hex string + return hex.EncodeToString(out) +} + +// AESDecrypt AES解密 +func AESDecrypt(key string, decodeString string) string { + ciphertext, _ := hex.DecodeString(decodeString) + + c, err := aes.NewCipher([]byte(key)) + if err != nil { + return "" + } + + pt := make([]byte, len(ciphertext)) + c.Decrypt(pt, ciphertext) + + return string(pt) +} + +// 加密 +func AesEncryptByECB(data, key string) string { + // 判断key长度 + keyLenMap := map[int]struct{}{16: {}, 24: {}, 32: {}} + if _, ok := keyLenMap[len(key)]; !ok { + panic("key长度必须是 16、24、32 其中一个") + } + // 密钥和待加密数据转成[]byte + originByte := []byte(data) + keyByte := []byte(key) + // 创建密码组,长度只能是16、24、32字节 + block, _ := aes.NewCipher(keyByte) + // 获取密钥长度 + blockSize := block.BlockSize() + // 补码 + originByte = PKCS7Padding(originByte, blockSize) + // 创建保存加密变量 + encryptResult := make([]byte, len(originByte)) + // CEB是把整个明文分成若干段相同的小段,然后对每一小段进行加密 + for bs, be := 0, blockSize; bs < len(originByte); bs, be = bs+blockSize, be+blockSize { + block.Encrypt(encryptResult[bs:be], originByte[bs:be]) + } + return base64.StdEncoding.EncodeToString(encryptResult) +} + +// 解密 +func AesDecryptByECB(data, key string) string { + // 判断key长度 + keyLenMap := map[int]struct{}{16: {}, 24: {}, 32: {}} + if _, ok := keyLenMap[len(key)]; !ok { + panic("key长度必须是 16、24、32 其中一个") + } + // 反解密码base64 + originByte, _ := base64.StdEncoding.DecodeString(data) + // 密钥和待加密数据转成[]byte + keyByte := []byte(key) + // 创建密码组,长度只能是16、24、32字节 + block, _ := aes.NewCipher(keyByte) + // 获取密钥长度 + blockSize := block.BlockSize() + // 创建保存解密变量 + decrypted := make([]byte, len(originByte)) + for bs, be := 0, blockSize; bs < len(originByte); bs, be = bs+blockSize, be+blockSize { + block.Decrypt(decrypted[bs:be], originByte[bs:be]) + } + // 解码 + return string(PKCS7UNPadding(decrypted)) +} + +// 解码 +func PKCS7UNPadding(originDataByte []byte) []byte { + length := len(originDataByte) + unpadding := int(originDataByte[length-1]) + return originDataByte[:(length - unpadding)] +} + +// 补码 +func PKCS7Padding(originByte []byte, blockSize int) []byte { + // 计算补码长度 + padding := blockSize - len(originByte)%blockSize + // 生成补码 + padText := bytes.Repeat([]byte{byte(padding)}, padding) + // 追加补码 + return append(originByte, padText...) +} diff --git a/encrypt/des.go b/encrypt/des.go new file mode 100644 index 0000000..47b1836 --- /dev/null +++ b/encrypt/des.go @@ -0,0 +1,69 @@ +package encrypt + +import ( + "bytes" + "crypto/des" + "encoding/base64" +) + +// 加密函数 +func DESEncrypt(plainText string, key string) string { + block, err := des.NewCipher([]byte(key)) + if err != nil { + return "" + } + + // PKCS7 填充 + paddedText := pad([]byte(plainText), block.BlockSize()) + cipherText := make([]byte, len(paddedText)) + + // 使用 ECB 模式 + for i := 0; i < len(paddedText); i += block.BlockSize() { + block.Encrypt(cipherText[i:i+block.BlockSize()], paddedText[i:i+block.BlockSize()]) + } + + // 返回 Base64 编码的密文 + return base64.StdEncoding.EncodeToString(cipherText) +} + +// 解密函数 +func DESDecrypt(cipherText string, key string) string { + ciphertext, err := base64.StdEncoding.DecodeString(cipherText) + if err != nil { + return "" + } + + block, err := des.NewCipher([]byte(key)) + if err != nil { + return "" + } + + if len(ciphertext)%block.BlockSize() != 0 { + //return "", errors.New("ciphertext is not a multiple of the block size") + return "" + } + + plainText := make([]byte, len(ciphertext)) + + // 使用 ECB 模式解密 + for i := 0; i < len(ciphertext); i += block.BlockSize() { + block.Decrypt(plainText[i:i+block.BlockSize()], ciphertext[i:i+block.BlockSize()]) + } + + // 去掉填充 + return string(unpad(plainText)) +} + +// PKCS7 填充 +func pad(data []byte, blockSize int) []byte { + padding := blockSize - len(data)%blockSize + padtext := bytes.Repeat([]byte{byte(padding)}, padding) + return append(data, padtext...) +} + +// 去除填充 +func unpad(data []byte) []byte { + length := len(data) + unpadding := int(data[length-1]) + return data[:(length - unpadding)] +} diff --git a/test/encrypt_test.go b/test/encrypt_test.go new file mode 100644 index 0000000..92c06b1 --- /dev/null +++ b/test/encrypt_test.go @@ -0,0 +1,39 @@ +package test + +import ( + "testing" + + "github.com/farseer-go/utils/encrypt" + "github.com/stretchr/testify/assert" +) + +// CopyFolder +func TestMd5(t *testing.T) { + s := encrypt.Md5("123") + assert.Equal(t, "202cb962ac59075b964b07152d234b70", s) +} + +// CopyFolder +func TestSha1(t *testing.T) { + s := encrypt.Sha1("abc") + assert.Equal(t, "a9993e364706816aba3e25717850c26c9cd0d89d", s) +} + +// CopyFolder +func TestAES(t *testing.T) { + // 加解密 + s := encrypt.AesEncryptByECB("hello world", "sqNWnLg7Y7dQbH6Y") + content := encrypt.AesDecryptByECB(s, "sqNWnLg7Y7dQbH6Y") + assert.Equal(t, "hello world", content) +} + +// CopyFolder +func TestDES(t *testing.T) { + // 加解密 + s := encrypt.DESEncrypt("hello world", "sqNWnLg7") + content := encrypt.DESDecrypt(s, "sqNWnLg7") + assert.Equal(t, "hello world", content) + + content = encrypt.DESDecrypt("GB3x+HDVotbZ3aAXvAB6mQ==", "sqNWnLg7") + assert.Equal(t, "hello world", content) +} diff --git a/test/md5_test.go b/test/md5_test.go deleted file mode 100644 index 0743712..0000000 --- a/test/md5_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package test - -import ( - "github.com/farseer-go/utils/encrypt" - "github.com/stretchr/testify/assert" - "testing" -) - -// CopyFolder -func TestMd5(t *testing.T) { - s := encrypt.Md5("123") - assert.Equal(t, "202cb962ac59075b964b07152d234b70", s) -} - -// CopyFolder -func TestSha1(t *testing.T) { - s := encrypt.Sha1("abc") - assert.Equal(t, "a9993e364706816aba3e25717850c26c9cd0d89d", s) -}