Master Go Encryption: MD5, HMAC, SHA1, AES, RSA and More Explained
This article introduces common encryption algorithms—including symmetric, asymmetric, and digital signature methods—and provides detailed Go code examples for MD5, HMAC, SHA1, AES (with various modes), and RSA, helping developers understand and implement secure cryptographic operations in Go.
Preface
Encryption and decryption are widely used in real‑world development. The common categories are Symmetric , Asymmetric , and Digital Signature .
Symmetric Encryption
Symmetric (or private‑key) encryption uses the same key for both encryption and decryption. Typical algorithms include DES, 3DES, TDEA, Blowfish, RC5, and IDEA.
Asymmetric Encryption (Public‑Key)
Asymmetric encryption uses a pair of different keys (public and private). Common algorithms are RSA, ElGamal, the knapsack algorithm, Rabin, Diffie‑Hellman, and ECC (Elliptic Curve Cryptography).
Digital Signature
Digital signatures combine asymmetric encryption with hash functions. Typical algorithms are MD5, HMAC, SHA1, etc.
MD5
The MD5 hash algorithm produces a 128‑bit (32‑character hexadecimal) digest, useful for verifying data integrity.
func GetMd5String(s string) string {
h := md5.New()
h.Write([]byte(s))
return hex.EncodeToString(h.Sum(nil))
}HMAC
HMAC (Hash‑based Message Authentication Code) mixes a secret key into the hash calculation, providing a standard, secure MAC for any hash algorithm.
// key can be any string; data is the plaintext to protect
func Hmac(key, data string) string {
hash := hmac.New(md5.New, []byte(key)) // MD5‑based HMAC
hash.Write([]byte(data))
return hex.EncodeToString(hash.Sum([]byte("")))
}
func HmacSha256(key, data string) string {
hash := hmac.New(sha256.New, []byte(key)) // SHA‑256‑based HMAC
hash.Write([]byte(data))
return hex.EncodeToString(hash.Sum([]byte("")))
}SHA1
SHA‑1 generates a 160‑bit (20‑byte) hash, typically shown as 40 hexadecimal characters.
func Sha1(data string) string {
sha1 := sha1.New()
sha1.Write([]byte(data))
return hex.EncodeToString(sha1.Sum([]byte("")))
}AES (Advanced Encryption Standard)
AES is the U.S. government‑approved block cipher that replaces DES. It supports key sizes of 128, 192, and 256 bits. The five standard modes are ECB, CBC, CTR, CFB, and OFB.
Electronic Codebook (ECB)
Cipher Block Chaining (CBC)
Counter (CTR)
Cipher Feedback (CFB)
Output Feedback (OFB)
ECB Mode
For security reasons, Go does not provide a built‑in ECB implementation.
package main
import (
"crypto/aes"
"fmt"
)
func AESEncrypt(src []byte, key []byte) (encrypted []byte) {
cipher, _ := aes.NewCipher(generateKey(key))
length := (len(src) + aes.BlockSize) / aes.BlockSize
plain := make([]byte, length*aes.BlockSize)
copy(plain, src)
pad := byte(len(plain) - len(src))
for i := len(src); i < len(plain); i++ {
plain[i] = pad
}
encrypted = make([]byte, len(plain))
for bs, be := 0, cipher.BlockSize(); bs <= len(src); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
}
return encrypted
}
func AESDecrypt(encrypted []byte, key []byte) (decrypted []byte) {
cipher, _ := aes.NewCipher(generateKey(key))
decrypted = make([]byte, len(encrypted))
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
}
trim := 0
if len(decrypted) > 0 {
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
}
return decrypted[:trim]
}
func generateKey(key []byte) (genKey []byte) {
genKey = make([]byte, 16)
copy(genKey, key)
for i := 16; i < len(key); {
for j := 0; j < 16 && i < len(key); j, i = j+1, i+1 {
genKey[j] ^= key[i]
}
}
return genKey
}
func main() {
source := "hello world"
fmt.Println("Original:", source)
key := "1443flfsaWfdas"
encryptCode := AESEncrypt([]byte(source), []byte(key))
fmt.Println("Ciphertext:", string(encryptCode))
decryptCode := AESDecrypt(encryptCode, []byte(key))
fmt.Println("Decrypted:", string(decryptCode))
}CBC Mode
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"fmt"
)
func main() {
orig := "hello world"
key := "0123456789012345"
fmt.Println("Plaintext:", orig)
encryptCode := AesEncrypt(orig, key)
fmt.Println("Ciphertext:", encryptCode)
decryptCode := AesDecrypt(encryptCode, key)
fmt.Println("Decrypted:", decryptCode)
}
func AesEncrypt(orig, key string) string {
origData := []byte(orig)
k := []byte(key)
block, _ := aes.NewCipher(k)
blockSize := block.BlockSize()
origData = PKCS7Padding(origData, blockSize)
blockMode := cipher.NewCBCEncrypter(block, k[:blockSize])
cryted := make([]byte, len(origData))
blockMode.CryptBlocks(cryted, origData)
return base64.StdEncoding.EncodeToString(cryted)
}
func AesDecrypt(cryted, key string) string {
crytedByte, _ := base64.StdEncoding.DecodeString(cryted)
k := []byte(key)
block, _ := aes.NewCipher(k)
blockSize := block.BlockSize()
blockMode := cipher.NewCBCDecrypter(block, k[:blockSize])
orig := make([]byte, len(crytedByte))
blockMode.CryptBlocks(orig, crytedByte)
orig = PKCS7UnPadding(orig)
return string(orig)
}
func PKCS7Padding(ciphertext []byte, blocksize int) []byte {
padding := blocksize - len(ciphertext)%blocksize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func PKCS7UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}CTR Mode
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"fmt"
)
func aesCtrCrypt(plainText []byte, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
iv := bytes.Repeat([]byte("1"), block.BlockSize())
stream := cipher.NewCTR(block, iv)
dst := make([]byte, len(plainText))
stream.XORKeyStream(dst, plainText)
return dst, nil
}
func main() {
source := "hello world"
fmt.Println("Original:", source)
key := "1443flfsaWfdasds"
encryptCode, _ := aesCtrCrypt([]byte(source), []byte(key))
fmt.Println("Ciphertext:", string(encryptCode))
decryptCode, _ := aesCtrCrypt(encryptCode, []byte(key))
fmt.Println("Decrypted:", string(decryptCode))
}CFB Mode
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/hex"
"fmt"
"io"
)
func AesEncryptCFB(origData []byte, key []byte) (encrypted []byte) {
block, err := aes.NewCipher(key)
if err != nil {
// handle error
}
encrypted = make([]byte, aes.BlockSize+len(origData))
iv := encrypted[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
// handle error
}
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(encrypted[aes.BlockSize:], origData)
return encrypted
}
func AesDecryptCFB(encrypted []byte, key []byte) (decrypted []byte) {
block, _ := aes.NewCipher(key)
if len(encrypted) < aes.BlockSize {
panic("ciphertext too short")
}
iv := encrypted[:aes.BlockSize]
encrypted = encrypted[aes.BlockSize:]
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(encrypted, encrypted)
return encrypted
}
func main() {
source := "hello world"
fmt.Println("Original:", source)
key := "ABCDEFGHIJKLMNO1" // 16‑byte key
encryptCode := AesEncryptCFB([]byte(source), []byte(key))
fmt.Println("Ciphertext:", hex.EncodeToString(encryptCode))
decryptCode := AesDecryptCFB(encryptCode, []byte(key))
fmt.Println("Decrypted:", string(decryptCode))
}OFB Mode
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/hex"
"fmt"
"io"
)
func aesEncryptOFB(data []byte, key []byte) ([]byte, error) {
data = PKCS7Padding(data, aes.BlockSize)
block, _ := aes.NewCipher([]byte(key))
out := make([]byte, aes.BlockSize+len(data))
iv := out[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
}
stream := cipher.NewOFB(block, iv)
stream.XORKeyStream(out[aes.BlockSize:], data)
return out, nil
}
func aesDecryptOFB(data []byte, key []byte) ([]byte, error) {
block, _ := aes.NewCipher([]byte(key))
iv := data[:aes.BlockSize]
data = data[aes.BlockSize:]
if len(data)%aes.BlockSize != 0 {
return nil, fmt.Errorf("data is not a multiple of the block size")
}
out := make([]byte, len(data))
mode := cipher.NewOFB(block, iv)
mode.XORKeyStream(out, data)
out = PKCS7UnPadding(out)
return out, nil
}
func PKCS7Padding(ciphertext []byte, blocksize int) []byte {
padding := blocksize - len(ciphertext)%blocksize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func PKCS7UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
func main() {
source := "hello world"
fmt.Println("Original:", source)
key := "1111111111111111" // 16‑byte (or 32‑byte) key
encryptCode, _ := aesEncryptOFB([]byte(source), []byte(key))
fmt.Println("Ciphertext:", hex.EncodeToString(encryptCode))
decryptCode, _ := aesDecryptOFB(encryptCode, []byte(key))
fmt.Println("Decrypted:", string(decryptCode))
}RSA Encryption
First generate a public‑private key pair with openssl, then use the following Go code to encrypt and decrypt data.
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"fmt"
)
var privateKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQDcGsUIIAINHfRTdMmgGwLrjzfMNSrtgIf4EGsNaYwmC1GjF/bM
h0Mcm10oLhNrKNYCTTQVGGIxuc5heKd1gOzb7bdTnCDPPZ7oV7p1B9Pud+6zPaco
qDz2M24vHFWYY2FbIIJh8fHhKcfXNXOLovdVBE7Zy682X1+R1lRK8D+vmQIDAQAB
AoGAeWAZvz1HZExca5k/hpbeqV+0+VtobMgwMs96+U53BpO/VRzl8Cu3CpNyb7HY
64L9YQ+J5QgpPhqkgIO0dMu/0RIXsmhvr2gcxmKObcqT3JQ6S4rjHTln49I2sYTz
7JEH4TcplKjSjHyq5MhHfA+CV2/AB2BO6G8limu7SheXuvECQQDwOpZrZDeTOOBk
z1vercawd+J9ll/FZYttnrWYTI1sSF1sNfZ7dUXPyYPQFZ0LQ1bhZGmWBZ6a6wd9
R+PKlmJvAkEA6o32c/WEXxW2zeh18sOO4wqUiBYq3L3hFObhcsUAY8jfykQefW8q
yPuuL02jLIajFWd0itjvIrzWnVmoUuXydwJAXGLrvllIVkIlah+lATprkypH3Gyc
YFnxCTNkOzIVoXMjGp6WMFylgIfLPZdSUiaPnxby1FNM7987fh7Lp/m12QJAK9iL
2JNtwkSR3p305oOuAz0oFORn8MnB+KFMRaMT9pNHWk0vke0lB1sc7ZTKyvkEJW0o
eQgic9DvIYzwDUcU8wJAIkKROzuzLi9AvLnLUrSdI6998lmeYO9x7pwZPukz3era
zncjRK3pbVkv0KrKfczuJiRlZ7dUzVO0b6QJr8TRAA==
-----END RSA PRIVATE KEY-----`)
var publicKey = []byte(`-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcGsUIIAINHfRTdMmgGwLrjzfM
NSrtgIf4EGsNaYwmC1GjF/bMh0Mcm10oLhNrKNYCTTQVGGIxuc5heKd1gOzb7bdT
nCDPPZ7oV7p1B9Pud+6zPacoqDz2M24vHFWYY2FbIIJh8fHhKcfXNXOLovdVBE7Z
y682X1+R1lRK8D+vmQIDAQAB
-----END PUBLIC KEY-----`)
func RsaEncrypt(origData []byte) ([]byte, error) {
block, _ := pem.Decode(publicKey)
if block == nil {
return nil, errors.New("public key error")
}
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, err
}
pub := pubInterface.(*rsa.PublicKey)
return rsa.EncryptPKCS1v15(rand.Reader, pub, origData)
}
func RsaDecrypt(ciphertext []byte) ([]byte, error) {
block, _ := pem.Decode(privateKey)
if block == nil {
return nil, errors.New("private key error!")
}
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext)
}
func main() {
data, _ := RsaEncrypt([]byte("hello world"))
fmt.Println(base64.StdEncoding.EncodeToString(data))
origData, _ := RsaDecrypt(data)
fmt.Println(string(origData))
}Source: guyan0319, segmentfault.com/a/1190000024557845
Article reproduced with permission from Go Development Collection (copyright belongs to the original author).
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
MaGe Linux Operations
Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
