Working with RSA Keys in Go
In this post, we’ll see how to work with RSA keys in Go for encryption, decryption, and digital signatures. RSA is a widely used asymmetric encryption algorithm. We will cover generating RSA keys, encrypting and decrypting messages, signing and verifying signatures, and provide instructions on how to generate RSA keys using OpenSSL.
Generating RSA Keys Using OpenSSL
Before diving into the Go code, let’s generate RSA keys using OpenSSL. This is useful if you need to create your own key pairs for use in the Go program.
-
Generate a Private Key
Use the following command to generate a 2048-bit RSA private key and save it to a file named
private.pem
:openssl genpkey -algorithm RSA -out private.pem -aes256
This command generates a private key and encrypts it with AES-256. You will be prompted to enter a passphrase to protect the private key.
-
Extract the Public Key
Extract the public key from the private key file and save it to a file named
public.pem
:openssl rsa -pubout -in private.pem -out public.pem
This command reads the private key and outputs the corresponding public key.
RSA Encryption and Decryption in Go
Here’s a Go program that demonstrates how to read RSA keys from files, encrypt and decrypt data, and sign and verify messages:
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"
)
func main() {
// Read private key from file
privateKeyBytes, err := ioutil.ReadFile("private.pem")
if err != nil {
panic(err)
}
// Decode private key from PEM format
privateKeyBlock, _ := pem.Decode(privateKeyBytes)
if privateKeyBlock == nil {
panic("failed to parse private key")
}
// Parse the private key
privateKey, err := x509.ParsePKCS8PrivateKey(privateKeyBlock.Bytes)
if err != nil {
panic(err)
}
// Convert private key to RSA type
rsaPrivateKey, ok := privateKey.(*rsa.PrivateKey)
if !ok {
panic("failed to convert private key to RSA")
}
// Example usage of the private key
message := []byte("This is a message to be encrypted!")
// Encrypt using the public key derived from the private key
ciphertext, err := rsa.EncryptPKCS1v15(rand.Reader, &rsaPrivateKey.PublicKey, message)
if err != nil {
panic(err)
}
fmt.Printf("Ciphertext: %x\n", ciphertext)
// Decrypt using the private key
plaintext, err := rsaPrivateKey.Decrypt(nil, ciphertext, &rsa.PKCS1v15DecryptOptions{})
if err != nil {
panic(err)
}
fmt.Printf("Plaintext: %s\n", plaintext)
// Sign the message using the private key
signature, err := rsa.SignPKCS1v15(rand.Reader, rsaPrivateKey, 0, message)
if err != nil {
panic(err)
}
fmt.Printf("Signature: %x\n", signature)
// Verify the signature using the public key
err = rsa.VerifyPKCS1v15(&rsaPrivateKey.PublicKey, 0, message, signature)
if err != nil {
fmt.Println("Signature verification failed:", err)
} else {
fmt.Println("Signature verification succeeded.")
}
}
Explanation of the Code
-
Reading and Parsing the Private Key:
- The private key is read from the
private.pem
file and decoded from PEM format. - It is then parsed into an
rsa.PrivateKey
type.
- The private key is read from the
-
Encrypting and Decrypting Data:
- Data is encrypted using the public key (derived from the private key) and decrypted using the private key.
-
Signing and Verifying Signatures:
- The private key is used to sign a message.
- The public key (derived from the private key) is used to verify the signature.
By following these steps and using the provided Go code, you can securely encrypt, decrypt, sign, and verify messages with RSA. The OpenSSL commands help you generate and manage RSA keys for use in your Go programs.