You can use example below for data encryption and decryption purposes in Golang. It uses x509 public and private keys. This is ideal if the encryption and decryption take place in two different machines. You can use the encrypted data in request body.


Alternative to hex encoder, you can use base64.URLEncoding/base64.RawStdEncoding functions for shorter results.


Public and private keys


The public key belongs to the sender whereas the private key belongs to receiver. The sender encrypts plain message with its public key. The receiver decrypts encrypted message with its private key. These keys are generated only once and used.


Generate keys


Once you generated both keys as string with package below, save them into "certs/public.key" and "certs/private.key" files respectively then share between sender and receiver machines.


// internal/pki
package pki

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

type Key struct {
publicKey *rsa.PublicKey
privateKey *rsa.PrivateKey
}

func New() (Key, error) {
var k Key

privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return k, err
}

k.publicKey = &privateKey.PublicKey
k.privateKey = privateKey

return k, nil
}

func (k Key) PublicKeyToPemString() string {
return string(
pem.EncodeToMemory(
&pem.Block{
Type: "RSA PUBLIC KEY",
Bytes: x509.MarshalPKCS1PublicKey(k.publicKey),
},
),
)
}

func (k Key) PrivateKeyToPemString() string {
return string(
pem.EncodeToMemory(
&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(k.privateKey),
},
),
)
}

package main

import (
"fmt"
"log"

"internal/pki"
)

func main() {
key, err := pki.New()
if err != nil {
log.Fatalln(err)
}
fmt.Println(key.PublicKeyToPemString())
fmt.Println(key.PrivateKeyToPemString())
}

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA8kelD7bzkvOl8D9dFAX8wqHzQwJM0cSS/eCOaXAxhX15TgomafXj
B29yJgUEU7Ti/sO3HHURnfCOmr8Fl7Ld/lzfUjkVV16JJBjtWByc+A7pQgnpGnHt
IURQgJaLaRje0q0pw81QxayFHA7Rb/5sNrp1u0fG+ElLwt+TyxfFJdf9Pc9crnOL
I/5+utgqOtcjhTuAxPxijRKlEltRxYs5v8wFfLq6vMQrs10qd9oZie5pfUqS3uOt
Ea8URm+qUipgfMyB5xXopdzK06qCdF4FnNhdLWA3DE5VNCnQVkhP3H5rwWacr0tz
0IfVt2oyRYUpBZbiEQIpwU4KXmnwBKbTtwIDAQAB
-----END RSA PUBLIC KEY-----

-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA8kelD7bzkvOl8D9dFAX8wqHzQwJM0cSS/eCOaXAxhX15Tgom
afXjB29yJgUEU7Ti/sO3HHURnfCOmr8Fl7Ld/lzfUjkVV16JJBjtWByc+A7pQgnp
GnHtIURQgJaLaRje0q0pw81QxayFHA7Rb/5sNrp1u0fG+ElLwt+TyxfFJdf9Pc9c
rnOLI/5+utgqOtcjhTuAxPxijRKlEltRxYs5v8wFfLq6vMQrs10qd9oZie5pfUqS
3uOtEa8URm+qUipgfMyB5xXopdzK06qCdF4FnNhdLWA3DE5VNCnQVkhP3H5rwWac
r0tz0IfVt2oyRYUpBZbiEQIpwU4KXmnwBKbTtwIDAQABAoIBABsIA1KNhv+OT6VO
bIQfZuQQTaPcTdXZqMzKkRkSe3P5W99pIoAP/xSFSqcTSDhOpkTmcTermBuXC1IY
nfce7cXDducll0v4MDTm0xRRnPHQOBY2JNveeiaMCK9QHJ3NOI8o4tAFyE1FwlQv
Ew77w/cXNqt+hqSNCPblGwg9zrE6AGO7QPkJcDOPxohUCy6t7WGV/90zat3/e7dn
jQ3qZTSIbtVGnbS5CDZ2uKQ/VT1QgDGBMosMyRQSj1KVo6vF418g9QnaGee2ePx1
EWroo11YQc+dQQdB4NKwlbM+UjS8g+tFZUPVt6Oa34NC3vIeVqIRGwt2HA1sHdQ9
C8G7GAECgYEA+58yc4nkI+GQkqCplhqtkAzkmntLxFR9Vi3nUirKgozkB5iSwslm
IHABVnAh/4AX+MwKbd0iYe5UhgijmHMP74R3WcESDw1QYRaBSKenZ9IdwXL9dn4m
/R/xgYAGPsRsOiY+zxG8cHdrsANunbBQAOPBmfUAb9wEtogcJjVvNEECgYEA9n7V
4kU++ZH5nNV4ZhiPqnRMxAFP/Efn37yQ+LDmI1mkF71QMl8+yA9MvB5oOYaOQ87k
IlZdcBRhuBMM1MNR7baj/uCVXSxr5f7FB2J8+pJN9sLSNFqEDNsIZjry5CxIOkvY
PVPKjNMj4W1RNb0TPWeVhdlONQKwkOI/OVO9KfcCgYEA1YcIalHm/6gIZtXedBoZ
lbfLO2lMJ8THRB3aQrk7d0QWsneAe7orZ3WFPRQVVdwe+6wzYX4aEl8M7V1hbxqd
uFWCbvFP4OQchPdzKPPVNV5yj9qES0zMy1uTN6EsK5HGgiY4gMJ9VjeRdCHFeh3I
FqkwfvURtNtSSJACy03nG8ECgYEAuO+8ZQFzGCfvUT3QETmIQGj1V3Fso2kHjROa
6Rs/73HH7Y+55bEUF2FzPwjJRa+weSt2elS10etYzZRtYgwRIfqP3CB/r+IuKecV
yE6aWhz+pY7RyznGLScAjELaDVsz7ZkN6iU9qJ6ZIv6zmU/8aWuYAU5ioN8dvfYh
XU94c00CgYEA3h/S0omiuEkBM+U8fTZK8GQndDHIkZFtchHYkFQ6WqL5IMJNLDHx
ys29GYK7beW59GHsO9cUJNM0l+lv0KHuGihKpBHtNG3z2r1SzbQqN93XmFQBaNSJ
zWu5OgK8vuAfSCPt4BWeDPReNka/QwbVtBm8O5YIfmLWgKGJtzkT7BM=
-----END RSA PRIVATE KEY-----

Sender


Use this package to encrypt plain message with public key then send it to receiver.


// internal/pki
package pki

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

func Encrypt(publicKeyPath, plainText string) (string, error) {
bytes, err := ioutil.ReadFile(publicKeyPath)
if err != nil {
return "", err
}

publicKey, err := convertBytesToPublicKey(bytes)
if err != nil {
return "", err
}

cipher, err := rsa.EncryptOAEP(sha512.New(), rand.Reader, publicKey, []byte(plainText), nil)
if err != nil {
return "", err
}

return cipherToPemString(cipher), nil
}

func convertBytesToPublicKey(keyBytes []byte) (*rsa.PublicKey, error) {
var err error

block, _ := pem.Decode(keyBytes)
blockBytes := block.Bytes
ok := x509.IsEncryptedPEMBlock(block)

if ok {
blockBytes, err = x509.DecryptPEMBlock(block, nil)
if err != nil {
return nil, err
}
}

publicKey, err := x509.ParsePKCS1PublicKey(blockBytes)
if err != nil {
return nil, err
}

return publicKey, nil
}

func cipherToPemString(cipher []byte) string {
return string(
pem.EncodeToMemory(
&pem.Block{
Type: "MESSAGE",
Bytes: cipher,
},
),
)
}

package main

import (
"fmt"
"log"

"internal/pki"
)

func main() {
plainText := "This is a very secret message :)"

encryptedMessage, err := pki.Encrypt("./certs/public.key", plainText)
if err != nil {
log.Fatalln(err)
}
fmt.Println(encryptedMessage)
}

-----BEGIN MESSAGE-----
unDCye9RCAad5xSMgu12fP3tUQUJA55llRIPugly7+ljFvR1fy+atyTP5dAryT8A
P0vGjnsjGKU1lMMelN5P6l2YTP9jCYYsntA0rUxMRroxvFuheJ943IHsm6tgArRR
XijTY+dCHjd08EQlOtU5bRmSXsZWBvUBK/s9jzUWDLFTeKXtTSxS2q9YP2DnUebt
kisbrg/bEeHtu9JrMpAl5bDftgqQL/mwbzm/ve5juM2tdfxtgWKKVBpV2WgZ2wMX
ptGHlZ8zIcVRYxE7KRdH7slak+djjhWCHR/sJy1Vp9vjbnZYNQr6wzpGoXSGki9K
pjtot4gahfINgvh0PknUdw==
-----END MESSAGE-----

Receiver


Use this package to decrypt encrypted message with private key then deal with it.


// internal/pki
package pki

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

func Decrypt(privateKeyPath, encryptedMessage string) (string, error) {
bytes, err := ioutil.ReadFile(privateKeyPath)
if err != nil {
return "", err
}

privateKey, err := convertBytesToPrivateKey(bytes)
if err != nil {
return "", err
}

plainMessage, err := rsa.DecryptOAEP(
sha512.New(),
rand.Reader,
privateKey,
pemStringToCipher(encryptedMessage),
nil,
)

return string(plainMessage), err
}

func convertBytesToPrivateKey(keyBytes []byte) (*rsa.PrivateKey, error) {
var err error

block, _ := pem.Decode(keyBytes)
blockBytes := block.Bytes
ok := x509.IsEncryptedPEMBlock(block)

if ok {
blockBytes, err = x509.DecryptPEMBlock(block, nil)
if err != nil {
return nil, err
}
}

privateKey, err := x509.ParsePKCS1PrivateKey(blockBytes)
if err != nil {
return nil, err
}

return privateKey, nil
}

func pemStringToCipher(encryptedMessage string) []byte {
b, _ := pem.Decode([]byte(encryptedMessage))

return b.Bytes
}

package main

import (
"fmt"
"log"

"internal/pki"
)

func main() {
encryptedMessage := // This is the incoming encrypted text as shown above.

decryptedMessage, err := pki.Decrypt("./certs/private.key", encryptedMessage)
if err != nil {
log.Fatalln(err)
}
fmt.Println(decryptedMessage)
}

This is a very secret message :)

Alternative version


package crypto

import (
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/hex"
"encoding/pem"
"fmt"
"golang.org/x/crypto/ssh"
"os"
)

type Crypto struct{}

// Encrypt encrypts plain value using SSH public key.
func (c Crypto) Encrypt(plain string) (string, error) {
sshKey, err := c.sshKey("id_rsa.pub")
if err != nil {
return "", fmt.Errorf("get ssh key: %w", err)
}

pubKey, _, _, _, err := ssh.ParseAuthorizedKey(sshKey)
if err != nil {
return "", fmt.Errorf("parse authorised key: %w", err)
}

key := pubKey.(ssh.CryptoPublicKey).CryptoPublicKey().(*rsa.PublicKey)

val, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, key, []byte(plain), nil)
if err != nil {
return "", fmt.Errorf("encrypt: %w", err)
}

return hex.EncodeToString(val), nil
}

// Decrypt decrypts previously encrypted value using SSH private key.
func (c Crypto) Decrypt(encoded string) (string, error) {
sshKey, err := c.sshKey("id_rsa")
if err != nil {
return "", fmt.Errorf("get ssh key: %w", err)
}

decoded, err := hex.DecodeString(encoded)
if err != nil {
return "", fmt.Errorf("decode data: %w", err)
}

pemBlock, _ := pem.Decode(sshKey)
key, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes)
if err != nil {
return "", fmt.Errorf("parse private key: %w", err)
}

val, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, key, decoded, nil)
if err != nil {
return "", fmt.Errorf("decode: %w", err)
}

return string(val), nil
}

// sshKey returns either a public or private SSH key.
func (c Crypto) sshKey(file string) ([]byte, error) {
home, err := os.UserHomeDir()
if err != nil {
return nil, err
}

key, err := os.ReadFile(fmt.Sprintf("%s/.ssh/%s", home, file))
if err != nil {
return nil, err
}

return key, nil
}