# Go Cheatsheet - AES Encryption w/ CBC mode

## Encryption

### AES Encryption w/ CBC mode

```go
package main

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"fmt"
)

//lint:ignore U1000 might be used in the future
func pad(raw []byte) []byte {
	padding := aes.BlockSize - len(raw)%aes.BlockSize
	padText := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(raw, padText...)
}

func unpad(raw []byte) []byte {
	padCount := int(raw[len(raw)-1])
	return raw[:(len(raw) - padCount)]
}

//lint:ignore U1000 might be used in the future
func encrypt(key []byte, raw []byte) string {
	raw = pad(raw)
	iv := make([]byte, aes.BlockSize)
	rand.Read(iv)
	encrypted := make([]byte, len(raw))
	block, _ := aes.NewCipher(key)
	mode := cipher.NewCBCEncrypter(block, iv)
	mode.CryptBlocks(encrypted, raw)
	return base64.StdEncoding.EncodeToString(append(iv, encrypted...))
}

func decrypt(key []byte, b64EncStr string) (plain []byte, err error) {
	encrypted, err := base64.StdEncoding.DecodeString(b64EncStr)
	if err != nil {
		return nil, err
	}
	defer func() {
		if p := recover(); p != nil {
			err = fmt.Errorf("malformat: %v", p)
		}
	}()
	iv := encrypted[:aes.BlockSize]
	encrypted = encrypted[aes.BlockSize:]
	block, _ := aes.NewCipher(key)
	decrypted := make([]byte, len(encrypted))
	mode := cipher.NewCBCDecrypter(block, iv)
	mode.CryptBlocks(decrypted, encrypted)
	plain = unpad(decrypted)
	return unpad(decrypted), err
}

func main() {
	key := []byte("12345678901234567890123456789012")
	if len(key) != 32 {
		fmt.Println("key length should be 32")
		return
	}
	data := []byte("classified data")
	encrypted := encrypt(key, data)
	fmt.Println("Encryped:", encrypted)
	decrypted, _ := decrypt(key, encrypted)
	fmt.Println("Decrypted:", string(decrypted))
}
```
