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.