Golang Encrypt Decrypt String, File, Binary, JSON, Struct


Written by - Tuan Nguyen
Reviewed by - Deepak Prasad

You'll be able to by the end of this tutorial:

  1. Understand the basic concept encrypt and decrypt
  2. Utilize Go to encrypt text/other data types using the AES encryption standard.
  3. Finally, we will examine how to use a shared secret to decrypt a message.

You should be able to use this to create your own simple encryption systems that can accomplish various tasks, such as encrypting files on your file system and protecting them with a passphrase unique to you or incorporating simple encryption into different system components that you are developing.

 

Encrypt a binary or string using AES in Golang

Data can be hidden through encryption, making it unusable if it gets into the wrong hands. We'll use the Advanced Encryption Standard, which crypto/aes offers, to encrypt in Go.

Package aes implements AES encryption (formerly Rijndael), as defined in U.S. Federal Information Processing Standards Publication 197.

The AES operations in this package are not implemented using constant-time algorithms. An exception is when running on systems with enabled hardware support for AES that makes these operations constant-time.

In its crypto package, the Go programming language provides symmetric encryption techniques.

The first step is to generate a 32-byte key for use in encrypting and decrypting data. Because the key must be saved somewhere in real-world applications, I encoded it to a string for this purpose:

key := make([]byte, 32) //generate a random 32 byte key for AES-256
if _, err := rand.Read(key); err != nil {
	panic(err.Error())
}

keyStr := hex.EncodeToString(key) //convert to string for saving

 

Encryption

To encrypt data, we need :

  • key (32-bytes for AES-256 encryption)
  • data to encrypt - plaintext in this example

Create a new Cipher Block from the key:

block, err := aes.NewCipher(key)

Using NewCFBEncrypter() function to encrypt data:

func NewCFBEncrypter(block Block, iv []byte) Stream: NewCFBEncrypter returns a Stream which encrypts with cipher feedback mode, using the given Block. The iv must be the same length as the Block's block size.

	stream := cipher.NewCFBEncrypter(block, iv)
	stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)

Because ciphertext is slice of byte, we have to convert the encrypted data to base64:

return base64.URLEncoding.EncodeToString(ciphertext)

 

Decryption

To decrypt data, we need to convert the key and the string to decrypt to bytes:

	key, _ := hex.DecodeString(keyString)
	ciphertext, _ := base64.URLEncoding.DecodeString(stringToDecrypt)

Create a new Cipher Block from the key:

block, err := aes.NewCipher(key)

Decrypt data using NewCFBDecrypter() function:

	stream := cipher.NewCFBDecrypter(block, iv)

	// XORKeyStream can work in-place if the two arguments are the same.
	stream.XORKeyStream(ciphertext, ciphertext)

The entire code for encrypt and decrypt string in Golang:

package main

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

func encrypt(keyString string, stringToEncrypt string) (encryptedString string) {
	// convert key to bytes
	key, _ := hex.DecodeString(keyString)
	plaintext := []byte(stringToEncrypt)

	//Create a new Cipher Block from the key
	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err.Error())
	}

	// The IV needs to be unique, but not secure. Therefore it's common to
	// include it at the beginning of the ciphertext.
	ciphertext := make([]byte, aes.BlockSize+len(plaintext))
	iv := ciphertext[:aes.BlockSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		panic(err)
	}

	stream := cipher.NewCFBEncrypter(block, iv)
	stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)

	// convert to base64
	return base64.URLEncoding.EncodeToString(ciphertext)
}

// decrypt from base64 to decrypted string
func decrypt(keyString string, stringToDecrypt string) string {
	key, _ := hex.DecodeString(keyString)
	ciphertext, _ := base64.URLEncoding.DecodeString(stringToDecrypt)

	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}

	// The IV needs to be unique, but not secure. Therefore it's common to
	// include it at the beginning of the ciphertext.
	if len(ciphertext) < aes.BlockSize {
		panic("ciphertext too short")
	}
	iv := ciphertext[:aes.BlockSize]
	ciphertext = ciphertext[aes.BlockSize:]

	stream := cipher.NewCFBDecrypter(block, iv)

	// XORKeyStream can work in-place if the two arguments are the same.
	stream.XORKeyStream(ciphertext, ciphertext)

	return fmt.Sprintf("%s", ciphertext)
}

func main() {
	originalText := "Hello GoLinuxCloud members!"
	fmt.Println(originalText)

	key := []byte("this's secret key.enough 32 bits")
	if _, err := rand.Read(key); err != nil {
		panic(err.Error())
	}
	keyStr := hex.EncodeToString(key) //convert to string for saving

	fmt.Println("Encrypting.....")
	// encrypt value to base64
	cryptoText := encrypt(keyStr, originalText)
	fmt.Println(cryptoText)

	fmt.Println("Decrypting.....")
	// encrypt base64 crypto to original value
	text := decrypt(keyStr, cryptoText)
	fmt.Println(text)
}

Output:

Hello GoLinuxCloud members!
Encrypting.....
jhaPlM3OHjJKDBSaB-25-2sat1IcPJ6iwL7lkRgA2eZvzhUriCzb1tK7ow==
Decrypting.....
Hello GoLinuxCloud members!

 

Encrypt and decrypt a file using AES in Golang

With the same ideal, now we can read text file and key file and then encrypt it. For decryption, it’s pretty similar.

func main() {
	plainText, err := ioutil.ReadFile("./plaintext.txt")
	if err != nil {
		log.Fatalf("read file err: %v", err.Error())
	}

	key, err := ioutil.ReadFile("./key.txt")
	if err != nil {
		log.Fatalf("read file err: %v", err.Error())
	}

	fmt.Println("Encrypting.....")
	// encrypt value to base64
	cryptoText := encrypt(string(key[:]), string(plainText[:]))
        fmt.Println(cryptoText)
	err = ioutil.WriteFile("./ciphertext.bin", []byte(cryptoText), 0777)
	if err != nil {
		log.Fatalf("write file err: %v", err.Error())
	}

	fmt.Println("Decrypting.....")
	cryptoFile, err := ioutil.ReadFile("./ciphertext.bin")
	if err != nil {
		log.Fatalf("read file err: %v", err.Error())
	}
	// encrypt base64 crypto to original value
	text := decrypt(string(key[:]), string(cryptoFile[:]))
	fmt.Println(text)
}

Output:

Encrypting.....
clJy-R9MOvbUa9Qx4hxDrGKEjDv8-YCIalmA5oss1J8VzpNZZAxUVXjZUhEE8_aFvTAqGqSYOiBMcb1ST6s0Ffe8XfzlGX1rgcDcjX_qJOjLAntDPfW1GE6wFI-DK5Zw4JmHILPrBFQHSmJHNrJwcUJy_lrgVl4Z6VgNliqbqmgOQYVko1dYxbYDXW4UWJcqIKiYqNKUdUDzPRstFFXtVtLZ-bo6Rv944x-SB5mvgUuYyzuCzg1AIgZnbsnMPht6_RAEOnQ3D0FrgZpWEHrpuDoYSX33M7ljmjb6BUmmtNhUPXlMRJMSVw95t8fbCoYGTtNvwFM86HDsT4DUCiy18SExmKEuecDzlA0iYWFBWgokxUU9UJQCxzBdRnwahtu-jTaJc6QxS5ShzcgQw5-3GxE0jCN2j3UNelbooz80nxst2BNH5J3G8bZ19TXjo1xDLeyvgLDEnWEKEZFQH3sn86VvWRtk2DxkI-WpIn0NyN9Fo6iNOX-jMtvdXoAANMB56ViDI8FTes5JOm_q9E8RQY3kcFTH-iMHBKsTG91om9ttQg8mnUo65R15yTUUeYRv7C6KDFJQPOoPGEUoWcbsc7B5egzZJ-n35hrA4xodTbw0wJAEYtcbMUElxh4HIggY9ilKaURYJOr_XuIH3ysbqJT1wunA3kd_6BJvSRz4dW9X1C5o3FGqxojdMAXQiE6Zq2mTIZ1ZH41dw5qnxM8VUndhgrntOdbM3L3edyThKvXFiu6fc4xQ_7mFEdZZ_HeVZ9r3rYfXgu13MCe8-0Aa_XOC0r3U8i0NprXlUh6asvnkv1MRqsmQaeF8ALw6AeESggdfnSNIWqWAflgajVTTYtyEfSx6mxGPRmV-nVyzb-SWumrWpkhuBSlPoTQ2yExCB9jdQjoO233fe8Q8xzM15rveCgq0OjGZhD6aO2Sv-4zITaaa7c9tG4QipzxTqf2coiAC0jLtq8sZQYVyGrekuJMTl9-3aBJFm1GkHKoe9UodQSIWdMxJVNtkvckxo5vfHdDnQxqaPMak-hH3eLpycilwNM47ftB_UDYwTaHabAe_zT-mPHsB1wXo_nq3q4S-sCMBWi_4xr_M3_-gdu4S9EfTIVNwmK6fjyS_GXMno4S8aMS_oXSdtWGzJJRnmRZEH4fJ-mC8Y7NrwCcsHb_Z7lhbrhGVKRVLeVem-M5JyNY4I_xMRHtRLn8xkkoZQvdFN4Fu12eEz10clL1nUaAdvIRK_zYI8t-v2AMPd6VcgfyM1T4INK9Lv8810ZR8Opl8dXA9VQBVaeiKdf41TD7o3dl0oS8hd9kWjpckE-8d1xMN0vHoUB7c0UQc3XC8O553fnCMYEAjbOdE4A-gXg==
Decrypting.....
" Y'ARE very snug in here," piped old Mr. Woodifield, and he peered out of the great, green leather armchair by his friend the boss's desk as a baby peers out of its pram. His talk was over; it was time for him to be off. But he did not want to go. Since he had retired, since his... stroke, the wife and the girls kept him boxed up in the house every day of the week except Tuesday. On Tuesday he was dressed and brushed and allowed to cut back to the City for the day. Though what he did there the wife and girls couldn't imagine. Made a nuisance of himself to his friends, they supposed ... Well, perhaps so. All the same, we cling to our last pleasures as the tree clings to its last leaves. So there sat old Woodifield, smoking a cigar and staring almost greedily at the boss, who rolled in his office chair, stout, rosy, five years older than he, and still going strong, still at the helm. It did one good to see him. Wistfully, admiringly, the old voice added, " It's snug in here, upon my word ! "

 

Encrypt and decrypt a struct, json in Golang

The problem is how we can convert a struct to a byte array. The encoding/gob standard package is one possible solution. The gob package implements an encoder/decoder that can convert any struct into an array of bytes and then back into a struct. With json file, we can convert it to a string or unmarshall it to a struct and then encrypt and decrypt it. Here is an example of encrypt a struct in Golang:

type Person struct {
	Name string
	Age  int
}

func main() {
	var network bytes.Buffer        // Stand-in for a network connection
	enc := gob.NewEncoder(&network) // Will write to network.

	err := enc.Encode(Person{"Harry Potter", 1000})
	if err != nil {
		log.Fatal("encode error:", err)
	}

	key := []byte("this's secret key.enough 32 bits")
	if _, err := rand.Read(key); err != nil {
		panic(err.Error())
	}
	keyStr := hex.EncodeToString(key) //convert to string for saving

	fmt.Println("Encrypting.....")
	// encrypt value to base64
	cryptoText := encrypt(keyStr, string(network.Bytes()))
	fmt.Println(cryptoText)
	if err != nil {
		log.Fatalf("write file err: %v", err.Error())
	}

	fmt.Println("Decrypting.....")
	// encrypt base64 crypto to original value
	text := decrypt(keyStr, cryptoText)
	byteBuffer := bytes.NewBuffer([]byte(text))
	dec := gob.NewDecoder(byteBuffer) // Will read from byteBuffer
	var person Person
	err = dec.Decode(&person)
	if err != nil {
		log.Fatal("decode error:", err)
	}
	fmt.Printf("%q: %d\n", person.Name, person.Age)
}

Output:

Encrypting.....
KJSu0JrEdqOKpB6pR_37bqoMSPsUzRF_u5LTULLtAaOv4HziwvCosRRDM9FRNzgXJAGf9OBXlxcWWIFL32_rW-TcFo8SbJm-rgxepQ==
Decrypting.....
"Harry Potter": 1000

 

Summary

In this article I have introduced examples of encrypt, decrypt string, byte, file and struct in Golang using crypto package. There is always a need to safeguard your data, particularly online data. We can prevent unauthorized access by converting information into computer code using encryption.

 

References

https://pkg.go.dev/crypto/aes#NewCipher
https://en.wikipedia.org/wiki/Base64
https://pkg.go.dev/encoding/gob

 

Views: 23

Tuan Nguyen

He is proficient in Golang, Python, Java, MongoDB, Selenium, Spring Boot, Kubernetes, Scrapy, API development, Docker, Data Scraping, PrimeFaces, Linux, Data Structures, and Data Mining. With expertise spanning these technologies, he develops robust solutions and implements efficient data processing and management strategies across various projects and platforms. You can connect with him on LinkedIn.

Categories GO

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can send mail to admin@golinuxcloud.com

Thank You for your support!!

Leave a Comment