Go DES Encryption Code Example (Online Runner)

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

Online calculator: use the site DES tool.

Calculation method

The DES tool supports ECB/CBC/CFB/OFB/CTR modes, PKCS7 or zero padding (for block modes), and hex/base64 encodings.

Implementation notes

  • Package: built-in crypto/des and crypto/cipher.
  • Implementation: keys and IVs are normalized to 8 bytes to match the tool behavior.
  • Notes: DES is legacy and not considered secure; prefer AES or ChaCha20.

Text encryption example

go
package main

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

func desCBCEncryptHex(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 := des.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 := "0011223344556677"
	ivHex := "0102030405060708"
	value, err := desCBCEncryptHex("hello", keyHex, ivHex)
	if err != nil {
		panic(err)
	}
	fmt.Println(value)
}

Complete script (implementation + tests)

go
package main

import (
	"crypto/cipher"
	"crypto/des"
	"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) []byte {
	if len(key) >= des.BlockSize {
		return key[:des.BlockSize]
	}
	out := make([]byte, des.BlockSize)
	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 desEncrypt(plaintext, key string, mode Mode, padding Padding, keyEncoding KeyEncoding, iv string, ivEncoding KeyEncoding, 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)

	block, err := des.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 desDecrypt(ciphertext, key string, mode Mode, padding Padding, keyEncoding KeyEncoding, iv string, ivEncoding KeyEncoding, 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)

	block, err := des.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 := "0011223344556677"
	ivHex := "0102030405060708"

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

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