Skip to content

Instantly share code, notes, and snippets.

@julie-is-late
Created February 21, 2017 23:37
Show Gist options
  • Save julie-is-late/259a87a7146393aab5819873a193b88c to your computer and use it in GitHub Desktop.
Save julie-is-late/259a87a7146393aab5819873a193b88c to your computer and use it in GitHub Desktop.
How to load rsa keys in go
package config
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"io/ioutil"
"github.com/CodeCollaborate/Server/utils"
)
func rsaConfigSetup(rsaPrivateKeyLocation, rsaPrivateKeyPassword string) (*rsa.PrivateKey, error) {
if rsaPrivateKeyLocation == "" {
utils.LogWarn("No RSA Key given, generating temp one", nil)
return GenRSA(4096)
}
priv, err := ioutil.ReadFile(rsaPrivateKeyLocation)
if err != nil {
utils.LogWarn("No RSA private key found, generating temp one", nil)
return GenRSA(4096)
}
privPem, _ := pem.Decode(priv)
var privPemBytes []byte
if privPem.Type != "RSA PRIVATE KEY" {
utils.LogWarn("RSA private key is of the wrong type", utils.LogFields{
"Pem Type": privPem.Type,
})
}
if rsaPrivateKeyPassword != "" {
privPemBytes, err = x509.DecryptPEMBlock(privPem, []byte(rsaPrivateKeyPassword))
} else {
privPemBytes = privPem.Bytes
}
var parsedKey interface{}
if parsedKey, err = x509.ParsePKCS1PrivateKey(privPemBytes); err != nil {
if parsedKey, err = x509.ParsePKCS8PrivateKey(privPemBytes); err != nil { // note this returns type `interface{}`
utils.LogError("Unable to parse RSA private key, generating a temp one", err, utils.LogFields{})
return GenRSA(4096)
}
}
var privateKey *rsa.PrivateKey
var ok bool
privateKey, ok = parsedKey.(*rsa.PrivateKey)
if !ok {
utils.LogError("Unable to parse RSA private key, generating a temp one", err, utils.LogFields{})
return GenRSA(4096)
}
pub, err := ioutil.ReadFile(rsaPublicKeyLocation)
if err != nil {
utils.LogWarn("No RSA public key found, generating temp one", nil)
return GenRSA(4096)
}
pubPem, _ := pem.Decode(pub)
if pubPem == nil {
utils.LogError("Use `ssh-keygen -f id_rsa.pub -e -m pem > id_rsa.pem` to generate the pem encoding of your RSA public key",
errors.New("rsa public key not in pem format"), utils.LogFields{
"Public key location": rsaPublicKeyLocation,
})
return GenRSA(4096)
}
if pubPem.Type != "RSA PUBLIC KEY" {
utils.LogWarn("RSA public key is of the wrong type", utils.LogFields{
"Pem Type": pubPem.Type,
})
return GenRSA(4096)
}
if parsedKey, err = x509.ParsePKIXPublicKey(pubPem.Bytes); err != nil {
utils.LogError("Unable to parse RSA public key, generating a temp one", err, utils.LogFields{})
return GenRSA(4096)
}
var pubKey *rsa.PublicKey
if pubKey, ok = parsedKey.(*rsa.PublicKey); !ok {
utils.LogError("Unable to parse RSA public key, generating a temp one", err, utils.LogFields{})
return GenRSA(4096)
}
privateKey.PublicKey = pubKey
return privateKey, nil
}
// GenRSA returns a new RSA key of bits length
func GenRSA(bits int) (*rsa.PrivateKey, error) {
key, err := rsa.GenerateKey(rand.Reader, bits)
utils.LogFatal("Failed to generate signing key", err, nil)
return key, err
}
@colm-anseo
Copy link

Nice work!

FYI L25 should be followed with a if privPem == nil error check. If bad key-bytes are passed to Decode, it returns nil, and will thus cause the privPem.Type reference to panic.

@yookoala
Copy link

yookoala commented Sep 30, 2020

If you want to generate a key pair for this with openssl, use the old genrsa subcommand, for example:

openssl genrsa -aes256 -out private.key 8192
openssl rsa -in private.key -pubout -out public.key

Do not use the new genpkey subcommand, for example:

openssl genpkey -algorithm RSA -aes256 -pkeyopt rsa_keygen_bits:8192 -out private.pem
openssl rsa -in private.pem -pubout -outform PEM -out public.pem

While both command generates RSA key pair, the key file format is different.

openssl genrsa generates private key as pkcs#1 block, which formats like this:

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,1DA219DB746F88C6DDA0D852A0FD3232

AEf09rGkgGEJ79GgO4dEVsArwv4IbbODlxy95uHhfkdGYmuk6OlTpiCUE0GT68wn
KFJfBcHr8Z3VqiHGsXxM5QlKhgnfptxfbrdKErgBD5LQcrvnqmf43KeD4lGQcpiy
...
...
mAKMCwiU/GKZz8ZwQ4qGkBlVVCOFfgwmfbqguJF2l8yzM8lYI9MZ9NEwKkvEbc
-----END RSA PRIVATE KEY-----

openssl genpkey generates private key as pkcs#8 block, which formats like this:

-----BEGIN ENCRYPTED PRIVATE KEY-----
MIISrTBXBgkqhkiG9w0BBQ0wSjKpBgkqhkiG9w0BBQwwHAQIKL+ordsVfqsCAggB
MAwGCCqGSIb3DQIJCQAwHQYJYIZIWAUDBAEqBBCipOAAxWkC0/zkNLNYTSMgBIIS
...
...
zfdxjZ0XmPiwED2azsLMnRrWnRj2UqMtnv9zO/ucik9za
-----END ENCRYPTED PRIVATE KEY-----

The function x509.DecryptPEMBlock only works with pkcs#1. If you provide it with a pkcs#8 block, it would give you an error: "x509: no DEK-Info header in block".

As specified in #8860, the core library has no real plan to support pkcs#8 in the near future. If you want to work with it, you'll have better luck with 3rd party library like github.com/youmark/pkcs8 (Documentation).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment