Modern Cryptography using Go

Rafael Escrich
Feb 12 · 4 min read

Today, a big part of the world information is transmitted in a digital manner. Because of that, private information of citizens and companies are vulnerable to attacks of malicious actors and/or authoritarian governments. Therefore, cryptography is an indispensable tool set to protect our privacy from preying eyes. The objective of this article is explain some cryptography functions used nowadays and bring some open source snippets of Go code.


Cryptographic Hash Functions

It’s a computer functions that takes an input, generally a stream of bytes from any size and computes a fixed-size string of bytes. This fixed-size string is unique to each input that we enter the function. The output string is called the ‘hash value’, ‘message digest’, ‘digital fingerprint’, ‘digest’ or ‘checksum’. This function is the base foundation to all modern cryptography systems that we use today in our digital communications.

The ideal hash function has three main properties:

  1. Must be extremely easy in terms of computer power to calculate a hash for any given arbitrary input of bytes.
  2. Must be extremely computationally difficult to calculate the input of the function if you have only the given hash of the output.
  3. Must be extremely unlikely that two different messages have the same hash in other words difficult to find collisions.
https://theccpress.com/all-about-hashing-algorithms-and-how-they-work/

The most common cryptographic hashes:

  • SHA2–256
  • BLAKE2
  • Whirlpool

Example of SHA2–256 using Go:

package mainimport (
"crypto/sha256"
"fmt"
)
func main() {
sum := sha256.Sum256([]byte("Modern Cryptography using Go"))
fmt.Printf("%x", sum)
}

To see this code running: https://play.golang.org/p/kFDe59--Q05

Symmetric Key Cryptography

It’s a cryptography system that the same cryptographic key is used to encrypt and decrypt the content that we want to protect. This key is also known as shared secret that needs to be exchanged between the people that want to transmit information in a secure way. The drawback in this system is that anyone that possess the shared secret can decrypt and access the secret information.

Example of AES-GCM in Go:

package mainimport (
"crypto/aes"
"crypto/cipher"
"encoding/hex"
"fmt"
)
func encrypt() {
key := []byte("keygopostmediumkeygopostmediumke")
plaintext := []byte("This is the plaintext to be encrypted")
block, err := aes.NewCipher(key)
if err != nil {
panic(err.Error())
}
nonce := []byte("gopostmedium")
aesgcm, err := cipher.NewGCM(block)
if err != nil {
panic(err.Error())
}
ciphertext := aesgcm.Seal(nil, nonce, plaintext, nil)
fmt.Printf("Ciphertext: %x\n", ciphertext)
}
func decrypt() {
key := []byte("keygopostmediumkeygopostmediumke")
ciphertext, _ := hex.DecodeString("13ca135cef69048ae33a21f8f4d52360c3e2f640a73ba46d9633e0b092dec4931689cc0fa225cbc66eeb7d1e27472a494a0183d6b5")
nonce := []byte("gopostmedium") block, err := aes.NewCipher(key)
if err != nil {
panic(err.Error())
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
panic(err.Error())
}
plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
panic(err.Error())
}
fmt.Printf("Plaintext: %s\n", string(plaintext))
}
func main() { encrypt() decrypt()
}

To see this code running: https://play.golang.org/p/7xMZv1OrOWF

Public-key cryptography

It’s a cryptographic system that uses pairs of keys, one public key that can be distributed and one private key that must be known only by the owner. With this private key the owner can sign a message or cipher. The signing of a message can be later verified by others users in possession of the public key of the signer, this way they can assure that the message was really sent by the owner of the private key corresponding to the public key. In the same way, the users in possession of the public key can cipher a message that only the user that have the corresponding private key can decipher. This way make more secure the exchange of private information because the users don’t need to exchange the secret key in an insecure channel, what is a big problem in symmetric encryption. The public-key cryptography is the foundation of today PKI, that means Public Key Infrastructure which runs all secure information in the internet including digital certificates in our browsers and webpages that we access everyday.

package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"fmt"
"io"
"os"
)// RSA
const (
rsaKeySize = 2048
)
type keypair struct {
priv *rsa.PrivateKey
pub *rsa.PublicKey
}
var kp keypair
var ciphertext, signedMessage []byte
var rng io.Reader
func generateKeypair() error { var err error
kp.priv, err = rsa.GenerateKey(rand.Reader, rsaKeySize)
if err != nil {
return err
}
kp.pub = &kp.priv.PublicKey return nil
}
func encrypt() { var err error secretMessage := []byte("This is the plaintext to be encrypted") label := []byte("mediumpost") ciphertext, err = rsa.EncryptOAEP(sha256.New(), rng, kp.pub, secretMessage, label) if err != nil { fmt.Fprintf(os.Stderr, "Error from encryption: %s\n", err)
return
}
// Since encryption is a randomized function, ciphertext will be
// different each time.
fmt.Printf("Ciphertext: %x\n", ciphertext)}func decrypt() { label := []byte("mediumpost") plaintext, err := rsa.DecryptOAEP(sha256.New(), rng, kp.priv, ciphertext, label) if err != nil {
fmt.Fprintf(os.Stderr, "Error from decryption: %s\n", err)
return
}
fmt.Printf("Plaintext: %s\n", string(plaintext))
}
func sign() { var err error message := []byte("This is the plaintext to be signed") signedMessage, err = rsa.EncryptPKCS1v15(rng, kp.pub, message) if err != nil {
fmt.Fprintf(os.Stderr, "Error from encryption: %s\n", err)
return
}
fmt.Printf("Signed Message: %x\n", signedMessage)}func verify() { msgVerified, err := rsa.DecryptPKCS1v15(rng, kp.priv, signedMessage) if err != nil {
fmt.Fprintf(os.Stderr, "Error from decryption: %s\n", err)
return
}
fmt.Printf("Verified Message: %s\n", string(msgVerified))}func main() { // crypto/rand.Reader is a good source of entropy for randomizing // encryption function.
rng = rand.Reader
// generates pair of keys
generateKeypair()
// encrypt message
encrypt()
// decrypt message
decrypt()
// sign message
sign()
// verify message
verify()
}

To see this code running: https://play.golang.org/p/OYQJWd5tKTD

So, in conclusion, in these samples we can see that is easy to implement cryptography using only standard library in Go. Hope you enjoy and if you have any doubts send me to rafaelescrich at gmail.com.

If you find this content useful send me some Bitcoin to :

31zHc12FsgLYbSMURA6SUPATTNdFDtgisJ

Talk to you soon in the next post.

Bye!

Rafael Escrich

Written by

Cypherpunk, blockchain developer, software engineer in Go and JS. Likes to cook, read and watch movies in the spare time.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade