Go Cheatsheet - AES Encryption w/ CBC mode

·

1 min read

Encryption

AES Encryption w/ CBC mode

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))
}