Sling Academy
Home/Golang/Implementing RSA Encryption for Secure Communication in Go

Implementing RSA Encryption for Secure Communication in Go

Last updated: November 27, 2024

RSA encryption is a widely-used public-key cryptographic system that allows for secure data transmission. Implementing RSA encryption in Go is straightforward, thanks to its robust crypto/rsa and crypto/rand packages that simplify generating keys and encrypting/decrypting messages.

Getting Started

To begin, ensure you have Go installed on your machine. You can check this by running the following command in your terminal:

go version

If Go is installed, you will see the version number in the output. If not, see the following instructions:

Generate RSA Keys

The first step in encryption is to generate a pair of RSA keys: a public key and a private key. The public key encrypts the message, while the private key decrypts it. Here's how you can generate keys in Go:

package main

import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/x509"
    "encoding/pem"
    "os"
    "log"
)

func main() {
    // Generate RSA keys
    privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
    if err != nil {
        log.Fatalf("Failed to generate private key: %v", err)
    }

    // Save the private key to a file
    privateKeyFile, err := os.Create("private.pem")
    if err != nil {
        log.Fatalf("Failed to create private key file: %v", err)
    }
    defer privateKeyFile.Close()

    privateKeyPem := &pem.Block{
        Type:  "RSA PRIVATE KEY",
        Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
    }
    if err := pem.Encode(privateKeyFile, privateKeyPem); err != nil {
        log.Fatalf("Failed to write private key: %v", err)
    }

    // Extract the public key and save to a file
    publicKeyFile, err := os.Create("public.pem")
    if err != nil {
        log.Fatalf("Failed to create public key file: %v", err)
    }
    defer publicKeyFile.Close()

    publicKeyBytes, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey)
    if err != nil {
        log.Fatalf("Failed to marshal public key: %v", err)
    }

    publicKeyPem := &pem.Block{
        Type:  "RSA PUBLIC KEY",
        Bytes: publicKeyBytes,
    }
    if err := pem.Encode(publicKeyFile, publicKeyPem); err != nil {
        log.Fatalf("Failed to write public key: %v", err)
    }
}

Encrypting a Message

Once you have your keys, you can begin encrypting messages. The public key is used to encrypt messages. Here's an example of how you can encrypt a message:

package main

import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/x509"
    "encoding/pem"
    "io/ioutil"
    "log"
)

func main() {
    // Load the public key
    publicKeyBytes, err := ioutil.ReadFile("public.pem")
    if err != nil {
        log.Fatalf("Failed to read public key file: %v", err)
    }

    block, _ := pem.Decode(publicKeyBytes)
    if block == nil || block.Type != "RSA PUBLIC KEY" {
        log.Fatalf("Failed to decode PEM block containing public key")
    }

    publicKey, err := x509.ParsePKIXPublicKey(block.Bytes)
    if err != nil {
        log.Fatalf("Failed to parse public key: %v", err)
    }

    rsaPublicKey := publicKey.(*rsa.PublicKey)

    // Message to encrypt
    message := []byte("Hello, RSA!")

    // Encrypt the message with the public key
    encryptedMessage, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, rsaPublicKey, message, nil)
    if err != nil {
        log.Fatalf("Failed to encrypt message: %v", err)
    }

    log.Printf("Encrypted message: %x", encryptedMessage)
}

Decrypting the Message

To decrypt the message, you need the private key. Below is an example of how to decrypt a message:

package main

import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/sha256"
    "crypto/x509"
    "encoding/pem"
    "io/ioutil"
    "log"
)

func main() {
    // Load the private key
    privateKeyBytes, err := ioutil.ReadFile("private.pem")
    if err != nil {
        log.Fatalf("Failed to read private key file: %v", err)
    }

    block, _ := pem.Decode(privateKeyBytes)
    if block == nil || block.Type != "RSA PRIVATE KEY" {
        log.Fatalf("Failed to decode PEM block containing private key")
    }

    privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    if err != nil {
        log.Fatalf("Failed to parse private key: %v", err)
    }

    // Encrypted message from the previous example.
    encryptedMessage := [...]byte{...} // Use the actual byte slice from encrypted output

    // Decrypt the message with the private key
    decryptedMessage, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, privateKey, encryptedMessage, nil)
    if err != nil {
        log.Fatalf("Failed to decrypt message: %v", err)
    }

    log.Printf("Decrypted message: %s", decryptedMessage)
}

Conclusion

By following these steps, you’ve implemented a basic version of RSA encryption and decryption in Go. This article provides a grounding in the essential tasks of key generation, encryption, and decryption, all critical aspects of securing your communications using RSA.

Next Article: Using the `crypto/hmac` Package for Message Authentication in Go

Previous Article: Understanding Symmetric Encryption with AES in Go

Series: Cryptography and Security in Go

Golang

Related Articles

You May Also Like

  • How to remove HTML tags in a string in Go
  • How to remove special characters in a string in Go
  • How to remove consecutive whitespace in a string in Go
  • How to count words and characters in a string in Go
  • Relative imports in Go: Tutorial & Examples
  • How to run Python code with Go
  • How to generate slug from title in Go
  • How to create an XML sitemap in Go
  • How to redirect in Go (301, 302, etc)
  • Using Go with MongoDB: CRUD example
  • Auto deploy Go apps with CI/ CD and GitHub Actions
  • Fixing Go error: method redeclared with different receiver type
  • Fixing Go error: copy argument must have slice type
  • Fixing Go error: attempted to use nil slice
  • Fixing Go error: assignment to constant variable
  • Fixing Go error: cannot compare X (type Y) with Z (type W)
  • Fixing Go error: method has pointer receiver, not called with pointer
  • Fixing Go error: assignment mismatch: X variables but Y values
  • Fixing Go error: array index must be non-negative integer constant