Go AES Encryption Code Example (Online Runner)

Go AES examples with mode, padding, key size, and encoding controls to mirror the AES tool.

Online calculator: use the site AES tool.

Calculation method

The AES tool supports ECB/CBC/CFB/OFB/CTR modes, PKCS7 or zero padding (for block modes), key size selection, and hex or base64 ciphertext encodings. This helper mirrors those fields using Go's standard crypto packages.

Implementation notes

  • Package: built-in crypto/aes and crypto/cipher.
  • Implementation: keys and IVs are normalized to the selected size to match the tool behavior.
  • Notes: padding applies only to ECB/CBC. For real use, generate a random IV per message.

Text encryption example

go
package main

import (
	"crypto/aes"
	"crypto/cipher"
	"encoding/hex"
	"fmt"
)

func aesCBCEncryptHex(plaintext string, keyHex string, ivHex string) (string, error) {
	key, err := hex.DecodeString(keyHex)
	if err != nil {
		return "", err
	}
	iv, err := hex.DecodeString(ivHex)
	if err != nil {
		return "", err
	}
	block, err := aes.NewCipher(key)
	if err != nil {
		return "", err
	}
	padded := pkcs7Pad([]byte(plaintext), block.BlockSize())
	out := make([]byte, len(padded))
	cipher.NewCBCEncrypter(block, iv).CryptBlocks(out, padded)
	return hex.EncodeToString(out), nil
}

func pkcs7Pad(data []byte, blockSize int) []byte {
	padLen := blockSize - (len(data) % blockSize)
	out := make([]byte, len(data)+padLen)
	copy(out, data)
	for i := len(data); i < len(out); i++ {
		out[i] = byte(padLen)
	}
	return out
}

func main() {
	keyHex := "00112233445566778899aabbccddeeff"
	ivHex := "0102030405060708090a0b0c0d0e0f10"
	value, err := aesCBCEncryptHex("hello", keyHex, ivHex)
	if err != nil {
		panic(err)
	}
	fmt.Println(value)
}

Complete script (implementation + tests)

go
package main

import (
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"encoding/hex"
	"errors"
	"fmt"
)

type Mode string

type Padding string

type KeyEncoding string

type CipherEncoding string

const (
	ModeECB Mode = "ECB"
	ModeCBC Mode = "CBC"
	ModeCFB Mode = "CFB"
	ModeOFB Mode = "OFB"
	ModeCTR Mode = "CTR"
)

const (
	PaddingPKCS7 Padding = "PKCS7"
	PaddingZero  Padding = "Zero"
)

const (
	EncUTF8 KeyEncoding = "utf8"
	EncHex  KeyEncoding = "hex"
)

const (
	CipherHex    CipherEncoding = "hex"
	CipherBase64 CipherEncoding = "base64"
)

func normalizeKey(key []byte, keySize int) []byte {
	if len(key) >= keySize {
		return key[:keySize]
	}
	out := make([]byte, keySize)
	copy(out, key)
	return out
}

func normalizeIV(iv []byte, blockSize int) []byte {
	out := make([]byte, blockSize)
	copy(out, iv)
	return out
}

func decodeValue(value string, encoding KeyEncoding) ([]byte, error) {
	if encoding == EncHex {
		return hex.DecodeString(value)
	}
	return []byte(value), nil
}

func encodeCiphertext(data []byte, encoding CipherEncoding) string {
	if encoding == CipherHex {
		return hex.EncodeToString(data)
	}
	return base64.StdEncoding.EncodeToString(data)
}

func decodeCiphertext(value string, encoding CipherEncoding) ([]byte, error) {
	if encoding == CipherHex {
		return hex.DecodeString(value)
	}
	return base64.StdEncoding.DecodeString(value)
}

func pkcs7Pad(data []byte, blockSize int) []byte {
	padLen := blockSize - (len(data) % blockSize)
	out := make([]byte, len(data)+padLen)
	copy(out, data)
	for i := len(data); i < len(out); i++ {
		out[i] = byte(padLen)
	}
	return out
}

func pkcs7Unpad(data []byte, blockSize int) ([]byte, error) {
	if len(data) == 0 || len(data)%blockSize != 0 {
		return nil, errors.New("invalid PKCS7 padding")
	}
	padLen := int(data[len(data)-1])
	if padLen == 0 || padLen > blockSize {
		return nil, errors.New("invalid PKCS7 padding")
	}
	for i := 0; i < padLen; i++ {
		if data[len(data)-1-i] != byte(padLen) {
			return nil, errors.New("invalid PKCS7 padding")
		}
	}
	return data[:len(data)-padLen], nil
}

func zeroPad(data []byte, blockSize int) []byte {
	if len(data)%blockSize == 0 {
		return data
	}
	padLen := blockSize - (len(data) % blockSize)
	out := make([]byte, len(data)+padLen)
	copy(out, data)
	return out
}

func zeroUnpad(data []byte) []byte {
	end := len(data)
	for end > 0 && data[end-1] == 0 {
		end--
	}
	return data[:end]
}

func encryptECB(block cipher.Block, data []byte) []byte {
	out := make([]byte, len(data))
	for i := 0; i < len(data); i += block.BlockSize() {
		block.Encrypt(out[i:], data[i:])
	}
	return out
}

func decryptECB(block cipher.Block, data []byte) []byte {
	out := make([]byte, len(data))
	for i := 0; i < len(data); i += block.BlockSize() {
		block.Decrypt(out[i:], data[i:])
	}
	return out
}

func aesEncrypt(plaintext, key string, mode Mode, padding Padding, keyEncoding KeyEncoding, iv string, ivEncoding KeyEncoding, keySize int, outEncoding CipherEncoding) (string, error) {
	keyBytes, err := decodeValue(key, keyEncoding)
	if err != nil {
		return "", err
	}
	ivBytes, err := decodeValue(iv, ivEncoding)
	if err != nil {
		return "", err
	}
	keyBytes = normalizeKey(keyBytes, keySize)

	block, err := aes.NewCipher(keyBytes)
	if err != nil {
		return "", err
	}
	data := []byte(plaintext)
	blockSize := block.BlockSize()

	if mode == ModeECB || mode == ModeCBC {
		if padding == PaddingPKCS7 {
			data = pkcs7Pad(data, blockSize)
		} else {
			data = zeroPad(data, blockSize)
		}
	}

	ivBytes = normalizeIV(ivBytes, blockSize)
	var encrypted []byte

	switch mode {
	case ModeECB:
		encrypted = encryptECB(block, data)
	case ModeCBC:
		encrypted = make([]byte, len(data))
		cipher.NewCBCEncrypter(block, ivBytes).CryptBlocks(encrypted, data)
	case ModeCFB:
		encrypted = make([]byte, len(data))
		cipher.NewCFBEncrypter(block, ivBytes).XORKeyStream(encrypted, data)
	case ModeOFB:
		encrypted = make([]byte, len(data))
		cipher.NewOFB(block, ivBytes).XORKeyStream(encrypted, data)
	case ModeCTR:
		encrypted = make([]byte, len(data))
		cipher.NewCTR(block, ivBytes).XORKeyStream(encrypted, data)
	default:
		return "", errors.New("unsupported mode")
	}

	return encodeCiphertext(encrypted, outEncoding), nil
}

func aesDecrypt(ciphertext, key string, mode Mode, padding Padding, keyEncoding KeyEncoding, iv string, ivEncoding KeyEncoding, keySize int, inEncoding CipherEncoding) (string, error) {
	keyBytes, err := decodeValue(key, keyEncoding)
	if err != nil {
		return "", err
	}
	ivBytes, err := decodeValue(iv, ivEncoding)
	if err != nil {
		return "", err
	}
	keyBytes = normalizeKey(keyBytes, keySize)

	block, err := aes.NewCipher(keyBytes)
	if err != nil {
		return "", err
	}
	data, err := decodeCiphertext(ciphertext, inEncoding)
	if err != nil {
		return "", err
	}
	blockSize := block.BlockSize()
	ivBytes = normalizeIV(ivBytes, blockSize)

	var decrypted []byte
	switch mode {
	case ModeECB:
		decrypted = decryptECB(block, data)
	case ModeCBC:
		decrypted = make([]byte, len(data))
		cipher.NewCBCDecrypter(block, ivBytes).CryptBlocks(decrypted, data)
	case ModeCFB:
		decrypted = make([]byte, len(data))
		cipher.NewCFBDecrypter(block, ivBytes).XORKeyStream(decrypted, data)
	case ModeOFB:
		decrypted = make([]byte, len(data))
		cipher.NewOFB(block, ivBytes).XORKeyStream(decrypted, data)
	case ModeCTR:
		decrypted = make([]byte, len(data))
		cipher.NewCTR(block, ivBytes).XORKeyStream(decrypted, data)
	default:
		return "", errors.New("unsupported mode")
	}

	if mode == ModeECB || mode == ModeCBC {
		if padding == PaddingPKCS7 {
			decrypted, err = pkcs7Unpad(decrypted, blockSize)
			if err != nil {
				return "", err
			}
		} else {
			decrypted = zeroUnpad(decrypted)
		}
	}

	return string(decrypted), nil
}

func main() {
	keyHex := "00112233445566778899aabbccddeeff"
	ivHex := "0102030405060708090a0b0c0d0e0f10"

	ciphertext, err := aesEncrypt("hello", keyHex, ModeCBC, PaddingPKCS7, EncHex, ivHex, EncHex, 16, CipherHex)
	if err != nil {
		panic(err)
	}
	fmt.Println("cipher=", ciphertext)

	plain, err := aesDecrypt(ciphertext, keyHex, ModeCBC, PaddingPKCS7, EncHex, ivHex, EncHex, 16, CipherHex)
	if err != nil {
		panic(err)
	}
	fmt.Println("plain=", plain)
}