sourcegraph/internal/encryption/rsa.go
2022-02-07 15:03:45 +00:00

69 lines
1.6 KiB
Go

package encryption
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"github.com/google/uuid"
"golang.org/x/crypto/ssh"
"github.com/sourcegraph/sourcegraph/lib/errors"
)
// MockGenerateRSAKey can be used in tests to speed up key generation.
var MockGenerateRSAKey func() (key *RSAKey, err error) = nil
type RSAKey struct {
PrivateKey string
Passphrase string
PublicKey string
}
// GenerateRSAKey generates an RSA key pair and encrypts the
// private key with a passphrase.
func GenerateRSAKey() (key *RSAKey, err error) {
if MockGenerateRSAKey != nil {
return MockGenerateRSAKey()
}
// First generate the private key.
privateKey, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
return nil, errors.Wrap(err, "generating private key")
}
// Then generate a UUID, which we'll use as the passphrase.
randID, err := uuid.NewRandom()
if err != nil {
return nil, errors.Wrap(err, "generating passphrase")
}
passphrase := randID.String()
// And encrypt the private key using that pass phrase.
//nolint:staticcheck // See issue #19489
block, err := x509.EncryptPEMBlock(
rand.Reader,
"RSA PRIVATE KEY",
x509.MarshalPKCS1PrivateKey(privateKey),
[]byte(passphrase),
x509.PEMCipherAES256,
)
if err != nil {
return nil, errors.Wrap(err, "encrypting private key")
}
// And generate an openSSH public key.
publicKey, err := ssh.NewPublicKey(&privateKey.PublicKey)
if err != nil {
return nil, err
}
return &RSAKey{
PrivateKey: string(pem.EncodeToMemory(block)),
Passphrase: passphrase,
PublicKey: string(ssh.MarshalAuthorizedKey(publicKey)),
}, nil
}