From bd06bd311c4720f8648030a1627fe64ef6dca89c Mon Sep 17 00:00:00 2001 From: miaoyin Date: Thu, 9 Nov 2023 16:34:35 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=8A=A0=E5=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cfg/cfg_example_test.go | 4 +- cfg/cfg_test.go | 4 +- cfg/cipher.go | 85 +++++++++++++++++++++++++++++++------- cfg/cipher_example_test.go | 13 ++++++ cfg/crypto.go | 76 +++------------------------------- cfg/crypto_example_test.go | 16 ++----- cfg/crypto_test.go | 8 ---- cfg/padding.go | 23 +++++++++++ 8 files changed, 120 insertions(+), 109 deletions(-) create mode 100644 cfg/padding.go diff --git a/cfg/cfg_example_test.go b/cfg/cfg_example_test.go index 7b9b57c..41d30fa 100644 --- a/cfg/cfg_example_test.go +++ b/cfg/cfg_example_test.go @@ -51,8 +51,8 @@ func ExampleCfg_String() { } func ExampleCfg_Read() { - data, err := cfg.New("key").Read([]byte(`a=AES(A/43wTj2AVQboZZ0lNMqbw==) -b=DES(LABOK5l6Q64=) + data, err := cfg.New("key").Read([]byte(`a=AES(oY8aex0d4WjWokMZSUDyDQ==) +b=DES(azzeIdDM09M=) c=DES[abc]`)) fmt.Println(string(data)) diff --git a/cfg/cfg_test.go b/cfg/cfg_test.go index 9cddbd9..38e3ead 100644 --- a/cfg/cfg_test.go +++ b/cfg/cfg_test.go @@ -12,8 +12,8 @@ import ( const ( _file = "test.toml" - _data = `k1 = "AES(A/43wTj2AVQboZZ0lNMqbw==)" -k2 = "DES(LABOK5l6Q64=)" + _data = `k1 = "AES(oY8aex0d4WjWokMZSUDyDQ==)" +k2 = "DES(Jiga4xHtvWM=)" k3 = "DES[中文]"` _keyErr = "key err" ) diff --git a/cfg/cipher.go b/cfg/cipher.go index 139b6ff..815c74d 100644 --- a/cfg/cipher.go +++ b/cfg/cipher.go @@ -2,12 +2,15 @@ package cfg import ( "crypto/aes" - "crypto/cipher" - "crypto/des" // nolint + "crypto/cipher" // nolint + "crypto/des" // nolint + "crypto/md5" // nolint "crypto/sha256" "encoding/base64" "fmt" "strings" + + "github.com/xuender/kit/los" ) type Cipher int @@ -15,31 +18,83 @@ type Cipher int const ( AES Cipher = iota DES + AESMD5 + DESMD5 ) // nolint -var ciphers = [...]Cipher{AES, DES} +var ( + ciphers = [...]Cipher{AES, DES} + _names = map[Cipher]string{AES: "AES", DES: "DES", AESMD5: "AESMD5", DESMD5: "DESMD5"} +) -func (p Cipher) String() string { - if p == DES { - return "DES" +func (p Cipher) Encrypt(src, key string) string { + return base64.StdEncoding.EncodeToString(p.EncryptBytes([]byte(src), key)) +} + +func (p Cipher) EncryptBytes(src []byte, key string) []byte { + blockMode, blockSize := p.Block(key, true) + + src = pkcs5Padding(src, blockSize) + + cryted := make([]byte, len(src)) + blockMode.CryptBlocks(cryted, src) + + return cryted +} + +func (p Cipher) Decrypt(src, key string) (string, error) { + data, err := p.DecryptBytes(los.Must(base64.StdEncoding.DecodeString(src)), key) + if err != nil { + return "", err } - return "AES" + return string(data), nil +} + +func (p Cipher) DecryptBytes(src []byte, key string) ([]byte, error) { + var ( + blockMode, _ = p.Block(key, false) + orig = make([]byte, len(src)) + ) + + blockMode.CryptBlocks(orig, src) + + return pkcs5Trimming(orig) +} + +func (p Cipher) String() string { + return _names[p] } -func (p Cipher) Block(key string) cipher.Block { - keyBytes := sha256.Sum256([]byte(key)) - if p == DES { - // nolint - block, _ := des.NewCipher(keyBytes[:8]) +func (p Cipher) Block(key string, isEnc bool) (cipher.BlockMode, int) { + var ( + keyBytes []byte + block cipher.Block + blockSize int + ) + + if p == AESMD5 || p == DESMD5 { + tmp := md5.Sum([]byte(key)) // nolint + keyBytes = tmp[:] + } else { + tmp := sha256.Sum256([]byte(key)) + keyBytes = tmp[:] + } - return block + if p == DES || p == DESMD5 { + blockSize = 8 + block = los.Must(des.NewCipher(keyBytes[:blockSize])) // nolint + } else { + block = los.Must(aes.NewCipher(keyBytes)) + blockSize = block.BlockSize() } - block, _ := aes.NewCipher(keyBytes[:]) + if isEnc { + return cipher.NewCBCEncrypter(block, keyBytes[:blockSize]), blockSize + } - return block + return cipher.NewCBCDecrypter(block, keyBytes[:blockSize]), blockSize } func (p Cipher) Stringify(data []byte) string { diff --git a/cfg/cipher_example_test.go b/cfg/cipher_example_test.go index 3019f08..3b7e915 100644 --- a/cfg/cipher_example_test.go +++ b/cfg/cipher_example_test.go @@ -14,3 +14,16 @@ func ExampleIsEncrypt() { // true // false } + +func ExampleCipher_Decrypt() { + fmt.Println(cfg.AESMD5.Decrypt(cfg.AESMD5.Encrypt("AESMD5", "pass"), "pass")) + fmt.Println(cfg.DESMD5.Decrypt(cfg.DESMD5.Encrypt("DESMD5", "pass"), "pass")) + fmt.Println(cfg.AES.Decrypt(cfg.AES.Encrypt("AES", "pass"), "pass")) + fmt.Println(cfg.DES.Decrypt(cfg.DES.Encrypt("DES", "pass"), "pass")) + + // Output: + // AESMD5 + // DESMD5 + // AES + // DES +} diff --git a/cfg/crypto.go b/cfg/crypto.go index a238496..c627532 100644 --- a/cfg/crypto.go +++ b/cfg/crypto.go @@ -1,97 +1,33 @@ package cfg -import ( - "crypto/rand" -) - func Encrypt(str, key string) (string, error) { data, cipher, err := Parse(str) if err != nil { return "", err } - return EncryptByCipher(data, key, cipher), nil + return cipher.Stringify(cipher.EncryptBytes(data, key)), nil } -// EncryptByCipher 加密. -func EncryptByCipher(str []byte, key string, cipher Cipher) string { - var ( - ret []byte - block = cipher.Block(key) - srcBytes = Padding(str, block.BlockSize()) - tmp = make([]byte, block.BlockSize()) - ) - - for index := 0; index < len(srcBytes); index += block.BlockSize() { - block.Encrypt(tmp, srcBytes[index:index+block.BlockSize()]) - ret = append(ret, tmp...) - } - - return cipher.Stringify(ret) +func EncryptByCipher(src []byte, key string, cipher Cipher) string { + return cipher.Stringify(cipher.EncryptBytes(src, key)) } // Decrypt 解密. func Decrypt(src, key string) (string, error) { - var ret []byte - srcBytes, cipher, err := Parse(src) if err != nil { return "", err } - var ( - block = cipher.Block(key) - tmp = make([]byte, block.BlockSize()) - ) - - for index := 0; index < len(srcBytes); index += block.BlockSize() { - block.Decrypt(tmp, srcBytes[index:index+block.BlockSize()]) - ret = append(ret, tmp...) - } - - text, err := UnPadding(ret) + ret, err := cipher.DecryptBytes(srcBytes, key) if err != nil { return "", err } - if _checkRegex.MatchString(text) { - return text, err + if _checkRegex.Match(ret) { + return string(ret), err } return "", ErrKey } - -func Padding(cipherText []byte, blockSize int) []byte { - var ( - padding = getPaddingSize(cipherText, blockSize) - padData = make([]byte, padding-1) - ) - - _, _ = rand.Read(padData) - // nolint - padData = append(padData, byte(padding)) - - return append(cipherText, padData...) -} - -func UnPadding(cipherText []byte) (string, error) { - var ( - length = len(cipherText) - cipherLen = int(cipherText[length-1]) - ) - - if length < cipherLen { - return "", ErrKey - } - - return string(cipherText[:length-cipherLen]), nil -} - -func getPaddingSize(cipherText []byte, blockSize int) int { - remainder := len(cipherText) % blockSize - if remainder == 0 { - return blockSize - } - - return blockSize - remainder -} diff --git a/cfg/crypto_example_test.go b/cfg/crypto_example_test.go index a160f25..6492705 100644 --- a/cfg/crypto_example_test.go +++ b/cfg/crypto_example_test.go @@ -21,25 +21,17 @@ func ExampleEncrypt() { func ExampleEncryptByCipher() { str := cfg.EncryptByCipher([]byte("123"), "password", cfg.AES) - fmt.Println(str[:4]) + fmt.Println(str[:4]) fmt.Println(cfg.Decrypt(str, "password")) // Output: // AES( // 123 } -func ExampleDecrypt() { - fmt.Println(cfg.Decrypt("AES(A/43wTj2AVQboZZ0lNMqbw==)", "key")) - - str := cfg.EncryptByCipher([]byte("123"), "", cfg.DES) - fmt.Println(cfg.Decrypt(str, "")) - - _, err := cfg.Decrypt(str, "err") - fmt.Println(err) +func ExampleDecrypt_md5() { + fmt.Println(cfg.AESMD5.Decrypt("lob52vO/Av/yk0Ty+DBDag==", "pass")) // Output: - // aaa - // 123 - // password error + // abc } diff --git a/cfg/crypto_test.go b/cfg/crypto_test.go index 25b5a26..424a50b 100644 --- a/cfg/crypto_test.go +++ b/cfg/crypto_test.go @@ -27,14 +27,6 @@ func TestDecryptWith(t *testing.T) { } } -func TestPadding(t *testing.T) { - t.Parallel() - - if data := cfg.Padding([]byte("1234"), 4); data[0] != '1' { - t.Error("padding error") - } -} - func TestEncrypt(t *testing.T) { t.Parallel() diff --git a/cfg/padding.go b/cfg/padding.go new file mode 100644 index 0000000..15d9a7f --- /dev/null +++ b/cfg/padding.go @@ -0,0 +1,23 @@ +package cfg + +import "bytes" + +func pkcs5Trimming(encrypt []byte) ([]byte, error) { + var ( + length = len(encrypt) + cipherLen = int(encrypt[length-1]) + ) + + if length < cipherLen { + return nil, ErrKey + } + + return encrypt[:length-cipherLen], nil +} + +func pkcs5Padding(cipherText []byte, blockSize int) []byte { + padding := blockSize - len(cipherText)%blockSize + padText := bytes.Repeat([]byte{byte(padding)}, padding) + + return append(cipherText, padText...) +}