package encryptor import ( "bytes" "crypto/aes" "crypto/cipher" "encoding/base64" "errors" "fmt" ) var ( // ErrInvalidBlockSize block size 不合法. ErrInvalidBlockSize = errors.New("invalid block size") // ErrInvalidPKCS7Data PKCS7 数据不合法. ErrInvalidPKCS7Data = errors.New("invalid PKCS7 data") // ErrInvalidPKCS7Padding padding 不合法. ErrInvalidPKCS7Padding = errors.New("invalid PKCS7 padding") ) // Encrypt encrypts plaintext with AES-CBC and returns base64 ciphertext. func Encrypt(aesKey string, plaintext []byte) (string, error) { key, err := decodeAESKey(aesKey) if err != nil { return "", err } block, err := aes.NewCipher(key) if err != nil { return "", err } plaintext = pkcs7Pad(plaintext, block.BlockSize()) ciphertext := make([]byte, len(plaintext)) mode := cipher.NewCBCEncrypter(block, key[:aes.BlockSize]) mode.CryptBlocks(ciphertext, plaintext) return base64.StdEncoding.EncodeToString(ciphertext), nil } // Decrypt decrypts base64 AES-CBC ciphertext. func Decrypt(aesKey, ciphertext string) ([]byte, error) { key, err := decodeAESKey(aesKey) if err != nil { return nil, err } data, err := base64.StdEncoding.DecodeString(ciphertext) if err != nil { return nil, err } if len(data) == 0 || len(data)%aes.BlockSize != 0 { return nil, ErrInvalidPKCS7Data } block, err := aes.NewCipher(key) if err != nil { return nil, err } plaintext := make([]byte, len(data)) mode := cipher.NewCBCDecrypter(block, key[:aes.BlockSize]) mode.CryptBlocks(plaintext, data) return pkcs7Unpad(plaintext, block.BlockSize()) } func decodeAESKey(encodingAESKey string) ([]byte, error) { key, err := base64.StdEncoding.DecodeString(encodingAESKey + "=") if err != nil { return nil, err } if len(key) != 32 { return nil, fmt.Errorf("encodingAESKey invalid") } return key, nil } func pkcs7Pad(data []byte, blockSize int) []byte { padding := blockSize - len(data)%blockSize padText := bytes.Repeat([]byte{byte(padding)}, padding) return append(data, padText...) } func pkcs7Unpad(data []byte, blockSize int) ([]byte, error) { if blockSize <= 0 { return nil, ErrInvalidBlockSize } if len(data) == 0 || len(data)%blockSize != 0 { return nil, ErrInvalidPKCS7Data } padding := int(data[len(data)-1]) if padding == 0 || padding > blockSize || padding > len(data) { return nil, ErrInvalidPKCS7Padding } for i := len(data) - padding; i < len(data); i++ { if int(data[i]) != padding { return nil, ErrInvalidPKCS7Padding } } return data[:len(data)-padding], nil }