Go RSA-OAEP Code Example (Online Runner)
Go RSA-OAEP examples with hash selection, PEM keys, and hybrid file encryption matching the RSA tools.
Online calculator: use the site RSA tool.
Calculation method
Use RSA-OAEP with selectable hash functions for small payloads. For files, use a hybrid scheme: encrypt file bytes with AES-256-CBC and wrap the AES key with RSA-OAEP.
Implementation notes
- Package: built-in
crypto/rsa,crypto/x509,crypto/aes, andcrypto/cipher. - Implementation: RSA-OAEP supports SHA-1/256/384/512. The file helper emits a JSON package matching the tool format.
- Notes: RSA-OAEP has a max message size; use it for keys, not large payloads.
Text encryption example
go
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
)
func generateKeypair(bits int) (string, string, error) {
priv, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return "", "", err
}
privPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
pubPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PUBLIC KEY", Bytes: x509.MarshalPKCS1PublicKey(&priv.PublicKey)})
return string(pubPEM), string(privPEM), nil
}
func rsaEncrypt(text string, publicPEM string) (string, error) {
block, _ := pem.Decode([]byte(publicPEM))
pub, err := x509.ParsePKCS1PublicKey(block.Bytes)
if err != nil {
return "", err
}
ciphertext, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, pub, []byte(text), nil)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(ciphertext), nil
}
func rsaDecrypt(ciphertext string, privatePEM string) (string, error) {
block, _ := pem.Decode([]byte(privatePEM))
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return "", err
}
data, err := base64.StdEncoding.DecodeString(ciphertext)
if err != nil {
return "", err
}
plain, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, priv, data, nil)
if err != nil {
return "", err
}
return string(plain), nil
}
func main() {
pub, priv, err := generateKeypair(2048)
if err != nil {
panic(err)
}
ciphertext, err := rsaEncrypt("hello", pub)
if err != nil {
panic(err)
}
fmt.Println(ciphertext)
plain, err := rsaDecrypt(ciphertext, priv)
if err != nil {
panic(err)
}
fmt.Println(plain)
}File encryption example
go
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/hex"
"encoding/json"
"encoding/pem"
"fmt"
"os"
"path/filepath"
)
type FilePackage struct {
Version int `json:"version"`
Hash string `json:"hash"`
Mode string `json:"mode"`
IV string `json:"iv"`
EncryptedKey string `json:"encryptedKey"`
Ciphertext string `json:"ciphertext"`
OriginalName string `json:"originalName"`
MimeType string `json:"mimeType"`
}
func generateKeypair(bits int) (string, string, error) {
priv, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return "", "", err
}
privPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
pubPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PUBLIC KEY", Bytes: x509.MarshalPKCS1PublicKey(&priv.PublicKey)})
return string(pubPEM), string(privPEM), nil
}
func rsaEncryptFile(path string, publicPEM string) (string, error) {
data, err := os.ReadFile(path)
if err != nil {
return "", err
}
key := make([]byte, 32)
iv := make([]byte, 16)
if _, err := rand.Read(key); err != nil {
return "", err
}
if _, err := rand.Read(iv); err != nil {
return "", err
}
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
padded := pkcs7Pad(data, block.BlockSize())
ciphertext := make([]byte, len(padded))
cipher.NewCBCEncrypter(block, iv).CryptBlocks(ciphertext, padded)
blockPEM, _ := pem.Decode([]byte(publicPEM))
pub, err := x509.ParsePKCS1PublicKey(blockPEM.Bytes)
if err != nil {
return "", err
}
encKey, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, pub, key, nil)
if err != nil {
return "", err
}
pkg := FilePackage{
Version: 1,
Hash: "SHA-256",
Mode: "AES-256-CBC",
IV: hex.EncodeToString(iv),
EncryptedKey: base64.StdEncoding.EncodeToString(encKey),
Ciphertext: base64.StdEncoding.EncodeToString(ciphertext),
OriginalName: filepath.Base(path),
MimeType: "application/octet-stream",
}
payload, err := json.MarshalIndent(pkg, "", " ")
if err != nil {
return "", err
}
return string(payload), nil
}
func pkcs7Pad(data []byte, blockSize int) []byte {
padLen := blockSize - (len(data) % blockSize)
out := make([]byte, len(data)+padLen)
copy(out, data)
for i := len(data); i < len(out); i++ {
out[i] = byte(padLen)
}
return out
}
func main() {
pub, _, err := generateKeypair(2048)
if err != nil {
panic(err)
}
file, err := os.CreateTemp("", "rsa-file-*.bin")
if err != nil {
panic(err)
}
defer os.Remove(file.Name())
file.WriteString("file payload")
file.Close()
payload, err := rsaEncryptFile(file.Name(), pub)
if err != nil {
panic(err)
}
fmt.Println(payload)
}Complete script (implementation + tests)
go
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"crypto/x509"
"encoding/base64"
"encoding/hex"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"hash"
"mime"
"os"
"path/filepath"
)
type HashAlg string
type CipherEncoding string
const (
HashSHA1 HashAlg = "SHA-1"
HashSHA256 HashAlg = "SHA-256"
HashSHA384 HashAlg = "SHA-384"
HashSHA512 HashAlg = "SHA-512"
)
const (
CipherHex CipherEncoding = "hex"
CipherBase64 CipherEncoding = "base64"
)
type FilePackage struct {
Version int `json:"version"`
Hash string `json:"hash"`
Mode string `json:"mode"`
IV string `json:"iv"`
EncryptedKey string `json:"encryptedKey"`
Ciphertext string `json:"ciphertext"`
OriginalName string `json:"originalName"`
MimeType string `json:"mimeType"`
}
func hashFactory(alg HashAlg) (hash.Hash, error) {
switch alg {
case HashSHA1:
return sha1.New(), nil
case HashSHA256:
return sha256.New(), nil
case HashSHA384:
return sha512.New384(), nil
case HashSHA512:
return sha512.New(), nil
default:
return nil, errors.New("unsupported hash")
}
}
func encodeCiphertext(data []byte, encoding CipherEncoding) string {
if encoding == CipherHex {
return hex.EncodeToString(data)
}
return base64.StdEncoding.EncodeToString(data)
}
func decodeCiphertext(value string, encoding CipherEncoding) ([]byte, error) {
if encoding == CipherHex {
return hex.DecodeString(value)
}
return base64.StdEncoding.DecodeString(value)
}
func generateRSAKeypair(bits int) (string, string, error) {
priv, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return "", "", err
}
privBytes := x509.MarshalPKCS1PrivateKey(priv)
privPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: privBytes})
pubBytes := x509.MarshalPKCS1PublicKey(&priv.PublicKey)
pubPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PUBLIC KEY", Bytes: pubBytes})
return string(pubPEM), string(privPEM), nil
}
func parsePublicKey(pemData string) (*rsa.PublicKey, error) {
block, _ := pem.Decode([]byte(pemData))
if block == nil {
return nil, errors.New("invalid public key PEM")
}
return x509.ParsePKCS1PublicKey(block.Bytes)
}
func parsePrivateKey(pemData string) (*rsa.PrivateKey, error) {
block, _ := pem.Decode([]byte(pemData))
if block == nil {
return nil, errors.New("invalid private key PEM")
}
return x509.ParsePKCS1PrivateKey(block.Bytes)
}
func rsaEncrypt(text, publicPEM string, hashAlg HashAlg, encoding CipherEncoding) (string, error) {
pub, err := parsePublicKey(publicPEM)
if err != nil {
return "", err
}
h, err := hashFactory(hashAlg)
if err != nil {
return "", err
}
ciphertext, err := rsa.EncryptOAEP(h, rand.Reader, pub, []byte(text), nil)
if err != nil {
return "", err
}
return encodeCiphertext(ciphertext, encoding), nil
}
func rsaDecrypt(ciphertext, privatePEM string, hashAlg HashAlg, encoding CipherEncoding) (string, error) {
priv, err := parsePrivateKey(privatePEM)
if err != nil {
return "", err
}
h, err := hashFactory(hashAlg)
if err != nil {
return "", err
}
cipherBytes, err := decodeCiphertext(ciphertext, encoding)
if err != nil {
return "", err
}
plain, err := rsa.DecryptOAEP(h, rand.Reader, priv, cipherBytes, nil)
if err != nil {
return "", err
}
return string(plain), nil
}
func pkcs7Pad(data []byte, blockSize int) []byte {
padLen := blockSize - (len(data) % blockSize)
out := make([]byte, len(data)+padLen)
copy(out, data)
for i := len(data); i < len(out); i++ {
out[i] = byte(padLen)
}
return out
}
func pkcs7Unpad(data []byte, blockSize int) ([]byte, error) {
if len(data) == 0 || len(data)%blockSize != 0 {
return nil, errors.New("invalid PKCS7 padding")
}
padLen := int(data[len(data)-1])
if padLen == 0 || padLen > blockSize {
return nil, errors.New("invalid PKCS7 padding")
}
for i := 0; i < padLen; i++ {
if data[len(data)-1-i] != byte(padLen) {
return nil, errors.New("invalid PKCS7 padding")
}
}
return data[:len(data)-padLen], nil
}
func rsaEncryptFile(path string, publicPEM string, hashAlg HashAlg) (string, error) {
data, err := os.ReadFile(path)
if err != nil {
return "", err
}
key := make([]byte, 32)
iv := make([]byte, 16)
if _, err := rand.Read(key); err != nil {
return "", err
}
if _, err := rand.Read(iv); err != nil {
return "", err
}
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
ciphertext := make([]byte, len(pkcs7Pad(data, block.BlockSize())))
cipher.NewCBCEncrypter(block, iv).CryptBlocks(ciphertext, pkcs7Pad(data, block.BlockSize()))
pub, err := parsePublicKey(publicPEM)
if err != nil {
return "", err
}
h, err := hashFactory(hashAlg)
if err != nil {
return "", err
}
encKey, err := rsa.EncryptOAEP(h, rand.Reader, pub, key, nil)
if err != nil {
return "", err
}
mimeType := mime.TypeByExtension(filepath.Ext(path))
if mimeType == "" {
mimeType = "application/octet-stream"
}
pkg := FilePackage{
Version: 1,
Hash: string(hashAlg),
Mode: "AES-256-CBC",
IV: hex.EncodeToString(iv),
EncryptedKey: base64.StdEncoding.EncodeToString(encKey),
Ciphertext: base64.StdEncoding.EncodeToString(ciphertext),
OriginalName: filepath.Base(path),
MimeType: mimeType,
}
payload, err := json.MarshalIndent(pkg, "", " ")
if err != nil {
return "", err
}
return string(payload), nil
}
func rsaDecryptFile(packageJSON string, privatePEM string, fallbackHash HashAlg) ([]byte, error) {
var pkg FilePackage
if err := json.Unmarshal([]byte(packageJSON), &pkg); err != nil {
return nil, err
}
hashAlg := HashAlg(pkg.Hash)
if hashAlg == "" {
hashAlg = fallbackHash
}
priv, err := parsePrivateKey(privatePEM)
if err != nil {
return nil, err
}
h, err := hashFactory(hashAlg)
if err != nil {
return nil, err
}
encKey, err := base64.StdEncoding.DecodeString(pkg.EncryptedKey)
if err != nil {
return nil, err
}
key, err := rsa.DecryptOAEP(h, rand.Reader, priv, encKey, nil)
if err != nil {
return nil, err
}
iv, err := hex.DecodeString(pkg.IV)
if err != nil {
return nil, err
}
ciphertext, err := base64.StdEncoding.DecodeString(pkg.Ciphertext)
if err != nil {
return nil, err
}
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
plaintext := make([]byte, len(ciphertext))
cipher.NewCBCDecrypter(block, iv).CryptBlocks(plaintext, ciphertext)
return pkcs7Unpad(plaintext, block.BlockSize())
}
func main() {
pub, priv, err := generateRSAKeypair(2048)
if err != nil {
panic(err)
}
ciphertext, err := rsaEncrypt("hello", pub, HashSHA256, CipherBase64)
if err != nil {
panic(err)
}
fmt.Println("cipher=", ciphertext)
plain, err := rsaDecrypt(ciphertext, priv, HashSHA256, CipherBase64)
if err != nil {
panic(err)
}
fmt.Println("plain=", plain)
file, err := os.CreateTemp("", "rsa-file-*.bin")
if err != nil {
panic(err)
}
defer os.Remove(file.Name())
file.WriteString("file payload")
file.Close()
packageJSON, err := rsaEncryptFile(file.Name(), pub, HashSHA256)
if err != nil {
panic(err)
}
plaintext, err := rsaDecryptFile(packageJSON, priv, HashSHA256)
if err != nil {
panic(err)
}
fmt.Println("file=", string(plaintext))
}