- Published on
Encrypt and Decrypt with PKCS7
1403 words8 min read
// This is an example showing how to
// => Generate a SSH RSA Private/Public Key Pair
// => Encrypt it with PKCS7, using the Public Key
// => Decrypt the encryted result, using the Private Key
//
// References
// ==========
//
// => github.com/fullsailor/pkcs7
// => https://systemweakness.com/generating-rsa-pem-key-pair-using-go-7fd9f1471b58
// => https://ericchiang.github.io/post/go-tls/
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/base64"
"encoding/pem"
"flag"
"log/slog"
"math/big"
"os"
"runtime/debug"
"time"
"github.com/fullsailor/pkcs7"
)
func init() {
build, _ := debug.ReadBuildInfo()
enableDebug := flag.Bool("debug", false, "whether to enable debug mode")
flag.Parse()
opts := &slog.HandlerOptions{}
if *enableDebug {
opts.Level = slog.LevelDebug
}
slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stdout, opts)).With(
slog.Group("program_info",
slog.Int("pid", os.Getpid()),
slog.String("go_version", build.GoVersion),
),
))
}
func main() {
str := "Hello World"
bits := 4096
slog.Debug("Generating new RSA Private Key", slog.Int("bits", bits))
privKey, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
slog.Error("Error generating RSA Private Key", "error", err)
os.Exit(1)
}
slog.Debug("Encoding Private Key to PEM format")
privKeyPEM := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(privKey),
}
slog.Debug("Creating Private Key file")
privKeyFile, err := os.Create("private_key.pem")
if err != nil {
slog.Error("Error creating private_key file", "error", err)
os.Exit(1)
}
slog.Debug("Encoding Private Key to file")
if err := pem.Encode(privKeyFile, privKeyPEM); err != nil {
slog.Error("Error encoding Private Key to file", "error", err)
os.Exit(1)
}
if err := privKeyFile.Close(); err != nil {
slog.Error("Error closing file")
os.Exit(1)
}
slog.Debug("Extracting Public Key from Private Key")
pubKey := &privKey.PublicKey
slog.Debug("Encoding Public Key to PEM format")
pubKeyPEM := &pem.Block{
Type: "RSA PUBLIC KEY",
Bytes: x509.MarshalPKCS1PublicKey(pubKey),
}
slog.Debug("Creating Public Key file")
pubKeyFile, err := os.Create("public_key.pem")
if err != nil {
slog.Error("Error creating public_key file", "error", err)
os.Exit(1)
}
slog.Debug("Encoding Public Key to file")
if err := pem.Encode(pubKeyFile, pubKeyPEM); err != nil {
slog.Error("Error encoding Public Key to file", "error", err)
os.Exit(1)
}
if err := pubKeyFile.Close(); err != nil {
slog.Error("Error closing file")
os.Exit(1)
}
slog.Info("RSA key pair generated successfully!")
slog.Debug("Starting PKCS7 encryption process")
slog.Debug("Generating x509 Certificate template")
tmpl, err := x509CertificateTemplate()
if err != nil {
slog.Error("Error generating x509 Certificate template", "error", err)
os.Exit(1)
}
slog.Debug("Creating Certificate DER")
certDER, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, pubKey, privKey)
if err != nil {
slog.Error("Error generating x509 Certificate template", "error", err)
os.Exit(1)
}
x509PubCert, err := x509.ParseCertificate(certDER)
if err != nil {
slog.Error("Error converting Public Key to x509", "error", err)
os.Exit(1)
}
slog.Debug("Encrypting input", slog.String("str", str))
encOut, err := pkcs7.Encrypt([]byte(str), []*x509.Certificate{x509PubCert})
if err != nil {
slog.Error("Error encrypting input", "error", err)
os.Exit(1)
}
slog.Info("Input encrypted successfully", "base64", base64.StdEncoding.EncodeToString(encOut))
slog.Debug("Starting PKCS7 decryption process")
p7, err := pkcs7.Parse(encOut)
if err != nil {
slog.Error("Error parsing encrypted output", "error", err)
os.Exit(1)
}
slog.Debug("Decrypting output")
decOut, err := p7.Decrypt(x509PubCert, privKey)
if err != nil {
slog.Error("Error decrypting output", "error", err)
os.Exit(1)
}
slog.Info("Output decrypted successfully", "str", str, "decrypted", string(decOut))
}
func x509CertificateTemplate() (*x509.Certificate, error) {
slog.Debug("Creating Certificate Template")
limit := new(big.Int).Lsh(big.NewInt(1), 128)
sn, err := rand.Int(rand.Reader, limit)
if err != nil {
return nil, err
}
return &x509.Certificate{
SerialNumber: sn,
Subject: pkix.Name{Organization: []string{"Wibble Wobble, Inc."}},
SignatureAlgorithm: x509.SHA256WithRSA,
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(1, 0, 0), // valid for a year
BasicConstraintsValid: true,
}, nil
}