In this post we will review the steps to use RSA encryption/decryption on GO.
This post is about using a-symmetric encryption for encrypt/decrypt. In case of need of a-symmetric encryption for sign/verify, check this post.
We start by creation a struct to represent the encryption:
package encryption
import (
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
"hash"
"io"
"os"
"radware.com/euda/commons/global/log"
)
type Key struct {
privateKey *rsa.PrivateKey
hash hash.Hash
random io.Reader
}
func (k *Key) init() {
k.hash = sha256.New()
k.random = rand.Reader
}
We can generate a new key, which takes about 5 seconds on my desktop machine
func GenerateKey() (*Key, error) {
privateKey, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
return nil, fmt.Errorf("generate key failed: %v", err)
}
k := Key{privateKey: privateKey}
k.init()
return &k, nil
}
To save the key to a file:
func (k *Key) SavePrivateKey() error {
privateKeyBytes := x509.MarshalPKCS1PrivateKey(k.privateKey)
privateKeyBlock := pem.Block{
Type: "PRIVATE KEY",
Bytes: privateKeyBytes,
}
var writerBuffer bytes.Buffer
err := pem.Encode(&writerBuffer, &privateKeyBlock)
if err != nil {
return fmt.Errorf("encode private key failed: %v", err)
}
fileData := writerBuffer.String()
err = os.WriteFile(Config.PrivateKeyPath, []byte(fileData), 0644)
if err != nil {
return fmt.Errorf("write file failed: %v", err)
}
return nil
}
To load the key from a file:
func LoadPrivateKey() (*Key, error) {
pemFile, err := os.ReadFile(Config.PrivateKeyPath)
if err != nil {
return nil, fmt.Errorf("read file failed: %v", err)
}
pemBlock, _ := pem.Decode(pemFile)
privateKey, err := x509.ParsePKCS8PrivateKey(pemBlock.Bytes)
if err != nil {
return nil, fmt.Errorf("unmarshal key failed: %v", err)
}
rsaPrivateKey,ok :=privateKey.(*rsa.PrivateKey)
if !ok{
return nil, fmt.Errorf("convert failed: %v", err)
}
k := Key{privateKey: rsaPrivateKey}
k.init()
log.Info("private key loaded %v", Config.PrivateKeyPath)
return &k, nil
}
To get the public key for sending it to other parties:
func (k *Key) GetPublicKeyPem() (string, error) {
publicKeyBytes, err := x509.MarshalPKIXPublicKey(k.privateKey.Public())
if err != nil {
return "", fmt.Errorf("marshal public key failed: %v", err)
}
publicKeyBlock := pem.Block{
Type: "PUBLIC KEY",
Bytes: publicKeyBytes,
}
var writerBuffer bytes.Buffer
err = pem.Encode(&writerBuffer, &publicKeyBlock)
if err != nil {
return "", fmt.Errorf("encode public key failed: %v", err)
}
return writerBuffer.String(), nil
}
And finally, we can encrypt and decrypt:
func (k *Key) EncryptString(clearText string) (string, error) {
encryptedBytes, err := rsa.EncryptOAEP(
k.hash,
k.random,
&k.privateKey.PublicKey,
[]byte(clearText),
nil,
)
if err != nil {
return "", fmt.Errorf("encrypt failed: %v", err)
}
encryptedBase64 := base64.StdEncoding.EncodeToString(encryptedBytes)
return encryptedBase64, nil
}
func (k *Key) DecryptString(base64Cipher string) (string, error) {
encryptedBytes, err := base64.StdEncoding.DecodeString(base64Cipher)
if err != nil {
return "", fmt.Errorf("base64 decode failed: %v", err)
}
clearTextBytes, err := rsa.DecryptOAEP(
k.hash,
k.random,
k.privateKey,
encryptedBytes,
nil,
)
if err != nil {
return "", fmt.Errorf("decrypt failed: %v", err)
}
clearText := string(clearTextBytes)
return clearText, nil
}
Final Note
This post is part of a series of posts about encryption. The full posts list is below.
- Using ECDSA in GO to Sign and Verify messages
- A-Symmetic Encrypt and Decrypt on Golang
- Symmetric Encrypt and Decrypt in Golang
- Using ECDSA in JavaScript to Sign and Verify messages
- A-Symmetic Encrypt and Decrypt on JavaScript
- Symmetric Encrypt and Decrypt in Javascript
- Using ECDSA in Python to Sign and Verify messages
No comments:
Post a Comment