I'm using crypto/rsa
, and trying to find a way to properly save and load a key. Is there a correct way to create a []byte
from an rsa.PrivateKey
. If so, is there a way to properly do so for an rsa.PublicKey
?
Thank you all very much.
You need some sort of format to marshal the key into. One format supported by the Go standard library can be found here: http://golang.org/pkg/crypto/x509/#MarshalPKCS1PrivateKey
func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte
The inverse function is http://golang.org/pkg/crypto/x509/#ParsePKCS1PrivateKey.
func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err error)
However, it is relatively standard to encode the marshaled key into a PEM file.
pemdata := pem.EncodeToMemory( &pem.Block{ Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key), }, )
You can find a full example here.
Here's code snippet that shows the import and export of both public and private keys. It's based on the other answers which were super helpful, as well as copy-pasta from the official docs.
package main import ( "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/pem" "errors" "fmt" ) func GenerateRsaKeyPair() (*rsa.PrivateKey, *rsa.PublicKey) { privkey, _ := rsa.GenerateKey(rand.Reader, 4096) return privkey, &privkey.PublicKey } func ExportRsaPrivateKeyAsPemStr(privkey *rsa.PrivateKey) string { privkey_bytes := x509.MarshalPKCS1PrivateKey(privkey) privkey_pem := pem.EncodeToMemory( &pem.Block{ Type: "RSA PRIVATE KEY", Bytes: privkey_bytes, }, ) return string(privkey_pem) } func ParseRsaPrivateKeyFromPemStr(privPEM string) (*rsa.PrivateKey, error) { block, _ := pem.Decode([]byte(privPEM)) if block == nil { return nil, errors.New("failed to parse PEM block containing the key") } priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { return nil, err } return priv, nil } func ExportRsaPublicKeyAsPemStr(pubkey *rsa.PublicKey) (string, error) { pubkey_bytes, err := x509.MarshalPKIXPublicKey(pubkey) if err != nil { return "", err } pubkey_pem := pem.EncodeToMemory( &pem.Block{ Type: "RSA PUBLIC KEY", Bytes: pubkey_bytes, }, ) return string(pubkey_pem), nil } func ParseRsaPublicKeyFromPemStr(pubPEM string) (*rsa.PublicKey, error) { block, _ := pem.Decode([]byte(pubPEM)) if block == nil { return nil, errors.New("failed to parse PEM block containing the key") } pub, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { return nil, err } switch pub := pub.(type) { case *rsa.PublicKey: return pub, nil default: break // fall through } return nil, errors.New("Key type is not RSA") } func main() { // Create the keys priv, pub := GenerateRsaKeyPair() // Export the keys to pem string priv_pem := ExportRsaPrivateKeyAsPemStr(priv) pub_pem, _ := ExportRsaPublicKeyAsPemStr(pub) // Import the keys from pem string priv_parsed, _ := ParseRsaPrivateKeyFromPemStr(priv_pem) pub_parsed, _ := ParseRsaPublicKeyFromPemStr(pub_pem) // Export the newly imported keys priv_parsed_pem := ExportRsaPrivateKeyAsPemStr(priv_parsed) pub_parsed_pem, _ := ExportRsaPublicKeyAsPemStr(pub_parsed) fmt.Println(priv_parsed_pem) fmt.Println(pub_parsed_pem) // Check that the exported/imported keys match the original keys if priv_pem != priv_parsed_pem || pub_pem != pub_parsed_pem { fmt.Println("Failure: Export and Import did not result in same Keys") } else { fmt.Println("Success") } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With