Golang Encryption Decryption: How to Create AES Encryption

Encryption is the process of converting the plaintext to ciphertext.

In simpler terms, encryption takes readable data and alters it to appear random.

Encryption requires an encryption key: a set of mathematical values that both the sender and the receiver of the encrypted message know.

If you have seen the movie Imitation Game, you will understand how 80 years ago, in the world war, countries sent the message in an encrypted format and then decoded it using a unique key.

The main advantage of Encryption is that it scrambles data so that only authorized parties can understand the information.

What is AES

AES stands for Advanced Encryption Standard.

We’ll start by looking at the AES, or Advanced Encryption Standard, as that is the standard we will use to encrypt and decrypt the information within our Golang programs.

AES is a symmetric key encryption algorithm initially developed by two Belgian cryptographers: Joan Daemen and Vincent Rijmen.

If you want to use encryption within any of your programs and aren’t quite sure how they all differ, then AES is the safest choice due to its efficiency and ease of use.

What is the key in cryptography?

A cryptographic key is a string of characters usually(32 bytes or 64 bytes) used within an encryption algorithm for altering data so that it appears random.

Like a physical key, it locks (encrypts) data so that only someone with the right key can unlock (decrypt) it.

What are the different types of encryption

There are two types of encryption.

  1. Symmetric Encryption
  2. Asymmetric Encryption(public-key encryption)

Symmetric Encryption

In symmetric encryption, there is only one key, and all communicating participants use the same key for encryption and decryption.

For symmetric encryption to work correctly and safely, the two or more communicating participants must know the key; to remain secure, no third party should be able to guess or steal the key.

Asymmetric Encryption(Public key encryption)

In asymmetric, or public key, encryption, there are two keys: one key is used for encryption, and a different key is used for decryption.

Either key can be used for either action, but data encrypted with the first key can only be decrypted with the second key and vice versa.

One key is kept private, while another key is shared publicly for anyone to use; that is why it has a “public key” name. Asymmetric encryption is a foundational technology for SSL (TLS).

Golang Encryption Decryption

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

The AES operations in that package are not implemented using the constant-time algorithms.

An exception is when running on systems with enabled hardware support for AES that makes these operations constant-time.

Encryption ensures no one can read communications or data at rest except the intended recipient or proper data owner.

Encryption prevents cybercriminals, ad networks, Internet service providers(ISPs), and sometimes foreign governments from intercepting and reading sensitive data.

TLS, also known as SSL, is the protocol for encrypting communications over a network.

TLS uses both asymmetric and symmetric encryption.

Golang Encryption using AES

We will start by creating the new file called hello.go, which will contain take in the passphrase from the command line and subsequently encrypt some text before writing this to the file.

package main

import (
  "crypto/aes"
  "crypto/cipher"
  "crypto/rand"
  "fmt"
  "io"
  "io/ioutil"
)
func main() {
  text := []byte("Mandalorian is currently the best DisneyPlus show")
  key := []byte("TZPtSIacEJG18IpqQSkTE6luYmnCNKgR")
  cphr, err := aes.NewCipher(key)
  if err != nil {
    fmt.Println(err)
  }
  gcm, err := cipher.NewGCM(cphr)
  if err != nil {
    fmt.Println(err)
  }
  nonce := make([]byte, gcm.NonceSize())
  if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
    fmt.Println(err)
  }
  err = ioutil.WriteFile("app.txt", gcm.Seal(nonce, nonce, text, nil), 0777)
  if err != nil {
    fmt.Println(err)
  }
}

First, we have imported the following packages.

  1. crypto/aes
  2. crypto/cipher
  3. crypto/rand
  4. fmt
  5. io
  6. io/ioutil

Then, we defined the main() function, and first, we defined two variables.

  1. text: The text is the main message we will encrypt using the AES algorithm.
  2. key: It is a 32-byte key for symmetric encryption.

The next step would be to generate the new AES cipher using a 32-byte long key.

For that, we are using aes.NewCipher() function, which takes a 32-byte key.

func NewCipher(key)

NewCipher() function creates and returns the new cipher.Block.

The key argument should be the AES key, either 16, 24, or 32 bytes, to select AES-128, AES-192, or AES-256.

The next step is that we will generate GCM in AES.

GCM(Galois/Counter Mode)

Galois/Counter Mode (GCM) is the mode of operation for symmetric key cryptographic block ciphers widely adopted thanks to its performance.

An operation is an authenticated encryption algorithm that provides data integrity and confidentiality.

GCM is defined for block ciphers with a block size of 128 bits.

We are using the cipher package’s gcm() function, which provides us with the operation which ensures data authenticity and integrity.

The next is to create a new byte array the size of Nonce.

Then we populate the byte array with a cryptographically secure random sequence.

The next step is to seal the message means to create an encrypted version of our original message using gcm.Seal() function.

gcm.Seal()

It secures the given plaintext message with encryption and an authentication tag covering both the encrypted and additional data.

Seal encrypts and authenticates plaintext and additional data and appends the result to dst, returning the updated slice.

The Nonce must be the NonceSize() bytes long and unique for all times for the given key.

Now, we are writing this ciphertext or encrypted message to a file called app.txt using ioutil.WriteFile() function.

The seal() function takes four arguments.

  1. nonce as dst
  2. nonce
  3. text
  4. nil

You can check the app.txt file and see that encrypted message, which you won’t be able to read. See the following unreadable message.

%ن���A���Қ�B
ϼ#�r��š*vhZn��q'����_7]≙�S�l��Y+RK�{����UmAp�z�

So, the above unreadable message is our ciphertext or encrypted for our original message string “Mandalorian is currently the best DisneyPlus show.”

So, in our Golang Encryption Decryption Example article, encryption is over.

Now, let’ Decrypt the message and get back our original message.

Golang Decryption using AES

Let’s write just decryption code, and then we will write the whole code file.

ciphertext, err := ioutil.ReadFile("app.txt")
 if err != nil {
   fmt.Println(err)
 }
 c, err := aes.NewCipher(key)
 if err != nil {
   fmt.Println(err)
 }
 gcmDecrypt, err := cipher.NewGCM(c)
 if err != nil {
   fmt.Println(err)
 }
 nonceSize := gcmDecrypt.NonceSize()
 if len(ciphertext) < nonceSize {
   fmt.Println(err)
 }
 nonce, encryptedMessage := ciphertext[:nonceSize], ciphertext[nonceSize:]
 plaintext, err := gcmDecrypt.Open(nil, nonce, encryptedMessage, nil)
 if err != nil {
   fmt.Println(err)
 }
 fmt.Println(string(plaintext))

Explanation

We’ve covered AES encryption and writing our encrypted message to a file.

Let’s now look at reading from the file and trying to decrypt that using the same shared key.

We will start by using ioutil.ReadFile(‘app.txt’) to read in the encrypted text as the byte array.
Once we have this byte array, we will follow very similar steps as we did for the encryption side.
First, we need to create the new Cipher using an aes.NewCipher() function, passing in our shared key as a primary parameter.

Next, we need to generate our GCM.

After that, we need to get our Nonce size using the gcm.NonceSize()

Finally, we will decrypt our encrypted ciphertext using a gcm.Open() function returns both our plaintext and an error if there is any.

gcm.open(dst, nonce, ciphertext, data []byte)

The gcm.Open() function authenticates and decrypts ciphertext.

We have used that function to decrypt the ciphertext.

package main

import (
  "crypto/aes"
  "crypto/cipher"
  "crypto/rand"
  "fmt"
  "io"
  "io/ioutil"
)
func main() {
  text := []byte("Mandalorian is currently the best DisneyPlus show")
  key := []byte("TZPtSIacEJG18IpqQSkTE6luYmnCNKgR")
  // Encryption
  cphr, err := aes.NewCipher(key)
  if err != nil {
    fmt.Println(err)
  }
  gcm, err := cipher.NewGCM(cphr)
  if err != nil {
    fmt.Println(err)
  }
  nonce := make([]byte, gcm.NonceSize())
  if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
    fmt.Println(err)
  }
  err = ioutil.WriteFile("app.txt", gcm.Seal(nonce, nonce, text, nil), 0777)
  if err != nil {
    fmt.Println(err)
  }
  // Decryption
  ciphertext, err := ioutil.ReadFile("app.txt")
  if err != nil {
    fmt.Println(err)
  }
  c, err := aes.NewCipher(key)
  if err != nil {
    fmt.Println(err)
  }
  gcmDecrypt, err := cipher.NewGCM(c)
  if err != nil {
    fmt.Println(err)
  }
  nonceSize := gcmDecrypt.NonceSize()
  if len(ciphertext) < nonceSize {
    fmt.Println(err)
  }
  nonce, encryptedMessage := ciphertext[:nonceSize], ciphertext[nonceSize:]
  plaintext, err := gcmDecrypt.Open(nil, nonce, encryptedMessage, nil)
  if err != nil {
    fmt.Println(err)
  }
  fmt.Println("After decrypting:")
  fmt.Println(string(plaintext))
}

Output

After decrypting:

Mandalorian is currently the best DisneyPlus show

That’s it.

1 thought on “Golang Encryption Decryption: How to Create AES Encryption”

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.