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 versionIf Go is installed, you will see the version number in the output. If not, see the following instructions:
- https://www.slingacademy.com/article/how-to-set-up-and-run-go-in-windows/
- https://www.slingacademy.com/article/how-to-set-up-and-run-go-in-macos/
- https://www.slingacademy.com/article/how-to-set-up-and-run-go-in-ubuntu/
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.