package crypto import ( "crypto/aes" "crypto/cipher" "encoding/base64" "errors" "fmt" ) func Decrypt(ciphertextB64, key, iv string) (string, error) { ciphertext, err := base64.StdEncoding.DecodeString(ciphertextB64) if err != nil { return "", fmt.Errorf("base64 decode failed: %v", err) } block, err := aes.NewCipher([]byte(key)) if err != nil { return "", fmt.Errorf("AES init failed: %v", err) } if len(iv) != aes.BlockSize { return "", fmt.Errorf("IV must be %d bytes", aes.BlockSize) } mode := cipher.NewCBCDecrypter(block, []byte(iv)) plaintext := make([]byte, len(ciphertext)) mode.CryptBlocks(plaintext, ciphertext) unpadded, err := pkcs7Unpad(plaintext) if err != nil { return "", fmt.Errorf("PKCS7 unpadding failed: %v", err) } return string(unpadded), nil } func pkcs7Unpad(data []byte) ([]byte, error) { if len(data) == 0 { return nil, errors.New("empty data") } padSize := int(data[len(data)-1]) if padSize > len(data) || padSize > aes.BlockSize { return nil, fmt.Errorf("invalid padding size: %d", padSize) } for i := range padSize { if data[len(data)-1-i] != byte(padSize) { return nil, errors.New("invalid padding content") } } return data[:len(data)-padSize], nil }